From 47001fa250d2d8af27e01e4d1b45cd6c85f5f586 Mon Sep 17 00:00:00 2001 From: acn Date: Fri, 30 Aug 2019 10:12:36 +0200 Subject: [PATCH] Original version --- Original/backgmmn.c | 2278 +++++++++++++++++++++++++++++++++++++++++ Original/backgmmn.com | Bin 0 -> 30976 bytes Original/backgmmn.lbr | Bin 0 -> 69888 bytes Original/backgmmn.sub | 14 + Original/gameplan.c | 866 ++++++++++++++++ Original/gameplan.hdr | 42 + Original/mylib2.c | 541 ++++++++++ Original/read.me | 56 + 8 files changed, 3797 insertions(+) create mode 100644 Original/backgmmn.c create mode 100644 Original/backgmmn.com create mode 100644 Original/backgmmn.lbr create mode 100644 Original/backgmmn.sub create mode 100644 Original/gameplan.c create mode 100644 Original/gameplan.hdr create mode 100644 Original/mylib2.c create mode 100644 Original/read.me diff --git a/Original/backgmmn.c b/Original/backgmmn.c new file mode 100644 index 0000000..ff20aed --- /dev/null +++ b/Original/backgmmn.c @@ -0,0 +1,2278 @@ +/* backgmmn.c */ + +/*************************************************************************** + + GAMMON IV, Version 2 + + Author: David C. Oshel + 1219 Harding Avenue + Ames, Iowa 50010 + + Date: March 26, 1986 + + Gammon IV is probably the best backgammon game currently available for + CP/M. I wrote it because I was disgusted with the price and dullness + of all other programs which allegedly play backgammon on CP/M systems. + + This program has THREE DIFFERENT PLAYING STYLES, any one of which can + consistently beat a novice player, and occasionally beat a good player. + In all three levels, the computer's strategy can even seem brilliant; + there is nothing routine about it. + + This version incorporates a few minor changes and bug fixes which make it + different from previous editions which have appeared on various bulletin + boards and club offerings around the country. This is a public domain + program. Feel free to distribute or improve it. Credit to the original + author (me) will be appreciated, but is not strictly required since the + copyright owners are abnormally mild-mannered (and extremely distant; + see Acknowledgments, below.) + + Version 2: + + a) Fixed the bug in which the doubling cube might revert to its + default value if the computer took back a move, and if the cube + had been doubled one or more times during the opening roll-off + but not yet offered. + + b) Fixed an odd bug in the Arrange command which occasionally caused + stones to switch allegiance to the opponent's color, or else to + mysteriously multiply to more than 15 on a side. + + c) An improved error handler now hints that BAR and HOME are words + used in the game; also, slows down the incorrect entry routine so + that it is less mysterious than before. + + d) Added a Graphic toggle to main command line. Same as Control-K, + as in previous versions; turns on/off the Kaypro '84 video graphics; + uses the alternate token set defined in the CRT module below. + + e) Changed the break character back to Control-C. The proximity of + the ESCAPE key to the 1 digit on the Kaypro keyboard sometimes + caused a game to be inadvertently paused during play. + + f) There is no longer a sanction against cheating; if you type + Control-C during play and re-Arrange the stones, your opponent + does not change. + + g) As before, the computer will not always take (or find) a forced + move. The rule is that the player must take both dice if possible, + or the larger if both are possible singly but not together. + The playing algorithm attempts to find the legally required move, + but will sometimes fail. It is sometimes advantageous to avoid a + forced move but the computer cannot make that distinction, in this + version; the program allows the same lenience for the human player. + + The cube is doubled when doubles are thrown during the opening + rolloff to decide who goes first. However, if the cube reaches 8, + further pairs on the dice during rolloff have no effect. + + Gammon IV knows all the other OFFICIAL rules of the game; + U.S. Navy and/or Saloon rules don't count. + + h) Improved coding in some routines, especially putstone(), which was + far more baroque than necessary. There is also some occasional + re-coding, where I could not prevent myself. The game strategy + has not been changed, mostly because I don't fully understand it + anymore, even though the documentation there is better than usual. + It was written months ago in a white heat of inspiration; but I + feel reluctant to submit myself to that strain again, without the + prospect of remuneration. + + + Acknowledgments: + + The opening dialogue, in which you chose your computer opponent, + is freely adapted from Alexei Panshin's long out-of-print, and + now classic, "Star Well" travelogues. Scholars of computer history + will recognize many allusions to this same opus in various passages + of Mike Goetz's 550-point Adventure (especially in the Ice Caverns!). + + The Xochitl Sodality, which owns the copyright on Gammon IV, is a + philanthropic society first publicized by Panshin. Persons who wish + to obtain information on site licensing for Gammon IV should contact + the Monist Association imaginary properties secretary at the following + address: + Monist Association I.P.S. + c/o Xochitl Sodality + Semichastny House + Delbalso, Nash. Emp. + + + Special Instructions: + + Terminal must be Lear-Siegler ADM-3A compatible, or else have + the same graphics capability as a Kaypro 10, 2X or 4'84. This + requirement is fully configurable in the video section below, + however. + + This program requires the Software Toolworks' C/80 v3.1 compiler + for CP/M 2.2. C/80 has a configuration program. C/80 must be + configured as follows, or else this program WILL NOT compile: + + Symbol table size: 512 + String constant table: 3200 + Dump constants after each routine: YES + Macro table size: 500 + Switch table size: 128 + Structure table size: 200 + Merge duplicate string constants: YES +NB: Assembler: C/80's AS + Initialize arrays to zero: < 256 BYES ONLY + Generate ROMable code in Macro-80: YES + Screen size: 24 (doesn't matter) + Generate slightly larger, faster code: NO + Sign extension on char to int conversion: YES + Device for library files: A: (your choice) + + Compilation: + +NB: Microsoft's MACRO-80 assembler and LINK-80 linker are required, + and are specified in the (-m) compiler switch! This is a moderately + complex compile, so the procedure is directed by batch SUBMIT files. + Distribute files as follows: + + On Drive A: + + BACKGMMN.C, BACKGMMN.SUB, CLIBRARY.REL, GAMEPLAN.C, + GAMEPLAN.HDR, MYLIB2.C, PRINTF.C, STDLIB.REL, SUBMIT.COM + + On Drive B: + + C.COM, L80.COM, M80.COM, WS.COM, WSMSGS.OVR, WSOVLY1.OVR + + Then, SUBMIT BACKGMMN to compile, assemble & link the game. You will + need about 180k of free space on Drive A. + + You must pay strict attention to the Special Instructions above, + regarding C/80 configuration. + + + Absent Files: + + M80.COM and L80.COM are from Microsoft, and are not part + of this distribution. C.COM, STDLIB.REL, CLIBRARY.REL and + PRINTF.C are from Software Toolworks, and are not part of + this distribution either. SUBMIT.COM is a CP/M transient + command; it came with your computer when you bought it. + + + Notes: + + Gammon IV is impossible to implement in any C which does not allow + functions to be passed as parameters to another function -- K & R must + be followed on this point! + + THIS CODE ASSUMES INTEL 8080 CPU. Inline code simulates an old, + archaic version of SetJump() and LongJump(), which are not features + of C/80 3.1. Use of inline code means you need 8080 compatibility. + + By isolating the game-playing algorithm into a separately compiled + module, I have allowed for the possibility that someone else may come + up with significant improvements in strategy, AND BE GIVEN CREDIT FOR + THEM, without having to re-design primitive parts of the program. + + The single exception to this rule is the code which decides when the + computer will offer, accept or reject the doubling cube; that is + considered primitive, even though the cube is a major factor in human + strategies when playing for blood or money. Gammon IV always plays + for the simple fun of aggravating humans, so cube tactics are neither + daring nor profound. Gammon IV does not bluff with the cube; if it + offers the cube, it is almost sure to win. + +*****************************************************************************/ + +#define TRUE 1 +#define FALSE 0 +#define ME 1 +#define YU 2 +#define YRBAR 0 +#define MYBAR 25 +#define YRHOME 26 +#define MYHOME 27 +#define ERROR 999 /* anything well out of range */ +#define MYLEVEL 2 + +/* put CRT stuff first so version differences won't affect it */ +#asm +; +; Note: Assumes assembly by M80.COM +; +; *========================= CRT Module =========================* +; * * +; * User Patch Area: ALL DB STRINGS MUST TERMINATE WITH A NULL * +; * Use contiguous data area for all console functions, so user * +; * may configure the program for some terminal not a Kaypro 10 * +; * * +; * CLEAR SCREEN and GOTOXY are Required Minimum Functions * +; * CRTNIT, CRTXIT, CURSON, CURSOF are Optional and Recommended * +; * * +; * The tokens TK1..TK4 comprise two sets each of playing tokens * +; * for the computer & human player. 24 bytes are reserved for * +; * EACH token, so that users may turn on video enhancements -- * +; * see the Kaypro '84 recommended settings for examples. * +; * * +; * The tokens TK5..TK8 and the KRTNIT, etc. strings implement * +; * the Control-K command to toggle the Kaypro '84 display. * +; * These should only be patched if you are configuring for two * +; * levels of terminal characteristics, as vis-as-vis the "old" * +; * and "new" Kaypro terminals. These two levels must use the * +; * same basic protocols for cursor address and clear screen. * +; * * +; * Command Strings must terminate with 0, and the 0 byte CANNOT * +; * be sent to the console. 0 is INCLUDED in the reserved area. * +; * * +; * GAMMON IV no longer uses any console command function not * +; * specifically mentioned here. In particular, the clear-to- * +; * end-of-line function is now handled in a more general way. * +; *==============================================================* +; +; Gammon IV.09 (Universal Version) User Patch Area, D.C.OSHEL, 6/15/85 +;---------------------------------------------------------------------------- +; +; * REQUIRED * +; reserve 24 bytes apiece for the players' tokens (must terminate with 0) +; these settings are recommended for Lear Siegler ADM-3A (old Kaypros) +; + DB 'USER PATCH AREA ' + DB 'ALL STRINGS MUST HAVE ZERO TERMINATOR->' + DB 'TOKEN1:' +TK1: DB '(',')',0,0,0,0,0,0 ; computer's token, () + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + DB 'TOKEN2:' +TK2: DB '[',']',0,0,0,0,0,0 ; player's token, [] + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + DB 'TOKEN3:' +TK3: DB 'q','b',0,0,0,0,0,0 ; computer's token (alternate, qb ) + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + DB 'TOKEN4:' +TK4: DB 'C','3',0,0,0,0,0,0 ; player's token (alternate, C3 ) + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +;---------------------------------------------------------------------------- +; +; * Optional * +; reserve 8 bytes apiece for the OPTIONAL console function strings +; patch the first byte to 0 for each function NOT implemented +; + DB 'CRTNIT:' +CRTNIT: DB 0,0,0,0,0,0,0,0 ; crt init, e.g., video mode on + DB 'CRTXIT:' +CRTXIT: DB 0,0,0,0,0,0,0,0 ; crt exit, e.g., video mode off + DB 'CURSON:' +CURSON: DB 0,0,0,0,0,0,0,0 ; cursor ON (show cursor) + DB 'CURSOF:' +CURSOF: DB 0,0,0,0,0,0,0,0 ; cursor OFF (hide cursor) +;---------------------------------------------------------------------------- +; +; * REQUIRED * +; clear screen and gotoxy (0,0 is top left of screen) are NOT optional +; default settings are for the Lear Siegler ADM-3A terminal (old Kaypros) +; + DB 'CLS->' +CLS: DB 26,0,0,0,0,0,0,0 ; clear screen command + DB 'GOTOXY->' +GOXY: DB 27,'=',0,0,0,0,0,0 ; cursor address prefix + DB 'YB4X BYTE:' +YB4X: DB 1 ;BYTE 1 = YX: Send Row, Then Col (ADM-3A); 0 = XY: Col, Row + DB 'XOFS BYTE:' +XOFS: DB 32 ;BYTE offset to add to x in gotoxy sequence (ADM-3A = 20H) + DB 'YOFS BYTE:' +YOFS: DB 32 ;BYTE offset to add to y in gotoxy sequence (ADM-3A = 20H) +; +; these strings must terminate with 0, and 8 bytes are reserved for each +; +; +;---------------------------------------------------------------------------- +;: The following strings implement the Control-K command for Kaypro '84 +;: video able terminals. +;---------------------------------------------------------------------------- +;: +;: * Kaypro '84 * +;: recommended tokens for the video able Kaypro '84s (10s, 4'84s, etc) +;: the second set requires that "video mode" be set in the CRTNIT string +;: the first set uses Kaypro underline, inverse and low intensity commands +;: to form the players' stones (24 bytes are reserved for each token) +;: + DB 'ENHANCED ALTERNATES->' + DB 'TOKEN5:' +TK5: DB 27,'B1' ; computer's token + DB 27,'B0' + DB 27,'B3' + DB '><' + DB 27,'C3' + DB 27,'C0' + DB 27,'C1' + DB 0,0,0,0 + DB 'TOKEN6:' +TK6: DB 27,'B3' ; player's token + DB 27,'B0' + DB '[]' + DB 27,'C0' + DB 27,'C3' + DB 0,0,0,0,0,0,0,0,0,0 + DB 'TOKEN7:' +TK7: DB 128,233,129,150,0,0,0,0 ; computer's "black chiclet" + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + DB 'TOKEN8:' +TK8: DB 128,253,129,190,0,0,0,0 ; player's "white chiclet" + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +; +;---------------------------------------------------------------------------- +;: +;: * Kaypro '84 * +;: recommended settings for Kaypro '84s (strings must terminate with 0) +;: + DB 'KRTNIT:' +KRTNIT: DB 27,'B5',0,0,0,0,0 ; crt init, e.g., video mode on + DB 'KRTXIT:' +KRTXIT: DB 27,'C5',0,0,0,0,0 ; crt exit, e.g., video mode off + DB 'KURSON:' +KURSON: DB 27,'B4',0,0,0,0,0 ; cursor ON (show cursor) + DB 'KURSOF:' +KURSOF: DB 27,'C4',0,0,0,0,0 ; cursor OFF (hide cursor) + DB '<-END USER PATCH AREA' +;---------------------------------------------------------------------------- +; LOF LG +#endasm + +static int kaypro; + +get1tkn() { +#asm + LXI H,TK1 ;load string pointer for token 1 +#endasm +} + +get2tkn() { +#asm + LXI H,TK2 ;load string pointer for token 2 +#endasm +} + +get3tkn() { +#asm + LXI H,TK3 ;load string pointer for token 3 +#endasm +} + +get4tkn() { +#asm + LXI H,TK4 ;load string pointer for token 4 +#endasm +} + +get5tkn() { +#asm + LXI H,TK5 ;load string pointer for token 1 +#endasm +} + +get6tkn() { +#asm + LXI H,TK6 ;load string pointer for token 2 +#endasm +} + +get7tkn() { +#asm + LXI H,TK7 ;load string pointer for token 3 +#endasm +} + +get8tkn() { +#asm + LXI H,TK8 ;load string pointer for token 4 +#endasm +} + +getcls() { +#asm + LXI H,CLS +#endasm +} + +getcini() { +#asm + LXI H,CRTNIT +#endasm +} + +getcxit() { +#asm + LXI H,CRTXIT +#endasm +} + +getcof() { +#asm + LXI H,CURSOF +#endasm +} + +getcon() { +#asm + LXI H,CURSON +#endasm +} + +getkini() { +#asm + LXI H,KRTNIT +#endasm +} + +getkxit() { +#asm + LXI H,KRTXIT +#endasm +} + +getkof() { +#asm + LXI H,KURSOF +#endasm +} + +getkon() { +#asm + LXI H,KURSON +#endasm +} + +gotoxy(x,y) int x,y; { /* this is solid gold! */ +#asm + POP H ; get return address + POP D ; get Y + POP B ; get X + PUSH B ; restore all to keep C happy + PUSH D ; ditto + PUSH H ; ditto +; + LXI H,GOXY ; blast out the prefix + CALL STOUT +; + LDA YB4X ; sending row, i.e. Y, first? + ORA A + JZ @X1 ; no, do it the other way +; + LDA YOFS ; yes indeed, here's Y + ADD E + CALL COUT +; + LDA XOFS ; and here's X + ADD C + CALL COUT + RET ; thank you very much, we're done + +@X1: LDA XOFS ; your weird terminal wants X first? ok + ADD C + CALL COUT +; + LDA YOFS ; now Y + ADD E + CALL COUT + RET ; tyvm, we done +; +STOUT: MOV A,M ; string pointer in HL on entry, trash A, HL + ORA A + RZ + CALL COUT + INX H + JMP STOUT +; +COUT: PUSH H ; char in A on entry, disturb nothing + PUSH D + PUSH B + PUSH PSW + MVI C,6 + MOV E,A + CALL 5 + POP PSW + POP B + POP D + POP H + RET +#endasm +/* using this C code instead of inline will slow things down perceptibly */ +/* puts( getprfx() ); + if ( ybefore() ) { + putc(y + getyofs(),0); putc(x + getxofs(),0); + } + else { + putc(x + getxofs(),0); putc(y + getyofs(),0); + } +*/ +} /* end: gotoxy */ + + +crtinit() { + if (kaypro) puts( getkini() ); + else puts ( getcini() ); +} /* here, turn 2 byte graph chars on */ + +crtexit() { + if (kaypro) puts( getkxit() ); + else puts ( getcxit() ); +} /* and off again on exit... */ + +clr_screen() { puts ( getcls() ); } /* standard */ + +on_cursor() { + if (kaypro) puts( getkon() ); + else puts ( getcon() ); +} /* optional "hide cursor" command */ + +off_cursor() { + if (kaypro) puts( getkof() ); + else puts ( getcof() ); +} /* optional "show cursor" command */ + + +#include "printf.c" + +extern char *bgversion; + +char *backtalk[] = { + "VILLIERS: At your service!", + "LOUISA: Delighted!", + "TORVE: Is interesting line of occurrence. Thurb!", + "Copyright (c) 1985 by The Xochitl Sodality Wonders & Marvels Committee", + }; + +int list[2][28]; /* two dice, two lists */ + +struct board { + int stones, /* number of stones on that point */ + owner, /* and whose they are */ + x,y, /* x and y coordinates of point base */ + lastx,lasty, /* last location drawn on this point */ + cx,cy; /* coordinates for column numbers */ + } + point[28], bdsave[28]; /* 24 points, plus 2 bars, 2 homes */ + + +struct { int cube, whosecube; } doubles; + + +struct { int fr,to,flag; } pending; + + +int level, dice[2], myscore, yrscore, player, movesleft, cantuse, myturns, + swapped, tswap, deciding, expert, tone, show, moremsgline, + firstmove, helpdisabled, yrdice, lookforit, startcubevalue; + +char *token1, *token2, chatter[80], buzzard[8]; + +/*====================================================================== + + OPPONENT -- A little scenario, in which to select level of play + +========================================================================*/ + + +char *chooseplayer() { +int ch; char *q; + + dissemble(); +loo: ch = getkey(); + switch (ch) { + case 'A': + case 'V': { level = 0; break; } + case 'L': + case 'P': { level = 1; break; } + case 'T': { level = 2; break; } + default: goto loo; + } + q = backtalk[ level ]; + clr_screen(); draw_board(q); + return(q); + +} /* end: chooseplayer */ + +/*==================================================================== + MAIN +======================================================================*/ + +main() { +static int ch; +static char *p1 = "P(lay, R(everse, S(wap, A(rrange, N(ew, G(raphic, Q(uit ", + *p2 = "U(se %s dice, O(pponent, X(pert, B(eep, C(ount, Z(ero ", + *myline; + + level = MYLEVEL + 1; /* fetch copyright notice */ + setup(); + hint(); + + while (TRUE) { + moremsgline = FALSE; /* show first command line on entry */ + debug(""); /* erase messages */ + myline = backtalk[ level ]; /* did level change? */ + msg( myline ); + firstmove = TRUE; + newboard(); /* note, sets starting cube value to 1 */ + + deciding = TRUE; + while (deciding) { + + /* display command line */ + + off_cursor(); + if (show) { mytotal(); yrtotal(); } + else { gotoxy(0,3); puts(" "); gotoxy(0,19); puts(" "); } + if (tone) beep(); + if (expert) msg("Your pleasure? "); + else { + msg("Select: "); + if (moremsgline) printf(p2,(yrdice? "my": "your")); + else printf(p1); + } + + /* get response and do it */ + + + ch = getkey(); + switch (ch) { + case 'Q': { /* quit play, exit to CP/M */ + finishup(); + break; + } + case 'A': { /* arrange stones (or cheat?) */ + /* play is suspended, so don't use the long */ + /* messages that assist game play */ + helpdisabled = TRUE; + arrange(); + update(); + debug(""); + break; + } + case 'R': { /* mirror board image */ + reverse(); + update(); + break; + } + case 'C': { /* show mytotal, yrtotal counts */ + show ^= TRUE; + break; + } + case 'S': { /* SWAP Command - exchange stones */ + swaptokens(); + update(); + break; + } + case 'B': { /* kill the beep */ + tone ^= TRUE; break; + } + case 'X': /* expert mode toggle(s) */ + case 27 : { + expert ^= TRUE; + break; + } + case 'D': { /* use my dice or your dice? */ + case 'U': + yrdice ^= TRUE; + break; + } + case 'O': { /* change opponents and skill level */ + myline = chooseplayer(); + deciding = FALSE; + break; + } + case 'P': { /* play the game as board is arranged */ + helpdisabled = FALSE; + if (level > MYLEVEL ) { + myline = chooseplayer(); + update(); + } + play(); + break; + } + case 'G': /* graphic screen switch, same as: */ + case 11: { /* control-K, toggle Kaypro '84 display */ + crtexit(); + kaypro ^= TRUE; + crtinit(); + swaptokens(); swaptokens(); + swaptokens(); swaptokens(); + update(); + break; + } + case 'N': { /* abandon game without quitting */ + deciding = FALSE; player = 0; + break; + } + case 'Z': { /* zero the score */ + myscore = yrscore = 0; putscore(); + break; + } + default: { moremsgline ^= TRUE; break; } + }} + } +} /* end: main */ + + + + +/*======================================================================= + + PLAY Command - this is the command that initiates the 2-player game + +=========================================================================*/ + +play() { + +/* any vars here MUST be STATIC */ + +#asm + MOV B,H ;set up to exit this function by saving caller's + LXI H,0 ;stack pointer for use in deeply-nested scope + DAD SP ;WARNING: this function must not use dynamic variables + SHLD _fool ;CAUTION: risky business if called with parameters?? + MOV H,B ;HL is restored on general principles, BC is trashed +#endasm + + whofirst(); + taketurns(); + +} /* end: play */ + + + +whofirst() { +int ch, myval, yrval; + + if (yrdice || (player < 0)) { /* board has been re-arranged */ + msg("Is it my "); puts(token1); + puts(" turn or your "); puts(token2); + puts(" turn? "); + loo: ch = toupper(getc(0)); + if (!(ch == 'M' || ch == 'Y')) goto loo; + if (ch == 'M') player = YU; /* player says Me, of course! */ + else player = ME; + rolldice(player); + } + + else if (player == 0) { /* fresh start, roll the dice */ + barcube(); + zoo: debug("Tossing for first turn..."); + wipedice(); + rolldice(ME); + myval = dice[0]; + rolldice(YU); + yrval = dice[0]; + if (myval == yrval) { + if (tone) beep(); + off_cursor(); + gotoxy(37,11); puts("[___]"); sleep(3); + startcubevalue *= 2; + if (startcubevalue > 8) startcubevalue = 8; + doubles.cube = startcubevalue; + gotoxy(37,11); + if (doubles.cube < 16) printf("[ %d ]",doubles.cube); + else printf("[%03d]",doubles.cube); + if (startcubevalue < 9) { + msg("Double the cube!"); + sleep(20); + } + goto zoo; + } + else if (myval < yrval) player = YU; + else player = ME; + dice[0] = max(myval,yrval); dice[1] = min(myval,yrval); + } + /* otherwise, continue with last dice rolled as play is resumed */ + +} /* end: whofirst */ + + +getmove() { +static int i, ch, temp, happy; + + cantuse = ERROR; /* important for human player in tellmove */ + movesleft = 2; + if (dice[0] == dice[1]) movesleft += 2; + temp = movesleft; + + getlist(); saveboard(); lookforit = TRUE; + + if ( nomove() ) { + debug("All "); + if (player == ME) puts("my"); else puts("your"); + puts(" moves are blocked!"); + if (player == YU) sleep(20); + return; + } + + + if (player == ME) { + /* handle doubles as two consecutive, independent moves */ + setchat("I move"); debug(chatter); + if (movesleft == 4) myturns = 2; else myturns = 1; + clrpend(); + while (myturns > 0) { + cantuse = ERROR; + movesleft = 2; + while (movesleft > 0) { getlist(); mymove(); } + myturns--; + } + strcat(chatter,"\008."); debug(chatter); + } + else { /* allow the human to take back a bad board position */ + happy = FALSE; + while (!happy) { + while (movesleft > 0) { getlist(); yrmove(); } + msg("All ok? Y/N "); + do { + ch = getkey(); + } while (ch != 'N' && (ch != 'Y' && ch != '\n')); + if ( ch == 'N' ) { + msg("Ok, as it was..."); + restoreboard(); + update(); + movesleft = temp; + cantuse = ERROR; + } + else happy = TRUE; + debug(""); + } + } + +} /* end: getmove */ + + + +taketurns() { + + while (TRUE) { /* NO EXIT! Only a Win or player ESC can exit */ + + getmove(); + player = other(player); + if ( player == ME ) { + if ( endgame() ) { + if (topstone(ME) < 6 && cubeval()) idouble(); + else if ( mytotal() < (yrtotal() - 8) ) { + idouble(); + } + } + else if ( bearoff() ) idouble(); + } + rolldice (player); + } + +} /* end: taketurns */ + + + + + +/*=============================================*/ +/* Y O U R M O V E */ +/*=============================================*/ + +tellmove() { /* show what the player's current dice are */ +int k,n; + + n = movesleft; + debug("You "); + if (!expert) { puts(token2); puts(" "); } + puts("have "); + while (n--) { + if (dice[0] == dice[1]) k = dice[0]; /* doubles? */ + + else if (cantuse == 1) k = dice[0]; + else if (cantuse == 0) k = dice[1]; + else if (n == 1) k = dice[1]; /* 2 of 2? */ + else k = dice[0]; /* 1 of 2? */ + + printf("[%d] ",k); + } + puts("left"); + if (expert) puts("."); else puts(", moving from high to low."); + +} /* end: tellmove */ + + + +yrmove() { + + if ( nomove() ) { + debug("You have no more moves in this line of play."); + movesleft = 0; + return; + } + else { +loo: tellmove(); + if (!getyrmove()) { + hint(); + goto loo; + } + debug(""); + } + +} /* end: yrmove */ + + + +hint() { + if (!expert) { + debug("HELP, BAR and HOME are useful words in this game."); + sleep(10); + } +} /* end: hint */ + + + +nomove() { +int i,j; + for (i = 0; i < 2; i++) + for (j = 0; j < 28; j++) + if (list[i][j] != ERROR) return (FALSE); + return (TRUE); +} /* end: nomove */ + + + +getyrmove() { +int fpoint, tpoint; + + + firstmove = FALSE; /* I got it, I got it! */ + + msg("Move from? "); + fpoint = getpt(YRBAR,YRHOME); + if ( fpoint == ERROR || + (list[0][fpoint] == ERROR && list[1][fpoint] == ERROR)) { + return (FALSE); + } + puts(" To? "); + tpoint = getpt(YRBAR,YRHOME); + if ( tpoint == ERROR || + (list[0][fpoint] != tpoint && list[1][fpoint] != tpoint)) { + return (FALSE); + } + + movestone( fpoint, tpoint ); + if (movesleft < 2) { + if (list[0][fpoint] == tpoint) cantuse = 0; + else cantuse = 1; + } + return (TRUE); + +} /* end: getyrmove */ + + + +/*====== Functions That Make The Selected Move ======*/ + + +setchat( p ) char *p; { + strcpy(chatter,p); +} /* end: setchat */ + + + +putdice( f,t) int f,t; { +static char q[15]; + if (t == MYHOME) sprintf(q," %d to Home,",25 - f); + else if (f == MYBAR) sprintf(q," Bar to %d,",25 - t); + else sprintf(q," %d to %d,",25 - f, 25 - t); + strcat(chatter,q); + debug(chatter); /* avoid using save_cursor() */ +} /* end: putdice */ + + + +lurch( f, t, zlist ) int f, t, zlist; { + movestone( f, t ); /* move the stone */ + putdice(f,t); /* tell user, the action is a bit fast */ + if (movesleft < 2) cantuse = zlist; +} /* end: lurch */ + + + +/*****************************/ +/* must LINK to GAMEPLAN.REL */ +/*****************************/ + + + +/*========================================================================== + + GETLIST -- Find the possible moves for any particular throw of the dice + +===========================================================================*/ + + +checkpips( whichlist, ptimon, pips, tops ) +int whichlist, ptimon, pips, tops; { +static int j,k; + + if ( !ptimon ) { + j = whosebar(player); /* 0 if you, 25 if me */ + k = abs(j - pips); + } + else if (player == ME) { + j = ptimon; + k = j - pips; + if (k < 1) k = MYHOME; + } + else { + j = 25 - ptimon; + k = j + pips; + if (k > 24) k = YRHOME; + } + + if (point[j].stones > 0 && point[j].owner == player) { + + /* no move to a blocked point */ + if (point[k].owner != player && point[k].stones > 1) + return; + + /* no move home if i can't bear off yet */ + if (k == whosehome(player) && cantbearoff(j,pips,tops)) + return; + + /* no other move is allowed if i'm on the bar */ + if (tops == 25 && j != whosebar(player)) + return; + + /* the move is legal (but maybe not optimal) */ + list [whichlist] [j] = k; + } + +} /* end: checkpips */ + + + +build( whichlist, pips ) int whichlist, pips; { +int i, tops; + + if (whichlist == cantuse) return; + tops = topstone(player); + for (i = 0; i < 25; i++) checkpips( whichlist, i, pips, tops ); + +} /* end: build */ + + + +getlist() { /* find all legal moves using these dice */ +static int i, j; + + for (i = 0; i < 2; i++) /* initialize the lists */ + for (j = 0; j < 28; j++) + list [i] [j] = ERROR; + + build( 0, dice[0] ); /* usually the low die */ + build( 1, dice[1] ); /* usually the high die */ + +} /* end: getlist */ + + + +/*========================================================================== + + EVALUATE UTILITIES -- Functions for legal and/or best play, telling who's + who, who's ahead, who won, etc. etc. + +============================================================================*/ + + + +mytotal() { +int i, cnt; + + cnt = 0; + for (i = 0; i < 26; i++) { + if (point[i].owner == ME) cnt += point[i].stones * i; + } + if (show) { + gotoxy(0,3); printf("%03d",cnt); + } + return (cnt); + +} /* end: mytotal */ + + +yrtotal() { +int i, cnt; + + cnt = 0; + for (i = 0; i < 26; i++) { + if (point[i].owner == YU) cnt += point[i].stones * (25 - i); + } + if (show) { + gotoxy(0,19); printf("%03d",cnt); + } + return (cnt); + +} /* end: yrtotal */ + + + +topstone( who ) int who; { +static int i,j; + + if (point[ whosebar( who ) ].stones > 0) i = 25; + else { + i = 24; + while (i > 0) { + if (who == ME) j = i; else j = 25 - i; + if (point[j].stones > 0 && + point[j].owner == who) return (i); + --i; + } + } + return (i); /* return normalized value, 1 - 25, 0 is home */ + +} /* end: topstone */ + + + +cantbearoff( mypt, pips, tops ) int mypt, pips, tops; { + + /* My destination is Home, but can I do it??? */ + if (mypt > 6) mypt = 25 - mypt; /* normalize inner table */ + + /* I can't bear off if there's anybody still not in my inner table */ + if (tops > 6) return (TRUE); + + /* If I'm the highest blot in my own table, I CAN bear off */ + if (tops == mypt) return (FALSE); + + /* If I'm NOT high, I have to have an exact roll to get away with it */ + return ( (mypt != pips) ); + +} /* end: cantbearoff */ + + + +whosebar( who ) int who; { + return ( (who == ME? MYBAR: YRBAR) ); +} + + + +whosehome( who ) int who; { + return ( (who == YU? YRHOME: MYHOME) ); +} + + + +checkwin() { + if (mytotal() == 0) winner(ME, topstone(YU)); + if (yrtotal() == 0) winner(YU, topstone(ME)); +} /* end: checkwin */ + + +other( color ) int color; { + + if (color == ME) return (YU); else return (ME); + +} /* end: otherplayer */ + + + + +winner( who, high ) int who, high; { +int gammon; char ch; + + if (tone) beep(); + if (point[ whosehome( other(who) )].stones > 0) gammon = 1; + else gammon = 2; /* nothing off is a gammon! */ + if (high == 0) gammon = 1; /* someone doubled */ + else if (high > 18) gammon = 3; /* backgammon! */ + + + debug(""); + if (who == ME) puts("I"); else puts("You"); puts(" win"); + switch (gammon) { + case 1: { puts("!"); break; } + case 2: { puts(" a Gammon!"); break; } + case 3: { puts(" a Backgammon!"); break; } + } + gammon *= doubles.cube; + switch (who) { + case ME: { myscore += gammon; break; } + case YU: { yrscore += gammon; break; } + } + putscore(); + msg("Hit ESC to resume play"); + loo: ch = getc(0); if (ch != 27) goto loo; + player = 0; + reverse(); deciding = FALSE; jumpjack(); + +} /* end: winner */ + + +putscore() { + gotoxy(39,0); blanks(39); gotoxy(53,0); + printf("SCORE: You %d, Me %d",yrscore,myscore); +} /* end: putscore */ + + + + +/*======================================================================== + + REVERSE Command - allow player to take the opponent's viewpoint of the + board layout, mirror the board. Returns board layout + to the arranged position as seen from opposite side. + +==========================================================================*/ + +reverse() { +int cnt1, cnt2, cnt3, cnt4; + + off_cursor(); + cnt1 = point[MYHOME].stones; /* save counts for erase */ + cnt2 = point[YRHOME].stones; + cnt3 = point[MYBAR].stones; + cnt4 = point[YRBAR].stones; + + putstone( MYHOME, 0, 0); /* erase old trays before update */ + putstone( YRHOME, 0, 0); + + halfswap(1); halfswap(13); + + gotoxy(0,11); puts(" "); /* erase HOME message */ + gotoxy(75,11); puts(" "); + if (point[1].x < 40) { + point[MYHOME].x = point[YRHOME].x = 0; + } + else { + point[MYHOME].x = point[YRHOME].x = 75; + } + + point[MYHOME].owner = point[MYBAR].owner = ME; /* restore counts */ + point[YRHOME].owner = point[YRBAR].owner = YU; + point[MYHOME].stones = cnt1; + point[YRHOME].stones = cnt2; + point[MYBAR].stones = cnt3; + point[YRBAR].stones = cnt4; + +} /* end: reverse */ + + +#asm + DB 'Gammon IV concept & text graphic rendition by David C. Oshel',0 + DB 'MidSummer''s Day, June 21, 1985',0 + DB 'To Whomever Destroys This Notice -- Nothing Shall Happen, Forever',0 +#endasm + + +halfswap( n ) int n; { +static int i, j, k, o; + + o = n + 6; + for (i = n; i < o; i++) { + j = ((o * 2) - 1) - i; + k = point[i].x; + point[i].cx = point[i].x = point[j].x; + point[j].cx = point[j].x = k; + } + +} /* end: halfswap */ + + + + + +getkey() { +int ch; + ch = getc(0); /* keybounce? */ + while ( (ch = toupper(getc(0))) == 0 ) acg(); return (ch); +} /* end: getkey */ + + +wipedice() { +static char *s = " "; + + off_cursor(); + gotoxy(47,11); puts(s); /* erase dice roll messages */ + gotoxy(12,11); puts(s); + +} /* end: wipedice */ + + + +update() { +int i, x, c; + + for (i = 1; i < 25; i++) { + gotoxy(point[i].cx,point[i].cy); + printf("%2d",25 - i); + } + if (doubles.whosecube == YU) yrcube(doubles.cube); + else if (doubles.whosecube == ME) mycube(doubles.cube); + else barcube(); + for (i = 0; i < 28; i++) { + x = point[i].stones; + c = point[i].owner; + putstone(i,x,c); + } + if (point[1].x < 40) x = 0; else x = 75; + gotoxy(x,11); puts("HOME"); + + putscore(); mytotal(); yrtotal(); + +} /* end: update */ + + +dissemble() { + + clr_screen(); + +puts("You are a passenger in the \"Orion\" bound for STAR WELL, a slightly disreputable\n"); +puts("planetoid in the Flammarion Rift, where you have a scheduled layover of several\n"); +puts("hours. You enter the Casino there, desperately bored. Your attention is \n"); +puts("immediately drawn to an unusual trio. Your instinct for good company (they \n"); +puts("are playing Backgammon) leads you easily into a round of introductions:\n"); +puts("\n"); +puts("LOUISA PARINI -- A young woman who gives you the uncomfortable feeling that she\n"); +puts("is even younger than she looks. In fact, she is the offspring of a clan of\n"); +puts("noted interstellar jewel thieves and con artists, on her way to a famous\n"); +puts("girl's finishing school on Nashua. She has larceny in her soul, but she is on\n"); +puts("holiday. Do not underestimate her. (But you will, of course. You must.)\n"); +puts("\n"); +puts("ANTHONY VILLIERS -- A mysterious young fop with impeccable manners, and (you\n"); +puts("notice) an even more impeccable dueling saber at his side. There is something\n"); +puts("between Louisa and him. His conversation is light, witty and just slightly\n"); +puts("cynical, but you are not wrong to conclude that this is someone you can trust.\n"); +puts("\n"); +puts("TORVE THE TROG -- This blue-eyed, golden-furred entity is a member of the most\n"); +puts("dangerous and unpredictable race in the galaxy (aside from humans). You are \n"); +puts("amazed that this one is allowed to travel. (In fact, Torve's papers were forged\n"); +puts("by a member of Louisa's family and procured for him by Villiers). Torve is\n"); +puts("lost in some inner rapture, emitting soft \"Thurb\"-like noises.\n"); +puts("\n(Hit any key to continue)"); +getkey(); +puts("\015You suggest a friendly game of backgammon, at small stakes, and your\n"); +puts("companions agree instantly. Who will be your opponent? (L, V, or T) "); + +} /* end: dissemble */ + + +/*====================================================================== + + ARRANGE Command: Move stones around in the playing area. Play will + commence with this final arrangement. Notice, this + command allows for cheating because the line input + function traps Ctrl-C and executes jumpjack(). Player + returns to the command line with the game frozen, may + re-arrange as desired, then resume play. The Ctrl-C + trap will increment play level by 1. The sufficiently + stupid player will not notice, and so may lose anyway. + Trap implemented in MYLIB2.C, not here. + +========================================================================*/ + + +arrange() { /* whoever calls arrange() must also call update() next */ + +/* any vars here MUST be STATIC */ + +#asm + MOV B,H ;set up to exit this function by saving caller's + LXI H,0 ;stack pointer for use in deeply-nested scope + DAD SP ;WARNING: this function must not use dynamic variables + SHLD _fool ;CAUTION: risky business if called with parameters?? + MOV H,B ;HL is restored on general principles, BC is trashed +#endasm + + moveabout(); + +} /* end: arrange */ + + + +moveabout() { + + player = -1; /* flag to ask who moves first */ + if (!expert) + debug("Type BAR or HOME, or the Number of a Point."); + + while ( TRUE ) { /* exit via jumpjack() by typing Control-C */ + mytotal(); + yrtotal(); + revise(); + } + +} /* end: moveabout */ + + + +getpt(b,h) int b,h; { +static char ans[6], *p; int x, d1, d2, look, try; + + on_cursor(); + gets(ans,5); + p = ans; + while (*p) *p = toupper(*p++); /* capitalize string */ + off_cursor(); + + if (!helpdisabled && ((index(ans,"HEL") != -1) || + (index(ans,"?") != -1))) { + x = ERROR; + msg(""); + if (point[ whosebar(player) ].stones > 0) { + puts("You're on the Bar, so let's move that one! BAR "); + x = b; + } + else { + puts("Are you "); + if (cantuse != 0 && cantuse != 1) puts("REALLY "); + puts("blocked? Try moving From "); + look = 24; + while (look > 0) { + try = list[0][look]; + if (try == ERROR) try = list[1][look]; + if ( try != ERROR ) { + printf("%d To ",25-look); + if (try == YRHOME) printf("HOME"); + else printf("%d",25-try); + look = 0; + } + look--; + } + sleep(40); + } + } + else if (index(ans,"B") != -1) x = b; + else if (index(ans,"H") != -1) x = h; + else { + x = atoi( ans ); + if (x < 1 || x > 24) x = ERROR; + else x = 25 - x; /* translate human to computer view */ + } + return (x); + +} /* end: getpt */ + + +whoseit(p,a,b) char *p; int a,b; { +int ch; + + if (point[a].stones > 0 && point[b].stones > 0) { + debug("Whose "); puts(p); puts("? 1 = "); + puts(token1); + puts(" 2 = "); puts(token2); puts(" "); + loo: ch = getkey(); + if (!(ch == '1' || ch == '2')) goto loo; + + debug("From "); + if (ch == '1') { ch = a; puts(token1); } + else { puts(token2); ch = b; } + puts("'s "); puts(p); + return ( ch ); + } + else if (point[a].stones > 0) return (a); + else if (point[b].stones > 0) return (b); + else return (ERROR); + +} /* end: whoseit */ + + + +revise() { + do { + setchat("Move a Stone From? "); + msg(chatter); + } + while ( !delightful() ); + +} /* end: revise */ + + +delightful() { +static int from, to, fcnt, tcnt, fcolor, tcolor; + + from = getpt(MYBAR,MYHOME); + + sprintf(buzzard,"%d",abs(25 - from)); + + if (from == MYBAR) { + from = whoseit("bar",MYBAR,YRBAR); + strcpy(buzzard,"BAR"); + } + + if (from == MYHOME) { + from = whoseit("home",MYHOME,YRHOME); + strcpy(buzzard,"HOME"); + } + + if (from == ERROR) { + debug("Type Control-C to quit."); + return( FALSE ); + } + + /*-----------------------------------------------------*/ + /* establish the color of the stones on the from point */ + /*-----------------------------------------------------*/ + fcolor = point[from].owner; + + /*--------------------------------------------------*/ + /* establish the number of stones on the from point */ + /*--------------------------------------------------*/ + fcnt = point[from].stones; + + if (fcnt == 0) { + debug("What's the point?"); + return(FALSE); + } + + strcat(chatter,buzzard); /* this avoids use of save_cursor() */ + strcat(chatter," To? "); + msg(chatter); + + to = getpt(MYBAR,MYHOME); + + sprintf(buzzard,"%d",abs(25 - to)); + + + if (to == MYBAR) { + if (fcolor == YU) to = YRBAR; + strcpy(buzzard,"BAR"); + } + + if (to == MYHOME) { + if (fcolor == YU) to = YRHOME; + strcpy(buzzard,"HOME"); + } + + if (to == ERROR) { + debug("Type Control-C to quit."); + return(FALSE); + } + + if (from == to) { + debug("Quite easily done!"); + return(FALSE); + } + + strcat(chatter,buzzard); + + /*---------------------------------------------------*/ + /* establish the color of the stones on the to point */ + /*---------------------------------------------------*/ + tcolor = point[to].owner; + + /*------------------------------------------------*/ + /* establish the number of stones on the to point */ + /*------------------------------------------------*/ + tcnt = point[to].stones; + + if (fcolor == tcolor || tcolor == 0) { + msg(chatter); + --fcnt; + ++tcnt; + putstone(from, fcnt, fcolor); /* one less */ + putstone(to, tcnt, fcolor); /* one more */ + debug(""); + return (TRUE); + } + else { + debug("Evict the other stone"); + if (tcnt > 1) puts("s"); + puts(" first!"); + return (FALSE); + } + +} /* end: delightful */ + + +/*========================================================================== + + INITIALIZATION and NEWBOARD commands -- start of a new game, or cold + +===========================================================================*/ + + +wipeout() { +static int i; + + player = 0; + barcube(); + for (i = 0; i < 28; i++) { + point[i].stones = point[i].owner = 0; + } + update(); + +} /* end: wipeout */ + + +setup() { +static int i, j, k, copyright; + + myscore = yrscore = player = dice[0] = dice[1] = 0; + kaypro = swapped = tswap = expert = helpdisabled = yrdice = FALSE; + show = moremsgline = tone = TRUE; + + init_lib(); + OFFinterrupt(); /* enable jumpjack() on ctl-c */ + crtinit(); /* Kaypro video mode on (2-byte graphics) */ + off_cursor(); + token1 = getAtkn(); + token2 = getBtkn(); + copyright = backtalk[ MYLEVEL + 1 ]; + draw_board( copyright ); + + for (i = 0; i < 28; i++) { + point[i].stones = point[i].owner = 0; + point[i].x = point[i].y = point[i].lastx = point[i].lasty = 0; + point[i].cx = point[i].cy = 0; + } + + k = 68; + for (i = 1; i < 13; i++ ) { /* establish xy coords for the points */ + j = 25 - i; + point[i].cx = point[j].cx = point[i].x = point[j].x = k; + k -= 5; + point[i].y = 4; + point[j].y = 18; + point[i].cy = 2; + point[j].cy = 20; + if (k == 38) k -= 5; /* skip over bar */ + } + + point[MYBAR].x = point[YRBAR].x = 38; + point[MYHOME].x = point[YRHOME].x = 75; + + point[MYBAR].y = point[MYHOME].y = 5; + point[YRBAR].y = point[YRHOME].y = 17; + +} /* end: setup */ + + + +newboard() { +static int i; + + startcubevalue = 1; + wipedice(); wipeout(); + + putstone( MYHOME, 15, ME ); + putstone( YRHOME, 15, YU ); + + putstone( YRHOME, 13, YU ); + putstone( 1, 2, YU ); + + putstone( YRHOME, 8, YU ); + putstone( 12, 5, YU ); + + putstone( YRHOME, 5, YU ); + putstone( 17, 3, YU ); + + putstone( YRHOME, 0, 0 ); + putstone( 19, 5, YU ); + + putstone( MYHOME, 10, ME ); + putstone( 6, 5, ME ); + + putstone( MYHOME, 7, ME ); + putstone( 8, 3, ME ); + + putstone( MYHOME, 2, ME ); + putstone( 13, 5, ME ); + + putstone( MYHOME, 0, 0 ); + putstone( 24, 2, ME ); + +} /* end: newboard */ + + +draw_board( c ) char *c; { +static int line; +static char *m = " ", *picture[] = { +"The Peelgrunt Game of GAMMON IV%s\n\n\n", +":=================================o=================================:\n", +":: .. \\/ .. \\/ .. \\/ ||| .. \\/ .. \\/ .. \\/ ::\n", +":: ||| ::\n", +":: /\\ .. /\\ .. /\\ .. ||| /\\ .. /\\ .. /\\ .. ::\n" +}; + + clr_screen(); + off_cursor(); + msg( c ); + off_cursor(); + gotoxy(0,0); + puts(m); printf(picture[0],bgversion); + puts(m); puts(picture[1]); + for (line = 0; line < 6; line++) { + puts(m); puts(picture[2]); + } + puts(m); puts(picture[3]); + puts(m); puts(picture[3]); + puts(m); puts(picture[3]); + for (line = 0; line < 6; line++) { + puts(m); puts(picture[4]); + } + puts(m); puts(picture[1]); + +} /* end: draw_board */ + + +/*========================================================================= + + DICE Commands: How to roll the dice + +===========================================================================*/ + + +peek() { + if (yrdice) return; /* you know your own dice, probably...? */ + if (expert) debug(""); + else debug("The Dice will Rattle until you Roll. Now on "); + getdice(); + printf("[%d] [%d] ...",dice[0],dice[1]); +} /* end: peek */ + + +getonedie() { + return ( (abs(acg()) % 6) + 1 ); +} /* end: getonedie */ + + +fixup() { /* ensure that the low die is in dice[0] */ +int d,e; + if (player == 0) return; /* whofirst? don't mess with the odds */ + d = min(dice[0],dice[1]); + e = max(dice[0],dice[1]); + dice[0] = d; + dice[1] = e; +} /* end: fixup */ + + +getdice() { +int ch; + + /* if it's MY dice we're using, generate random dice... */ + if (!yrdice) { + dice[0] = getonedie(); + acg(); /* bounce a little for luck */ + dice[1] = getonedie(); + fixup(); + return; + } + + /* but if it's YOUR dice, then ask about the roll... */ +zoo: msg("<> "); + if (player == ME) puts("My"); else puts("Your"); + puts(" roll: "); + if (!expert) puts("\008\008, using your dice: "); + puts(" First? "); +loo: while ( (ch = getc(0)) == 0 ); /* don't bother acg */ + if (ch == 3) haltgame(); + ch -= '0'; + if (ch < 1 || ch > 6) goto loo; + putc( ch + '0',0); + dice[0] = ch; + + puts(" Second? "); + while ( (ch = getc(0)) == 0 ); + if (ch == 3) haltgame(); + ch -= '0'; + if (ch < 1 || ch > 6) goto zoo; + putc( ch + '0',0); + dice[1] = ch; + + puts(" All Ok? "); +roo: while ( (ch = toupper(getc(0))) == 0 ); /* don't bother acg */ + if (ch == 3) haltgame(); + if (ch != 'N' && ch != 'Y') goto zoo; + fixup(); + +} /* end: getdice */ + + + +haltgame() { + player = -1; /* if play resumes, ask whose roll it is */ + hint(); + jumpjack(); + +} /* end: haltgame */ + + + +rolldice( who ) int who; { +int waiting; + + setchat("Your Turn: "); + if (!expert) { + if (!yrdice) strcat(chatter," P(eek,"); + strcat(chatter," D(ouble, Q(uit, or to Roll "); + } + if (player == YU) { /* not executed if player == 0, i.e., whofirst */ + waiting = TRUE; + while (waiting) { + msg(chatter); + switch ( getkey() ) { + /* bailout is Ctrl-C instead of ESCape */ + case 3 : { haltgame(); break; } + case 'P': { peek(); break; } + case 'D': { udouble(); break; } + case 'Q': { winner(ME,topstone(YU)); break; } + default : waiting = FALSE; + } } + off_cursor(); debug(""); msg(""); + } + highroller(who); + +} /* end: rolldice */ + +highroller( who ) int who; { /* parameter is not redundant */ +static int y = 11; +static int xme, xyu; + + /* get the values for two dice, either yours or mine */ + + getdice(); + + /* display the values of the dice in the board area */ + + off_cursor(); + xme = 47; xyu = 12; /* decide which half to show the values in */ + if (point[1].x > 40) { + xme = 12; + xyu = 47; + } + if (player) { + gotoxy(xyu,y); blanks(18); /* erase, if not whofirst */ + gotoxy(xme,y); blanks(18); + } + if (who == ME) { + gotoxy(xme,y); puts("My"); + } + else { + gotoxy(xyu,y); puts("Your"); + } + printf(" Roll> [%d] ",dice[0]); + if (player) printf("[%d] ",dice[1]); /* whofirst doesn't show this */ + +} /* end: highroller */ + + + + + +/*======================================================================== + + MAJOR UTILITIES -- Miscellaneous functions sans which the game will not + proceed so well as otherwise.......... + +========================================================================*/ + +jumpjack() { /* Much too simple-minded LONGJUMP. (But it IS simple!) + CAUTION: C/80 has no idea what's going on here! + The in-line assembly which sets _fool MUST NOT be in + a function which uses dynamic variables, or the stack + will be disrupted. See arrange() and play() herein. */ +#asm + LHLD _fool ;Retrieve old stack status... + SPHL ;...diddle stack pointer + RET ;...and execute the ad hoc jump back to outer loop + +_fool: DS 2 ;stack pointer is saved by doit(), read and used here + +#endasm +} /* end: jumpjack */ + + + +acg() { /* additive congruential generator for pseudo-random numbers */ +static int arg[] = { + 4292, 60, 4947, 3972, 4489, + 1917, 3916, 7579, 3048, 6856, + 1832, 7589, 1798, 4954, 2880, + 5142, 5187, 3045, 1529, 3110, + 4333, 167, 5556, 7237, 5906, + 5419, 6632, 5833, 3760, 1081, + 1434, 80, 6212, 344, 7303, + 3044, 7675, 5420, 457, 3434, + 2657, 700, 6777, 4436, 620, + 2129, 629, 3550, 1639, 4546, + 1220, 6469, 862, 3280, 4664 + }; +static int rp1 = 0, rp2 = 32; + + rp1++; + rp2++; + rp1 %= 55; + rp2 %= 55; + arg[rp1] ^= arg[rp2]; + return ( arg[rp1] ); + +} /* end: acg */ + +finishup() { + crtexit(); on_cursor(); /* restore for user */ + exit(); +} + +saveboard() { +int i; + for (i = 0; i < 28; i++) { + bdsave[i].stones = point[i].stones; + bdsave[i].owner = point[i].owner; + } +} /* end: saveboard */ + +restoreboard() { +int i; + for (i = 0; i < 28; i++) { + point[i].stones = bdsave[i].stones; + point[i].owner = bdsave[i].owner; + } +} /* end: restoreboard */ + + +getAtkn() { + if (kaypro) return( get5tkn() ); + else return( get1tkn() ); +} +getBtkn() { + if (kaypro) return( get6tkn() ); + else return( get2tkn() ); +} +getCtkn() { + if (kaypro) return( get7tkn() ); + else return( get3tkn() ); +} +getDtkn() { + if (kaypro) return( get8tkn() ); + else return( get4tkn() ); +} + +swaptokens() { +char *temp; + + swapped ^= TRUE; + if (swapped) { + temp = token1; + token1 = token2; + token2 = temp; + } + else { + tswap ^= TRUE; + if (tswap) { + token1 = getCtkn(); + token2 = getDtkn(); + } + else { + token1 = getAtkn(); + token2 = getBtkn(); + } + } + +} /* end: swaptokens */ + + +blanks( n ) int n; { + while (n--) putc(' ',0); +} /* end: blanks */ + + +msg(p) char *p; { + on_cursor(); + gotoxy(5,23); blanks(74); + gotoxy(5,23); puts(p); +} + +debug(p) char *p; { + on_cursor(); + gotoxy(5,22); blanks(74); + gotoxy(5,22); puts(p); return(FALSE); +} + + +nxtyp(i) int i; { + if (i > 9) return ( i - 1 ); else return ( i + 1 ); +} + + +isbar(p) int p; { + return (( p == MYBAR ) || ( p == YRBAR )); +} + +ishome(p) int p; { + return (( p == MYHOME ) || ( p == YRHOME )); +} + + +putstone( pt, cnt, color ) int pt, cnt, color; { +int i, xp, yp, slack; +char *background, *token; + + + if (cnt < 1) { /* empty point has neither stones nor owner */ + cnt = 0; + color = 0; + } + + point[pt].stones = cnt; /* number of stones on this point */ + point[pt].owner = color; /* and whose they are */ + + /* stack stones 5 high in the home tray, 6 high on the points */ + if (isbar(pt) || ishome(pt)) slack = 5; else slack = 6; + + /* locate the base address of the point for animation */ + xp = point[pt].x; + yp = point[pt].y; + + + /* decide on the background pattern to be used for empty places */ + if (pt > 12) background = "/\\ "; + else background = "\\/ "; + + if (point[1].x < 40) { + if ((pt % 2) == 1) background = ".. "; + } + else if ((pt % 2) == 0) background = ".. "; + + if (ishome(pt)) background = " "; + if (isbar(pt)) background = "||| "; + + /* get the token pattern to be used */ + if (color == ME) { + token = token1; + } + else { + token = token2; + } + + /* draw the entire point with token and background patterns */ + off_cursor(); + + /* first erase all blots from this point (draw the background) */ + for (i = 0; i < slack; i++) { + gotoxy(xp,yp); + puts(background); /* string has point's width */ + point[pt].lastx = 0; /* future, not implemented */ + point[pt].lasty = 0; + yp = nxtyp(yp); + } + + /* now draw all the blots there are on this point onto the point */ + for (i = 0; i < cnt; i++) { + xp = point[pt].x + (i / slack); + if ((i % slack) == 0) yp = point[pt].y; + gotoxy(xp, yp); + puts(token); + point[pt].lastx = xp; /* future, not implemented */ + point[pt].lasty = yp; + yp = nxtyp(yp); + } + +} /* end: putstone */ + + + +hitblot( from, color ) int from, color; { +static int barpt, addone; + + if (tone) beep(); + barpt = whosebar( color ); + putstone(from, 0, 0); + addone = point[barpt].stones + 1; + putstone( barpt, addone, color ); + +} /* end: hitblot */ + + + +movestone( from, to) int from, to; { +static int opponent, subone, addone; + + + opponent = other( player ); + if (point[to].owner == opponent) hitblot(to, opponent); + + subone = point[from].stones - 1; + addone = point[to].stones + 1; + + putstone(from, subone, player); + putstone(to, addone, player); + + --movesleft; + checkwin(); /* never but NEVER let a win go unnoticed! */ + +} /* end: movestone */ + + + +/*======================================================================== + + CUBE Commands -- commands related to the cube, doubling, etc. + +=========================================================================*/ + +notyrcube() { + gotoxy(75,19); blanks(5); + gotoxy(75,20); blanks(5); +} /* end: notyrcube */ + + +notmycube() { + gotoxy(75,2); blanks(5); + gotoxy(75,3); blanks(5); +} /* end: notmycube */ + + +barcube() { + /* startcubevalue is normally 1, but it may have doubled */ + /* if the opening rolloff for first turn came up doubles */ + doubles.cube = startcubevalue; + doubles.whosecube = 0; + notmycube(); notyrcube(); + gotoxy(37,11); + if (startcubevalue == 1) puts("[BAR]"); + else if (doubles.cube < 16) printf("[ %d ]",doubles.cube); + else printf("[%03d]",doubles.cube); +} /* end: barcube */ + + + +notbarcube() { + gotoxy(37,11); puts(" BAR "); +} /* end: notbarcube */ + + +mycube(value) int value; { + notbarcube(); gotoxy(75,2); puts("CUBE"); + gotoxy(75,3); + sprintf(buzzard,"[%d]",value); + printf("%-5s",buzzard); + doubles.whosecube = ME; + +} /* end: mycube */ + + + +yrcube(value) int value; { + notbarcube; gotoxy(75,19); puts("CUBE"); + gotoxy(75,20); sprintf(buzzard,"[%d]",value); + printf("%-5s",buzzard); + doubles.whosecube = YU; + +} /* end: yrcube */ + + +idouble() { +static int ch; + + if (doubles.whosecube == YU) return; /* not mine, can't double! */ + if (doubles.cube > 256) return; /* maximum, don't consider it */ + notbarcube(); + if (tone) beep(); + debug("I double. Will you accept the cube "); + printf("at %d points? ",doubles.cube * 2); + loo: while ((ch = getc(0)) == 0); + if (toupper(ch) == 'Y') { + notmycube(); + doubles.cube *= 2; + yrcube(doubles.cube); + off_cursor(); + } + else if (toupper(ch) == 'N') winner(ME,0); + else goto loo; + +} /* end: idouble() */ + + + + +backgame() { +int max, barred, count, i; + if (topstone(YU) < 12 && topstone(ME) > 18) { + if (mytotal() < yrtotal() + 4) return (TRUE); + max = barred = count = 0; + i = 24; + while (i > 18) { + if (point[i].owner == ME) { + max = i; + if (point[i].stones > 1) barred++; + count += point[i].stones; + } + i--; + } + return ((max < topstone(YU) + 1) && (barred > 1 && count < 7)); + } + else return ( mytotal() < yrtotal() + 24 ); + +} /* end: backgame */ + + + +cubeval() { +int ineed, yuneed, yrtop, mytop; + + if (endgame()) { + + /* calculate the number of dice that are required to end */ + /* the game, with appropriate fudge factors for position */ + + yrtop = topstone(YU); + mytop = topstone(ME); + + ineed = 15 - point[MYHOME].stones; + yuneed = 15 - point[YRHOME].stones; + + if (yrtop < 4 && yuneed < 3) return (FALSE); /* obvious */ + + /* topstones still running? use a different method */ + if (mytop > 6 || yrtop > 6) { + ineed = 2 * (mytotal() / 8) + 1; /* number of dice */ + yuneed = 2 * (yrtotal() / 8) + 1; + } + + /* count the stones on point 6 twice, they're losers */ + yuneed += point[6].stones; + ineed += point[6].stones; + + /* you doubled, so you have the roll */ + yuneed -= 2; + + /* odd number left? */ + if (ineed % 2) ineed++; + if (yuneed % 2) yuneed++; + + /* is the one point empty? */ + if (ineed > 4 && mytop > 3 && point[24].stones == 0) ineed++; + if (yuneed > 4 && yrtop > 3 && point[ 1].stones == 0) yuneed++; + + if (mytop < yrtop && ineed < yuneed) return (TRUE); + if (yrtop < 5 && yuneed < ineed) return (FALSE); + return ( yuneed >= ineed ); + } + else return ( backgame() ); + +} /* end: cubeval */ + + + +testcube() { + + if (cubeval()) { + debug("I accept the cube."); + notyrcube(); + doubles.cube *= 2; + mycube(doubles.cube); + } + else winner(YU,0); + +} /* end: testcube */ + + + +udouble() { + + if (doubles.whosecube == ME) { + if (tone) beep(); + debug("It's MY cube, dummy!"); + } + else testcube(); + +} /* end: udouble */ + + +#include "mylib2.c" + + \ No newline at end of file diff --git a/Original/backgmmn.com b/Original/backgmmn.com new file mode 100644 index 0000000000000000000000000000000000000000..fffa1720ead894aac9ef5b4d126ed55e33ae60f1 GIT binary patch literal 30976 zcmdtL33MFAwKv{lX~vdhTORMSyma??k$NQAmTdvT+AVq0GM40hV=RqjVM!y;;*qc| zAdmnF%X=Y^M+lI>170A(>?V*n*0c?t2~CiLiE+q-feZvDEQXjRPUP=*tGZ`Kvco(7 z|M|XizVjJcU3Kf$-Rf3#)vf9tb+lLbzxSWL_?Ghd?&7~LJrv$(KTvo}d7)CGZnT%0 z3O`(m`$2vyJzx0QQtfEYLENr76uc+3*jhR$9@$s&RrsFN!Eq<c2p#UGRmjygSP*R<5qkpdh zlWR%_r4vi?Lcki#0ckBaV{jhb86%zqD3?Ix8N}iUF}IxV$t$&3KP-{9mM!l)6nrLi zTEI5J9K1fSJEXmqN7UwXDo0<=#=s{b6{)>b_Mw?{ryWzF|R9oNRxNvFy zVCK<&Fi2J3&XcQ3w9b4qQ{lpr!L`SG-n%AvFtz6kv2a0&QdI);YJVIP>!IelPAm?V z9y+dSsi@QU#WjKbsDiq@3XmZp#QOpC?0c{L@h`-H&1>`6PR5k~E{P!(0gg1$ zqQn^d89yO)Oz#4@`AA=w4Y_ew9=9WIlEjtI{I`)0l=^Z*{nRcdw$=0so`k_ zwr#d`CbIx!by|UPsw8Ggr;KTgNqM~_w(m*!k=kW~lbn6+I`QN&c%XFtyu7$XE-E=t zIKM>eo+kZmzIJk&w5Vk9V#!lhYSw;uxwdIq@uHH!OJ74NgMYwKo-Qj*;icNs^OcX5 z?tdoy+k&X}*0f0R)8$JGHbH}mCeOQ zA+j5ivuhih8tN0Jl&wi*Yn$>*r|DIfH#9eF*qC3MUBUqyD;IAND>pV*7n?RT)HLy= zxG|Beu3u46Usb&fR)R5LifT|}x-Kcsu3VU1xgfi8QR&j`szupV3$m*g5?NMUgyKag z-n^9+Bq_#l}i`^Su#a-m7e9M$gW(> zOSvhst9W*4es%paaaj9HK}$%A;1WiLq*=H$Tz|!tF)Ab}xO$K-#Z`xEH?A$XRsy~O z*Irz0qe78^{$nSj(v2gvQEA0L8hI%E^{C>{!co%`BYhABcoPN{R^s!;&=ZrBP8W%h9ivq-lqEQZHMRru|kg+nA=kpqFV+ z4MEzQru|+=>PyqqA!XlB(|)Iy{U}ZQjb0{=5H6F=rjTMb+3iSZS9_vbc6vX-V*qO9 zp76_QNJOvO(%#t@OLwmOp|q_pk*)<-I*bcB$+`-y=gR430Ah- zp_D9|6cH^Ynru<6Z!B8!7ef)KnWS_fsy#f07mgC3y82lLfO=vaC5BL?Hk@fvW`giE zShC{cbirGeO^S@hkWKc!L*dIutM<{z+mR=cv^Gx+ifHMc@Ve2IK-;#BMgc*ys4j^P zTto5@G-T}!_fg+Whc4R9o*!ql2*1u~6;5Zkg?BUj!e29bgh`m62S(G_q4ta>UsGnA zqSUansXcXLE)cYHd%~}eCi`C|Xn$wE_0Q2jwPK#}5ZoluSOZzqlBlk}KnSr2k}>X2 zu*F=H;o~_b$pVie^TYa4Wv zF?wFx<56EVGO}WVbuP0yge-X~Y_7ms>-0W65{}U?Pd3HrT%*nNoGut!Ji(-0<*~j^ zo*SMsR?3GHp(`q5(7t0#YQb1#GE$RGMfpfX6_91kC^>}7zSbp6Vrj55?wY~&VwL$Y z64lj&8_9VlWg_dHKiB1oDtTb|F+39qJIXOMginp7cB0m?p>^V;havLM$ASpZJ{pS- zPVT}97|k359(r7OQl{S8L-hT4tbu1uBWDWdWunik^E0JOgcuumuJ&YwewBGD^RJn+ z#wm}Rqsn9EsMbDD`}rLCF*7o1Zzj2Dj#<4UQ!*Ke5qd(c%>*3&z9F+h*pRtSaAwxx zatK#uHj|%wGnE{3uJy9aEb5()o3%}8#6+7}+>bjP_Azq=;8p|)Y|%BBjGEOT|Vx9#$|S|v;a8rM|=w9+fKcllf%m)Ft%Pw6a?&w9KOWfdY+12jr z5S!es&W?6puejdb)#~zi#kpdg)3evr;T5agot^DIpUWlOHvaf{DTVac{;f#M&w^3V zI=7A|E7h2#m&Ql6JF5DV)qdKnJPn;&s`|-*E6iH|rIaW&E2U;s{oZ)(>NI5;CAD$d zBQv#{S?ZVLsG-3os{LV9f4_7dRPnrKzzM^EN+netVbwAmN;xGbS*4T-jGwy3Dox-? zrG|=XtlHga%C2!yrIxbAR%ylrwZtlkKzbkzW9=G-uyY*Ck`p{>R-QDg<>R$yD%2at zliaJ!+5-jJ?74=j0BgH!03ZQ14t#8K%gf9JeYaAFR&r=1K_MeUDQB5lo~dQ{6`AtW zX0l@`Wht@B3`1J~c{Musi4UzBLjX-}&IF=gnuZAtBbH*)|S zTwvCw*+`Na&b)@oh~CYft=2U{i?u?y%GxMgXRQ+c&Dtc~Wvvt*vTneYEj(pihHI^G z#M&VI4g=Gt*5$Y|gz@9+1!?>ya`^@0)hEWOd&h+wIUUa4Jh3sywHLnR$`hM%0?zI{ zu_DLgadx!-Ya(ew9SD7d@xjI}eKJ*izvsa*A zB`kwAE|Whjzd~CwL93qtY0#x+cHtY+=D^nndTvN zm6>Mir-XF+)`{p<(yB>Ofb@QJF9WSf0>x>betx2~0c>eJn8?|xf1aSeIT1p~&=mAQ ze0`#BjW;Li)}SUrQ)y?q@!V6)tjQ>!wFmh;jH1utdJfm~<`4~vKC!bGKH>9wx~p`G{FtFjM5)lN8UVBuIX+1m&6ARq-_h)LLV9PCVW$v*0J(CqGzU1-v-_oWumO#? zi_O-5Fh{aZCc!Q>t5YTu>r2hrq$cH3v-Lb{&&J6^ghwq7Up|?n&FxeRCj;4zYBqJ+ zWTGzRfl~#nY_L*OrohwXpjio;$&pj05OYrERz~KxQ`O$d(tOlI8`B_q*sL5jTc3pc zqeH2aDMNh$nIkMivoW@cz~A7V3DFseWxRQK*OQQSDcUKAR3=ZQ|{Hvy-Y zJORc-i>Xtz_DQTOZkPIbucQWeZi@D&Mil>I3ecijY*xS3!e(+eP0?OlO^V$yMH^VD zJ~9Olv?!ivG=&_Xc?uwaqyBfOKJEi68F}jIG#tGMcRGp-9`vGF`j4r+b<3HhKc5mG za_&X}4Mq3xJF3}%Pt&Q6sYxz5b1IDvN6qTSsY(%ZodrW6P^E(Kbretmq$vr)YE$oi zU@DV~KPAsik$$E#W>4H3rb>_Tyn5SI>2aQnfM^6lg)k_K!Y=1tmxvzKx>Xc9TswV2 zfsjW{!MdTx-6`(E)I{{T#SV9%K;YdaI#m*~m;uP)7Mnxr`Kj8`DcU(&-G#rLirI$> zoIH-h_%JqIZcs*}^X6~wLf38g#^*-ecq|nNcnlMfnk;F#&Vtrk7y?5ps%ss1##A(l z&aPH*MMGUR^B}+1wbS1r2Hc)jnsafQZO%>?Xob;W$I(?F<#97o)SM}y z999iu%BVh@rQS)?FZIt^$}5oIWiG)Avy`6AhgX_IO@msa=3|h2*$fP#1-*kCrXiC{ zd~^n6jI|uNGa1PHWw>J+XZ|vnzXImcWUwFy9KzxiGXybMypYTyiURGgd&18pv(SM$ ziLdgzh-%j@$2tK+3pZwJc9O)bCWhQWs)MmuP0gmk4udkx;ha{7elPBXS7EFd zo89=!MlvG+@*Rw3@pVCz4K&Vda`IPU!PD7MDGPQ>XDcl%W1`yMFf;5|k7nyD4D0)> z$`9gI-q)*)y0D5t_45m;UX%$NWJ!!6BW{QuN9Y02X8?+q85#o)xqxh2=uV!VQklJ)Mn7UyJ?nTV~}gScR`$nKi!S?w2EG^^b%@ z!^O|0>!laq0!@kNkA~9^O_#C-UXiIDHx{o(>t&K8ORw}kdtCi-I{cR)Z<%xP&w8(k z`72h<7)sM-B!O)C~7iGDc4uw4{Y;q!!cFVMKc$sHU@4WOTc)AgQ^5{28p zi>nCybmxNrZ_kLx@1oO1&0ID-YLF(cf7c9jE3?z-{F!RTOk{0<+SM~NbY_g8PAp0c zw6f_Cyk8Y&s(+Y4MBXAA!*A>||J8H1kS@DWocW=7un9vc?N z&Qed!MAjz9z~?X}hcqNPUB;{=C>k+_EC$XPC})ABs?Fpp%0;tCjQB#5x?{zxDDh`c zG9)mf#$aD0LNwhIlrxa+6E52sCfg@w8`aQ74gTcHd=@rQ z1Vj0AvwE8-O{IkLxiLWlg!g!obE${|`K(!8Nfn~VP}JtESveb5iiq;wwogm~^A4qV zS-r=7o2Z3w*@^WumeWTD>({I||5Bv$ewH1);zM6{(5ppNP; zjt*w@Ks$B6F%nc!$4LxTSCtjal`xd3xe`X95GG|%f0;yH3Fd497u9+s^y!*eDA^_v zluBu8$4lZ|Q0}GjkQyKYq0r^Zmv9*tg}70|A`5X}8p)y>ri^Sbxv+(vrJC}WX7yJ@ z2?@!}>VWouQS`o~1Fau1>miS@3sCEN@(m-AC^l$8R2zl0ALASxy+ z3-sIq%He;IX$P4A$iQ``*`ySNxoNeB=AbUm7RiXLQXWxXD|-TmRayOsj8aUp5l*2* zsacDbN5FYeNLWcrdqE7ecL|apI>qJA&Q5n1OIA8tc4HpKvMaFet8S{I$0I^w{!SNy z0nT1QnupdT#w?hGj8+bDmLvhG&o$bj&?O4(c)#lpHB~huVq*d{v(!e~oxnihRzj6r{-iG%NR-UKytY>1v=t3#-3Z*B5-cDg+CyeL8>Xq6wq$-;$sEcS>s zxVU~7CNu~RA+YK7dEC8TL?ba#uXpNJ+DB7eKs7PO~s?h=-2SEHsk+ zVUD)FLVaNlP%-@DPslo#;y3e?JVA-f;qEc|B0$!L)Q*XNf|6;8Dr0bEfIqw=!-AAP ziMV5~>X?fxw&`H3B1*=s1BGZvO9qYQAl9d-`&==PKj$*YxOy0qiOThNJ5~Ok_Dos8e>Tkhdq(xOagHQp{T}socj9Q zL`RuFkC=?Hs7vNiF98V{BhlMh=P`3)(BgsU2;_+XD+0=)IfbnPEe8ce@uf?1xZ!Wo z@2BGvCS_^n zd8dAVUcdjH-w}8J6ktXjKnE+JH1{PLbD#ez;%gog9n{k7Iz@h+RDOZ zP0d&sudlAHMYu%tvi*pTUW97B9#^;D=R}|^UBH;z- zaw3T5rlbdP;#QXz(P5|01#xy@glOgX9?^+yi!L@sVQfhk+A$=xwsX8zk28Rkyc;Wh z(ck6w`kfu34`Lcs+q-C6rNzfIZ*#j_F%EWiJG*+t9B}OgHL@E$VrY~~Jcx2dgrE^7 zAO#VNZih(Nr2!k!!wd=CkoUM-{VgPzw>VwjFxFqA&BS{ThNe5r3+nd>^hOmh~&e<9aw>0=?b`DtzGTlf*2dz1J4LV zN__2JpEplL8tozmoW0DxVAbjNd((xsc25T$2s_)m+P!RSN6Wk2h{Sb?^-k|DzY~%* zL6Thv#(_Rqc014>ULLNn%V;ceO^m}~;x#>bhee;Tj`i-Ko8ONKUvllAEDg4a#FwIVP zHwgK5iS3=;u9g<^c@b^Y1>2xgzz{iL#cYPhST6Y%YX}ySN~+T8=S}8y?tpS=HhT7X z+gtgT9rX{&;|a;0f$72ymoMN#gVwtJ?OrEiw5z=nDy#q=Y>&R;bsB!oIwtxV_Uw8Y z>Xpzj-e1#&mfo)R7N>4bvJ5#gnJ?gRlN-5-VoQg=mEzuz4Kg6=#pS_n3^Qg6H1m1L zcIkXSQfyvPEjBkcEGNV9XZel}zboI>>%!!z&E3)J>dN0q8zvuAS=au#9e;0hBsGl zTv81Ew9|PNxF&QVC5U+k;*C^*am0fVWk-RS6Ym(!Zft(SS-YJWS-fI^+5|nW&DDz5 zfLW6S=Z!*+?d+uPPHxccabp)2#A%xWO+|C0b#TCT5F_arc?gj%bU61SH<+X~&ce0#f9XEWRT?dxr1ALpo`u<@GstyL4xUb9mq{Y}})Z`mQZo`VO)I&?XY*qkdS?Y=!;5Tc_z*yrMb*p~{VH}O0| z7$4ITL_7ajz@NZc&LZ`tf>3jBw~NJOL5QBgj3RkUz2ER1r|58FghDu0!W3W@t{J$p zab;mD(2^!u@uW9nj_s_+G~8;Dr&yFJ7My@-o{xJJmkl6({s0?zSfHqd^J#9sibaZV zoX-eczA&n-!XA_jVV&T&Ijk%R1~3JD9$Y}16j>Ij6lGZZ7%?GZLWTK@zF61hOBKMO z2l80921G6O{soeU0}&1)deQk5zt@R>K403WSGi8VW0^n80;P4LKU#pa5#E(03rxbJ z$iXGNgvWT3OTxD;pjq6#3;8T=R$>-MmEU6_PY*+R5Ii49>sN1LxkvO0QlbJ)v6wV= z+-$08fs_NYBet$e3z-pr0Se5BXy{`LlJwTg4GamxP%$V*WyzfUYtRT^x@h@+^c| z@odC~gv*D1O?wG^_`t{^iOd&;3SiUVDd4DUZS6);(6^c3_syPOszV*Oh6W{JPAfXR z$S06kL{X6&7!Z))onLE&J|q7d6RaEeVndOA=A+Bu-j z04(GACdwQOb&`h=9z3>$cN9Qqxr3;wkHUg;jrf z3F=@Ug0T4(#Jh{6SAk6t1KP70f_*Xxo9zY#&n=Qp14!c~f?}Xz*oQBK@-0aqS}f&S zlw1qiZ_#4uvqU|%Edp)g+YM4`Q6j^FHbc~(cY*qV3{!ueq5i?eO1_2dVBf!(hJ<;; zGzTKr{8SwAw~Hy>uOr5l1|nDb)5SxSo`+Ez=0|8SZHbf)!F6j4(Mp*&%rx^YNgy(f z-J;9~rF^0ktXqN%+<`jTkCzZ7Hhkw=>|{bao)JKw1N2;0MPFlrVibi$M2AQ(=~hOB zP(8Xtn!&{b65r1{@!S$=5nwd#FVXL4$Pk8x9Zrvc?MF;)J6(LdU{Aj)H!T@D@>z6i z4^GMy2yaGS}fHMtf zphC002w!MX7FzU8%A1SSokhsnW}|q99^lwqguQwk`WA391BW$0 zSZ3#r2vTdtsV2GHEH5?7#b!ChL}7?ZGtQ3T)RZRFYZdi$mg(v=?ep2{py<`Yss9lt5D-x8X$^;uvup|c1r)b15 zJc3Om7$~1+W8YnuQkrv7gO^Bi1^IrHT$qxGO_~L{IYnNaB3T7_S&IChrV!c0VaCxW zt)z&JgP9l$DLR^noDzfr_6Z20rb!Szpq~Vxc2=fI1@DtXK36O z`!&Pp(AbS*1W7Vmbex11gfnso4oOG6hT<3-5L{Ezk|Z38GgO|bC?8TQlzI82%Zo3+ z_VVMGXD&t1ilT>nON0$-lr<<&U|bnr%*G=;;gpHRQRNATzW=1dmC3xEx?hP!DY01p z&RqBIV)e#iWNm=j)vjWLjxv?ws|OOGX&e+s`4{=&EC!3!Sc1hsg5GqU#oGyxE+vnC z3e6bt90-oId2m*cwhh>-XL&_kT|+$r+jG3>>FGjo$^Z1v{XZd;Acj+1EEZrnByO3H zKNm~w-@pIj1##qJP6qYA;U6RO4dtS!lbOE-Sd8|?QjE;S3gR##!%xa?UmC(f4byec zQt9@k>`AL$wN&~6PijgDO^bp{*@iFM=fwg6hb)-+mr*pIA}?YiVsQwTpe5Qn*u=Tf z-GLQ1;`{-cb@Ssv?2Hhdz(V+&&8uRVDQYiyVz!V{fk$i^E_NXD+|r0#h6#LyB}Dto zj4eA3SZ0am*>S-N3o6l}!3ql=Na|-xl`7DvWy`wy67AKcC<8M}Rd{9T$x>tG zMq6xGmPpS6fXB7!DUp83lhR>+*VnM$E0JE*3*OZ4=wEas6a;Bb{cwqTJKhS#q=-m9 zQ=*+KMUK71P-USMU(UQnICP*agS|=eC%u++0e_N2*;_I|f!I>?qKw9ss{cqZnpyfU z7?m*gaYi+zYCU6p0i!&#^yyGW{E#bGtFKgb5hbqH%?3C9yx#+i2|w>gv#OsH7g$+c zS+cZL6zY0u-Q^Jw8tv#P7KKrx@$4kIWv&NNCN=oxqwYnP*C5*|d=7SMsi zKf!9yBoM16_0BSwQhlsUTep<{9e6N^*7$mDLgmbfJXIYBSQRWalWy^$~ zvNd!{`j#@)QAPvs+h9)9R=U$3DPQbh+qk?x0s<7AN9Y8nSjh+u9DLr5Q$Nda@)=P_ z{lqkjg)FV;>Rs*XEv4uW^(s-w5U5+S4I_EE1&e5TrG+*^{=jyVFE1wu;PV-rI#jr` zTv>^Zky);9l#Ykj$0};O}IYuChLKbwV8L%_)Es|X*nYw zoM9QcX+n9%4xcl z&Nw$CZ&Ju~>3Bg91!Z%EP2OB# zSGMB575B{*F}y}XBNM=Y#&cUMP?l@`s2nE?Y13>g&mgTmxd&4)qZEJ;4)G&4r5*Ez zl+|!sc+F}HQu^e3cBT4m1+q3k?P`dUY$CWV1yfW#&Cf&;*+e0xx<(GgY)J?N^;AU! zghEOk=Tv7wO6PQIrCL{stWB;1r$v-BrkqhD4X&gEI3)^+lb%CyoKt0G1cdaLD(|n< z9vBr;AF9-DA7#9R`D~^3FksJDYCnv_!j;;ifW1@2}5B4E~RRH$IBQD9}usuQ!SCF^o| zqeY!lEls9GVk_8DtrMpg!KfFrV?uS+QZ}owdw4NDzyV~X$#TO}zEv%WR4EQ-`i1YR zmgX=p5A4!dd9a$Cb+bi%rkeb9vxQH>KoNa+W^J^xN6ocXddQr z)LtxVFti1%SfyU9W$@M{hg17%;i`U^NPVT62AVY%y=4r(U)88?3#wU+rWvXSeD7cAL4KI<7Q>TB6Y^3Tf0A^msfj?72n2~hwFrDB zf|iKDv>}?u3N#rPXbz021OCvYSKx=WmMo{kT1MBS!>(H`#`9M)7DjCOrEHB4hHx^Q zyxjswRN0Q6!o#=vf|MW8q&Eee#(5M&dNwjf6(DN`;Vh$Uq5v_bIBv_zL?g0;-c+y)Knjb} zJOtA_s1~YPTUpH(D8iilC0;?&dBp7*OyXhK)8O&a#dy4&%me4MF63dHoq2O*h)j0A zk6r`(U}XsUaS#4-C3&!C6`Mj5vmdS^OX8>r6WmyQw6Vp<>{aTxRZ1KD4ZBaa0s(~iNEvn&s4n`z(PXdv@h|{$SX5i04IwlDO5DTpoTiHaE_5f*pM|&a87IsjK zB8~L6lqg_V5qlpjKIz3&U2(%bJ8|vC)s7xStwb--jAk#;oMem`V7##adSW&90@+(M z82;H?G%2eg4z?27(b0F~>cr*7wgS0frv)IC(9u`71?=?mlLuBKJ)}F*fb1bCu#?Kr z%k&uSmer8b26FbH#W5(51xA3{!NaCbT5YIdi$N(G#Q%%x^0VdP2Unv4eHtL07IgSu z{dAS8#YF1wFj-mUNq{hGZ@HziXAeO$pMRmfEW%R(s8yuJcBRh zAmg=w2A-BAiLDm2taxjkaSxZ(!b-5+9@xx_%a1Dn+kr7(a|WAhsd9W-*i#Gh#}Gur zh@WdiJsgrvWWmXc=fNPp4S?hxJ-LUV_|ydlL3Vn;;z{{fEl`MtooXfEFOrNlpxaSS za^rmeA8Sb@$jz6*@7F3bQ~1Osd^VYkj-FmeQpeFJ*C~(D%jdM@oLv{E?uUQ@)eY^%ndmSuC7^Eej=k_3@UR|d>w2BgWwRranIzC({ zJyXZKq&TE=(LuMTSwn)3eyVuo@D79hYaE$_XTD#@JNcV+)X8IMm3alN=9M>qZ;sV;3D`}LS$bA3s$vECeX)UyryYmH};9;>*%UPrfHZ8X&F z3{=!W^F@6KI#75W8-pILr!$SW*DKdrtOEOF!LLa``C3ac5b)swya@=^->lakhlnU& zYYC|-4!xLvh#~lOy`I0;n97D{HvrQPLNs%i8l;g3UeewQ*3;+Z#Yiw@eh0(I(X|AQhUu6ieec zn_0}$j~iTIL*7Zx=@5o)uwdUuh;o7G%M?%+3fqa3LHPFi&?s?~z#`0Kds?^{4T_@< zB}^tVNa9-yBu|!uBjGbFtjVaFvX6|ji)%sOXE}huh|xm;~<*a z4)9A`gS#{zZ-|W1=f}GBMl^rPE=Yhh2m8P_9gx{mF1$M3UvZYZNzRaYL3)+&dk1 zwT3`6CY{4u3TcA8hcWRwlsyjXKiJ~#+!~~ZGND=YJIP>rAjMx&`gD!r1$8gD?19F6 zpz)&wvYun~G8)mD>Fo)fm)`+YV8XPWjTf*2^zue^M{)rvgf6(LQSpO~A4;HjILB!O z;$v<2TZBpWW}Zu934flm#~m9}0&%aS@2}`bRNiP*0${+)z;vh$NQBo3Bc$Hl2yZ6$ z$k_c@e(M&-h0^+Xf0HbCv_bCk@r>PL01b|_aHl|N}x=QqbkmtM!a=$!OtAN{!+ zf248E?|y&)JXYD^`OT1l5O~)f#2bJ#rwyquHL2faI&gien+<)gbtu;wBAM5!u4ZI0 z(mx{}H)~fe6BWnZHuHHz=xG`>UC^s0Df77g< zPv~qtn0 zp+P&LYzW^5fCS!kSXJ6=>R!6bH#wA>9QuU$ZiBv27aBr~WP8ZBIN}|S>p=6>?>Rs^ z26FVS(QOXpHVkdIIp|rwYQ1s`n)`bWLc7I*j2@Oc%Y;Qfi5EtVjP>eo*A0czU@~_- z({MRaGb-qcp>)}LQe0h5b@6{v^BFIoMYWadSanAmD%&;OGK&0&%m4qyyGY0LpWX2M=T`jd@}Y2gOL@g^|$pR>V`H{ROw zH!xeY8zn=zf@#<_ya?^cR}=6tIEe1r;DCp$kz+6UoxXWPlJ%@?4Hy2IL5}kLlU`3T z8H}n}`(eWWY8(xDj&^zo8q*;BWgHE8j%M08yw`DIvNk3OW9%c!|L#!!9S_9dC9D?G zbWQ=TwsE6wDg%?AaCp4LTZ@NM4TYl`YmeY}jB2chQYZYkWVVKN$%O1F9zJ4JNGclI z)by=0oNJ71Gz=793&%KV8e=XT0a#b#!;gHsL%Ch=mZyKWNmVu>YXj7-j@txd$#*!E zJB*pm%bV0yn~=2uYF8H!YVw=CcQ}$iL=f!Uq?T>cEfqyAjL{dz$GH6;o9HHR~8@FO;sOVVFc=lC64E)+D5?!q%-xRE8`N3btOPpXdjv{|CYEb13(b;P-CDJ=a>e)e!tX z2!7vi!SRp@e|M|exK+J-tMu0`Q7wHFNsSCi-MBS*AcC+-)7BWzhEHwPeKE-#dfSAg zC$>hl-!qCIF^bat0B{zA9AMdGU}SD1o^0y-AX{+!)S>*;p`X^dZkt-P4OyG~Q*@!} z+v5KJQ}%>?z@a=4Z;!Yo!=7zP;P^;JW8F2|lm|iVK@hW3l1F1g)bbBIl!tY;Cqmnh zj%wq!kx>p)MurjI+{$t!E+BT)u&K9iW2VxNHS7MDJa^^I9`|`*8(j{g1-=dhVu0Zj zM*8-Ku>p0#UDLMF968QnI7>ZmpplS|qU-+*7rtVL$Kshl z!fV^P=3_ z{SIUv<4h6eI8%iZr&(C*947PV9jqc93M9gGr;7}s-;>+GK%slGO_SltHcgfdP2ztK@h{ksDs0?g z7WV8IW|L1jZ-XG+>7pZ$`aPLB97{iY5z9N)0f#o$Sz81&UZ8}xd5r%8Bg z=Lq4;ohd?QTdFXx%`B9)F++VC*Ju2$3p$j}Brfzt1_+WT$=R4G{{M6+qLb9oRQoQ- zeSO;q;b2>e@DgNx3o?H>T;|7i8QvbhQ;#7-==b4mKw#pPKhP2za zVEX*e_K+IBQoCgv(rH&xI%%a@b)|IQI%Ai z@0HS~jRpbNkSbn=CanZTzB0KU#nYRN_1gE5dt<#(_7mie#tA)!Tsv~S-mj2LND{s> zq-*vEFgUWCYxXWnCuufgcammeQE@9_)kV~-q z6uAV;LF5v49^IMDavE|8mN}g`MS2h`xL;uD#Xibg+@;i0RC{%&VQ2o$zU(eqMb?|8 zOWbTLnU-xgbxI{Xr~ar@s!1dr@gxe+Yh9g!(A{Yg_I1+oj1BKA>iaeR5nH?wchCW5 z^h&}(2i`eI{w6P$uUNVgvoAWO^&pEkRn?JQ(zZl$S3HRVFgpQee*&|=aAx`^foTQK zme}egT|^X`(C2)+QJEcmXNzU9QWv|mmhCV=eOE;O1y-^LvFWzh%{PU*x)d2W=lH^=+Kvn-!*ju%-z(N?ch zo@ak*TStfOY;NthSCW+d_@y+rcBUPFDRHxBtXmK!x=q3~H(NMY zc8$WjCZbSjd?0u|K5vqTPb)}xcZGd7edMM_ z__hPDFADnHhJQdj{D51}(=R(bVq`+_34z+=7hogEj~Z}%4Nd)%n_gx>0k(>aje7M% zlKi+kUwFlBr>cA#i9Vjje=lQ9cM>T6vl*9lE04PMpUt4~fI*JFaiITp#-nb~R(|1* z0TWvQ+77$l6e9R~?j;Yq|-0g&{ypS;4Sr#CRq_ zqJ{yDm`xms$1zWItH0}3YCyK88`W)~ruKEKhlkTd$o@m(8B*K2VI*ThX;7uD;IMU% zF19*#k8YC-@vzr$Ssbr?I3CVPY+B)T8eGkMPt3?)~?-h4w#l z90tv!vi;8=Kr;CDo)>WCg$|-D{PG@v4jQE<;m8X|@~-V-~hIy|u%U*)P!4+PtHhx@7@w}tHc=eHf0?+*33N8Z;K>a*>1hhmX; z@k@0v-0N*Mww@=#4|@7+FZ9`hw|bt(bw&FJ%jgi*RfkH)1)uRWZOP1y<;G6@+LKm- zZ0O)w^@QiDpP&7C>>qn@T(gZ({AgYS8+y0&!O>6qurrY)tTSgp@JwrE=9 z#5qsegpy#)6Fc*1481I-?qP1MSOohVxy?UEcHwIAo8CO1CO_>@lb^)(xZl)!KCMWQ zukhK6uD5?}&G4R-?(5acJdtp%S8no2*9hB+#K}U|bdw+)tFhPHXUzC)qgPTyL^`~5 zXz{W>+oAB&Ui`40+uJZGhi~)_&cmOvq8&$bChQ+S;bas}a43AA_m{!%dvP@TUHl5) z((r5E!P4-1UTL&=OxN!9sV%;-82}tQKGuZWU`kjJ21kT# zzQHlUdwiwo+fl90e)v_};(Cja<}FQsVeE*P&G;0j%~vW)A-}fDf9hEA4&N_>fADE7 zK9JoG>-VW|`evR7y?&56;~NwF2;A^Xg=TuBhQL!nA3l`EVj#<{vAb zj9OBseIXtWe(9fJGY9|dABeO=X9V0MSp%c-laFuvEf(npf8XHw@Z`O~7`0bj7$9@R z`fN2Z>zC*8CV(}M-UqOLeLkz3{sgQx$`@|mYd!3bX;?S$Ygrwd|JRBFnxAD ztgvST6O7WYb z(}Nj-IcK8i$0eUl58y;}eNTV?z`l}`&}r;ANWL_31S~EINluW#V0A1aU+)iT_XiGz zpYsihC!Y5m{G~nU3q((XFt#5|_@yKwaWZB)>`(JThX|YwUZ$U=ivcaG29gbAmF_qk zzBkZ=U)fw1V6J%xiCt)_2q_%hcj)+__$n!M7z!~p!2g%~j#z|ld-n<(6C(IVfH%E5 z*$)f7k9LgU=j_xhKOR45qCPmXwI@oJ=!4c{d!&q>CBe}>rDGzhwZ~Lsij<~9qO`!f z(dZTJblNX+@Ngtp)kNJ*6~A1I3KI+0_n;RaI(m&yGxr|D z1K>;#9)~AmW2cd~6tC}Tz`g%a@NkcG&H1!tbrJkbYu12zdryQ42PXy3^hB(G=wU+{ z#8SWPS?^&Vv+#H@j^&HX+P%9)e2Bjzea!5EE859p$4&zcP>rY?daNXCUkN^z2-iKi z&c4l#u{#nAnKFbl*^AdB1NJe&IlTu1rqM!Lz-9}W#^Y{!`+Qo=)@L6q4mx`Kuom=U19S i>)UQy_vDeNG#j&JyDt`rc~(lAW9cdlwzSOpfn58R8C?^LT?hP5PFqfM5JRV zQWX(UDHghbpfvs7!S8?XefO^SSZA@4DSKx2{ATap-g5%M{?8u-0)sG+kpKN>XkcW1 z%F@!x$Po*JEI=sE|GOIUKlPSNkOIiS%m1JHGj@jYP#EOw|LuRuz|z>-!r(xDBGeeN zv-E%Z|5v?VaTZ$|EJ#4!NSx~8H)w`e}bw*lC%C#y{)mqiGw9tI%2tDY>@NM z{&#)gpZ{8byb%@)5yL_bg-3K5!Z{vvUsFl5%%2H}BuMj;3~Wq92+3$Ff)k>QXG*n{ zNO-^$Ur|9gr<@*rB_X(hpd1Cu30G!*Gw-R9{@4%-MYRX2rZ6!n`G;rTROPpfs|ix%^2q#io(nYhD^^n|YV9UR#RfJ##d(aBE5O0hB^dB1?3{o1ZM;zF z5sOwL(M2^4i4U7ey<-K9?S*alV9c=EUljQEcgVeNiWyeH?WYkPai!_~`+Z%gRj>4~ zMZuzRxv$a{(+VFM6;+J;)(HJN`9r;92&?gR;No0x`WGrA<242eY2QTVX!a_r&5=C& zv*yh$y7G~3L7$l5v<>_-xaU`1#c966KUK16tNT&ekfHepu&h`q1YPS6G}e73h2 zN+Khp(!|+Fg`GQ23m0ujZ_jXPh}-=_eb#B<&Jnehdt)TO#sn8bzBe6hIC8WFc_v)c zcFx)0hVAmur#NMJPRrGXI>M+?RdQO*G~!N2ZOTwg!b_DBYxu1%1?mLr>WA`NSCbog z^9Gbg%b(k%S1w0cGGF-)ztCSxA}^|bLM7cAP`MHGQS+!4VQ8={#@2pZEh@ZAj@{_` zQ2%&`GlS>*T;O*Y6Z9lXIflPkF<(WVws86^zjo>XLeio}dvH#KXKcuqFkW}4%|bQl z+_JO#F~w=cjv~a^Q!c8*;%qH$VmtrT!>FVaDG#fkC=NbnV)M8@7@d++^V4eDgrOWc zU_Ul zyBY8(sWN9CI`g`%(*J~YK-!2vk^>?_Le5CaA9mc-dk;ot0#8QMHZBa!` z+&2boCn;iAtanRuSt34myN@D6<{i(;_B2*A@c@T zvZ6AndRnL>SdyAov7m7!vYhh16nQ0VtnzVW$vAU*{NQtil%M1xuI-!3N(NG0YHxXa z0EWilifOIs9)ammid>t}{$r-Z{tnHnr&qXJnjY89P(@$ro`OiF-gI_1Dk5vLRo^MFZ&H^ErFt8zP2!gXPX>8dyT-{)~cGGhg7aUX{U6QX(6sa zT@NEsXx4F~<;pcrn$W1;CQsbrT~yHO1I66P*TP>@1##m_8G z4tB((YOu(c{c5yz3CY=uI>PNBRTTaxSaR0@5^VR?JO7DBhWVBLNyK&X+jF@bSgLU8 zp^EVR(z+<*pe?ELaN&-^*~o^cH%0B)!du$0ef*u_hmq@L_jP$U%`hX6Y|y#OPkCCy zS-sIJ=I#TqhjB(<7TYAQKH_`vt?!yw+z0kk88)vv$GT)L1X6!Od*$fJuzsk6c^&_y zKFEkq{*M6%r1iuR+~K>|mCLnnV0#YlF?`Y-oXm>bDs*xW-{q>c&-V((H*G@FqId8o zOfRw?LHr!{RXKV3D{WKVy7&F0Ii)d|en^Hju@OGk%Oz|+ct}3j z)*^f-3?;rfJ=382gsDm1QPGpVTo5Wj_;M}W3VJu$GEVx}V*J^X&7_qtb&p7r$3A5w zgmWAU^`O`7Wy$0^t#Hq)C1=H7o%ZXr%wtK1#5$pKO_jbEzR}^0OpVxWJ;Iw=df4sk zU1VI9-(jT>nQ*+L^WpoMtc-#48uW@h_A5$~s@+7$*f&1>I$0}7f<7IOYBw=pjuBYk zN5|nTbrSEko#j2G9L+^#PI0JyvHM!X#7#arz}=;RD`hk5*m>@9NLzLh6K(2zuZXpb zB6P~-hh}k}7DC>#?(~O#CoZtTAlvcS_&4L38!$H;yv}^LS)v?S(4#DzQ=hwvtiTe-!_0a**%@f1)!mf7|z{4l+^73|I0|^rZWh z-0E`Nv&-CEmsGMx68oG9H{r#Qmc4(tj=_HceQk=W5oA@xTOW>`aUIjllT*v3{t*&9 zeNk+~ru;$r^}d=CmPF}b`eSvT%E6*oJiqDqrVjs&&_GHn6R9wVw90OuXX%CLeTl#&u>EpbHogDy(T$;}=j(mlY7A?# zM=c$=d7_&YOJ?!mDpfunl>yHBrZ||VYWcKi4M7V&A_^^R(3jy)MwOSK#-eOz>dBuI zmzbL>sW4M{B41XaA|61X^Cri0j3C5zbjTS&D|*wjr&vZVr0t2u-gp>2tgj|=>)4)xVQV+D60^=|JSVAK45^=EK!tfGr&N^Z z5z(n5FZt(q1#E3mJE8Enz$cKeB)&2IG*67lYE&z5lu&nUZkH8DBvko zHQ_E=fhA(a0Z)D+3#W`y;4`It5$6H5Gn+K}i-zKR@z#uJ+iE!KeNnr2f@{7+RwISL z4{O_p(nFy+Pa;X1X-YM0Ze^9)IR>5PPhuBidiRvA2Us}f`E$>o)QW;PeW_s zH@?Sj!(m#@T2f%aJ1kt(mVYo?~OhDUKX5O7Ixi1GLwt*P;2MQ*%~?Lok0~)}b^pz=EwJ(;QbV zqKGA?Z6+{Q3|=e?GWN@1f&~9w=6Mu!ng$dKLLtIdno?AP1k72s#Y8j$l2k~L!pVM3 zlrhZc{DREl=~LYqLJxKY?+9KPrL6Hww4&t*_`1_hfkKetLwl+NdLA=o@Ds7}|Et;IWce;~fz|q{ST@>btEzFV_wy18o{ySl}DFG$U z!4P{R@|qmf3e!JW$CqMZy=#eW#a9nh=sy1Ph4Dzmsltm_K5ITrlT!YR4APN zj+Pc{(GX_|O1KF7PB4+pn!uS%;{q}z+=rM*$gdH;`qNH#TSs(yS zbWTL<8gUe2--+F{oj-iORpi~<8!&=>)Per{;sbaO0KQ8-sJ5$0ZPzb!tl`{cc4a(~Vh2T)Ff6wy

afKICG$G0Ng*|1MKlfjyy$asEN9tn5k2FDYpvsje#5=@plYW`H>s>kF+3cg zwdIKX9Nbn3IaPV`RsRV-{Q2W*Rcy|qEN!2NLQStfKV>^Jk`?g=j{4db{9f#?Z@8rR zd#Yh+1JY&Ei-N-z>mv*BHaTPMEc9Wv6twlX!*G~wrCEI67+t)s{?}|Eq z`{8-A)cK5%(%LHf+hqHA#>#LGxUxYyTh-j(ovR+MLieZd~b zQf$;lj}iDTT5Tn~=>~Z601z?YP#F#hw3wEhi`7myw;>c=${9jMy}3su;D(wLiNf4N zY|goAtm6+O0j6pT)JJver(C_BHn=5v!vt#^DK?<(O$A=gA$DZ=$k8xgc$S#uXxK$X zapoYEIf_wzr$qK}vmn%k^96tX8l2O(*8*KLfqe=q7H^u?aQ!WY;ZT$Cg*hqGUHhwF z%9Quuu9dip$OQ=_84U5!^6J;mShY7|jbLy$xK0m;=y0k`tMZ51b7<<6xu>$eSwwkk zEr-x?7mP4fR6)Lu<(X`Jck3#bQy{03X@Br_kF4qz6Rp=D{-j+veB9!v^W2T;$;0&y zX-PXK%*J<#Vk{i?q7+3DiU<`ZDdOla3cH)r9E*d=rF>dE<1wAB(vvFNHqU(hF#ASY zvRCkj>cby;Q<1qvW!wRLm<_16oM7 zvqc6O6q2Hl%I1sgQ&sQpBo^0p2D>90HIn-PPL;=o4a1$WujJP8vFl9kJkIl0$b2gS zn)k~To4cj_9M!C=b}7>WmAx|KO0)>OPlR24^ZD1_+A&2(qdIb<4v~fV-F}DjBELJ+so{yYAjENqB zsW`(@xCiCm76uLA6j44VhkP;Wf4 z#03MoD$zTtON`p&2gbOPP6=#y>x#I=X$ab z{knOw=VF2Ae0mO^^`-*X)Vutl$r-h-CE}^0h2)K|SEg!STJ0`*sz@pS2t>ZQpK6m_ zwt7s0*6Z`4`bUi5x`IGJy%38O76-*#wYvF1QM7+Zg4ini!Cp$SG%ekNqiRGZ4kdci zo%umHeDnMX$t-EuZP$0+RN^Z;s-!eAR*G^ga4W`vsP>k4?{NY?nRdz|-?IV}PQRsL z{NS;`j|51j?L#D48g`Kmy>q3YV>WtMyth9`I*T#DQ{x>S7I@k9*2&65`RJIkGH)}a ze3SBUd>EYP#}g0J2trc55{>7S-#Sg?4FV@=QgMwW{3FCZf%aO$L)uK_ZX!*C$9k=Y z!I*g^x2eyc-X65ck!l)w2(41~lfzt_gM5d!o9@}=Jd8w4Gu_tU|EUp=P;h?=sR(oy z0}6Qq!^MEEQNAp(!e@4{oT6+-&Y*u8ZN?~JKb`U{AyxSmR@zrsj_NkgXJ*Dhe#Qwqgw~^ag1_`_ixc@m zMV87+Bp7(Wa~|-_R<7U>A5zwT6+)JJ07Y%VoAyml8_*NOH4~ov3V$7{Un}C#jNCmX zpcuU?6x|@gO$Lr;+DM{#qcM;tJSQ%~ahKd=ZYFG(#3u2w9w`c!$llSwpGnSreKm@4 zyl&rq_A8C=(hSvHKagGeDeP8%+|%sT+JQ{Vw%4=fT-(#;cw3IwcVOj`SJBz3gA)q@`L((^7!Sq@K~PAb3*$q_(0Zm!1vVsNVk%B9ntJT?Yiva!|Fq8`zaxx zc4^QZeXf6wFjIcEQ51Qh;l)sbbk)es3-~t$_@aQJ-Sru<^=(B8LFBv~otPOkJ|qYY zQS6fxSc~O(5H22Y+=wiNCX%Izrs!|HXN>b$+Yf5P-l1ICB9eT)@?jzrPm-40{LXoPxL{(n5~8w0%|M0(6O{Me~0>qLh!P#STZYn3JsX!7{$!`}=&wGLH! z_U-OXPdVZ|)oP&q2ZZP5|2$v`aEVU>ntGXBaHTDGxu8%J&|4s(xB!oaABP*E@JzY3 zRl0@;x~QvA5-+Lwf|;O6^T1dQUWI!6^Iwl8B6s|M1 z<|{%a^3P0Gi9wREEF4A9`QFuEAWn9sRWg0D-)^_^6+qba15;(ItA6?Dq`tK1;a`&X zL5U*xyk-OG-O-{TY8BFd-I58i8DIFwXbYCR< zwxwr6CY!DK(ZV>&8akxSmF@H}DG6iMi@%+4ac{POs5Thr&tt?^o_VB!#ei4H`cIA2 zuiR>vu0y8+S~w9>e(GuAf!j)d?u@ayn9&S0FxEOq2KpSu7IXGP!hY#B0{*wBhCuv| zy})oXB7alsF($LGm@aVfvOjR-T1-hP!+w`>{V^kEYVRH|RaE;~J~ycUr&w`Vh98Ki z^ZrtlJ%iUoluJ2#igd^sPeKvCTlpdDG2`V^$0r@Nxl|=K|cO z?3+sN;x5M6fA?|L0i_j`e+IH-t+Qk|o<5%3mW94qUTI(gKCofik8^aq81|@b}9BO9yoE`|Vi6N?_4fIby z6Fv=$Kgg0h-Wyv4WlkRWk6D3O0P-S`KrMo?O-fJtrS4N#4 z2ln4g{FR_!g`Qv5XJ%f4%yN9%nVyNf|McrSx_CQmSL@0@fIFcoq@d|xLC?HL$X?ia z{a~a%@F~YX=-AM$MY1d*sKA(c(HgB0kx`H&;j^O2+?;QzP|&~t2#twCG?Sz0IcFCc z)1N6pbfXVuJaA!vJH~Nu|DIv70b}*&NvG~%DPpqZM%tn8YhXF;s;0p9{VTt4%h_KSh$uclH)0z0M-JTX9zCe0F!Vv7E|*?& zp)mhn003*4QywK#_f~vq!i_5>|2!WDG=91Q8p$ zu-qvXZ{Kooe)(0GI~5chn_mI=!dD(8eY@>mx0b)0SsDOMfomZYG(-cvK=Zcl@Gt zZuI0H?jul+t4aI=^qO{dWzT#XZEAhPX``Pl`JeXxB<2P*{W_g2NLf9%$xA6{ab;d@ zXpP+vGJC|{p%CIMVD~uFu^;~GA7z|*f5a1R-3OpW65FZ6gQw%-k+X}2n0E{=B1!U;+~3rzET(+kjQClDV?VOq=MOt7!6UYF$+3^x&1 z8%M#MMOV%{gDjDfKF;e&79DkzH|Rsq{{UnywQ@Y^<6HT0D#xqyEQLIQo_x(aBgVrO zOJ7Bkc?1+rCow;of(p68(-;tIJxb~yAeo(XYt83;VlzrSbQ^bkTI~7uv6|4fG){=C z-l3Rs=N)UBU-NW~L}G(&Lva@W+KR3~a+c3vVzh+BJej|F@6-$aN(CWaDa#7UvlI7t zI;Z`qL9FA?<^}v$bZt+*4K{aY55jqp1$6(mBq-~;`K=MSbAm;^eJzjB@$^$o3Ag-s?w zw+x=h9!P$A^ybiau5-=4Nzy^0e@k{p-|oHt2SpSpAl~>ZM^de_V`$x(s_WymTA%h; zPCV(7*{2s`Lzvi)>QjZY?@eiHF*k=kx+h;4DH#1T6?^aYTXJ$U+gH;Y;d93XR|c|6 z$U8}EIsicj>a3F*uM1^rg!h`kKW-qT&d}!2$JXdv0c~$Jj$CpZhJ{NI!;4>tm?~`64*1n_cPSL8gD1 z3F+>=!)yO^Z#@uWP1V&1Bc76p9{ysFTsoJ2lh~^t;@En%c!|x$3*M<8Zua!XFoqZ; zP0SmC;V9h2`WKdNC7IMIoAAo}%Z}h{VhfLxvzWf!qQDSTh=~|%2nB=48Wihu4khyQ z&0$$j%l#hlO2eL{>vLsC9~CwyVH5EXWx5($Gy2gtln9v~egj4CGX42uLC7DGOH9@0 zGj^ma%7Ub8Zk|rg3%>C-kyzXpZi*%rw1`!%O$$2-A;U;Ucj1y;X`|Omotelv>;{RO zjD$)7aN!;s8=uq56rJ6c)HwG8Xu+;t*ACwh2~J5yy~aDWpmbiRU%VDM6?nJWj+% z*X=^|T+SF}sgSenDce+ny)Yv85SW`HHc*c-WZ3WCM5+wC ztbT`H`QFT%S%(lH=c=6T@A0_P`=(c9zs!P&r5dSO5DCW zyTvUOnqU(a6IAAYi-}&W<7Zr&!lzAnV0V=Lab!dPnm-X@9s(Hlld^h9iaKr??4X`Y zmAYg#Ka2H+rY3mlh)j`=sR0n~(*Em50~IwGA1C1sLSXxTyb?-i)Cd&4H3Y89SnP{Ozm zyV17ZcZoJG&LE|my`OY+0DmxYH-Q+sK+Zwou?nQ8W23`G&?6@s8V=eg^7{Gb#-!R4 zUq9+Brn*3^lZkt8MX^wD6d&o>U4M=K)^s;m|Ju^T<={RqWpVmQe|G3tpQtLZ*tGYTmWA|5MC;Hzjs%Q^Uy;S9x zyXmhK>BKe($v+6v3gO$poOpjjhDT zKIgHxzZA@dd5u1YqNJ||?hg6mN^VFY*FSv@zzLiFigG=Ef1Ulr<@ey`0-V>{^MsMx zXwh?%07D2`b}3GAwL21*66XCf@>(QAh7y{Gj4EUOE|!R*ulTR9wkqd&QibAa;b&;a z)>(+-{IGesJ*@m%{>IPB)EJh@Fdz*Hs?@Htvxg`hrP9nr)2K86RZY677){uXHwsl3 zp>SOiZM%QOD7-nXQjxiQBU>>;#Pf9>&@81H4UwQxjP8GzM4bqD;E|P4Z+dy}ifCI9 ziSF6QIzE9aZPZk~&U|v?tL<}P^N|$Pes!%ho(F6I)++VIDy3ngA$l9}MB|llM%B6` zpY@|8S%wQSVM$Lk86{U_oe1Y38LY__*_!#u@F=9}qWR&;w%nRh2HDmb(iP;_g@?{h z4{lzgshGz+%lf?R9`lrbz9?e+-RI)0`N3o?55}4Yt~deLGBerJt+%|St9c0jxR%9( zOARZR3`rD=lVo#F6pY0ujVn`5-7*Z2i!jjdZB69#)WY48@Y4!pH7S6I*}RMkg^Nu3 z&1>4IM`~^i8QZIyVJ+n;7tzo~H>&9+obQg& zP|LO|eundCAvc^#Yep@AIV-NcFrjL1V2CN+9#cBVPLkBAZ|j3t+C&eFt^5d(38Lx< zD@RUql|E^cX3TeCWuTgwn?7}yP<*&-OD=1*VFJ}WPe7tjT$lFm2T9%3`jTuj{vgas zV>_G6^$qP|g0wiGDJ@qPKNU3tjcb<@X8?z*!_6LJXj;~{3tOi((kpvF(2}BNETFxn z1UYIY0XWozpqG-I@vwhvqns-=+Rg4NDv}x$UXCk637QkJOkKo4q1#0!_&l;g`KY&w z%fzo;YwiF|5f=ZWXQ4u5I!qjONN~GM7ddYD4e`XZ&&VrwvO!Z?5e$MjVBu)g317g# zjM>#9ZW_(%sd*KGW^?4wz)BclPPI4X>cxpM6C?qH8su*IL_;%Rtto8%w__n%#FH~R z!IqgI0T_go$-RfQqQQ-Zp_RTw1(u8YU5u48I&M(Tll7Y@>AFj6=B~TM{lG6@CU1=| zH-F;^FNRhsef>;)t;D5f&PVVmC{iSvcaFwKqhN3vEXY$CBNyFK$F;2WZu!J_O&S!tj zQ?yYmygSDvA9|?C4@;yn=uWN)JWd5$&ust$*N96a=0i-I)UO{=(&wRlIuh;sb777& zVv@=YNtcuQnRVXKB~}i4v9gOA$$-lL30UAVM1UCJEf<<47;O0@Ptq)f1SOv+^^-j6^AyO9H1OKUX1 z&90B9cs%$6ygn$&u!c73nRM1%01t~m>}QXNFriv;A)D?l@V%9In;wsfG9EVeNdD(x zTjZQ}llFRY78Ch99~AA&wQD_eYl~bUAC4Jm5U`ou??1k+CGu4t>Y)Z6t09;q6qN~Z z%{1z=8~v_hbl>OY=?9|NjrQ8F+EaDJHzHIoaWCFF%Ao|(8~yo|zN}X0V*lE_@+7($ z1V44H)#oqxoxGI0u#yb<4TKCUUL!;fN*Au(F4Al+3}UE2G&MTjY|O*Z!)n(f^}!F< zG@}z_ZEbIh2wZLxW*N|^wdWzUBv@-fcZ&S|qXq1VB~BGOZi7FWVb@6XFuFJ`XH9>; z&`-KVrUzP{HP~|fbZ&xDYil#rUR{2haqp}#sQDZ7FqW6UG@6T8i1?S}7aDDSEWkWZ zkV=pH!P?(=$6qH?Z!Dt``Dhz@2r-ceI@~9UZx?AAG|5+KyBy$Dque&YUZ5P&r%J!T z53BzqoL|>PH81I08P47?0hcC!Qv^5;cRSf-zcZ!nTc(u|@$n{X4HKt|1&8>)qjvw5 z{Ksps}umKzAK;Sh}}Q)hWi zZGBY?+MHCbVb=GJA(8|4&A-A5MZoF(_i{oCxrkv0y~-R1L^ww(ydJ>QQ)8m)2(8WY zFGrv&>g8>Cic^?Sy?i)smS8*sQ-=Nsr~cL6!GxQ6ivfMC`Ol5hA-%a&Zw`e4?IRgw z&U7jLtyQ6+<7G2Jb*vxzhFL$3Ogf{WTkklwMZT9f&sjKlHd&nUUX~BX|GOzUPnGs0 zsRsg4%_UC%FTHtLf>?rSO@MkUSajWz97C7cjG0*&X}>#IS|q=%_{PS*0nBmId)9qF zCH2K_FR0b2p6=+;zjGGe-aNip#l76j5zyr%g!SsXv3O|YQ<8*H7%unL_rE)pb;0YW zQFd)(-b@!Nv$#xt=nT@Dc%Ht_PXa@bM?bb zdwE7~lad75R33unWq09eKG!%oKVdU6sV%6b-CrlOh6htcYvvjGV{QwD=)q^Y?hwFN z7aE~f1g3B%KiPGB;Xq<>|Fs1Vs)W;eI0wu$S|_M~@Pb0Zt(qMN=LNu z=VMB@Ixe{fTWdfQn<3_1Jt2YCOwFuSrK|5#a?= zF}gFx9=^NOXRq=b2|aboeC#&3A`#z_egXzqd}}M5N0y>dZ7M!)C#vk^Sa%{J=EQ3A zFrf-2(y#_dV={sI9`|wu5s30HlgN=k=#4jhLrl>FfwiI_&uLfLOTwu(yYDPr;zq*8 z`J5`KJhMJR$8HlD(nHfvLGLCQcTja5q#t?WmuU)YqUT+Adz29!I=pkIH&*|Fo zK)gDhL3Q#Sd7Asc`w#+37PMl~6`AIMjiaEF^fOsJ$8#U3n3KbWBCoCoh>+y~Nj@k| z+3@|YiIM8i7y0GS7Y>F<+Oiu*85-7ur~69#KD_rm~OFW&-F3jpr28 z&0I8XK>ilvrEk*mJ-+<H7Of}lz;xl zG$Z4=^I+Alo6HY7ail%@>qvQDq*)h8Ec;|+FIcxug8-xG0I-FkGp72z9k-!NZit-8 zl4CPx%#Wh?+U1M?6iv32FrI<52bXiey;HFVp02!nB&X%*r;vJbP6B~M@SXdg;2jvqys^L}}Idu1@Iht`&la@iBlN^3v7v@#o&l}uTUE_Qt zcj?H?`aX4kD}@8a^XQZ4qSS%FF4c;)L2yL?L_i>3@|bcUu;g~dQT)qBAd(Cc>^}1x zp6YRB(3Ln8{>eX$%}@?(-~Lz9Lrh!pnXn0sujQPrCb|EEbx{eJCFu87!moi z-xr3XOZxw2*9!-sby>n0KhxG1#0N6HlhNmnRIx}wojG9B4L~dJX@@w8ZIzV`y*?1ZPOk3aIpi0{FpHU$-rla(`O9$KrMw5s7}`- zJ!V288GmU{UR~xx1t@xpocBe&HRWG_^lU{cpF=a;rk7`U)TW#u|BMYVI_D0}Bg^)$ zu0OF;%yqx!X^}m}bE1=zg%R&PBp?D(=nzraW{6d&{8|zKnz93gWQ>JlCeR*WU=?uv zLXe^|F4+(K3@-T|v_Yc+jZ-SJe#pGlHqCCZq|x>HX}11>-<*e;baw+M;c-7ALmj#V z6Efy9g?5Avgn(64%oAD9<|WN&@L{x}k@F>4ry5znLSJh4v4x>-+RO)bqd(N<$e8&X z1@dgz0=GZ9IxC1QVt^*kTHr=kvNt*Fx%^h@O0 z!?XZ*c-MD(e(TR_v6K6!9fF#v35{(*+egKi>O4VD_W z1}xlE*JtsQ+7$~e$mg;*X+ujsECyC57k|%Kzv30D+5UQEWM)DYa5wqI60>b^(0Gp(rtPmT*+Z{*p_A=?(m5UjlI4X=EoxRhR}pY=`8-dx zzOm|>rlZ2L%{~eph3M7TaSrIMt*;m4n7b9lyjweiZ{+mM3dl%B$` zYPivV_ovxpT>QI#%?0ns=95x$JJH7dw705l{VYEVf9)n7L@S`dv0392s`Qnn2MX0u zx5uvF)|zxgvq)Euf{t=ZApcRlr%5{^&D*jnqdi*~pn!qi=x`0!@#p;6zix4Ad1_`{yj)I*a*Ou-3L z{h2^3#F|lLlzG6WL{4ZScR?Y_BQVhZ*8t9Hpu4PEL+cG;-n71&-lHOexPglp9T9%G z-OOEol$j+WRKyH^He&c2PuHt{;)tz}EY08CL}q!}IN9<6@yPsNIz zvWqUNsdFLtWuf{IQ?ufeFPAv~R5+u3d1j$kW_&xF?=2G=!!f`riyyoJK27yTz<^Wz z>;7`HDFLpaNnB;Y>8tMd10n-bzot6DuZsDq$)eys-fIbslV-wuY*t?eI{zA6 zh`{p$zu5upGI`Ss#*YRf8ub-u{zsy-@^pE8gz;Z1otm#&B6}fhkQeq*Y9Hh(%eA7z zMJ^y#S1b^@+h0BY=)asyucJ2e(%icI4gM0g?VrC75H;#vc5e`T>n3(aEn;z15qS{X zZq91-pDwm6?Uv5L0)(EEcG6_BCN6KQ%cTJ{#q?Mn_+vaswzoGPDYJ=MjZ8J#(4beW z*P`RmyY=K;^*^Ns07R345}2%@f^PB7Jmy2-Qm#U>Q}90|x;#9>2!L=Faiqcwi)!?> zp@)S?s?Fe8I|?e~`-HD>k!o9`3gYU!2V3P69cK38{~<)Wvy5{=I8@~JdPxt(f` zH~MpcMx*>%F>Ol9LwIZpa55e_ln8&<-)*avZBRV>u0J<#Yt+21{-tf?Z+7PLV$t9n zjT$5Yy9OAdJy^^@41AZ#O1ZBw<-hKtUBP-Q9=Wq13rkp$1FbrY5@jvfD-JB?q*V5q zfCCvkyk*iV&eaLEHi4`TdDBmxwU>Z7(BJ)ir}WY#98);^>+*fi3KN+1^Y#W2VxIAa z-=kx3N>?~H6lzs}BM}#CZhE1 z+!S*eZla0i{{jzZq{d%u3%$EPcv-qId23CTL@E*_-YU5VOV5=TEmVVE-AB-?8u?I> zeBEv)OuZ(Ucym5YN%S3Kb|_P9#FOqaR@v6x4$Ws!0ltYjrreqSqonlaYdVn}Cl4q@ zQP~Vquobi|0z$bTT2)EJTjV^DRId#^ysefuV}Ek_UpsTzAp^RCsGsgpdNU1jTAs<< z$XHd<ACkB_sB0vGw2!&PP-W0U2brA9#ZRb-M_4 z`2v4bYS}l8SXPvZu=kU0EZ@+!O^J>%I(3}zi)6wT$7RF5L|o&Y77S;A_J4?+Ht{Am zhbJNW+N5&^#_9UsUQ*OML5zy14#1#1ZCfX`vcdqGi8{o)0&fpvpkR}C_Xp(j)#ZUD zM^I6J9U@M4`$6qn5RF%(Xv$FIq=Ui%didGdz9o+^D4?U9jc@F@~0yQ8B3Ey!t=%K zgcazD1@d01tZYPTTpn3Qh=2VPAs{EL?++r+Kp-p^v@p=a+7z;o_4SD1FLg_6a&OPn z;FD&ISMNwg4D;N32b^qAR&ndLEBe#XE$l^A&Q6W|jN}P>xzfy~umxKV&a1T7dQq_& zvoLFaNc*qT`Lnd)qGL3BeObhJO-3Cey%EPvER?pWbtRf&>%R&SHEcLzhPn*EUVWM~U;Yx#1I=K+x@Fbl%(;wJ7W3|P(9xeS8J54$`fpIY{qwTgmNq%N5kHkQ zJ?ogbyV%bL`Z%if>G_YmYcGe3p;hgSmj|ZXRma5zgfs~I1;MxfHDX9OuSP8&^hE6p zLlqjko?O7w)tvw`r3sEAGZRc?h?z;}5BE;c2&<;ogH@vQ?0<#qS8uga zo&20#wXn8L+6T*7GBWNDXuLada!lwljcRv^I`Do}_plgvxw8Yv39dt|TIrbT4?a!z ztjUSsdxLnyfH>DfKP(8*FK|-mnTC|n;Lt1r+FASX?SC;G{u@t}w3qAwPluJW=55!- z?~>w?19xexBTW#TbgCjZV9FjG7p-`lyo_{c&o9wLK`V;_wvL-$5?cRN4uU^zp(SJU z2zH^VoMlg(YuHcnTOD~Wx$zOba*NqsnXV+l?XT>#5Ew(LIMyzCenZeUx)rFrk(6~>Q#Ki>R{&7F>q|eme$vsDfE#O&bVi zTKh1lffs9NlQ&!;jQDl#R(k=RO!14gHuPFs136eCCu%#pq8iTfDVnQ)izT7lVX4@2 zuy`6gyrtLgb07HGwf3D70?2S&8c`e(Mkj5x7Ia&|Ty(iZ7wa?zSjpD9`@k1B2TQWO z9!6@`9-nDYZe$Gw_g%C+VG6ubH~W%A%djxP#5EPH@+>p2Jn-%Mm0ou{g{c8f-}(WQdnHkz+!OuGZ zk`Y2{_#1k=q3{-lE?y0X*g>)OXjR3;qYJa(>iXJZ;Kr@3sKHpbh8c;s5xcY!;VxVL zB6j0KzM2E*t}$Yugq@>VXfNGgGftt%NQI~c^~Dd>U`z_4w`RN>jJutDH<}zi6+Arq zLQ}&|{fu$@mhU*`iLUZTwCK%G=ZjNB`FWn4a7BVK3%@UL!-RY{2Lp#`#KHW*7<^{)Km6R(>-<5IYI2{Qp#g>);g&XIrd?;`Ra>RS+mb|7 zUuIZOlfY}HrQGK>S+u^*gO;p;2(P#7*c7$v(a*sfE6dy#@b=-=T^0o4p(#&>^_+|K zpXXqBd-+iWA^2kifmg-!;1+DmLYj0>b&!36DBI$!Z`|cN~cb=4{zoU=mZ65H#tKWVI%eT4&W)X!Ck^pg1{mi7r zx!+pt50)~Cpyd|>FXPzUBbZ7M>+H zesbBxDb#2oZ|mNry2a6|wWQ%(qy-B%bU9Y_@XTEkUXXb=qg#QD84!fyCuhONp{&Ce zEMfmPKr;>+6orP2@S*SKFEgL|SazPp(|@1t?IVTSFNb^|vT$N4E0kxiA%AqM5KfbT!MZ-iUE0(3Y?SgC46H7S;hu9#(vLb*})fLQP% zy9jty2)60IF9PV4TV%y>S3Hee>y?K_y|Uk_6}#nMzR5Bz^|mLOXtba*o(NO=&0WC- zTzQWQN_jh=sTYgpmh})VotF6zg;u2y)R+x;j>gkoaL+IkFGDN)4qQ2U8hP(%cEc;s zm8T40(rsr0X#4_Cgx;OG2eJhn;p|x*7hi`ya7RK&XQcXLRhhOA{=-wC{yN}MUA1*{ zu~#bkx8z3p-1vW@Z)Y!v8)@N8W2_xn`TwEoOTc0Z-?z`1nWkx<_GwYms!iJWWm?p< zV5CS{nl=+fB+8OGGi}mJr42)iQpl1PV%j575vio26e1GI_PuA~|NDLa@A_P>t~uwt z>v_+4-{-mS`+3ih^bN1}BY>6uFu3&cmL}_*lin|h)z?Zs#|M^a6x^Q9FFs3o@_ACv zR|%P_ccBenNyfF!?)tuW=kn2sdga@5>+4ctdodgR!<=@%Z6zi5!utrL0tmMv;?|DuX7FaWC*bz#?_=+U-n*--ME7`4k&}V)^?m=Ku(4Gk#*p zl#PA7{lr`Pnm)@p<-@v%{ZnJIJ+d@`1*ifH$PYtR`UUVs)YNI>m5*9GTWXL{wRRb4 zHpvEnC{O!uODSjt*9cvXD~OeOR;a!UXV zhgOl^2am23rr_bP)Xe+fjqKVghHyp@Owp5euuc`B@5K#XXQk@lV|F+0ykG107EFL( zk_`D`O`F(RKlE>U{A@W#0(Q$ldfwzxR<1l1^jZc$H~ljrSe}zf?86k_RiTo_@K(UaRJhRzJ z?4_1MqWRG0Ufu7^)~=P3dn~9$1ensD+Wo@24h5fA=9Y8dOUbK?1#fH-PRB^na?=jl zhQz8^t+}Drb6?C%vhm1^9oiy@^o!l01~5-M)S0QJ4lAY~O{AXa;b2xN8aqiwG|1pF zq%uhS zPqoAbs%gb^I&m)h=9}low1e1ZY`H;M=7;)=4T5#E9RkDK$34WX45XR8*3hXJyeb5G zU)rTtu~Z5auqAbD)xw4GdT11;s7NPb3_g^RDlLxA-}djZf+MBS^nBaFs7-zX-9M6L zk@cmHC#gyhS_nR-aY9>mjhp&&Mj>;|rn4j4;&r;$4@JXU*>dsgH*G}o@;8eWddZ&< z4v#{LkH;#$Q#dZc5FEdq?)s?sp3CybxgD^V`F5M7zKA+koy{a-=o?d+wIs@KHe(dy z;N{#9Wvg4Q8`faca@7nm#Co}?UTza^TN(&McGrqMMh2kSAc_-PcYk~9NC465hOSDz z~S;oK5kp3Ry%(7p5W3=vrBuhTqWM@Q`F*06D5OqY57vgFbGSq5x&=UY^UR$ z3UOo2D*yT0S8|rx)`k`4*Ost*%nnqpM?G#MwVzG1W`Y({=+INL-QQ@OH@d!x_NxQ4 zIg@0xbO#R5&B8?*-cdBAPRoDk#FfhHIejXxb1D5Y zRj#>T#k0@WVqJKL!iwAbZ?2zu#2OVRzFr0X!eKA<$5se4Z@^34CrM!(&QlUT4W17d z?70ei&i8{ESOy(mm}M~3Bp{O@m%30ZtFcJbdQbzadwOR{D0LMsEOa9gQgZQj%g}y# zpBNTX6u27s6v!#FXCH_{x}(Clf*LbG_p^&H6#1lKu4#ys>&R#S1$ei4{wi~)?`|1i z|5H_PN_*q6W#U^bHKX~Rr(#lB8wZ;g?xQ;)CI`*E2Az1Hc|%qw#h>>CDll(5hxyUb3OTw&Q@ zXP!g*-JaXR$)>A&ObHazTJESv!4x(VHKeJp;fv0wqwDK~XgCI7CKV5DH^`xjidEpFVW`M+-Zd>DG&C7!!5yN&bA zrE5C#qUF_+R*GA-wBf=Q<70&j5AM=FS+QQ;q6%U-Kf6b+P4=%jQhK24Qd}XQA18w+ z8#})05gzD6PG)l!KN&hGJp8sjY1ksGV5{}D%ip)X%9{sP0ifNtghz4*I{Pm@+e?=# zsBK_z)T>hHK#$!hqr{}Dz}su#VcX*T^XGnU%28?cd5042TdjT*ik}w6fZ&~%-OTuV znCxqxT241jg(N?K8S@f_P0a=EE{7ADRBaafWi?ehdfhUCkHOKz_9IQziWWxeXWQh2 zc~pBu8HV!zq1v}!B8?}WbZDJCJtShKjm=X=7E+dVpIu4(%d-PkNVYSNsL&_3#Iy57 zRUPvRo$AG^b_TxM03dXI#$c)Ozx8Eq)#JMS%R6r$Yn^ohWXGCAaJbrT)o&u4%PQ4V zX9;)KuQqntupY(dH_(#HI7~%BpwiS~Jlv)7)4<^;iL>03Wi3Ie#UxGueEu>Zj~pa7 z;zGPMlbr4!J|4+?09)8CDm`Zz*-#!xy<>Bq|&%D}R`r;}cq8z0S`PL)f6tB>{5407t zT|)tRL}1mU9wh)hN^jn1ybW76ni4-0460wuth77mTO1d3k!sX$DyWW42i#vpCtI<` z=TSPatJ81XRlaU}89vaG8$ymJTJKbg65RD%pK z8S;_(XKw&(75W}%c(C4Y!=Ls|Ky$)p2Q-Q|8s)Z1 z{nMP}@YI8?^8j)=4m2l&f2Df5E1DyCYLnIraWbAjs&Np>aVj`<^=9RhMRU zJ=$#FM{fg!GPv4WMgc$45>T_*br%&pGy8V(ILfi$5u#ymD$41@vX6m7H(AmMK%3k( z9m!>=%NBtm-haE3_RjsZaSs+4x}kmJb~l&$m^SlnfhdKQR1XcDX!~&BAHSpU(xr2C zxpmRk6yy@2_0Ais?Obcq~FucNQt^C@6Ln7m5e z_79~I+5QW74fZ2#gj+o=Kp??>oAy1w&xU*H2Di_mSzvHTn0&gC3Lwp}C8`TvMTJA+ zceP5|$|ieHNy)_6VtZLPEF?}n3C7A802B@|ZfS#WXLR3Y5mCk`yluW`jd5h>j9U<^ zG=gfAtnH)HWuv}9Az4c1&~=io(+Bl=a325w4lD-%fd49cAG8|x`JuwQ)?C8p4FgWN zT{7>%kO6WEaoAomT4iE~KGlp$xUGd(#RtJ{s%r_O1PVvodF+s&4m!V`s|f%zVe+|M zt_r6Rmq%nd>8_{IVAdrpFNUx1$I2wFW_G2r+|T+&$heLd3aFW>mdYiCjoZl1Mol8? z;(*&LXSciaL-pQq0Ng&t5HM^YTjc)k0e9Sn6j$o|g ztJ(d^HAlC%GL-J&>)CPAwMzqMz(Y8vy20}hr&8v>f&ovLfi7EwTt)R)iHcyXi)#LK zHYlDF=eeBk!0VIeDWaB2K8>zx+G>K=d?O`tB@CpLXxW6fisRaO;DuVcq)Z4J?l=V$|f z2#_pbZUMm8t$n;^d^^4Txi4^*%L6SNc|`$GWo4DW0#YCD1)kMS1~E!c?}!%mC{4d$ z$QlQY0A+=YK1yVBaAz|dkZA#j$^9b|woMabK<2TPSjrCkI4x<0%Qswd- zMU-ix;s7oLjE!|T6cJLmW(|loLW#tOjpguO9%R9MfPfhWw-D;ZJ4_4_1}i=nMfP@? z)_@6w2cA4Y?+ln8W6vSgii$P3-)Uox1|6ddB&49Z^EPVZtxn>kLN+1iSN(bWgXS5P ztd9k6!E*d0apKr43dQV_{oouu2Inb)Q3L1y7c2?jqd?1wZi1|EHxF@jKtLOg&C34| zeu$p8;>?m&$9#G1Y52=5Xa!mVgZZbfp;+Q2bgA2c-A#xz3d+GI~|uVqVHymk72}Uw)w7qS1D)V z<9heMj)2e!UiO6bL`C`receoC3}mEra=x}698FAe-A;L-D3@tOH ziBqkBP#F#D16p?>EGp>bIBS($y|aw+7Ix4C_uqw%0;CFKYvd?4Axs$%oM_`~)-!n& zSUA?7X-#Kk9ej;nZI2Fu%uxG{GrP>dsFSGQ)h8Dmsr01H^=u;nzUChI^Z3g^QGqsV zU~{5rjMPry8h2W^u_HvCw(byvAFEo(u|7txulfHUzHjv0>FM1nl{!IyZ=~h~qtnQ3 z(2{=zA{>3d6#w^`9=*TDvw1veTh$HaW)hqRo2xEdl#&!W?#LeQNRtEmT?B(NZp65el3d)cD_7 zO;9ye4a!K?Ht-6*`DuTC9LAgWMHE`D#%%}om=D9sa=pgegIcppqri`-3J%%(1PKw| z6DdP$MKB+E+|bv^vx0P!^A{xys({G~_{}ZaZEOHyH&wt|#E2c+bj+7@N56|CSAc~~ zCeuc(Xx2@PZ4w`mtsYLy2tHu<5c%p(m-eFh2uqZ((U%X4{D0_TLDLa2j(i4Vl zwtRd$zupH$;~Bp{R~gKxn#K!QjG>{#J(CunA2gE3tDa|NNejb!+a^q#<2<~A);`Q2 zi~`%Zk5u(T&;B+!9&3GAozwVHdn4W8llP&knjR}j>psml@|HPXvZ@GNZh zmpk-rEO>%SjM#mZ^SujNJBc_17Y0ba5MAB4WJP?mzg+17LR>SFfkqc}?LN3~|I@qt zyi`uI{0VdIv5&I9pF!USGxK=Nuka=-L+CM z0J;vhu;Rjhpv~vs?+58?`Zxdi^U>^7mTRgSP&HH;)!e9T*Qu#g7F9@nWj`cF6_9jgEi&0({rbe)s#iL_Wymo$gCC+ zYc~a^mn;cfd*%G?0lpMw^LKhQ{@o4WM0(9MDn(ej;i8|{##GMvS?gwgzfnFH?kPLF z&kQVlzzCVStroyr1hL%f$0#<~POFNHs;UQ@Qpes2$^O2w_IgiC#qImnb_#(OGJTrj zYjlcp9L%foD<4%=q$pKiJw$&|qj{)qd9_Z8v(R3;4Uc^Th9$No1$l1-H@IWDHbbD6 zTPaRwK0j1*Y@FGA=0UMQZy@R1J0XeMm51$7$&h75kCv?SzLkKq>LaJvsC@+@&o`75 z8?p_y`!-t6ttV5wF@5E^#Mzdz{?J_e@nC-dbJUSF95T{et>%AD51RhU*TP8OILwFqRAVqYjY^3 zguTNKUOAie`4mM4Otza`^2UZoi~F=@6BkM&(22KatTb641P$>YcZvwFJH7k0V3{OO zqBggaNLVbBDg4+n4s-%fAdT&jL=eriBm;YULwsKMhnW14Q|nr#fVpB^MPULRYXLIk(qw$3Ve)oX1Juu@}hNW?37UCZ;1vq$vrPqL;U(t z1wwi?;S#*d)!Vd6=SAREDjCgiE?~@?;G=XWly7!azrUDHk zYqN3-fjl%o41Thmm4^d6x^yS`eekljl2Vr0x81M+f6Va&x!zDc^1M%Z{s`D&6^=}S--^ij0VY)r=~Up(fPq*?}A za}TalM1q#XOmI~OWQ4i$sl*f;jT*Q}3|wXS${eW@;a!r4JLQM+a6ib@YXyY| zglEcZT##Q48c&snFBigPPWNbXaJ4+AT;X^!uM2hQpo-^^Tq+TVT-75KH^V30mI~xG zQvNtoW-odN&=NwI&;2xzli-5t%8@ZNd<8)$7g{CgKDXx;0?Svq>^{?tEzo$7euXOTdV*n$3K2a zsWYC$+XIgkfChz~#*_T7fZeOD%X=BYA~;TmypmoUSvCq*wfQOES~vyl;SdL)2nFJh zl~IRW}uBb^s9Qb%DasJdb)Y4(}l_?dFD`-vM+2s4cV7>u1O+q&s`mdB{|0ktt`H@i$48?KH>+kuEeGmg?FwG{CD z?Dms}Kh9&3F2D#Q2if>2!7%-F&PD&h$LVy(YnPom?j%^LcGNl6jtX>w>q84MzjN?!Bt#=Wa(os7(^ga%iAg0FNj6T=3 z-8Vm#J>JdK zYbHRgy&|qw#HqCLekbf|4cV+WgW>>`dt0)(Z8g_2fClmitET2TfbxdLjs`b2ve_;Q^abqk!{_r+b(+(*=cs0a{WWisEdhwU>oPK3A@)vRn98dp%Gq%L{~%yu3Mq z8Nvfp(^DnoG}$t;^yx_%h3k1nU`G^9aZtkNZsZftVsY=~ys3LgnEQD$FPnDeMvbJ_ zuJykO;HGgqZLj0yPmRmZX24E(`Fa6|-g7->A&a+{$&(bc0oLvE`80V#RC}h@E=QDf%U91G|kchb)5 z8ei2iJYR6lRZwlEu41?WarW*g8ZcrI>J7Golh1AgY2fL7uE0;96_4bk0Bz@k4K=Y% z`>av-UtF6<^iX9cMi=BoP_|A}ktSsjM#5-{6yd-UhA-LDKH^I>pxd>ZQ6Ej zERuEpBI}q}sWEu4>pYc)aI;m{_#t*dR zFGeR*G&GB7e>JW_9z)-Ku3u7DbKe<`(qR$vjdyeWt@?oe?XL%?8?$@#L)uQEd(a~; ze~x6Yq34DgLDlQl5^Ug*{zVwZPkmfT&CdIIKFl_??)#sQVfE-pF1cdk%Oz6nTP;XvLcVABF<(Ldq|JnhA94d3lv*7Y>yGL=;{ zmgOC!U0`t6AZ*>1Z7-!Y)zbIu*{qlu&Jykc$~Q?D@c3ap(Pps!jl1#1ZNAS-Gqaar zH%COQNUL!ZaOg2D0B_B7&$$Yk=IV2A&*6AC-d4*M9MhVKd68tom5W zX-x#+iYR2~^fv8xIdDslXsd0NQG3UzL|?S(&eAVx;CV(9Pn5iUPCtWiXB5kGgg`OEwe^< zMQ}`GEu*6XmB`M8?YB~spKg*H+$=XLx=J!EC_}11ah^%VxYMC^>w#=93dAh5T@BCv z{g}&}@T(euqY<7x(x1sYyuyQYzHs)rje;dZ+DIz|Y_zf@GL*TudIp{Fb$jHy9={)w zGGjb%Mwg7GET7h^CUO9eP^Z6H7r2}*pP%p|&8^`(g+CSH6azv_$H_BWW%Cym=YFTU zw4WEUJ^jP}0(<4YagvCWmZtO@d<|I%Of|&Optp6u{$ZzYPxb8tCm zd)(dmozDoN$_Kj#(_yPB02;7V7g#Tr$bHOnPvAj=32H`rk?O*sF-bE!QTGQk^boC5UNE!(2!Cy24AP3Fm4(_K@058^cKs*YNIC_8sS`sdrF@~Nn*A!vT>!SqR z6#}RlZ1hBXZO`=Jd1qQONV#Qc7)qOZ^n#Wv@H&3(F9Q5oYX=66IbEu>zioaqh$e7b zZ=q{aQj89VAa7qCMAn)`R0Z8%(vI$m*yJB~;XKMME&{)=Gz>Hq?4|Zk;TeJ0j-vEs zWN5AsMRrNUne`91SI9*N6vPy7XRQSxNOyl9(ZBp(QqO6Hwg-E9HUQSFnu^_Pmi!1H z1APaDm+raauaKE=0|2bO>}8z8dLWi0F?yFY&E@j2M(q9QPl+96wx{#X#I=^q5B)`fLKU&qfj*wMT$1O+%@>% zaoz|zq0LP3BH$(n_XUN%ql-@Gyc3`){lmbMxmmI1Ci-aMkISL)@AZEbs=^Uu9Aeor8{#iwM;a856Uhr%|*cdZ?FJaI)MIU z?rGi!pG$ot5DOD60`+IAA4enE{Z^+gNH1|!z_4#5qQT(oHGqxs$pyrvKsi>}m4-}U z6U5PG&`_a{g?5eOVsVtmuBIadxbDRglAym8TR&pilen(sYK6v}%-`UbFKwFVLHO`u zUE7U-Nq3W-yQS`I50R^L+&@>yLIXqg3%b!9(Kx}ZYBQ15S=S4F9Y*w37)D1F*0&> z0gH#DsOZ(6#IzA$a5|^)_Q<-QBC!{2SG8Lk4QP_0@6Sk?Dh~4w)^0f-S;dKYnyYhB zpyxRGJ{p6gkm!x@3H;XBdB*!i^Y5oGebaO3t*<-eJ`0_Gl_xviRH5-j4M1~C#@_qE zlgU%O#!TgXI&Ipv83gJ4O+zU4Nxop4th=k}aJrX5pg^Kp(-DFD_ZFncHi%`T{RUEW z9WNt@Yr|6Dn<$rEgKSXrh(;w1kOCkjL8tBs84ulCRQy^OpynfQY(GonWnn1g?>Kdj z@SWW2^?+q&epZar|~EHOdEx^cA% ze`BV~!F$b%si)lDBo0=(e0Ig6$~eXC?${b^zr5ou=X&l>pZtBTIcV_vPUn-hPjahRZT+EjDwl(GBqk@E@pbb#{b%J)$3FDNk-CQzI)cq;)35QxvtvrT{zw5 zkDN_X>QnOh)q1uo2HbkcQ>u1H2_*ij@5XY>j^gCk(?{=(+icA54mafN+N_n|9r{W7 z7WtcGWXel!+3UeQRz!o!?N>894|Yo@ZYrKt6CRZh&2fl!EuZeQJ&I9SJLYd%fK!HB z^$n+oT~w7b0>#OZBFPmZx3@L7uP@(lZ z#jYJ(3cWxup)C35CPSh@Cmlw@h2h+wTUuR;BHs%NNdb`GAq?@*6Z+Y)U}5{S&EnM? z)8A-s6~8KJ*gUGAH7aONoGiA-l!wv|%bexLCO>KyI$R`9*hw9fsZz-dY!ob`%tjIM z;#)Cd{M8gWJUr!NZ|LE66Ms6Wxu~2-hxXC=@7E`CA6=?{PZ51J!Ec{%W0kav*KyB7 zn4;Da2@Itfrn_Fn=DAqnLMxt1D>O|%+m`MsVsS9Pl$*Ou+2Q-HK+&<7eX-|VRA{ni zR0LJ!#hRw$SMWU|$9*BW68(sYD)Wz{<2B2f;!LsuM7Vvad4C9m?D>g%d2a9WqsrV} zH~~xmS)RU3HlRv5UD!j0A9C5LLBNd>b}Wyl3@}f@i6GwJtM7Gu6ai0sD$C`nWQ*`M zk#38pa0xeo}E}8kGXI{^T!>=8Ew9Ev*pW=1!@(Mk{l@7Y{9;q~5u1u&0-dUZ8$BTn_wvKUU>&|>YyQ@F6~S{< z?fBW#0_U7{1jgiLaRzx(FRSIrql#+r-)3bnU0<;QU)aomYea&~+(QPY(iTifCW^K$1mTMabCnErDD#=cs2EH%ncPrR~Ev6AjZ^2_%=%P%&gw zfz>-=i8Bav;HnD=a0kue$=ekJoMY2xH&dbV-y%&t%w?)L4`QUYa#L%%@_F1gH-l4n z&TA!5f_!GA&~g<;jr7m)RCkN@f@9&k@F$Wr?$-q=I4WMrAnea^AgWD3EOiqfki9hEc@cHWp717FXP)nvLAIs``W zhux5ytQ(V8!v&_TyH9YY@XK+?IQBUcxHIoN3{Ck$d+^4T?C(+>MM@7vBDCCAfO7+b z(9WGWh+id$3lcpny5XWNB@!?6%CtyKoMp0}a*vN94Arm87NHUamK-A~@c`S> z^CNk}gTV%2rdp*AF1e`x>Ztj`Jy>cYR_-QBJhP0Cmiu9ZSPfGYBvGy3=!r^ z2v&L&$e9k%k6XzGa77|6&9_=&$fCVfnG;v{o88&C+(c;SHNC5*m)keIGYp3OU2f!V zxalW97V5%Sbv;+L4a1za;cA3l{kr3!=OKn@_>nBgbbRm`*%`BwNryK~j`~?2wom$X zyxnhzl6aD6dWf!j9j3e*8_OvYI zT#pjuK$NfTW{AV>X$SSCBO92>glBNue*RzWI5HCwkJRkFN)eYo5Fa|uapu#BypLW3 z$~M=-=$R%P%7k=U6v`8ZcSpC=QcPkP1m?bA%!kWS63$c`bK&u1Ibj& z`j(_g3jBBm5`StDyA~i`vy%SrqIbiq?rdFDTQhYhp`V-lwSA#H1ZN;G*f8+!iB>0l zmw2M&t+gBPp1xQo#2uexR*RLy;H3Afe0si%3t;dnBGV*TrX{mQ;`Af^ua3{3$8St{ zyX;2j*FSO-)*(0K?r4ce-ZH3;6p%?UoU3fr-c3^fsDYDWe;e!!5igT-D2N*zD8 zD%jYmXD>#LZ6M5X$0CFkkiu*LtL(UcfmX{8ZspqzAIn9M-Cw`ktGSzzh<9}R8=d-X zgU0OCUcr)oV4=yzhI($$8_0Uf?&Mqh@%wk@4pDG0f7ivTuD;8Z&{{|wrWYFyDe7}K z*!`HjD}TR9rJFyBj(AJx?vq$~t_$BXzvA&48KG(`-Ea1+cB97*O;l;a!5sdb^M(gw zGhfTzR1~chCgXS7Cej3%F~o-Z{a2#C-Az@&E0P>z2uzPceXfk-b4J(H#t4;hGv)9AGU2sb%Jy&T(p8&)#_*J)Xz}0&-YHTIYexyIlJ5v zhAi1yme^_&Hp!^WR}%xi1^~iqgu^goBX)oZ+rk9PF=DHRoaJgOJBMMYmI!3R-WP+- zG-Bsjxegd3xc%5jBLp&Mo5W*DhV89KvHK$7NTPD2i3`_I(^rKZW1(NNzaxeSB2f@3 z5l&V_xbg^Oh<%Vkwa~-H7_uoQY>t@{Xbjn)Bf!dyrpt~o$Expg?UYmobI1GWjt8l1 zhS|N;7_1hAixI$61Z-^F70Rg)q=0A06tuck&|KY9U04Pfgb>8c>c*9;+&%2xc6)Q% zU?(33gLu~}_84|q5L@%aF%Auh1VxVu(L#>2!ucGWuYhh!6NZebpoKD-p$RlGJVOmy zpeNN444PwaJ9OjgaQaA9mugW((S4X8aF-GKptYO-=R@rtX^d1$Q8f&uYGatv7+ild zhj80Mpey@&B1x;eT%fxyw5#x27bXW|@(efFgryMl$~9N#0mDF)nMVh56$JN^kA%B% z`$b~-E0|`yh8p^?I-ph2F(JG55t+`yH6@gj6G_hQskboe8WKpdc!mUQa@F(ob@AY@ zi3}51aS=B8Y9Q5uojL#!%n_*;8X+`^q_XxG1io_Iqk)B``e}!s({ixgIs6Z|2*Xkn zJv1^iM%*JRTcH%HcV1XkPDq-vztdxh&x~FjP3)CxcvK#W=uNF1P}Y;kroGL^?--+P z!S{rycWnXI~gl)x&7@DPC&1K|(j_?ZNj z1>{ZRV?qK@=5h!kGBZ~YEZ{^E3Cg4=Bopu?Yls=lVoG5H4A`AAFr*DrjMz8MvR8Ps z@}#hJ2J8fH7C{P|X^AD6V{Lt5Xt_^-bw5?DzuWH~)3Beag;1>S9hYU5OSynOGW8C# z)pz$VEJr97*!VM8y*MAL-i9Z;u%+HC=?&Nw{xGD1IPZM=ecmU)5_?D%!A>zDz4qJT zY^E7j%Ya=Jj@44W8l&CeYs4m5xnx3Eh7A+9(}fFR)P!{{qA`#Go*~c73uQ$LRTyk> z8kOd2%iycYSmU?I$`n9+G;I+%bKRoEP632~V^$5@$7nk(o?gwD@A>WlpvnJa#A z{SQrerKKZ2=~b69@r>>I+yMXVer=jKv*g(WG7-`Jiio&Axc#8APSp?h$g?_>MOkhi zqqVA9e2cI27GFYAqs*OwFwCf+se|Z?=zfGK<{|QM`RPa9%X$!>5oU7CmckFX=m%>I zh%BG{t?KrVU>V%}1d~c+rM-DE-MuyE+2H*1b&(N#{X?v_qK9DUOM16B$ndLA;V0^S zrvo=1+M7t*xux-%zv(xRiECX)GW9OCCo*E#tSQ@HzkTQbFuP0qs4_0AN&`YNt#Z;6 zJrBD++2QLG%PtAW?u&QnPHgXlV7xFk)7+N;VL0aOJj+fZ5o=)H-f4`bT2k@EfKJ(s z$1HG`z z%+^)G<+88dkFF((^L?p(6G=!oX{pbpPwL0`UHr5;_mJOQr(eUT%XM_z%_DEps`+!> zkq^-x7O!aGi^v9}R|Mk3WoFZNubkx1yeC=0X7T*rCSE5Zsyzi3S?=o$haA z7%VD1VZ((7^lr}>!fk?ZVyd?8?*{y?x8^04x}lJktdKNqgCO78K;N&1 z?_-GZT;ZU~Z{0an{CPr%&l#QOTk#`Z&wGgRA9}l8Ix6>fG*yRS1B4xNG6K6h6KP@* zN1EOzr_aP`2WOHZYP4p!dNWV@6N%)RI6g#XG$QWFm2&M5W-nXgMu*qDR=70Dr__aP z=o}e-mlbeivd(+P&Z+xE4$eXtCT!ddUXZxY35j2sw36~UI|xjtZZ+QcJ# zM||uGyN@;8GEkG}s(qq`KI*#pI{HZ>RUMwxG9kVko zGB1Sx=qjh6im2j>sLbfu0sp845BDAjPujbWxZQU)G^)y_tA)mVk^f*(aWf=4s=N)^ zxQ&_Ny@x=@a7Fe9`$uCB%-eepa&^9*-PTrTyuYD-|AFwU8;? zkI1YIj8NBv#ey!}4IW&(71_A;n=FIx<*xl#XkCH#=chuG0^jp>9R2z&(h5AV=3u4@ z`sTWsEp~K4(LSD}b~$lN)Qee&Eb_I)e?f5QKySlL-qDy`f4p+Wwx`-2qx1!i=BJy| zvvv~7k>+EXVOQP`g=^wkpuIzoK}y0TKFKQaSs+Xh9-iiK_Yo`eLX%3~wIv5a!@7+z zQA3dXLFsn~Rb!Lvix=HvYu1*T!`%m&0gIJoW~!tYtnIBNMQo;;!8E@ny?TqSeMz?cT+YDc|lb9!T|kcK^cJ z2Z;>X;I41uS8St3m7!NomnO9}?e7nAEuhIZJmWCJSCaU%_SdQILrE8K2Ihm*$kv#M zU!hgT1n*zV?<2C$;f;foKMk<#3uNPq3E_bwd21|c3*aiiQ6`r zWasvgKk5ka-x8j0xRXf3F+aXqRr}>AP58>$tiI3{mYrMwB)#}!Df{Qb z554Z2F*@(zkH3$e`txVA+q-u~EVAh9c>C`1fT}Am#(P4rNeglI4}QCzjz2qKcf5#Q zf9KcA$i=(FM4HE+#EK&a2K25xkI^kM&Rcu*T0wsH)T`>^6mvXD8x9(c^&-HqD_-y{(SVpq;IXrB!(bXRVDu6 zS(<}l5V^48FgF;{C)Y8g`O`A^5AH+6IhL*$k&PGcZ?xkp>cn#D50 z55sTT%`Y}&aiY(V1Et-a_V)jZ3HUR2;DG4v7aT#DzaA#Ww#K+#APEzvV!L8u2R~1) zi#zaSY}v|kB^Z+CKdqHioo@BHqbNm(eKy?#8+cDa>q-I<9?X zx$3eF)x!p%@09uQ44WNQvkwj~vOe|e>cqYygg#d3j*a3k+u(*RN~$)Xv+EnH4T6yY zY5vBH)m}L`M+VbZ3l_5JWQM*iKG_hHJw+OwNcJb@iJSY<6J94}zKcc#iYR**6OSD{ zrWJL1;|aUE{S(Kl+)w=IB1H5i-L0$}zTv*ev=E00yQr$?faMPpc2hM9lcZRyDJNJ2 zaYiajholXQH&fN(5h5|EgyqJe-@Q%4W{TcqKrlsIS4$3&Y_-dXV`>L(nNIyNR(RR@ ztL-oCT(#)h1npM#OC-Vk+Z3iYLCcvb4*rXlo7~))enN{~v_DV{i=` zg0a_weYOT@o8(D*vF`VsnK=a92T#)3^LhwIXV30-WnuQm0SKlY9hi+9m_0Hud$?u6 zzKXcqE?dvz$Fxd-G#oXpT`ql;CN9k&J|5PXE$M|bRY4(t6g3>zbvu5%UfaKxpDCeR zhwmmPR^E*r5mZA6nuul(Owbsfk$NE%f&Qj#GMWmH8pR=M*%--bOpYh>q=}A*pvbw4 z#3_tc*(%xLWoyEUruliL;UFa3dfcTm7ogk$_nY-+#hui zxErTui5RLb3>n^g9f^$xAIXlvw(cufig>h3y|u_=|#%;oGe z8rT2`vvVIN&+5MOF4*R94#B3Ms)4OyOELQqh;&bf#wv}))R`P!v7vpG=<3bfm~7M0 zsk7%r0QNAm10uo8QBw~i~StOAk!**okSvIW^_E2fS7i}M;<=koyJd)xYLp`g6mba zklrxTV>T;5UEr^XT2LVKRYd=ailN>DEnsLQ9GzdGLaNH^zDtX$K9-myE;aM6{Gl?x5Z?Zpz)d(1(iX)i`$F( zAGam%^#2^lJm$0wlFfVKa+*U&D$)$;gT6r*x8S<5WXTyQw6Ch|L3l^QsW(E*mIK+WT&}=!i0A@o9g)E68kVi zyPwy2Wwt)zuMqb9Mz!OTuT1vgj!18++uiF^hy=*kH8W?(cE)ji_^|cQ>qOz5@1?Ns z`FdpT{2$id!>x(nTOZ#|LI_AnfI#S>haNgXkbsB*DN#WI8=)C`N2EwL2?425Kd5fKov5>ODVv7=bN>%I4L@9z)zJrB?1?3uDN%a)ll?|Dy8CKxp<0vo9? z;??7mh$SignIG{nWeK;4JKsh>c>m?Iw<^sRhe)L$J!&nPX0F$3=l9Cj4jUx28GhpH z`qIdQ(#ykKiyDNP)<8M?ArCCG!rw%YFQQqS?I^`%>W`0c~F zsS|&i_c7&Hge_$xBlWXNDkQSqwR5NI7-)0IxJbusYu$-r zB4-?*K{IRn^L&MD_ssA z%!l^k@oy(RmDc8AW{h2hik1y+o z02}NM$snI7PIV+F)Q2N)6z5vAd8}4pZ10uL8mcLpkcjo`q!S9iSZ^#-<2+)Fm*o(+ zOyTf)ju)RQuuu@maDCJp&$Q;WvS5y`N(_-5XAsBKLkweGL-xC}uwKeGem*Q$f#pYT z1fOrw1=v!w%Q-HY$jG-Gg4vK~=1SRK8kyq$$(gY%=NFU2xDh#m-wQvUfe#f|rat-^ z&#h}SN1oS87^Vz)eQ7+PIyjYtGO{H57lTZ%_sPFZlmy7tSBK7$m$d-$r=gYNCbOMQtYv5TkZYw zCyJQJ8>yd0tT?KVIe~T~-?SSO(h^-VIJFKVFFC@ybGue4q*Vnai8OVm?+J&$Blvo3 z`$j1IA>#BxHPO{=BSkOO_JG z+;?%Gjw@sStvr&OwWE`>*-P8^X(WJkkSdELP=+o^Y9OP^8l!`2*clT*5C*RCJm`A4nB*dG}Me{>8Fc%-RR(4HW?w3m(5bprJUPkbmi^TMKmQ5y(E2;^i^rzzX^4Km+8Rw)263!!(f#4qXSs! z03LM!qsKjezX9@&gJRVx6Xa*^*I2no5WBAP%{FOjD58G2Q**SFIMAuBj*f1)wk(Dw zC@OE<5BjVI^th;|S?QIlLhzJ^ZfnBAT_7@0`m?72^(S3nuS&(f8&+qN2+aHyU>FHv z)TQkOQ9B=IvPyp;KbeFo@WLOmF`r*W&cV58!d9DQitCPz3nkS#`ojzSTd#h;6|H#4 znZ01x<&^j78mm_-KMubxWzQ?X6J*cii$==kPeR)#zc2iR&Wq+B$hPR;`}oR!*t!m7 z-$Q-9R_;E-vYtXmzYl0j+yzjiYnDVvpYI`^F?-&K_+I<5eexaoP0W+hbqO;p^DFBT zV5`p|Xw#QxGzNqr!1hBBv!mGl7Ft3XO%J-VvYr};1MXFbyYD#-?1c4>0cE0whr0fV zvqmJ^lQ*N8JAaS7uv(U2S;*l^5|&_>Bf3N}A^~qfVKpd(Hc5OaE`!II7M^Q6i*zN! z#hR60G`o~EuS;xpF!leGs|x_?4=+XDoKxTRd;c#Q#g|5TSeD6YK!sOx8lOh&SjN`G zX(U{(KDb|=gCNt1`<%x6pvlVGRJ#rmf;m zi;f=l?s3$b?JG|*OKd&MFZ~7XzBskPq^HD+swnJvX}qV3m8$p-z$40P&vvbYYFyv` znFN@MQ(WibIJ|TmhL_oduvPTy5~34(1Fl^}lq;fDOF@h@SUaY-aAX(g``uiy6m&is zU~uCKO&(Nrj{__+79uL%9Jur|X<9ldI6796MN<53z1tZ1=5$Xux=ZnZ`BgMw+d>!O zRzvG4bIgYB528P~c6TDO4I6JYk`Cw^W|I_Clf&_D55Zh4`0ijSPu(m%`KEFCdKFrr2xC*v1U`QB)&CjW|4ZP2nfiViglv%p z*Fuh|m+2pJ$h_Aver*}rcKm5*n@Fk>NSEiwxQXDpTq2G`V*Y3bqh$N{=2T46=uckX zjZ^ZL7crq#Y!wifTgLy_D|z>@WcQyrP?z~F3G70Ne%dHRLMnBkptCR`%nSZP@DdaI z*Wko&dg#-<QZVPxQ7*l%;ocrM{GdgRsd8{V!FnsSDhgp$I^P?(VpNsfq@b$3<^PN!+o3K73w8wDnl0g$on(7pEj(L{ z_7&Q(#ME+Y>yzd1@iD=t*W&)A$FG{hX(#Rdvgi6rX?$9~_oX%O8uXG~zz~d{u=8JU zD?9sU?RJh(8I*K{u*xi}-vl~darxk9ffv}jEe`qv$$oC7D*xD;od#nbS|PZd)A2or zJt;*umt-+-8lLb=G(C5p8-=!c0=bzNFv}IIr5B-e*03_5ahvvgl*qQ)Kvo8hgu>lR z>o)*!p^)#WZbci|CN96Puo#Hm1$aQWue&OTYQy$_m?at`i(TGIo>jD&l1E_Az$<$B z{uQtx(;*wRfxper_xGMXA`mGIdf!=Si)CewPk)`dS^V)#h3=Wkj%loB`ufZiTWneV z6;J%sBy4K1>c_I+s#^k;lb*h zLV&O8$$iJFcZ2ADY~H(Mf44_dYcBXIn6#;LS*;kzOcZ!R)8D`eJh-9_-!^Pq?$^CgpcJ5^&u!IU7Vjoy+n230K^`BcE5W z=);uqS&=Ba7=x)M+v`hN1O@h@UDon{rSITe>_7dPKhXcC4ND+;e)!j7 zGu;$gDDga6hUBY(7&mBX3{7yr47-D{z$|LtNU ztd#2&G|GeT9uXgz`kR)mjhFS1sq2SbB>}+r!>kE}{vEq?8pk(fi`~ua3A`3|k+(h$ zQYt}+b$~xQwuSzHUNq}}ZdM8^!EbfbA4e5z-+T13NcBW&h3~1#uq!O@Y>Ugh`YpNsYN!06_dk8n}a?Xy_bC*3}XDjuN5!4e{$#_v#)qQnqYAFAG7ay zz9a5SdYlr)ZR zdk6OZb>K75r;a=szj*OUHE+2{OHQ*R5(>bEv?YEY*xLN8ypCz!COt%O6|a+j5iD0<8;*N*+9vF1TaH)Sjx&WJ zMQ&)K`rOnAw0)$R?g#y?zWeLqJuHLUrvAy6k)0HTXghL3Fu{&I2mZS0B=~1n3^*dM z{-V^r=9yHJ1-LeV3{<~KqJY00IX&v^!YycmE40dBbAx1rar^6DT-;Of#6B0z#IS+D z?vjy@f#rxsiAR2F z`1@Ph8TX$_x>rnh+njepmB{45n#_5R38r>t4VtjM-7q=w)8--PYrM+Mj~?7Z_icXa zarjooYczd-g~$?m^#o(~P0S-UqcbCL%@7$l`eEh|Z57^j&p2b{iY8(}0e~nM;}S)= zGz@1MIk4=>T22D|LVyW5z;@dJAIY8&V*?_rHgN<&T$Ciz*CPuArm$GsSwH~Lq{$M9 z0bO`jQxY&7!fNva;#62fPrz`2O_V_N09;!sQKCrBtP~U|4qGodbo6=BUI1&)nlJ!z ztpO~FMYUsLV*#cGi_8Gv%^IR6YuFSZFo8f7+i~gPRbw`0fIUlu{P2i(eUJk4pD;_j z7GlMVjF+7QdLgG1`;)Z}JFBb?GL|Eb(U`ygLIu`8m4649I=;s zCGn{$ptI~z4-h0SRF1Oua_`HCo6({W>zWY(!603??}rpSaxa@HR4x;ul1Qh4Z}2Dha(QXV%ggIgiOX7UR}~dXUj2j=4cqD%Y^;V|$v1uTQhoYXI&*7d z7bDvW&8>`VexWAPiO#l*(k(Wo^Drf2AbA-lVG2|+E>x+vux6&^4 z_>v1dvR_(9yya^0FZzFe6mqq)r1swQ7os806&;dGrGj_LDzhl!kD4~}i(-N_a$NvX z5*G{#>+pIj55w~|hFtUrJc5xQ&{+4VQjkyQmW5qzi#f3C#gd}ZByVEO|m@C_b)h`2CrFqC4^JX{!D8-ceMY&+ax?g#n3VL zENb@$;T@}icm`s)>Zvz&;cl=>(vuSYraOI0Ik^!L2yG!kqBU-P2E|aTR1)Px z4^hE!BbC1_o~2*XZc#%hvJ1;Mt(9Od=`z(c38rA_eu`n8%NIge!%-xFYm>yblRXsB z9AYj8u#ISQ`L_A>C62`Kk*9nL%G;-Wr8f5LZt2{5jHVXX+l(i3hjr=ZXOT^O1g1)6 zCVF?j1+t63zpW9sK0ksaZcp)MV# zf&E*`N}jIL%X%dD?991+h?M)VF!#IPJipK|U?M4B>yk}j%oqAnu7wUTYaDsdYiN%Q zeQxG$Hfz+#a}w`=K<8v%xhcLOeD2#fWK{3!vqfxBN2*p_sI-rMQOj`(C#gJ$T+rw+ z8a&(R;2u2DXg?Y}7?Qmpptj{hhe`pF-jr&r6BSsc0g)IV4K11=LaUJh>!`VW`x&0SNL!^h{<`Dk58-whodb@FpD``C8V_!@Vk$@GfGZ#(t=7-hcbSpDzV z(0-vqlaCT`!}L&Cwv%|R&iT43(v9;41Mb+>Hw67fvKpiE*6N*>hW%;z-)ojpMD@nu zpZ5*qN!nDQ_$0~+5Dz;X|S?2H| z&8VxAt0LgD*#=OjiP5vQ3I=X2u}x34I5|(7JI^{}G-xI);4%gzg`lw2#%y|^M8CG) zp$pGG0^|~4kVfP}w6=o#kAJJJJyvYZz-BKeTq;za%P@_RIIiI_--`*(A!gq?*}EbV zaNQfFanj&6!BNBm05=z33gMDluxukzc3ia#dm=(*!pQ012aS&sq@%;n*Cr27M351< zVtmlG5XJV;UY2c_h2}5W0@uuMfZsi(;N7OYK!nW@77#zdG|b{)Vo*mF5TdJxtax2X zqZkORd}O0GuhV8td?}MxSLV_lx8)8=TRd1SJ^F>Eraa$8@!`=l)W2O1pj5mO=OfcQ z5D4MC;*QvQih18e!ZUcx2@e?q=#q8=@CV^ah_A3P3LAS=Yt&fsTe6pg9dv!_&*{%I zPCOdStv@Q`1cXS=Pn)58MyH*Cost@D)(GIUqZ7c8U=*0=0LvI;9aEx?Wp?ki0f3am zWe2is(ZWe(PFf?h*|Cf?_H#Mc&94&eRfxW?`i18JHML72!^&Pyl_*iP> z>~|MWO>IF1Zs=hR-#^n&0=ZXVII_RT>C@(ArK8)n>)XE3e?3~tHrRn_W@;cYpGw#* zUZ~9x{z^_?bY@r*FM1UZm(-75nM@n#*I%Dvh5UJ0WOUAbMhC{l_ubSZ`nvo1>YtZ7 zR>C&pi9}?ZHWCYWO+Jn=Fv6e_W=9+I0_NPQxuT7EZ-r_g&t8|@-;^xhFkN|P+sfDG z@|h;QXyUM{H!;y3y3H({IOW+t>}j#Mt%hxw>=R>UhT0*(vOW!n!{H4jR=nnRubq@W ze{%a3R?9Q8K?J5R(BKMdlkkFNkaQp8R7+sqoZOw%?Z)>#uHX}%JQ_IQ&BOX!KXB+5 ztNYO6#vYF*) zL8zxY_pZ-m&seL|yPVdS#22Q%TNt=!1Ypj4_Tq{{Wn~~Li1LA;c0}}0o%C)x z*zTKsy;-S|RabSOb@A0O9#|KO+YNXHnV~8+E6!J~iz&O&)mZnz6bOyw7+X;>-(}1t z$o^ST^GS{M2T1eR9n%be@UHCRwjpJ)v1sO+6y+BqM_6gG$#QU<^6M3O;CR_+PjwAbp>2KHdacGNYIE5r9Z0QqVZr& z!9yf^k1RLle$Pl3RqTajP>vZ7`-`+D+An=0>HKB8pTa%~hU1MIv-^))fFtizk|#e- zc5Ox-h<)EVb^U`yK0B}(C(@-{EeHFcxpy)=7Hk~VpeHE{gK7%(A1*h z%4qSe?3vQyt7Ns(XByNUl#H(X(sf%dwR$_exdw&(sQz34u&9?0J^g5qeG+?>|I2ug z?(lVS%QgJ1I*X0>?tFK(;QZCXH#=Go=UzUwbYu=Vmgihq_bHz?1OPMyRg9h2ffHC( z;rx*>WWY!Ca2JYQAdX=7=UsKl;fnR7U3IX~QfbPfR*M-CNJd7YHAbSXtbM&?5^#7U z83=*m6hY`T$RxshM4*{Am%_!1c9--L8PNg)}S!4B)5Z1bf zeUVyiR0LXcTP2*wu!R-&)lC~VN=T}z;G`nzP(BjKRFb?l9ALocn6}X|Tdj>5gbVAP z#Zys71h#!sVm;MVR_-Cgz|5WjYQKt<>_ohak7W&g+UT=EbyF&}htgl*)P70sLXs_y z;5#rt$a#Dj@Y6TQJ#*x#x4NGlo9hJmP!D%mvrGM44(nC39v$vdW%C&vxd4~lR+~ot zu%`nyg$Hd455E2BlgqTn!2INZ_%JXX;BrUZfa&CFL@2eeDq=6{PnMrk=C`bj2?(+4H@3X(aU_Q22qjP1 z`=ANIqr;or>Ly2^^Ju!}=*!A347I0v^3J+?7Ri7|FlRTMaG9PwW~*~IX>xS;m7{zd z%1G?)boXfcAFkX97S^B(9(w5qdFcmpU6$@dHQw#n*i-%H?uu;o zuM;`HZq#Hv9MgX0p}jDs{btNI&cow2pI$Zo?6u>%c`kc&j4D0LC75Oa;;bpM!^$BlxLzRvwy@s%xdTLC{uFi{?>2ov0rky6I zH%{>AI*2a(_KBQn3D(gX2cH5$aYKF1IYWfpvkY8uOjF>T|$fzn#SmLIx$^)J%hr15=o>O<*6q=K2G?N+%@{N2~ zS8ClWA>)Hrt@MuMDm<*w=Xhq!{E+l5C_>ZCXC>Fs9t&M(pVMfVhnJLg)?p?}>bao@ z@2ckLzfsBd2k@9h37onMXHzBzX7OLP2zQ z#IQqDQPcd?xis<9iCZTaD63XCUzHtKN4fASUiIkxLQ3H;cf25QmnV19!g%KPVFmCY z4;%Mrv0&n7o#>t}x6ZDk(TK@swMPVQJvBp93~OGhF`9r!OyGAP4BCA#n8h--#klv> zO!R%O=Y@{4eaH5Q1?>?FhO)>1$vx_54A$>^ zcNP6n*Tv?1N9+h5h*?HX&Dg%JLHo7_^X}do65>!}VskH(rsCY^SYqs1{J#0gxrJfT zyFZ?HzSvV=x^MBROzAuIW#xS=6ynhnfl&|S`)%)yN6%d)19Jz)Y{~3r%UdTxQO6Mb z1UZ8D=y^0|?|bGmIY2$MD z2M$z1bkA#i>;mnq1B|_mK?Iez4|^On08og<_9rT3BjNlYAZLLPmctn3oHz4JMB!&c z!6lnn+~h`m0-I#Qcw4a0w({ceUSybA@K<7RUtMs@1`lCKjxE?gY&s#fB2n4V|3eG+ zC@TNtBq&}1VZC~4y$*LJAq4o4x2HM7CZ2=(iz;3(mvIZFyMp}YrkFE4egs0m;EwMS zH8Dd8jPvR&*|l<^({~nc;}%m)ijElpxh9KAsZSn_LUAS!8=cQNM1_QH2GBGB?FOLT z0rVCC?SVD%!G;2oACK zaw6X@Zc5?u1SW@XUfx8-M}m`Y5W}e2V|UdY-6TqN-YdOO-4KNuox}O7{vL$zCdUt6 z#(wOG3f&hKPvgaOVs{vfxZZqw^>XBL*xOTsk#)Y$>wMtgG3xOSDBM84!MAsW#%S^L z>U$>_4NV|$ z6vudk-AMGEeB~z}o_xH*Y_Hu9s1rokKPbf$8Sm0M@(I0=#NT|yU*e7Tu=F#>?g9DD zs=`}hQB4T(ERp=SZec36|F7iOerX8>Z2pCHQ6Hqlvv9E=);X%n$CDYnCUPv10`SRN zL^Tf3#BL(1!=QCg3q>NYtMlT3svlT-v2E{o1Y4vuc+~9Hx(fzz3Cio#adC&+;;aYb zycH7e8Ld-{i#HXI{cb26EB$OE^;zw2!tBMk6V}2X$WITAKAwO#%3L_oDxwPN0D$I* z2_X{sC|Qkz=|(gU!e%L+y6%TAG*ZDP(bO&ff_v1=bsQc%(_K$k@iLtn( zGr0JDlz0jz-rGE}Se^%C(-c%tSDXMK@Cyk*-*W+g)GzyV6XI526K~RST)du5ij8!` zOLT3qXTo<>bk_E-`*B|n$fo$OOZIE$OIu4ed3`RSt&4t*0+M0O@@{+sw^|K`{$3g3?X`99pf zx!#%_YX%so^)B_PRmbM!sCi<5?*<(=8%Os;fbcz@x>RH z9HT!UApE#cownick5@Z+56{FJ!1SP|NDU#U&0L1O8Ao};0N?y58IL4&BXBdTHX{kCF~2U{ zOBN0PDqWZPy=pCX|8LRj`4_gP*&O?J{KePQ1DRf*IDa3q0N+eLfL3_CCfc5YA^vcz zUmH5GPW|A4;=6y;ZDK#vfB&!=K_ZlQyWaNxw>b+cz&0KdO=a7QeYH{1I;;*qJ zBaV_eNHZ7DjrkpD_a`^?PaWxR){zh8;T*3u_JqZceIGvjE&r+U`tMNsw;Z#$)!wxe zb3*l7DHoo7YY#lM`IOd~dw=y^Z`}HV?6UaS6R-vLy<4>q&rRo;30bKYN6E4r+ivhD zBbA)$?5)S*TPB=1vDRUibwy76%r9T>iS(V5Yqz=&{=Js|$aU@E%QWxj39o#31UzT6 z3W{ivm%Ecg5%TN}Umaax0qMCWt2&3)vg7I7@7+ndXP$K;=dX_akMH+OWACTW{rK|t z3tH{)2a*cXNeGjJ%8(s6)NWL{Wd^jGkgDM9_3YhTaGZ?aU-e&q^cG2uKMsk00aq={j+}u5cXcmLF^$Q}b zD_5ZRj^lrVy3qtvguIl^o-q1Os^S>egj2(o2j!5pvms3Ej1*kO*@rKMsD(YQs<>rt z=wZVZFF6qrH?)>;MM_R2*$wGwMP9DTUb+_UC5PTIYxw9bMiBW9J_}$q^Rhix5dSVa zi?e4w*h^ETNs8l#9e+`^qUweu7>Z4V0)bYyz5A|D6ah0LQ>T^xz#n4I%7)djilbIy-ErX1omXjk4oB+$-x~{$_Sd6>^5+BKm5c>Jogk1nvOp zGR55l&fOMVn*6Vy$0!jiPgk}%=F(5r_7tI`D&cV5Ieq5 zCE7@#22=r9>#!NPIwl~H0Xfx>FjcIzPFP4^E<%v4LGg1k%T>_1Mwz{E8I2C8Mx>l1 zN7F|Ja@e^-G}f3Cobc4WPNc^=gJ=kM2ASCiN>H_^Rh)N?Af`)oybQIc5tN>|$S*?O zg|q&vhYpQyBTrZ80iTH2x^_e4& zLn{7UE&~Fs^D_Rm08Cg5D&Q96kj!k5zVmtAjvF-lyTVWq4sKC;kL~{>cyn_wgTR`# zQQwsZVw5>)AUvx=(X1hiTASemc*3xoszv@Ef%M-3lF8uSuZbm@bC?~lBWVNCfx~Q? zQ@Dzt>fu;&xnvp8`Vojf^c;%|BH(u}iHBPnpcR^Y9cJWo4j`@}cuXme zCI)LmH~aHH**vlV#8{F^VXQ?_WRel`fC{?Q4gg|a<^rNlJCXvi?Dl7!e>`zZS6+1~ zziG|wI4ZDF+iCK?#`}#vzy6xeL|1iU-2HKD*&p07t2w|tUknLxMW({$0H0Xf|JTP^D75(od*dvJZ30o>w7da zkmC=hsT{ZWYOhp)IGcQuI5N!~n6UYf<$7in1;(Gv$7uZXbt71DOv?bkkYm8HPPL(= z!p@yAOqG(v2lOVaIjQSmmvKa(`DHSt33dw}1`tt0q$W#FIRFA=PJ+BVW<3OGL$=m1 z&Np?!>|BC8*05xqL1nh`@uJxU#7p?knhvkqPQ z0-b6LZWTYKAwJXa2gJMb2##LleP%}NpzZ;jZ8DO*CfQ`sZdl0N?U2{e2v666T-y)j z5^_!NI?K`wf>odq_hH&)^U%u=>l_{FCWOTA*81>FhS=M#B006JTX1~?dtgJIm{^zd zC4EmGEiebeh_dBu~)BA2%wZ`nE`ZBB#H7m6AmJQnZPmyIfbyb zjx)%ON~dlRv1`hikmT?KT2>FB01MXW9^Ebm2t!ks_q61OgUgikjd}Od5eUcg+3%{> zsL33`I@WRqQXtK--N5?cjfh{LoyuTC>tQ8GV{kAOx~&7Z$%ZrG<#li?l>Qey1R;es zEL-pKR7a3t!IWvvAy6R2^`|G|*l{>E8OQ1IXH6hQpv$iYRQK38Wm|o`M1Z1dOx-Mp(mAT0{U%(gOYTKtCzg z@G0ovulv=&H`4G5?o2!ts#VCORn63HBjlR*=L zIOXeq5STnn5U;s#t}TI=i^?Ij=)fARmQ5g9R5$=KDV}s}*F>ObKpKw}$8+n(_-BeY zR7eju0T@-psvRi6lZ5-wJt3lgq5xeIKB-8mVis8%poejVc4&gx5=-QtvMU6L``0B= zA;_b5@FdG)dJaU?;lEjzqV!ZL>qH!v8gxk|YLMCoTF%Jh?5)HZGOZkRuw?%%Y0| z^5R(iIP{hr(Fr@fu27LCJ5iw|nhtWBY#_@&4tN({Q_#qvd%Vcsr>8CQ31OUOV`LMP z*AtQBw;@L;g2pOxnxp|{kl@TNExsw-f6A;G%=rOMP>@6lIAMzsn|^9%tuoH3L;6u4 zo2c&V*<5OWQyxHj4}84_#PowT{zMe3?9X2s$db|MVmWK#SkweQ7Ql$Wi!18jy6lq= z653s~N}6n)HXuQyHv{p5``wN^5V%8@|N4GhrArT*=7Is@cmc%zPtUjlJBZaMN16Wh zC#!=!6p@d?rZ5V;-YUMq&m6)XsbMHw`(Q-y!&q|JlKYp4@`gvhc$FL5oWqJ5nWc8zupZ5Fj;8S2uJXfe&ZQM5iFJ;Y$eyUI ziu#L{p8Z3@m!YVbaF=DVUNNO*r0!XFiuCELr8ucq{;%;^PSd9>30J!IdX9$B@-2sl zm0!<2lkZFgz?GL$QuAB<^rX?^UmSAU&+ZmQNKsSc%CQrGaz95ROwV*lzYj-4yH#$L z`ZyA2M;$zpWQSiI-ocRKTpf)VdU4kIyA|ilRZul>oi(Z`_Hk>d*2*Vc8n5H=wjK z!Zu0?sqp(8!u(uT)4JLhk~8!t>B!^K(1v`upiYzsv&Sz1gzI+;91;7&-bvTHvKV@28s^U7WcjzpXpp`YQ^XG z`W4_04~fl$u!y@_a8l82R3X%eb+^9;U=~P z%056_?85CEYz4)Qn9m|Pd~NbvT3s5e6%U>H^tb;ioxrHJKg{o6tDw``%KnSs4cJd!!>mS9cfCIMnR2yL;0kbXY{m0T#X@87!C`7Nx$%&gn+v zx1m_Sd2CaNorY=oGn7IQ4#nG|RpNF@^N3tI(X8B)cSqmylc&wgO^EVi{h^oSUUyc$ zF}psW%6oY}E^2why#J$7scJJ(y;`D$qSpd4vwAdvGQ<@L@I2l|w5XC?G7deif4iIW zD)G^8)NY!l99LAfxv`db#MNM^R=~CBFqxR-agoGPv%k!2s(_`7>-jWEuS>{qs4r^fq#mDO<`NqW0K|8D zSx_M-aA$AX;Xq!B6A?V0JXK&Nb+(79m?P;+YCM-TCg`C}IuG93TAHb)Hi<2ltIj#a z+O?T=l1VkXSf~0NX3}hCb8QgK2vp??6tX+3-a7iMK7FNM?{cYQXJ}7 zUfxdGNY?ZABKGX0N%lDQX=$jXAP9@#Vzc;V$ztJ8;}$*yjC~&tSe( zc#6TB8<+!_9;39$sl480UF*vdslw%vmlU<|((w7gU0q9*+RUo`AUX*vTGbR;yZ^E1 z{+3pyu05^S?2-irukB8xH-sx~uWB^vUi5nQY9{PO`{Ip>sn@TbczJfdyOtH8z8$K4 z&yF>*UNw(>IwWDOc^!-2Q22s4VAEW#cJKxxI7>OkOF2?zqbafD(rp7}+S$s~P1)n^ zC;OK7D4({XWmt8G^}SZir6lv+9$IV;@_klCiYYE+-$-G9QeEqfj84wz)NQ)2`gt@w z+Nv8Ve+yN6M>ndc^OA*Na)Ry_7vnjhq7ob#U)?2omnKAqLb_TE%tG&o8db!QiP1`zBA zD?iVl!iB{8U^j<6l&sQv81*5%6TRaRu8OO~HC3WoD?~ioM-f#Iu4PsYQ0i&^y-+~~17FUL3~38jth+32z3M!l zY%0(8Ja%zHZkh0Q*uZJJ&3s3u<@Qzvr{K9Xf?c54XqXu0wWMNAX;oD=3Kzk4p7kh0 zD(`-BZ=I>UCT-~Y+gC=%LDMMIz>YcNuv6t(ruDbBd=e1C!oB4$oz5kKnCd- zoI!6}#mF4|CaHfpg*aWCoEsk;tTUc@&rRiRFW-vP_{UF$yw%>x?OM#yn}j>0V;G%I zup~)eYJ#2M>9jxvfF7la-s!snm*)R#eh_$SbXumhSBa z26wXDc&Npi0Ty0N?toKrhBk`MmSfl7Ga<5I3fY#3h);n=XDSURE}A6v2W5I>S6iRg z&hb7@fgNXhzj#$#_ZdFQEMJ)!@WUpW9$O+>ccqw>)UfCw`qr-Jj2pQ$YjJD$ zGYYL(bruG!Tkb}x9^8WPlT1QRRRyXO`v z#`8kV0jg5#Ar&d8CF|PNsW{WczS@M&M^CpD$~+1mydb92;+{Bmo7NIt>BR4{+cb{Y zouM8^ynU=ACraYvd`VQ|;S%Kv*Rgj{~Gsd49vib`n()7^_nT|{jTGM zkgn9R&UoyRf)=l}M6t(xY=B}#z7!Z-%AxNG%QsJwj~e^@X?)k6j(AJasDUpmwe-GC zr%mm*A1h@7WsCL5^g~e>R}O}$dSNu4 zJUvx-OMdr3lONFyhk91EZFkiqC@J2QxS#4A!mQTMJ{dCBPj-|FmsCArrj|a?TRR?< zXWSaU=k`qbEwPJ<6aK!M7K2ZG&K*}d;B59OKBdr6V`O(B|8vyXNX+T%SL7=-3Dw#u z2mR+?{kqCEU&B49C{Eh{z`N2WEb`e;W!vVl>iZqJyT*UK+PJt^;h6c%?>j?#a$m>j zoFv!gi`WHAFR!Ur6h1EjDt##7naVjDjR%3sbb5G?XcHXF?}5}CU!%MJm|Y7Vq6 zxnDY!qT>5HDZ{nCko>@0m*DQ6r!i9gLR9;*e>yc;vOf2)a^r1Tubm*GT*YCER#adcaXl|)L zGrB`fC}$_TpwsvGX7DTH5jQD63X<7=GcCpF?A?}*pw^a;W}1aH?U804GQD=ctUHo! zR3?|WNYsYUH~f@$)}NDH#Zm+0AcTMK#s={tpwr<-FQcfU8 zG~ZF){|pRhm&m0IlI*N{76&hdUNEa0^oTrzaO_c(&F9?LU{a2*k2`HptXcQU;2`4q z{g<+4CyLB$Ieytlk95w&2=eO2O+CLcy;i*k(Xs~-{H@^y&^?WT?H8yv{S8mc5E*tT zje(Oamv$slZr5osHH>z8Z$YM04G8>f=CG%dR2OpUPb9eI#Q)e?*h_9MZ_Dv@BGd^_Yb&d zty#%VX3txmz4v4?@1Ffg$i5R8RObH*At=I(Da!k@XuYKb$iS1xwqoR}UU9rs4wTE< zscq*ZhOLv+l%d$OQhK?a({r<#5=LA0lL&Oe6vpx^be+iDoi)YNdV{`^@niaRJ$l7c zvitdfRP6v99Uy)cjiamVBquv=%yig}MpKtk!=;BG^_u4+se&lPjY&HiW1MmsYHnyV z=cSqN(2%M$S1Yv7Gc)1nlh&!EJ7}2_XF4ynx}WggF8lTN_(FWR20NGCh?xff-lOom zKaroo?%kLYc)AOU0J%;r^OgZB!R9yFxdK*W|@64blsg=6sq)4&2to-c2c2M99Q~}nlE?)iurZSwEJiGu?+remi@Mooi(Atc4 zu>|{Im&Bq>7AR54d&HR?d7HD_zYb%B#bUQSXO?2_2&D$%U1f~lScmBuN!he9Gd z@)Ggs_7QoxLS(A1?@Vk{Wwc_eBgXwnTQ+RV>l3RiDp({d%N?UU1!(W?+zh~E=vg#NX>sM^ZZ|q-b_WV*Fti{s?9q!b zAKp`?1DX5gRa%}89_yZEvNpX@!0zJ&LQh%1 zAGOh8)qLsmoYujL1WH}6+M)^PI^e@;gbj;tNzlAizDI|7D%IhgjcN7MXA z2{H<|GfvTj@+==yRXGq=iYc$_X6KuL6ma8|*G+|r4mAU-7Ml(+8CH|6Z!{&d=Sf69 z&t|meFYpy!7UlTfli-~&`Q{-gx!b~&C z9$=Yiv!>d_oj;`Mf=SGJyo5pZ#|YLy-mrddU{IAA8BvSDhnT*UvSBM_=4zdcU$7FF>`-N_UxiKR36Tj%$7nlK4s6+=l;$1gAGrlCU z13vvWag;)gH>^aUEI2$`V@d?!KmzFFHLsu?ayTfy_s|(dE;(+*pv`I7Ny@7;duaYzmP& zYg#(n>LU`RoiWLqDW>l-`LE5l2-}X`|0EdezGHFrvrs~!w zU|B7kN*_(+Q7d5{>4z3fN%uX09JIPqZG`@tkOGMcXb&mPt=AR>4My{2?(r*xSr&hG zS2`%cJs4=s;`ipJ+!EFh+%Dq}osinji1@06g>u_;(YCUY&auq+cxA8Sku1I_uTFMS z$rh$xyO+HXX!M$QUzD5SL#nwwHU5PGeK)&X**(LRN$)xji@64tZ?*nqFqPab{au?o zR~cX8UN+~3kz0MZm|4qMv3An%4AS%4r7`2LWTk^iTcSp9(sT$TmP*p2d%Kwa)dtlk z;8LNMdm;iRn06RvsvkYjD%!1neb^L47r8K8_u0|#d6ucKwPm&|sHpzwrR_G_mC5XbfVUr5GDIrB zMBj}WH#QnDUh=w2WE`F-jWLiwM}EB<|LE2b%M@>h)Q`z5fjrw{ucZ=R;py(ismXW5 z-_D(;l?V^6kW$8d9h$4@Q5a9D4Np6IPuneY%JyN=u4mC#&)x&it#9V%N4)bANY)?e z(M0g9GLBE9tH%B(4`}RzXUT{!@+(Zay8O1Jm{=d|e$MjJk)nF2BKutS{SV|@;|p-veW!=g1bQ3%v-ubU0l&Y7pFK88%N0Ij zU;0xsbmQwyPcUua%cwkm&PQaqV?2Le(tm8r808}6TP<dtB#nK+!$6`{xhU-_A8x6`38VVwS<=@rFNWc+<1zFrl5g=&@uDL;z9i2bf% z^y2y^mu`xKUmrf7*N~}*AE_9Cuip)(SAdG6?ci!R2QI6IIwzA6?IQq3z4YQy=hPt( z-&k=^Z6DCx+)1+&Vixd3@A9SeYS~?oo8O-slK?yTZX`WOh90D`|7>*V&+^irp9uWT zfK2agClvHq_CRnB{WCak$nzzT^l}K0*IwWD*>jCQwTs!gy%i@;!Jq5VNa&?`3re5N zvL@p>O3uMsUydq+#9LqWQ~uy#!Daj9o@)k(wi*Ohc-|@ae7di=Lw4X;>vdY$8IfMB zr92wl4nvsy1xun|?tpF@gEJ@6*`boGED#(l^SFO=aR(iz@MK|vGYQC|?8;Qy&g(7} z`KAJpN~|6n_O>*oc>Lha;!fPo_GR&^0!vW3xEEz7zHzbho*K=Pe)w(Y}E22ZP5PgUj3(O|&q>u*ljLKc>+ ze{?Y3xo5wwwC5GD;b}wt2P3`mK^|Rk=bW|u@c!oX66qhb<>L+}yw24#kE*MEbE^zG z(r5H`f3XZHtAg^$?K}e~i2(I8=VvbByExADk9WXD_CIB=!uO%LpFsf1l@_up98cG-;RG z!OID2ig^6n#f@u}tbg<(KRcEWi5stGMzQ@nDN)Z8>+8l_74cKHSbk2T_TDr^2|lji z>WJkJkqbC9hvC7&HQW_E_;LE}zY#99PMO z%7b+olX+H{h}c1=F519v95snMXkf^?Z%m+0Kuy{HUL69ozE_k30bg{iyh$%;So2%P z10ys9zm6Yv{q22egC7zTK5Fn58JVmX&G~~5I%eFHmsi);Nxh!CCw`@H8E*aRA1}pQ zfs;33GfG4LR9@*I&qGal;Mzqelix|xhuJ*z3=AC}a%!~a{r8Y-Fx#bvw*~QsOyK1K z(C=?s);qUkdRo6&;H~^mJI2}QXPC?Xa#w+le=U1G47S~E(Y=YOHHXnz8;=jyO-YJq zNBnbmOVQu$SsTwD{4k8u@U~u0`Mm$Oh&sQWZNb;ug=f0+aU^84Cs=dkFfMTOQ`kCI z=gU9fncdfp8BDS1F8hF0RqW>pfWcg3 z&k=Nqjw_Tg z0p#MA>3nIb6Bj7WMv0gCyYy{}8}vub*}|vbm5zhaF}#UddV6&+mcJ+w`mBFc(e2T`KsxE`k3OO20qP8&KO$kK%D*TYzc~h<{2crhLixQ4_ti7a z=X3SiQ}62I%1!zQmSK%f|_JWS%Elu!Ok*voV5un z4mPD@p6DwieZp3RYc8U3N6{p|S@C!7OE=-f?13cOLWhO7-Pk0*Xw6yP(?{-I5oQnYH_M2Dme7e$DB6dOWmxYIw|J!_w(fhkwk74d-6NF!uVr~5KI6R`3 zqPTVH6b62LjhJ@rvqw2li9ld7B|p{qtq0EBu&49cEAJQrt$v#57cYHVW5Bkyh4j%(#g8wo~Bj7>uj32H&&cUjSHApfIq{bvcsuswN;|g z*kJAR1m%&x<=xkwkp0Fx?I$Mp_eJKVJGYzdi2U=X+^cw;dpFphe$w{5apvDtcK*pE z(DxVz?O5qQ?%{~xKk3FMs%&SsY!n~-UWqD%i#YqdR3a-G35;rg%_p8vPC`(!rP!SaZjRw=-Cb@g9|!OH?g8F<^BTD(XS7mM-*fri8XGRRf0z{Qyq z#|XpA-j!#N^nxt<5`%f&G<($=`?_t-LYW5ggYN@w{Q6Ds5tBv>fZhUx!T_DNp$z1* z1-@5cTGDo;_?~=&Ut)WF%<(LTV|6(IOvULG_BQVs^{PqcF@|#9NIo?{{k!`xxTZ z86JJsw0)G-nmt4#QIGJwA~CR@jemB*lR^UW(m`E0||=hs3;>jpHZ)=`&b## z=E!-^@^U*Kll3bs6NZgS_BU?xG*D?|ZaOD)T?Ck%dOl#0d~E>0;wEvr4wOI<{SR>b;Iv zQ3Df}6J;^Vl?|*H2#JCB0%;APC>mBk3aZ$4mpbkR0jO1ymSm9gJ@Gw|T8I(L^LmeG zw(4(Ynm)Pjl+^=j`TitSs8v{ANfiM8a8bW2bLBmXl8U@Z;cEH^oxOjUi9g$X^1zf; zE2jVabQ0B1G5mW%XOoPy6a=e{qT*|xS^M5%!o9v|_#7V**M4p$`bKCKxPVXjjiLuJ z_gRts6H~3cGd2P9e^Ir3j%(Yx76;k$x zQb%}1Iatx4z51ncN74OnR^>$Gr8!^1LqTz3@~N8+1{^w7(en6{hprBDozA zFuh)1{?Nroa*X6~Bf@$WAw*UWv7=V4K8~bM#Zax@Gl-rl9a87$msMgc7_Sauq@#}I zsBD~n? z_Xw(_fAsFS4UE(fpp81_7)0KPe4hv|bP#|K(8n+s+)xwf{~{{QLP$K2KGq1owRf9n zd^S{tFzxlo8i=Ey*O}h^{DWiqgsTeC1BrP6@#TiU_%1~Al%&6(T``igBi%DG7 zHoqUaU9h`;c=-xock&l4ft9onkE;ZQ6Oag(tGo?Ct(-*2%*K#CO zt=q9{tc8+BX{9X(b+I=}y^ch$vrj!sIF*l~i%=hBCPySmu? z>TXeN1GT8JOa-a>c3x1^&RUFphuw^+3%ezXXkgvhN={TvB^oQpex01>{vp1gR3?ir zIt-b>2R@)#OfM>JVZPY0rDoY zu1-M9qPs%hCkOEUy!)+4AU-h*0ZZ^qV~!&}jSt^tmCb?_Noa-7vP)$SCz+I+_Opu{ zj?}}c!h0V|r0F$Ec!h0wz(*t1sTqXh^mr33+5c2zLd2aqHzGIU3WKVKj))z)Eq^5et5FDU=9G+j)%Bh>kc7 zs{VFYGOK3|2(x7-1`yo8Ni3Y_lp(9)g@lrV99CioJ!vB0oSoG3Qsi9JjN;*_-<;!+ z60t#P5z#=TLOxd_8y&=@dW5jfv$hELLG%Qb$U|b7&J>jwn!pPdp9Dh%9N4?$$%Rla ziK5msc%|4oBb{I`IS6n#nQmVkd)&YpguP1d_bur*6#_RHF~wdAFN7&|q0Zh^F zyaDZCaR}yV$&Q=~fjhL+9>7i*!x{J%N|IMnB&a-K9i&;Xc0tQQ1VAA_0dOwS zBhB%(92{qKfMKCUA<#enE*d3iOLil7mmOr`s!E$=$wAZx`aC5kgNO^ego~RaQPlJ^ zTF%_uB%EnTE)vdUuWXB(AB$b0^PGKz`l&Xfp`=~>1*v909OgE-afHKTY&{Gii%+OB z30f-u`gXI7ba3Je7bY+G4PhlZ@R-^qP6)`mS84P(7ER_LW?h z?_FG(2T=GkAt-V$`i@#eWLZyX>}D|}Uu?KC-{<6(*pVL6fr%)eZsBbimweJtWS3M- zy1CZiaJ>sA!wnt>Kz?Zu|HI`VO?3EGJ+Eh-OveBl^<7vZmK2Jlh4gnDa&&O`hteKV zHb+hR^Y?l}rD$gF&rPz#@XBIcAzFFdZz^+SD6)9ICdCd8->r-#x6~qbin@?28&G`X zC_aj)-rYa7ot-@VeGzhJIJjLtLlaeweR+G{Y!1WBH#!Jt#bx~k;e4bhgK(mT5iB4( z5wOz*X{T4XPB&?W>uSr=O*IJX&4=H?V{%~SG~VYq^)QTK8%2bSl7^wI6r~6h!JRXB zvwvOOafGL^YYNWTUzd7c8yBlEF$M;`r@6Hgf1DLymx)RLMWKzWbl<|*GOcg6U+I*Dp>Ap;XE^DOL?R5tROrgW$Ew91}( z&lXnHumh)0R^(O*g{lf<6RK_L!thz~MJ`-KhFQ=F#@{w%B`r*bORS)N zeoBIBg%61>p%|@P@~xhXY+&#&4DJab!4Yd1foF2;xQzf2o#+iNF0sV9b(b(CMEx{L zBkl-J9QUl8F@g6@XKCI8jl= z94L%?3v|Sg^Mg%~rA#u?24|_C<@NjO7nR89)N#@S2MeT%N~9WY_?oE>F#tG`fSlf@ zyZ2WMiVTA?lMH7W1cR#!R=1KSs!w(9a7pRbJNS)#T#5p5UC8)Z&^50)=xpy!KazqC zC{oMQcRQ1FmZbC;TG4;o_wvb}VD6UMFi`9E4Ta>+iWX#2kg7PUKTMLER?bs{uh#lj zmeOOh>=xW6jJq1n?iUbeK6~gmP*1Va#?qWB7zN5Wc!_YzG1?uT7x7hBT+P^{8meHm ze7zVQwSl`K70IIJOp#>*U$M3Nl({){p|=q#2mHP0uDeG^aYt*MJMyWr2;gq3pA+sS za`EQ3vnyMjDO_sKf&vC7>RD8Rn>$hcS^g(i3OBZkP?cexd6L#4QAoPT zXdSDicWf}XSi)z3SB~WA0TxZhRpj-=&cg@PA7-BDX$y!17nX<@-zQ73uNS^8xZ1@M zA-7Y+Fi=EzgJCb_=^I0K61U_Jf|+!K$N8mqgkMw=4ebSg&J?V*6e0|gc6&yUtAa1V zgF;Dgnn4P}aCg83FsfWryW0U${Rs<#-I^@PumFxka8HG+dqrB&&8>M0WVb7)O-bWB zaY91q0qMxVqYwAr3KMS9H_r1{Ge!{x?S!KU) z+T-2sEsy~_f86G8UgEwBos4=4UsZCP%xNSC?ke$cbSGCX#f)E&SS$XK%sup{n8;tI z;q0uayy0_b$g(VmxUarf=Qn5+_>;7a+g<$q9XEP4x>6XFdFDZ&}l~1$b@xFLQBjwYAD6%|2 zD4x5NiKM&WgSi}Vk))%nG*V0njejOqT&|sl5<{~gMdpf;u%lmaYlKab>8xN}Fe-^> z^@(_9yN2H;?T(j8g_UeMD9w51Lp z?HDlhR}3~C(?qM9C;A~x=^cZtilbd)Jq!RiKvG>0m`bs(kpMv7r6taRLm!ke55oAf zNUh;2IzB4a2$iQ(9Ryr#?++spsyzy_YWW+@>0jBoiKPZ*)aJh+FX8WmzNzV|vb!Er z7}It80eenvbjaHGxDct;y^A&GDS`<~DJXXD>#CD|>o!&GK&Yz)jcBxJDw~IEm;@Iw zYo#Pn5|}CjnCYYlEfuxuBE{=6QK^|EC{SpYhWr~%^g?8g3~-hKxbHxoBaI#-d{6bN z{d5|j@*x8W%b?jv946Kq6??q`1%PQa(Y{46ny~&We6HK=-A4cd znlP^`w62Mgt~YFj7C?1_zm|#FO(?5-iD|B_m0z0VxQQi-E;H>W!|$v9hr3L}kJ`_a z33PA8dN18}$Djyk`syh=$wsII#^aC+JKGjw8C`5tX_7)Z2TkG zDAo?IEc6NkAT0}oqC;EQzlTz3F{k$mXH>x8G^Lww)G|e;UUy6Qs`wtU82d+xj~82q zkiEBWwv#65kxk9?)A62Ykex1Qihf-xj-!4+*2Kzt#H4C!s*}G-E5}VLJ{W7xO|@Q! zC*@ViG6lNug;f)VLFs|^LFfglxB&+iFBnVM!0W7bQUW+wOf>8#C(sUd8_Zj9L>LC9 zr`Un%o-M>cGoZs$R085??D*?~sS)exFgw@?b}nbo9WcB&vhZT$IElIAQ&uhw)@y>d zpEnGts4qMNNb(9}=Lo|QhB1!<9j5Yd;~2Ya;5Y%AfE|+-UG4fM(NzRfBG!<`Pd>X; z94OI-;sJVz5a>?ppKgpoj>8~-$H)Pn#9(8HW8Ke0hIBx^;8975teY;`x){HPMSFVF zV6vuPr2O9?@NCKgvu@!*tpX~omWH9J0ZsLK87Lk7Pg;3-KL7z&7{4GegS~~ChOs(U z(TjBay;|$OV4M%PAZ{Cb7Mtgji4CkIJ=zvBq$7RUORJ(mYk!*t&%#~EiF07fGaru^ z^aaUebJxj|r&F646&eG|CK?3s<>TIm#?nz~0(0+0T8vVKjX@%zXb7!Qhae^tF4>>g z`SnxFB|F9?TMe8|7z&&Ogpk(UBoz^tryeDN@d4BL!t9;pjufWAC;~;!@v>0$dKDd$ zX)wZJ7Yo$0Ir3668|%Zgw};wMCxPlc@uzYcGv2j8!x?Z>~ZO9^7K;Pg4?Sq9XUm zOKb%7@)IJD<*Wv&0F52 zk)-^CMcIVB^+THBf;s%z#s$`X77Wm^%4q3=BGBW1V$ml$031^aOM!-igX)|aVJIP( zy{J>gY<^rVER7$?&k=@7Mg!b{r4Q+i9K+%r$c{RI;7&HRy7})F;o;rAmtJ{6u)d9F z13{laFj_$Pi@uUq7??zddKD+4RdJ;yvIdfH{H1OGDK?GP64GVOA{q0+zQc>Kvm-~Q zdD~n}I(A_B%{~_f+61x`Wc8h$N2K=s!mkm?cD7_vi4DBPvEl4ZWUBkCd`TjA2rP11|#W2#=N+ZQN zZ5;cxth0~uK_aVC-`BL9L>H%?v<%u!ycbFfa=tl^PF*wR5lag5mksMkoFbbYFbM%S z%p^{w0awIPv|%>k#F!4IFocOsNrR1H1@6Tc_OMrxpTF4h74y^#V(6{ARtCQ3wp$7W0#90XwupA+%P}yqHF~g3Ma11TU!| z(68q(bHvgrdQ>)3>1+6W>)dy4q*a43erSJ6B*)S$;XLA=e5f2f3xqxKucI@Kw&0WS zP|{IDIcxu(q0W4nl^@OH(%88hajMaDVy{4ka#1)*8>3N&n2oh8Q%6st+h>?1EhW3) zurHA?!0S!B`YQHW`mndKoTgJ-p4N=QAu3*Kl#{807=8OW3>92Kqt9qxpP+#xTua>8 zj2)bZU@VI?ZSwtOlb4NgRi!8X3>+<}&*7HjYn-d!9Pw?oq-*JWIHg!v1~TBpXaImb+}nMZ^a%L5@M(fNznEaQIJZm?J6y}h@ISG(3ZziyPnwM>g8-`Mtozm3yN@V zxXeLqE=loYY@{3$O&68YE9Zcx9F1~lVw$9@B+5372yr;d^98=*eqW>e&CHDfvCjkQ zN`q%qUFxrmuoAt7_3w;Xr#dihZftitXvzO%eNJ*g8_EvmlUa<|$mPTosk7Db*K88y zyx-J``H+n%?T#~CamoP{du^2k@Xe~dq#0ABFqHo4`*B&~Sw6Cx46Ufy*vwshLUQz# zHMEu4Wj(6=X9IY?Su%s*PBuuh0vjpqtX?oL<)q7~L(fv=z5=xj5}1#--#RD(H2-z) zn6h5~t8LDLUJ6Z8@+-2gRnm6^SJS#U5p!yEEHc>lOAap!n2-v0I|~Kz!+seK(A!V< zEq%#bto*WKCu{R&%<;vX`(+r5lBr8;@m?bt>Y<->n(WN)IC8Ef11Qw-pc_>1JH1Vr zr=!7>;|`iQWF{BjQX;$4X1!z`v5ft&P0iBeKKAYtNJ)R>z#Iw?P&_31q}>r~4W>bR z(V(3>mrF_Gy$}0mv-MW$Cj4hSUlAUeGak7U9|iW@yFqeP`6m4p_}Gk0Nx%HtqRWFa zUlk&H9gtt{R;da8bcE0yPsEu-LLM0&U_;KcfkW5}N>gusmD@IkA$_neyzw;SwO%n6h|D}aL40a}}-DhTv zC^qshwmr>A>1MXj+EfgSWDKGFO?<%FnfL8_JKU0)Q; zPbG1$gzcuFR4sM+@=QU!)XToYKm1~?6iH4hOw51sPFPMa)SYFTAuy}e?_^Ks+xE_J z0hDOpQL8os>vK`K|xJK54yO z@93t-;1iHj=zq7+!Hi`^fwW{fZrtQ2LI1B@lfu-D-XeKgIm@D%rvX)WnY(B6bHBD1 zZlKc`(1#CEk7DrMeZDu@mxq;*P20EhY)Q z8^3m69fUkSbRJ^}W261M?Bqjv+N!-u{h`4IIpzhKx@|Reyou*RLV}>=K=2I6G&qYTC4A z`y%;(PZWN}GcYFVR`Ks%NfwrP&s3fp3m%`Ieo=< zV)EcndFKA}Ma#=ayJBA{%S(tfzf!MCJWVyxv{&KNR5B}udTVQI*^NqR_U#hVv zs%M>!2M|WTbLK(&DQfNQ zom+P(ABSNR4rstcw}zO1Huu4{w?o$dh~574{j*JyJRh`-A8DQd85p4{lO#76N(|00@B_xAwUu22mxK_vyq3X01zOyJk5o-V1huJhMizc z)K^9n)azRtWEOfLMqUzyNsW`cArS@@4$I*z+(A@25EXH5Mdt%be+7)g=x1PgHLfNM z$ttw+-hfEhXAWY*P}*7o(g%v~2t(;j04eE#C?JTPK;=Egi@qpRvNnn|IS`CRN&h2| z)e-^ROpXA6Y08d*;V~GEVC`kw01pQ79B=$KTo{HKb3sOuD1h#HV z)U^=fpbXFl;W+7Zxo5PaR-y0IX0k?5`z>}wBPfiN5!v0%9YSIpwR@tR4ixU*=1ha{ zXdDGZH?aT&K)RBsx|o1^`5AQka~y3qFW+;VI4V?pI6QpQhsrF}MU*ZO;_7eg>V-1h z4yKiD!A8*41H>l}4f#pt_DIb{Xx^A4U@lBOZUx;@d?rRt6Y&1R10<1wY8sDe;s@!7 z#DFt#>Y@Z$FjKE}H!jcuS;W zZ$DDvF|(qXndETD4oB%ryjhbPc8Cz5TW_86>lEDVddx7A;m;eCeg z$;)y~Ki$PQvJid+u1n0tnNIhm%vGW?-B)ER8i`;1P&4&r`=P|TOu5$$l0M1>va0eS z+iw9xxksV2s%&ZZ*vc_o#ZT&=YJX$5FfhL(t0%Av;`KF)za3Y^*tRbxoYfsr`E($k ztS`%@AC26n7{hWMNuYn(H!DX3NuV4jHGj#qpi|$!Q~%hO9l(l%nx%x#mUV?aNWH+p z%5F4Xj3R%%IBwGq^ixg?P8}97TzJwx`XxH!b{}cfWU>@uhhh(0V_ncRt5dUxB-rT(Sk3&1>nZ|j z{A2@pJKWF`7yLpoT@7Gt%o(b~GYJ%LS#qbD0Y}jEhZ-R=N!5u>I0|-o;+TfJz%BRn zSgU5$i5+#ZJM2x_-fvR!_+^(Jd}x*1LG(k`t@3pdzZ zuK+F{PoMpHdT(IgSnAUazp*_zt`m<6K5WUwRS{QSJutP1CWd;5V$8$*Ok|J7P9nA& z^_|x`l>3c%W66}Osk{K4ExumD+gyi5$}f#ALh+G{+qPKpL&;BEtqP0wYR|$HCI|NK z&IppNlRHn|VoHA{`WB8W6k{O#DQ+A+sKLvxLbwJc)W$!c7(1FjVC@VVMC8hLQQRvr zIXjO{RL<8_*0eXgs$C?6&Mx8^Hr%U(ha5VL?ojCJDYX+py;dq9o&hgE9R42Z!Y*G6NO7j>>B$)yXQ57VKTghI z=tzw=e58~_k^AmFRelq&Jt04#Nfxy(>akY2z}@7NF&ksoM^A`cdb)n)>RW7WoA@2dZRlPSsm{|fPD5P5P$Jbgv1EBlmLI8J(DJg@nXKIR)%afX@=n-8 zwlaDj%}pNa?aG(kPk+Sl?$k&0KA@!BRYQv4i$ZuU`I{R>h?Bjq9gr1lPk8Sj?LAfr zda*c3*7?Llpme3Dp~+^}h236zzXtJgdNFR?AJUn&apU&l!;Ktg5%2vxZ3cH19crNS z*TXw`(wt1wB{H$(#}2o;G^BI@f0c8`6zU=qHd8V_XXy|Tu-AE(f;c{rXxT{&LWd(U zZq@9GsAh@k>DwxDpY0ylGiuydzYR9&wc4*=Q1TjN2Ia@!=^scl%lmI+>-Dh3q3M4#*b`pVA5y`0m)J1Yz7H7cDpr>c;_HAag&7WhW2{-Zbl=G z4iT10I&%X?L@TQr7%^*z8Q4>-^L5M{2Wd$|qZ+9Pg&(AzFp+j+tb~ngSfnsMu$Z7+ z#Qmhn7kKKOVl7Ldq>CIaH>^GL?hZLeoK9Mk@pB`lB#Q9&dg-bkd|v%NFhJ8v!^TdD zbbpeHRLYbjhQ47Q0=u(^_At;Ok<^^!xnTaWQ9|0h(*8Yh2zw|ahQKZc#m-1g5FSe4 M{6Bvt{=dop2f`6scK`qY literal 0 HcmV?d00001 diff --git a/Original/backgmmn.sub b/Original/backgmmn.sub new file mode 100644 index 0000000..acb857c --- /dev/null +++ b/Original/backgmmn.sub @@ -0,0 +1,14 @@ +era *.bak +era *.mac +era backgmmn.rel +era gameplan.rel +era backgmmn.com +b:c -m backgmmn +b:m80 =backgmmn +era backgmmn.mac +b:c -m gameplan +b:m80 =gameplan +era gameplan.mac +b:l80 backgmmn,gameplan,stdlib/s,clibrary/s,backgmmn/n/e +backgmmn + \ No newline at end of file diff --git a/Original/gameplan.c b/Original/gameplan.c new file mode 100644 index 0000000..5d5b93a --- /dev/null +++ b/Original/gameplan.c @@ -0,0 +1,866 @@ + +/* Gammon IV, by David C. Oshel, Ames, Iowa */ + +/*--------------------------------------------------------------------*/ +/* GAMEPLAN.C -- separately compiled module, contains the tactics and */ +/* strategy for making the computer's move in Gammon IV */ +/* BACKGMMN.REL calls MyMove(), MyMove() calls topstone */ +/* and movestone and a few others. Uses the globals in */ +/* GAMEPLAN.HDR quite heavily. Bgversion declared here */ +/*--------------------------------------------------------------------*/ + +#include "gameplan.hdr" /* contains external, global declarations */ + +/*-------------------------------------------------------------------------*/ +/* */ +/* Bgversion is an external reference in the main module. Use this string */ +/* to take credit for a decent gameplaying algorithm if you find one! */ +/* */ +char *bgversion = ".20 -April 1, 1986- by David C. Oshel"; + /*....v....1....v....2....v....3....v...*/ + /* just 38 characters for version info! */ +/* */ +/*-------------------------------------------------------------------------*/ + + +/*=============================================*/ +/* M Y M O V E */ +/*=============================================*/ + + +naked() { /* am I leaving too many blots? */ +static int i, clink; + i = 24; clink = 0; + while (i) { + if (point[i].stones == 1 && point[i].owner == ME) clink++; + i--; + } + return (clink > 2); +} /* end: naked */ + + +yourfolly() { /* look for lotsa blots in your inner table */ +static int i, clink; + i = 18; clink = 0; + while (i < 25) { + if (point[i].owner == YU && point[i].stones == 1) + clink++; + i++; + } + return (clink >= 3); +} /* end: yourfolly */ + + +goodboard() { /* look for four made points near my inner table */ +static int i, clank, clink; + i = 9; clank = 0; + while (i > 3) { + if (point[i].owner == ME && point[i].stones > 1) clank++; + i--; + } + if (clank > 4) return (TRUE); /* bar is nearly blocked */ + + i = 6; clank = clink = 0; + while (i) { + if (point[i].owner != ME) + ; + else if (point[i].stones == 1) clink++; else clank++; + i--; + } + return (clank > 3 && clink < 2); +} /* end: goodboard */ + + +bearoff() { + return (topstone(ME) < 7); +} /* end: bearoff */ + + +scanahead( from ) int from; { +static int count; + + count = 0; + while (--from > 0) { + ++count; + if ( point[ from ].owner == YU ) return (count); + } + return (7); + +} /* end: scanahead */ + + +endgame() { /* Is no strategy required from here on in? */ + return ( (25 - topstone(YU)) > topstone(ME) ); +} /* end: endgame */ + + +/*------------------------------------------------------------*/ +/* MATCHUP */ +/* */ +/* 2-stone functions that force the choice of the next move. */ +/* These are the HEART and SOUL of this backgammon algorithm! */ +/*------------------------------------------------------------*/ + +setpend( from, to ) int from, to; { + pending.fr = from; + pending.to = to; + pending.flag = TRUE; +} /* end: setpend */ + + +clrpend() { + pending.flag = FALSE; +} /* end: clrpend */ + + +natural(f1,t1,f2,t2) int f1,t1,f2,t2; { + clrpend(); + if (point[t2].stones == 1 && t1 == f2) setpend(f2,t2); + return (pending.flag); +} /* end: natural */ + + +matchup( test4 ) int (* test4)(); { +static int i, j, ti, tj; + + if ( pending.flag ) return (FALSE); /* this is probably redundant */ + + for (i = 1; i < 26; i++) { + ti = list[0][i]; + if ( ti == ERROR ) goto zoo; + for (j = 1; j < 26; j++) { + tj = list[1][j]; + if ( tj == ERROR ) goto voo; + if ( (* test4)( i, ti, j, tj ) ) { + lurch( i, ti, 0); + return (TRUE); + } + voo: ; + } + zoo: ; + } + return (FALSE); + +} /* end: matchup */ + + +matchhi( test4 ) int (* test4)(); { +static int i, j, ti, tj; + + if ( pending.flag ) return (FALSE); /* this is probably redundant */ + + for (i = 1; i < 26; i++) { + ti = list[1][i]; + if ( ti == ERROR ) goto zoo; + for (j = 1; j < 26; j++) { + tj = list[0][j]; + if ( tj == ERROR ) goto voo; + if ( (* test4)( i, ti, j, tj ) ) { + lurch( i, ti, 1); + return (TRUE); + } + voo: ; + } + zoo: ; + } + return (FALSE); + +} /* end: matchhi */ + + + +/*--------------------------------------------------------*/ +/* CLOCKWISE and COUNTERCLOCK */ +/* */ +/* the rest of these are single-stone decisions based on */ +/* rules of thumb, board-scanning functions */ +/*--------------------------------------------------------*/ + +plainstupid( from ) int from; { /* don't break a safe point */ + return (from < 13 && (point[from].stones == 2 && scanahead(from) < 7)); +} /* end: plainstupid */ + + +unwise( innertablept ) int innertablept; { + /* if it's a hit, just for god's sake don't put him on the bar!! */ + if ( innertablept < 7 ) { + if (point[ innertablept ].owner == YU || + point[ YRBAR ].stones > 0) + return (TRUE); + } + return(FALSE); +} /* end: unwise */ + + + +covermine( from, to ) int from, to; { + if ( from < 8 ) return(FALSE); + return ( (point[ to ].stones == 1) && (point[ to ].owner == ME) ); +} /* end: covermine */ + + +idareyou( from, to ) int from, to; { + if (unwise( to )) return (FALSE); + if ( (point[ from ].stones != 2) + && (point[ to ].stones < 2) + && (scanahead( to ) > 6) ) return ( TRUE ); + else return (FALSE); +} /* end: idareyou */ + + +hitandrun( from, to ) int from, to; { + return ( point[ to ].owner == YU ); +} /* end: hitandrun */ + + +dbuild( from, to ) int from, to; { +static int diceleft; + diceleft = (myturns? 2 + movesleft: movesleft); + if (diceleft > 1) { + /* can't possibly be only one stone on from point */ + /* or kamikaze would have covered it on last move */ + return ( point[to].stones == 0 ); + } + return (FALSE); +} /* end: dbuild */ + + +kamikaze( from, to ) int from, to; { +/* cover my distant blot, or razzle-dazzle 'em with the long doubles hit */ +static int j, k, diceleft; + + k = from; + j = from - to; + diceleft = myturns * movesleft; /* NB: 2*2 == 2+2, "fourtunately" */ + while ( diceleft-- ) { /* predicting where doubles land is easy! */ + k -= j; + if (k < 1) return (FALSE); /* out of bounds */ + if ( point[ k ].stones == 0 ) continue; /* simplify */ + if ( point[ k ].stones == 1 ) /* found my blot or yours? */ + return (TRUE); + else if ( point[k].owner == YU ) /* found your blockade? */ + return (FALSE); + else continue; /* found my safe point, so ignore it */ + } + return (FALSE); + +} /* end: kamikaze */ + + +hittite( from, to ) int from, to; { + return (hitandrun(from,to) && to > 9); +} /* end: hittite */ + + +safehit( from, to ) int from, to; { + return (hittite(from,to) && idareyou(from,to)); +} /* end: safehit */ + + +foolsdemise( from, to ) int from, to; { + /* annihilate orphaned blots in enemy's inner, my outer table */ + return (to > 17 && point[to].owner == YU); +} /* end: foolsdemise */ + + +landonme( from, to ) int from, to; { + if ( plainstupid(from) ) return (FALSE); + if ( loneranger(from,to) ) { + if (from < 19 && to > 6) return(TRUE); + } + else return ( point[ to ].owner == ME && point[to].stones < 4); +} /* end: landonme */ + + + +/* these evaluations have meaning only in the endgame */ + + +nobackgammon( from, to ) int from, to; { /* endgame */ + return (from > 19); +} /* end: nobackgammon */ + + +crosstable( from, to ) int from, to; { + /* always move a table ahead if possible, in the endgame */ + if (from < 7) return (FALSE); + if (from > 18 && to <= 18) return (TRUE); + if (from > 12 && to <= 12) return (TRUE); + if (from > 6 && to <= 6) return (TRUE); + return (FALSE); +} /* end: crosstable */ + + +fiftytworule( from, to ) int from, to; { /* endgame */ +static int p; + if (from < 7) return (FALSE); /* not in inner table! */ + p = from % 6; + if (p == 0) return (TRUE); /* improve the six */ + if (p != 5) return ( (to % 6) < 3 ); /* best improve under five */ +} /* end: fiftytworule */ + + + + +/* these evaluations are universally applicable, last resort moves */ + + +gohome( from, to ) int from, to; { /* always go home if you can */ + return (to == MYHOME); +} /* end: gohome */ + + +scatter( from, to ) int from, to; { /* scatter, esp. in the endgame */ + if (plainstupid(from) || unwise(to)) return (FALSE); + return ( point[ from ].stones > 1 && point[ to ].stones == 0 ); +} /* end: scatter */ + + +runnerup( from, to ) int from, to; { + if (from < 10 || from > 18) return (FALSE); + return (TRUE); +} /* end: runnerup */ + + +loneranger( from, to ) int from, to; { + return( point[ from ].stones == 1 ); +} /* end: loneranger */ + + +run( dummy1, dummy2 ) int dummy1, dummy2; { /* MUST move something! */ + return (TRUE); +} /* end: run */ + + + + + +/* clockwise and counterclock make a 1-stone choice on rules of thumb */ + + +counterclock( test ) int (* test)(); { +static int i,j; + + for (i = 0; i < 2; i++) { + for (j = 1; j < 25; j++) { + if ( list[i][j] == ERROR ) continue; + if ( (* test)( j, list[i][j] ) ) { + lurch( j, list[i][j], i); + return ( TRUE ); + } } } + return (FALSE); + +} /* end: counterclock */ + + +clockwise( test ) int (* test)(); { +static int i,j; + + for (i = 0; i < 2; i++) { + for (j = 25; j > 0; j--) { + if ( list[i][j] == ERROR ) continue; + if ( (* test)( j, list[i][j] ) ) { + lurch( j, list[i][j], i); + return ( TRUE ); + } } } + return (FALSE); + +} /* end: clockwise */ + + + + + +/*-------------------------------------------*/ +/* Make Prime */ +/*-------------------------------------------*/ + +static int prmchk; + + +buildprime( f1,t1,f2,t2 ) int f1,t1,f2,t2; { + clrpend(); + /* check for the doubles bug */ + if ((dice[0] == dice[1]) && (point[f1].stones < 2)) return(FALSE); + + /* look for the combination */ + if ( t1 == prmchk && t2 == prmchk) setpend(f2,t2); + + /* stick like glue to a made point, but doubles may move forward */ + if (dice[0] != dice[1]) { + if ((f2 < 8) && (point[f2].stones == 2)) clrpend(); + if ((f1 < 8) && (point[f1].stones == 2)) clrpend(); + } + + return(pending.flag); + +} /* end: buildprime */ + + +makeprime() { +static int i, tab[] = { ERROR,1,2,3,20,22,24,9,4,6,8,5,7 }; + i = 12; + while (i) { + prmchk = tab[i]; + i--; + if ( point[ prmchk ].stones > 1 ) continue; + else if ( matchup( buildprime ) ) return(TRUE); + } + return(FALSE); +} /* end: makeprime */ + + +coverprime( from, to ) int from, to; { + return (((to == prmchk) && + (point[prmchk].owner == ME)) && + (point[from].stones != 2)); +} /* coverprime */ + + +cleanup() { +static int i, tab[] = { ERROR,1,2,3,20,22,24,9,4,6,8,5,7 }; + i = 12; + while (i) { + prmchk = tab[i]; + i--; + if ( point[ prmchk ].stones != 1 ) continue; + else if ( counterclock( coverprime ) ) return(TRUE); + } + return(FALSE); +} /* end: cleanup */ + + +/*-------------------------------------*/ +/* Walking Prime */ +/*-------------------------------------*/ + +swivelhips( from, to ) int from, to; { + return ( from > prmchk ); +} /* end: swivelhips */ + + +slink( from, to ) int from, to; { + return( (from > prmchk) && (point[to].stones == 1) ); +} /* end: slink */ + + +weasel() { + if ( clockwise( slink ) ) + return(TRUE); + if ( counterclock( swivelhips ) ) + return(TRUE); + if ( clockwise( run ) ) + return(TRUE); +} /* end: weasel */ + +ihaveprime( from ) int from; { +static int i, to, ez; + ez = 0; + for (i = 0; i < 6; i++) { + to = from - i; + if ((point[to].owner == ME) && (point[to].stones > 1)) ez++; + } + return (ez > 4); +} /* end: ihaveprime */ + + +walkingprime() { +/* looks for the walking prime anywhere in the front tables */ +/* then tries to bring up a runner from behind the prime, */ +/* ensuring that a back stone WILL move before a front one */ +static int i; + i = 12; + while (i > 5) { + if ( ihaveprime(i) ) { + prmchk = i; + if ( weasel() ) return (TRUE); + } + i--; + } + return(FALSE); +} /* end: walkingprime */ + + +/*---------- Book Moves ----------*/ +/* only valid if my move is first */ +/*--------------------------------*/ + +zip(a,b,c,d) int a,b,c,d; { + lurch(a,b,0); + lurch(c,d,0); + movesleft = 0; return( TRUE ); +} /* end: zip */ + + +zoom( a,b,c,d,e,f,g,h ) int a,b,c,d,e,f,g,h; { + myturns = 0; zip(a,b,c,d); zip(e,f,g,h); return( TRUE ); +} /* end: zoom */ + + +book() { +int a,b; + if (!firstmove) return (FALSE); + firstmove = FALSE; + a = min(dice[0],dice[1]); + b = max(dice[0],dice[1]); + switch (level) { + case 0: { return ( book0(a,b) ); break; } + case 1: { return ( book1(a,b) ); break; } + case 2: { return ( book2(a,b) ); break; } + } +} +book0( a,b ) int a, b; { + switch (a) { + case 1: { switch (b) { + case 1: return ( zoom(8,7,8,7,6,5,6,5) ); + case 2: return ( zip(24,23,13,11) ); + case 3: return ( zip(8,5,6,5) ); + case 4: return ( zip(24,23,13,9) ); + case 5: return ( zip(24,23,13,8) ); + case 6: return ( zip(13,7,8,7) ); + } + break; } + case 2: { switch (b) { + case 2: return ( zoom(6,4,6,4,13,11,13,11) ); + case 3: return ( zip(13,11,13,10) ); + case 4: return ( zip(8,4,6,4) ); + case 5: return ( zip(13,8,13,11) ); + case 6: return ( zip(24,18,13,11) ); + } + break; } + case 3: { switch (b) { + case 3: return ( zoom(13,10,13,10,10,7,10,7) ); + case 4: return ( zip(13,10,13,9) ); + case 5: return ( zip(13,10,13,8) ); + case 6: return ( zip(24,18,13,10) ); + } + break; } + case 4: { switch (b) { + case 4: return ( zoom(13,9,13,9,24,20,24,20) ); + case 5: return ( zip(13,8,13,9) ); + case 6: return ( zip(24,18,18,14) ); + } + break; } + case 5: { switch (b) { + case 5: return ( zoom(13,8,13,8,8,3,8,3) ); + case 6: return ( zip(24,18,18,13) ); + } + break; } + case 6: { return ( zoom(13,7,13,7,24,18,24,18) ); + break; } + } + +} /* end: book0 */ +book1( a,b ) int a, b; { /* mostly follows Becker */ + switch (a) { + case 1: { switch (b) { + case 1: return ( zoom(8,7,8,7,6,5,6,5) ); + case 2: return ( zip(13,11,6,5) ); + case 3: return ( zip(8,5,6,5) ); + case 4: return ( zip(13,9,6,5) ); + case 5: return ( zip(13,8,6,5) ); + case 6: return ( zip(13,7,8,7) ); + } + break; } + case 2: { switch (b) { + case 2: return ( zoom(6,4,6,4,13,11,13,11) ); + case 3: return ( zip(13,11,13,10) ); + case 4: return ( zip(8,4,6,4) ); + case 5: return ( zip(13,8,13,11) ); + case 6: return ( zip(13,7,7,5) ); + } + break; } + case 3: { switch (b) { + case 3: return ( zoom(13,10,13,10,8,5,8,5) ); + case 4: return ( zip(13,10,13,9) ); + case 5: return ( zip(13,8,8,5) ); + case 6: return ( zip(13,7,13,10) ); + } + break; } + case 4: { switch (b) { + case 4: return ( zoom(13,9,13,9,9,5,9,5) ); + case 5: return ( zip(13,8,13,9) ); + case 6: return ( zip(13,7,13,9) ); + } + break; } + case 5: { switch (b) { + case 5: return ( zoom(13,8,13,8,8,3,8,3) ); + case 6: return ( zip(13,7,13,8) ); + } + break; } + case 6: { return ( zoom(13,7,13,7,24,18,24,18) ); + break; } + } + +} /* end: book1 */ +book2( a,b ) int a, b; { /* mostly follows Becker */ + switch (a) { + case 1: { switch (b) { + case 1: return ( zoom(8,7,8,7,6,5,6,5) ); + case 2: return ( zip(13,11,24,23) ); + case 3: return ( zip(8,5,6,5) ); + case 4: return ( zip(13,9,24,23) ); + case 5: return ( zip(13,8,24,23) ); + case 6: return ( zip(13,7,8,7) ); + } + break; } + case 2: { switch (b) { + case 2: return ( zoom(6,4,6,4,24,23,24,23) ); + case 3: return ( zip(13,11,13,10) ); + case 4: return ( zip(8,4,6,4) ); + case 5: return ( zip(13,8,13,11) ); + case 6: return ( zip(13,7,13,11) ); + } + break; } + case 3: { switch (b) { + case 3: return ( zoom(13,10,13,10,10,7,10,7) ); + case 4: return ( zip(13,10,13,9) ); + case 5: return ( zip(13,8,8,5) ); + case 6: return ( zip(13,7,13,10) ); + } + break; } + case 4: { switch (b) { + case 4: return ( zoom(13,9,13,9,9,5,9,5) ); + case 5: return ( zip(13,8,13,9) ); + case 6: return ( zip(13,7,13,9) ); + } + break; } + case 5: { switch (b) { + case 5: return ( zoom(13,8,13,8,8,3,8,3) ); + case 6: return ( zip(13,7,13,8) ); + } + break; } + case 6: { return ( zoom(13,7,13,7,24,18,24,18) ); + break; } + } + +} /* end: book2 */ + + +/*====== MyMove ======*/ + +torve() { + if ( makeprime() ) { /* this will use doubles, if it can */ + return; + } + else if ( walkingprime() ) { /* i have six prime points, so run!!! */ + return; + } + else if ( dice[0] == dice[1] ) { /* this is too easy! */ + if ( counterclock( kamikaze ) ) + return; + if ( counterclock( dbuild ) ) /* claim new turf */ + return; + if ( clockwise( run ) ) + return; + } + else if ( cleanup() ) { /* cover my single blot on prime points */ + return; + } + else if ( bearoff() ) { /* I'm ready, but you're in the back game! */ + if ( counterclock( gohome ) ) + return; + if ( clockwise( run ) ) + return; + } + else { + if ( clockwise( hitandrun ) ) + return; + if ( matchup( natural ) ) + return; + if ( clockwise( landonme ) ) + return; + if ( counterclock( runnerup ) ) + return; + if ( clockwise( scatter ) ) + return; + if ( clockwise( run ) ) + return; + } + +} /* end: torve */ + + + +villiers() { + if ( makeprime() ) { /* this will use doubles, if it can */ + return; + } + else if ( walkingprime() ) { /* i have six prime points, so run!!! */ + return; + } + else if ( dice[0] == dice[1] ) { /* this is too easy! */ + if ( counterclock( kamikaze ) ) + return; + if ( counterclock( dbuild ) ) /* claim new turf */ + return; + if ( clockwise( run ) ) + return; + } + else if ( cleanup() ) { /* cover my single blot on prime points */ + return; + } + else if ( bearoff() ) { /* I'm ready, but you're in the back game! */ + if ( counterclock( gohome ) ) + return; + if ( clockwise( run ) ) + return; + } + else { + if ( clockwise( foolsdemise ) ) + return; + if ( clockwise( idareyou ) ) + return; + if ( counterclock( covermine ) ) + return; + if ( matchup( natural ) ) + return; + if ( clockwise( landonme ) ) + return; + if ( clockwise( runnerup ) ) + return; + if ( clockwise( scatter ) ) + return; + if ( clockwise( run ) ) + return; + } + +} /* end: villiers */ + + + +louisa() { + if ( makeprime() ) { /* this will use doubles, if it can */ + return; + } + else if ( walkingprime() ) { /* i have six prime points, so run!!! */ + return; + } + else if ( dice[0] == dice[1] ) { /* this is too easy! */ + if ( counterclock( kamikaze ) ) + return; + if ( counterclock( dbuild ) ) /* claim new turf */ + return; + if ( clockwise( run ) ) + return; + } + else if ( cleanup() ) { /* cover my single blot on prime points */ + return; + } + else if ( bearoff() ) { /* I'm ready, but you're in the back game! */ + if ( counterclock( gohome ) ) + return; + if ( clockwise( run ) ) + return; + } + else if ( (!naked() && goodboard()) || yourfolly() ) { + if ( clockwise( hitandrun ) ) + return; + if ( matchup( natural ) ) + return; + if ( clockwise( landonme ) ) + return; + if ( counterclock( runnerup ) ) + return; + if ( clockwise( scatter ) ) + return; + if ( clockwise( run ) ) + return; + } + else { + if ( clockwise( foolsdemise ) ) + return; + if ( clockwise( idareyou ) ) + return; + if ( counterclock( covermine ) ) + return; + if ( matchup( natural ) ) + return; + if ( clockwise( landonme ) ) + return; + if ( clockwise( runnerup ) ) + return; + if ( clockwise( scatter ) ) + return; + if ( clockwise( run ) ) + return; + } +} /* end: louisa */ + + +mymove() { +int i, d; + + if ( nomove() ) { + if (lookforit && (dice[0] != dice[1])) { + lookforit = FALSE; + puts("\008... "); + switch (level) { + case 0: { puts("Blocked!"); break; } + case 1: { puts("Well, no!"); break; } + case 2: { puts("Thurb!"); break; } + } + sleep(10); + restoreboard(); + update(); + + /* put the high die in list zero */ + d = dice[0]; dice[0] = dice[1]; dice[1] = d; + + cantuse = ERROR; movesleft = 2; myturns = 1; + switch (level) { + case 0: { setchat("I move"); break; } + case 1: { setchat("Let's try"); break; } + case 2: { setchat("Move is"); break; } + } + debug(chatter); + prmchk = 12; + weasel(); + /* the rules say, use both dice if you can, or */ + /* the highest if one or the other but not both */ + } + else { + lookforit = TRUE; + strcat(chatter," and now I'm blocked "); + myturns = movesleft = 0; + } } + else if ( book() ) { + return; + } + else if ( pending.flag ) { + lurch( pending.fr, pending.to, 1 ); + clrpend(); + } + else if ( endgame() ) { /* very solid tactics here!! */ + if ( clockwise( gohome ) ) + return; + if ( clockwise( nobackgammon ) ) /* no excuse! */ + return; + if ( clockwise( crosstable ) ) + return; + if ( clockwise( fiftytworule ) ) + return; + if ( clockwise( scatter ) ) + return; + if ( clockwise( run ) ) + return; + } + else if ( point[ MYBAR ].stones > 0 ) { /* I'm on the bar! */ + if ( clockwise( hitandrun ) ) /* wreak havoc, please */ + return; + if ( clockwise( run ) ) /* note: uses low die first */ + return; + } + else switch (level) { + case 0: { villiers(); break; } + case 1: { louisa(); break; } + case 2: { torve(); break; } + } + + +} /* end: mymove */ + +/*------------------------------*/ +/* end of the GAMEPLAN.C module */ +/*------------------------------*/ + \ No newline at end of file diff --git a/Original/gameplan.hdr b/Original/gameplan.hdr new file mode 100644 index 0000000..49f8c27 --- /dev/null +++ b/Original/gameplan.hdr @@ -0,0 +1,42 @@ +/* GAMEPLAN.HDR */ + +/*================================================================*/ +/* change nothing in this file */ +/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ + +#define TRUE 1 +#define FALSE 0 +#define ME 1 +#define YU 2 +#define YRBAR 0 +#define MYBAR 25 +#define YRHOME 26 +#define MYHOME 27 +#define ERROR 999 +#define MYLEVEL 2 + +extern int list[2][28]; /* two dice, two lists */ + +extern struct board { + int stones, /* number of stones on that point */ + owner, /* and whose they are */ + x,y, /* x and y coordinates of point base */ + lastx,lasty, /* last location drawn on this point */ + cx,cy; /* coordinates for column numbers */ + } + point[28], bdsave[28]; /* 24 points, plus 2 bars, 2 homes */ + +extern struct { int cube, whosecube; } doubles; + +extern struct { int fr,to,flag; } pending; + +extern int level, dice[2], myscore, yrscore, player, movesleft, cantuse, + myturns, swapped, tswap, deciding, expert, tone, show, moremsgline, + firstmove, helpdisabled, yrdice, lookforit, startcubevalue; + +extern char *chatter[80]; + +/*----------------------------------------------*/ +/* end of header -- change NOTHING in this file */ +/*----------------------------------------------*/ + \ No newline at end of file diff --git a/Original/mylib2.c b/Original/mylib2.c new file mode 100644 index 0000000..4082da3 --- /dev/null +++ b/Original/mylib2.c @@ -0,0 +1,541 @@ +/* +MYLIB2.C + +These routines are CONDITIONALLY compiled; i.e., only as needed. + +---------------------------------------------------------------------- +Incorporates special mods used by my Backgammon game, BACKGMMN.C etc. +---------------------------------------------------------------------- + +A set of common I/O functions that seem to turn up a lot in my programs, +including terminal functions for Kaypro 10, 4'84, 2X etc. + +Uses Software Toolworks' C/80 3.1 compiler. Place #include "mylib2.c" at the +end of your source file for correct CONDITIONAL COMPILATION. + +David C. Oshel +1219 Harding Ave. +Ames, Iowa 50010 + +Last modified: March 25, 1986 + +----------------------------------------------------------------------------- +** WARNING ** These routines use direct console IO, bdos function 6! + + YOU MUST CALL INIT_LIB() BEFORE USING THESE ROUTINES! + + ======= UTILITIES ======= + + * init_lib() - CALL THIS FIRST, OR THE RESULT WILL BE VERY STRANGE! + * + * puts(p) - unformatted print, e.g., puts("Hello, sailor!\n"); + * gets(p,max) - printable input only, no prompt character + * + * ask(p) - demand Yes or No response to question p + * random() - effective random 16-bit integer IFF gets() is used + * sleep(n) - sleep n/10ths of a second, roughly (from C80.LIB) + * rollup() - roll up 23 lines of screen + * ONscript() - printer echo ON for output via puts, chrout + * OFFscript() - printer echo OFF for output via puts, chrout + * ONinterrupt() - Ctl-C, Ctl-B cause program exit + * OFFinterrupt() - Ctl-C, Ctl-B cause comedy + * hide_input(p,max) - like gets, but used when entering passwords + * chrout(c) - if scripting, echo output also to LST: + * putscreen(p) - like puts, but always and only to screen + + + ======= KAYPRO 10 TERMINAL/VIDEO FUNCTIONS ======= + + * gotoxy(x,y) - 0,0 is top left, horz <= 79 precedes vert <= 24, + * where 0,24 is on the 25th, status, line. + * beep() - terminal bell + * home() - home cursor, do not clear screen + * clr_screen() - home and clear + * + * shadow_box(h,v,x1,y1,x2,y2) - like box, but with shadow, calls box + * box(tlx,tly,brx,bry) - draw a line box, coords: topleft XY, bottomright XY + * note that box calls ldraw(x1,y1,x2,y2), below + * + * clr_lend() - clear from cursor to end of line + * clr_send() - clear from cursor to end of screen + * rev_vid(), + * nor_vid() - reverse field + * dim_vid(), + * bri_vid() - low/high intensity + * on_blink(), + * off_blink() - blinking chars + * ul_start(), + * ul_stop() - start/stop underline + * save_cursor(), + * retn_cursor() - remember/restore current cursor location + * ins_line(), + * del_line() - insert/delete screen text line + * on_cursor(), + * off_cursor() - hide/show cursor + * vm_on(), + * vm_off() - "Video Mode" commands + * pixel(x,y) - draw pixel at x,y (video coords, x <= 159, y <= 99) + * no_pixel(x,y) - erase pixel at x,y + * ldraw(x1,y1,x2,y2) - draw/ erase graphics line, see discussion for box + * lwipe(x1,y1,x2,y2) - range for video coordinates as for pixel +*/ + + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + + +/* hide this here so's not to worry about it elsewhere */ +/* "printf.c" collides with one of these, can't remember which */ +/* puts() takes longer to write, but executes faster */ +extern char Cmode, IOpread[4], IOpwrit[4], IOpeof[4]; + +/* make these known only to what follows */ +static int MYbstout, MYscrtp, MYretnirp; /* odd names mark semi-private */ +static unsigned RNDloc; /* effective random location, bumped by gets() */ + /* and scrambled when the LCG random() is called */ + /* makes a decent algorithm for interactive games */ + + +#ifneed init_lib +init_lib() { + + MYretnirp = fopen("LST:","w"); + OFFscript(); + ONinterrupt(); + Cmode = 0; + IOpread[0] = 6; IOpwrit[0] = 6; + +} /* end: init_lib */ +#endif + + + + +#ifneed random +random() { /* depends on effective random location spun by gets() */ + + RNDloc = 2053 * RNDloc + 13849; + return (RNDloc); +} +#endif + + + +#ifneed ONscript +ONscript() { + + MYscrtp = TRUE; + +} +#endif +#ifneed OFFscript +OFFscript() { + + MYscrtp = FALSE; + +} +#endif + + +#ifneed ONinterrupt +ONinterrupt() { + + MYbstout = TRUE; + +} +#endif +#ifneed OFFinterrupt +OFFinterrupt() { + + MYbstout = FALSE; + +} +#endif + + +#ifneed ask +ask(p) char *p; { + +char ch, resp[2]; + +loo: puts(p); + gets(resp,1); + ch = toupper( *resp ); + if ( !( ch == 'Y' || ch == 'N' )) { + puts("Please answer the question, Yes or No.\n"); + goto loo; + } + return (ch == 'Y'); + +} /* end: ask */ +#endif + + +#ifneed rollup +rollup() { + +int i; + + for (i=0; i<23; i++) puts("\n"); + +} /* end: rollup */ +#endif + + +#ifneed sleep +sleep( n ) int n; { /* sleep for n/10 seconds, 0 <= n < 256 */ + + n; /* get n into HL */ +#asm + MOV B,L ;delay B/10ths of a second +__DL0: MVI A,100 ;100 milliseconds, 1/10 second +__DL1: MVI C,249 ;1 millisecond per unit of A at 4 MHz +__DL2: DCR C ;Leventhal, Z80 Assembly Language Programming + JNZ __DL2 + DCR A + JNZ __DL1 + DCR B + JNZ __DL0 ;on exit, HL has FALSE if n was 0, else TRUE +#endasm +} /* end: sleep */ +#endif + + +/*========================================*/ +/* GETS(p, maxinput) */ +/* Local getline function with special *---* WARNING: */ +/* input handling, 1 <= len <= maxinput *---* Execute INIT_LIB() first !! */ +/* Updates effective random, RNDloc, */ +/* Forces input from CONSOLE only! */ +/*========================================*/ + +#ifneed gets +gets(p,maxinput) char *p; int maxinput; { + +/* This function depends on BDOS Function #6. Init_lib() sets Cmode=0 and + IOpread[0]=6 and IOpwrit[0]=6 (courtesy of and peculiar to C/80 3.1) + YOU must ensure that the target string is long enough to collect the + entire maximum input allowed and specified, INCLUDING FINAL NULL! */ + +static int len; +static char ch; + + len = -1; + if (maxinput < 1 || maxinput > 127) maxinput = 79; + + /*--------------------------------*/ + /* SPECIAL ROUTINE FOR BACKGAMMON */ + /*--------------------------------*/ + +loo: while ( !(ch = getc(0)) ) acg(); /* keep the game lively */ + + if (len < 0) len = 0; /* don't destroy prompt by backing up */ + if (ch == '\n') { /* end of line? don't store newline */ + *p = '\0'; /* mark it with a B for baby and me */ + /* chrout('\n'); */ /* but DON'T echo newline */ + return ( len ); /* <--- HERE IS THE FUNCTION EXIT! */ + } + else if (ch == '\b' || ch == 0x7F) { /* backspace? rubout? */ + if (len--) { /* where's the prompt? */ + puts("\008 \008"); /* we're ok, echo erase */ + p--; /* delete from string */ + } + } + + /*--------------------------------*/ + /* SPECIAL ROUTINE FOR BACKGAMMON */ + /*--------------------------------*/ + + else if (ch == '\003') { /* user bailout key is Ctrl-C, not ESC */ + if (MYbstout) exit(); + else { + haltgame(); /* sets whofirst flag and does jumpjack() */ + } + } + + else if (ch == '\025' || ch == '\030') { /* Ctl-U, Ctl-X */ + while (len--) { + p--; + puts("\008 \008"); + } + } + else if (len == maxinput) { /* test specials before testing len */ + chrout('\007'); + } + else if (ch > 31 && ch < 127) { /* printable char? */ + chrout(ch); /* yes, echo it */ + *p++ = ch; /* collect it */ + len++; /* keep track of it */ + } + else { /* control chars? */ + chrout('\007'); + } + goto loo; + +} /* end: gets */ +#endif + + + + +#ifneed hide_input +hide_input(s,len) char *s; int len; { + +/* receive at most len chars in s buffer, + terminate string with zero, + but echo each char with 1, 2, or 3 meaningless dots */ + +char ch; int num; + + if ((len < 1) || (len > 127)) len = 127; + num = 0; + for (;;) { /* forever */ + while ((ch = getc(0)) == 0) /* bdos 6 does not wait, so we do */ + ; + if ((ch == '\r') || (ch == '\n') || (num++ > len)) { + /* not sure what the CR key actually is to bdos 6 & C/80 */ + *s++ = '\0'; + return; /* this way out */ + } + if ((num % 2) == 0) putc('.',0); /* deception, illusion */ + if ((num % 5) == 0) putc('.',0); + putc('.',0); + *s++ = ch; + } + +} /* end: hide_input */ +#endif + + + + +/*------------------------ kpro stuff -------------------------*/ + +#ifneed shadow_box +/* like box, but with horizontal & vertical displacement for shadow */ +shadow_box(h,v,x1,y1,x2,y2) int h,v,x1,y1,x2,y2; +{ + box(x1+h,y1+v,x2+h,y2+v); /* draw the shadow */ + box(x1,y1,x2,y2); /* draw the box */ + ldraw(x1+h,y1+v,x1,y1); /* draw the corners */ + ldraw(x2+h,y2+v,x2,y2); + ldraw(x2+h,y1+v,x2,y1); + ldraw(x1+h,y2+v,x1,y2); +} +#endif + + +#ifneed box +/* parameters are topleft X,Y and bottomright X,Y + X ranges from 0 to 159, Y ranges from 0 to 99, top left is 0,0 + */ +box(x1,y1,x2,y2) int x1,y1,x2,y2; { + ldraw(x1,y1,x1,y2); + ldraw(x1,y2,x2,y2); /* appears to draw the box anticlockwise */ + ldraw(x2,y1,x2,y2); + ldraw(x1,y1,x2,y1); +} +#endif + + + +#ifneed gotoxy +gotoxy (xpos,ypos) int xpos,ypos; { /* 0,0 is top left corner */ + putscreen("\033="); + putc(ypos+' ',0); + putc(xpos+' ',0); + } +#endif + + +#ifneed beep +beep() { putc(7,0); } /* send bell character */ +#endif + +#ifneed home +home() { putc(30,0); } /* home cursor to top left */ +#endif + +#ifneed clr_screen +clr_screen() { putc(26,0); } /* home and erase screen */ +#endif + + +#ifneed clr_lend +clr_lend() { putc(24,0); } /* clear to end of line */ +#endif + +#ifneed clr_send +clr_send() { putc(23,0); } /* clear to end of screen */ +#endif + + + +#ifneed rev_vid +rev_vid() { putscreen ("\033B0"); } /* reverse background */ +#endif + +#ifneed nor_vid +nor_vid() { putscreen ("\033C0"); } +#endif + + + +#ifneed dim_vid +dim_vid() { putscreen ("\033B1"); } /* low intensity */ +#endif + +#ifneed bri_vid +bri_vid() { putscreen ("\033C1"); } +#endif + + + +#ifneed on_blink +on_blink() { putscreen ("\033B2"); } /* blinking characters */ +#endif + +#ifneed off_blink +off_blink() { putscreen ("\033C2"); } +#endif + + + +#ifneed ul_start +ul_start() { putscreen ("\033B3"); } /* underline */ +#endif + +#ifneed ul_stop +ul_stop() { putscreen ("\033C3"); } +#endif + + +#ifneed save_cursor +save_cursor() { putscreen ("\033B6"); } /* remember cursor position */ +#endif +#ifneed retn_cursor +retn_cursor() { putscreen ("\033C6"); } /* return to remembered pos */ +#endif + + +#ifneed on_status +on_status() { putscreen ("\033B7"); } /* status line preservation on */ +#endif +#ifneed off_status +off_status() { putscreen ("\033C7"); } +#endif + + +#ifneed ins_line +ins_line() { /* insert text line */ + putscreen("\033R"); + } +#endif +#ifneed del_line +del_line() { /* delete text line */ + putscreen("\033E"); + } +#endif + + +#ifneed on_cursor +on_cursor() { putscreen ("\033B4"); } /* (in)visible cursor */ +#endif +#ifneed off_cursor +off_cursor() { putscreen ("\033C4"); } +#endif + + + +/* Video Mode ON/OFF: video WORD, 8 bit video if 15 and 7 are both high */ +/* VM-ON 10000001 11111111 VM-OFF */ +/* ^video ^x^video */ +/* otherwise, video BYTE, high bit 7 interprets bits 0-6 as screen dots */ +/* 11111111 */ +/* ^video */ +/* e.g., */ +/* Non-VideoMode VideoMode */ +/* xx 1 11:0 where % is 1 01:0 1 11:0 xx */ +/* xx 3 11 2 the video 3 00 2 3 11 2 xx */ +/* xx 5 11 4 flag bit, 5 00 4 5 11 4 xx */ +/* x 7:%1 6 x is pixel 7:%0 6 7:%1 6 xx */ +/* ^ ^ ^ */ +/* to set the pixels, first do a gotoxy to character screen position */ +/* this mode is faster than Pixel ON/OFF if values are drawn from table */ +#ifneed vm_on +vm_on() { putscreen ("\033B5"); } /* video mode on */ +#endif +#ifneed vm_off +vm_off() { putscreen ("\033C5"); } +#endif + + +#ifneed pixel +pixel(x,y) int x,y; { /* x <= 159, y <= 99 */ + putscreen("\033*"); + putc(y+' ',0); putc(x+' ',0); +} +#endif + +#ifneed no_pixel +no_pixel(x,y) int x,y; { /* x <= 159, y <= 99 */ + putscreen("\033 "); + putc(y+' ',0); putc(x+' ',0); +} +#endif + + +#ifneed ldraw +/* use x1 <= x2, y1 <= y2, order is significant (Kaypro bug?) */ +ldraw(x1,y1,x2,y2) int x1,x2,y1,y2; { /* x <= 159, y <= 99 */ + putscreen("\033L"); + putc(y1+' ',0); putc(x1+' ',0); + putc(y2+' ',0); putc(x2+' ',0); +} +#endif + + +#ifneed lwipe +lwipe(x1,y1,x2,y2) int x1,x2,y1,y2; { /* x <= 159, y <= 99 */ + putscreen("\033D"); + putc(y1+' ',0); putc(x1+' ',0); + putc(y2+' ',0); putc(x2+' ',0); +} +#endif + + +#ifneed putscreen +putscreen(p) char *p; { + + while (*p) putc(*p++,0); + +} /* end: putscreen */ +#endif + + +#ifneed puts +puts(p) char *p; { + + while (*p) chrout(*p++); + +} /* end: puts */ +#endif + + +#ifneed chrout +chrout(c) char c; { /* SPECIAL FOR SCRIPT OPTION WITH LST: */ + + putc(c,0); + if ( MYscrtp ) putc(c,MYretnirp); + +} /* end: chrout */ +#endif + +/* end: MYLIB.C */ + + \ No newline at end of file diff --git a/Original/read.me b/Original/read.me new file mode 100644 index 0000000..148039f --- /dev/null +++ b/Original/read.me @@ -0,0 +1,56 @@ + +GAMNIV20.LBR +------------ +Gammon IV, Version 2.0, April 1, 1986. Full-screen backgammon for CP/M. + +This is the April Fool's Day (1986) edition of Gammon IV, the first major +update in many months. + +BACKGMMN.COM is the compiled and ready-to-run object file. It requires +either an ADM-3A compatible terminal ("old" Kaypro) or a screen with video +characteristics exactly like the Kaypro 2X, 4'84 or 10. However, this +version has the same CRT Module as formerly, including a clearly-marked user +patch area for non-Kaypro terminals. + +Improvements for Version 2.0 include: + +a) Several bugs and poltergeists, especially in the Arrange command, have + been completely exorcised. No bugs have been found in the Play command + for months; but, as before, Gammon IV will not invariably recognize a + forced move, either in your play or in its own. Gammon IV knows and + obeys all other official rules of backgammon. + +b) There are no "hidden" commands anymore. All commands are now shown in + the command lines, including X(pert and G(raphic. The G(raphic command + turns on the Kaypro video-able display. + +c) Input error handling now documents the BAR, HOME and HELP commands, so + first-time players do not need to read anything else in order to play + the game successfully. The X(pert mode dispenses with these messages, + so X(pert actually does mean expert, now! + +d) The "break" command is Control-C again, instead of ESCAPE. It was + all too easy to hit ESC instead of 1 on the Kaypro keyboard, leading to + an inadvertently paused game. + +e) The sanction against cheating (your opponent became Torve) has been + removed. + +f) If the cube is doubled during the opening rolloff to see who goes + first, and the cube value reaches 8, additional pairs on the dice + have no further effect. The cube's opening value will not go above 8. + +The computer's three styles of play have not been changed. Judging from the +feedback I've received, Gammon IV plays acceptably well at the current +levels. All information needed to re-compile the program is included in the +BACKGMMN.C file, including the details of C/80 3.1 configuration. The +compile and link steps are governed by BACKGMMN.SUB. + +This program is in the public domain, so distribute it freely. + +Enjoy! + +David C. Oshel +1219 Harding Ave. +Ames, Iowa 50010 + \ No newline at end of file