dlnash@ut-ngp.UUCP (Donald L. Nash) (01/16/86)
Here is the latest version of PC-More. It is version 1.3. The clear screen function should work well for any machine which makes a half-hearted attempt at replicating the IBM bios, but don't gripe if it doen't. I KNOW it will work for a CGA and a Mono display because I have tried them both. I have not tried it on any other PClone, so I can't say for sure if it will work. If you have a PClone, try it, then let me know if it works or not. I would like to get a list of machines it will work on. Read the history section of pc-more.c to find out what's new in this version. As usual, I welcome any bug reports (flames to /dev/null; if you can't say it nicely, I don't want to hear it). Don Nash UUUU UUUU UU UU UUCP: ...!{ihnp4,allegra,seismo!ut-sally}!ut-ngp!dlnash UU TTTTTTTTTUUTTT APRA: dlnash@ngp.UTEXAS.EDU UU TT TT UU TT UU TT UU UU TTUU UUUUUUUU The University of Texas at Austin TT Hook 'em Horns! TTTT # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. # # Pc-more.uuencode is the uuencoded executable. Use uudecode to obtain # pc-more.exe. Use Kermit (or some other file transferring method) # to upload pc-more.c, pc-more.doc, and pc-more.exe to your IBM PC. # Be sure to use "set file type text [or ascii]" for the first 2 files # and "set file type binary" for the executable. -----cut here-----cut here-----cut here-----cut here----- #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # pc-more.c # pc-more.doc # pc-more.uuencode # This archive created: Thu Jan 16 13:02:07 1986 echo shar: extracting pc-more.c '(35944 characters)' cat << \SHAR_EOF > pc-more.c /* History: Ver 1.3 New clear screen function installed, written by Harry McGavran. All references to crt_cls() and crt_mode() eliminated. This new clear screen function works on either a monochrome or color monitor. Nextfile() rewritten to understand that "-" on the command line represents stdin. The " case 'f': " part of wait() was modified in the same way. New functions cpi() and opi() added to allow stdin to be reopened to the console when it is redirected to a file or a pipe. This allows the user to execute a "!" or a "e" when a pipe is present. Of course, you still can't edit the pipe. The knowledge to implement cpi() and opi() was provided by Brandon S. Allbery. Nextfile() modified to find the file's size and put it in the external variable x_fs. Wait() also modified so that when it constructs the prompt, it uses x_fs to compute what percent of the file has been read. When the prompt is printed, this percentage is included as part of the prompt. Wait() modified to clear the screen when a file is rewound. Ver 1.21 This version fixed a bug which prevented PC-More from working on a color monitor. Under previous versions, only machines equipped with a monochrome monitor would run PC-More properly. The problem was a hardware-dependendent function call to crt_mode(). The problem was fixed by determining the type of monitor in use and using the correct function to clear the screen. Ver 1.2 This was the initial release to USENET. Other earlier versions were too buggy for a general release. */ #include <stdio.h> #define TRUE 1 #define FALSE 0 #define NCPL 79 /* Number of characters per line. */ #define NLPS 24 /* Number of lines per screen. */ #define NLPHS 12 /* Number of lines per half screen. */ #define CMASK 0377 /* Masks high bits of an int to zero. */ int x_mnl, x_srf, x_argc, x_siold; long x_rwp, x_fs; char x_file[128], *x_argv[128]; char *x_spc = " "; FILE *x_fp = 0; /* x_argc and x_argv are the external copies of argc and argv. x_file is an array which holds the name of the file currently being read from. it is large enough to hold a very long pathname. x_fp is the file pointer from which data is read. x_fs contains the size of the current file, or 0 if reading from a pipe. x_mnl is the number of line to print before calling wait(). x_rwp is the offset relative to the beginning of file which is given to fseek() in the bang() function. The fseek() will return the file to where it was left before the push took place. x_siold is where the duplicate of the redirected stdin is kept. x_spc points to the string used by several functions to clear the screen. x_srf if a flag which is set to 1 if stdin is redirected, 0 if not. */ main(argc, argv) int argc; char *argv[]; { int ci, c, nc, nl, nlp, ts, i, isdev; char *strcpy(); struct regval {int ax, bx, cx, dx, si, di, ds, es; } reg; /* c is ci with the upper 8 bits masked to zero. ci is the character read from the file. i is a working variable used in for loops, etc. nc is the number of characters on the current line. It is used to detect lines that are too long and to determine where the next tab stop is. nl is used to determine when to exit the for loop and call wait. nlp is used to determine when to clear the screen. The screen is only cleared when it is full. reg is a structure used by the sysint21() function. It is used to set up the registers for a DOS function call. Each element in the register represents one register. ts is a working variable for the tab expander. It is the number of spaces to the next tab stop. */ x_argc = argc; /* \ These 3 lines set up the external */ for (i = 0; i < argc; i++) /* > copies of argc and argv. */ x_argv[i] = argv[i]; /* / */ reg.ax = 0x4400; /* DOS function 0x44, subfunction 0. */ reg.bx = 0x0000; /* File handle for DOS stdin. */ sysint21(®, ®); /* Call IOCTL on the DOS stdin file handle. */ isdev = reg.dx & 0x80; /* Is stdin a device or a file? */ x_siold = -1; /* File handles never < 0, this means x_siold not used. */ if (!isdev) { /* If isdev is false, then stdin is redirected to file. */ x_srf = TRUE; /* Since stdio is redirected, set x_srf = TRUE. */ if (argc == 1) { /* If no arguments on the commant line, then */ x_fp = stdin; /* read from stdin. */ strcpy(x_file,"stdin"); } else { /* If arguments on the command line, then */ cpi(); /* close pipe and reopen stdin to console, */ nextfile(1); /* and get first file on command line. */ } /* else */ } /* if */ else { /* If isdev is true, then stdin is not redirected. */ x_srf = FALSE; /* Stdio isn't redirected, so set x_srf = FALSE. */ nextfile(1); /* Get first file from command line. */ } /* else */ x_mnl = NLPS; /* Start off by outputing one screenful. */ nc = 0; /* Haven't put out any characters yet. */ nlp = 24; /* This will make sure that the screen is cleared. */ while(TRUE) { /* Loop forever, guts of the loop will exit the loop. */ if ((nlp >= NLPS) && (x_mnl != 1)) { /* The (x_mnl != 1) condition keeps the screen from being cleared if only one line is to be displayed. */ cls(); /* This clears the screen. */ nlp = 0; /* Reset number of lines printed. */ } for (nl = 0; nl < x_mnl; ) { /* Put out x_mnl number of lines. */ if ((ci = getc(x_fp)) == EOF) { wait(1); /* Prompt for next file. */ nlp = 0; /* Wait(1) will clear screen, so reset nlp */ nl = 0; /* and nl to 0 to reflect this. */ ci = '\0'; /* Ci will still be printed, so make it a null. */ } c = ci & CMASK; /* Mask off upper 8 bits for safety. */ if (c == '\t') { /* Tab expander */ if ( nc > NCPL - 6) { /* This is part 1 (see notes below). */ c = '\n'; } else { /* This is part 2. */ ts = 8 - (nc % 8); /* Find spaces to next tab. */ if (ts == 8) /* If it comes out to be 8, */ ts = 0; /* then it should be 0. */ for (i = 1; i < ts; i++) { nc++; /* Increment # of chars. */ } /* for */ } /* else */ } /* End of tab expander */ /* If 73 or more chars have been printed out, then part 1 of the tab expander will turn the tab into a newline. In this program, tab stop 81 is the same as column 1 on the next line. Since 81 is the next tab stop after 73, changing the tab into a newline is the correct solution. The rest of the program does not even know that this has happened and simply thinks that a newline was read from the file. If 72 or less chars have been printed, then part 2 finds out how many spaces to the next stop and increments nc the proper number of times minus 1. The tab is not actually expanded, the char count is just incremented. When the tab prints, it is automagically expanded. It is important that this tab expander should come before newline detection and the truncate-too-long-line algorithm. */ if ((nc >= NCPL) && (c != '\n')) { /* If beyond right margin, */ nl++; /* increment # of lines, */ nlp++; /* increment # of lines on current screen, */ nc = 0; /* reset # of chars on current line to 0, */ putchar('\n'); /* start a new line, */ ungetc(c,x_fp); /* put the char back where it came from, */ c = '\0'; /* and make c a NULL character. */ /* c is made a NULL so that a test can be performed before "putchar(c)" and "nc++" are executed. If c is a NULL, these operations are not performed. The "ungetc(c,x_fp)" is executed so that the char is the first one available for the next line. This stuff is needed so that printing out one line to the screen will not result in the char being printed in front of the prompt. This does not happen when printing several lines. A newline is not ungetced because it will cause a blank line to be printed when it is put on the next line. */ } /* if */ if (c != '\0') { /* If c is not a NULL, */ putchar(c); /* print the character, */ nc++; /* and increment # of chars on line. */ } /* if */ if (c == '\n') { /* If c is a newline, */ nl++; /* increment # of lines, */ nlp++; /* increment # lines on current screen, */ nc = 0; /* and reset # of chars on current line to 0. */ } } /* for */ wait(0); /* After max # of lines have been output, prompt user. */ } /* while */ } /* main */ wait(e_o_f) /* Print prompt, then wait for and iterpret command. */ /* If wait is called with an argument of 0, then it has been called in the middle of a file. If it is called with an argument of 1, then it has been called at EOF and it will call nextfile() as necessary. The prompt is also made different at EOF. */ int e_o_f; { int w_c, i, arglen, pgf; char cmd[116], prompt[128], arg[6], *editor, *envfind(), *strcat(); char *strcpy(); FILE *fopen(), *temp; long fseek(), ftell(); strcpy(prompt, x_file); /* Prompt with the filename. */ if (x_fs && !e_o_f) { /* If file size != 0 and not at EOF, */ strcat(prompt, " "); /* Put a space on the end of the prompt. */ ltoa( (long) ( (double) ftell(x_fp) / (double) x_fs * 100.0 ),\ prompt + strlen(prompt) ); /* That last statement requires some clarification. The contruction (double) ftell(x_fp) / (double) x_fs determines the current position if the file as a fraction. The casts are necessary, since integer division would have resulted in zero. The integers are casted into doubles instead of floats since real arithmatic is done in double precision anyway. This saves an extra conversion from float to double. Multiplying this quantity by 100 determines the percentage of the file already seen. Finally, this value is cast back to a long, which is what ltoa expects. The construction prompt + strlen(prompt) is used to pass the address of the first available space in the prompt string after the filename. This address is where ltoa will put the converted number. See the PC-More User's Guide for more information on this function. */ strcat(prompt, "%"); /* Put a % after the number. */ } if (e_o_f) strcat(prompt, " [EOF]"); /* If at EOF, make "EOF" part of prompt. */ printf("--%s--",prompt); /* Print prompt. */ arg[0] = '\0'; /* Initialize the argument string and */ arglen = 0; /* its length. */ pgf = FALSE; /* Set the "prompt gone flag". */ getcmd: /* Get char from keyboard and mask off upper 8 bits, which contain the scan code of the key pressed. Then act on it as a command. */ w_c = (key_getc() & CMASK); /* Get char and mask off scan code. */ /* All the cases in this switch statment (except the for the default) which end in a "goto getcmd;" statement contain the statments: arg[0] = '\0'; arglen = 0; pgf = FALSE; This resets the argument back to 0. Even commands which do not use the argument must reset it to 0 to avoid problems. This also resets the "prompt gone flag" to false. This flag is used to determine if the prompt has been erased for printing the argument. If the prompt has not been erased, pgf = FALSE. When a digit is typed, the prompt is erased, the digit printed, and pgf set to TRUE. When a command is executed, it will always cause the prompt or some message to be printed, so pgf is set to FALSE again. This is not needed when a case ends in "break," since wait() returns when the switch exits. An argument of 0 is interpreted by the function getval() to mean 1, so when no argument is entered, the default is 1. */ switch (w_c) { case ' ': /* Space means "next screen". */ if (e_o_f) /* If at end of current file, */ nextfile(1); /* go to next file. */ x_mnl = NLPS * getval(arg); /* Get # of pages to move. */ x_rwp = ftell(x_fp); /* Save current position in file for !. */ break; /* Break out of switch. */ case '\n': case '\r': /* Enter key means "next line". */ if (e_o_f) /* Everything else is similar to above. */ nextfile(1); x_mnl = getval(arg); x_rwp = ftell(x_fp); break; case 'h': case 'H': /* 'H' means "next half screen". */ if (e_o_f) nextfile(1); x_mnl = NLPHS * getval(arg); x_rwp = ftell(x_fp); break; case 'r': case 'R': /* 'R' Means "rewind current file". */ rewind(x_fp); x_mnl = NLPS; /* Print out full screen next time. */ x_rwp = 0L; /* Current position in file is beginning. */ cls(); /* Clear the screen for the next file. */ break; case 'n': case 'N': /* 'N' means "go to next file". */ nextfile(1); /* Nextfile(1) goes to next file. */ x_mnl = NLPS; /* Put out a full screen next time. */ break; case 'p': case 'P': /* 'P' means "go to previous file". */ x_mnl = NLPS; /* Put out a full screen next time. */ if (nextfile(0)) { /* Nextfile(0) goes to prev. file. */ arg[0] = '\0'; arglen = 0; pgf = FALSE; goto getcmd; /* If you tried to go before 1st file, */ } /* if */ /* a message is printed and you try a diff. */ else break; /* command, otherwise, exit "switch". */ case 'f': case 'F': printf("\r%s\rNew file: ",x_spc); i = key_gets(cmd, 13, "New file: Aborted."); /* Get filename. */ if (i == -1) { arg[0] = '\0'; arglen = 0; pgf = FALSE; goto getcmd; } /* if */ if ( !(strcmp(cmd, "-")) ) { /* If cmd is a hyphen, then */ if (x_srf) { /* if stdin is redirected, */ opi(); /* reattach pipe to stdin, */ temp = stdin; /* and assign stdin to temp; */ } else { /* if stdin isn't redirected, */ printf("\r%s\rCannot read from console.",x_spc); arg[0] = '\0'; /* then abort 'f' command. */ arglen = 0; pgf = FALSE; goto getcmd; } } /* if */ else /* If cmd is not a hyphen, then */ temp = fopen(cmd,"r"); /* attempt to open file. */ if (temp == 0) { /* If couldn't open file, then */ printf("\r%s\rCould not open %s.", x_spc, cmd); /* say so. */ arg[0] = '\0'; arglen = 0; pgf = FALSE; goto getcmd; } /* if */ if ( !(strcmp(x_file, "stdin")) ) /* If current file is stdin, */ cpi(); /* then disconnect pipe from console. */ else /* Otherwise, */ fclose(x_fp); /* close the file. */ x_fp = temp; /* Set x_fp to the new file. */ x_mnl = NLPS; /* Set x_mnl to its default. */ x_rwp = 0L; /* Find current read/write position. */ if ( !(strcmp(cmd, "-")) ) { /* If cmd is a hyphen, then */ strcpy(x_file, "stdin"); /* set x_file to "stdin", */ x_fs = 0; /* and set file size to zero. */ } else { /* Otherwise, */ strcpy(x_file, cmd); /* set x_file to cmd, */ x_fs = fseek(x_fp, 0L, 2); /* get file size, */ fseek(x_fp, 0L, 0); /* and fseek back to beginning. */ } break; /* Note that x_srf is not reset to 0. Even if you quit reading from stdin, it is still redirected because of the < or | on the command line. This means that all of the restrictions still apply; i.e. you still cannot push to an inferior shell after you change files, etc. You will also not be able to edit if you change files after reading from a pipe. This should not be too much of an annoyance, since reading from a pipe and reading from a file are usually not done in the same invokation of More. */ case 'q': case 'Q': /* 'Q' means "quit". */ printf("\r%s\r",x_spc); /* Erase prompt or message on last line. */ exit(0); case 'e': case 'E': /* 'E' means "edit current file". */ if ( !(strcmp(x_file,"stdin")) ) { /* If reading from pipe, */ printf("\r%s\rCannot edit stdin.", x_spc); arg[0] = '\0'; arglen = 0; pgf = FALSE; goto getcmd; /* Go get another command. */ } /* if */ editor = envfind("EDITOR"); /* Get editor name from environ var. */ if (editor == 0) /* If there is no such environ var., */ editor = "edlin"; /* then use EDLIN. */ strcpy(cmd, editor); /* Start command string with editor. */ strcat(cmd, " "); /* Now put a space. */ strcat(cmd, x_file); /* Now end command with filename. */ if (strcmp(editor,"edlin")) /* If editor != "edlin", string was */ free(editor); /* obtained with malloc, free it. */ bang(strlen(cmd),cmd,prompt); /* Execute the command. */ arg[0] = '\0'; arglen = 0; pgf = FALSE; goto getcmd; /* Get next command. */ case '!': /* '!' means "execute DOS command". */ printf("\r%s\r!",x_spc); /* Erase last line, print '!'. */ i = key_gets(cmd, 115, "Push aborted."); /* Get command string. */ if (i == -1) { arg[0] = '\0'; arglen = 0; pgf = FALSE; goto getcmd; } /* if */ /* A command string passed to DOS must not be more than 127 characters long. DOS will ignore the rest. Since the system() command must always pass the string "command /c" to DOS (see DOS 2.0 manual), that leaves 117 characters. I rounded to 115 to give myself a bit of headroom. See definition of key_gets() to see what it expects for arguments. It returns the number of characters read from the keyboard or -1 if it was aborted. */ if ( !(strcmp(x_file,"stdin")) ) { /* If reading from stdin, */ cpi(); /* close the pipe, attach stdin to CON: */ } bang(i,cmd,prompt); /* Bang pushes to an inferior command.com. */ arg[0] = '\0'; arglen = 0; pgf = FALSE; if ( !(strcmp(x_file,"stdin")) ) { /* If reading from stdin, */ opi(); /* reattach stdin to pipe. */ } goto getcmd; case '?': /* '?' means "help". */ printf("\r%s",x_spc); /* Erase prompt or message. */ help(prompt); /* Help prints out the prompt, so it needs it, */ fseek(x_fp, x_rwp, 0); /* and reposition read/write pointer. */ /* The read/write pointer is backed up so that the screen which was erased by help is reprinted. */ arg[0] = '\0'; arglen = 0; pgf = FALSE; goto getcmd; case 'v': case 'V': /* 'V' means "print version number." */ printf("\r%s\rPC-More v1.3",x_spc); arg[0] = '\0'; arglen = 0; pgf = FALSE; goto getcmd; case '\007': /* ^G means abort current argument. */ arg[0] = '\0'; arglen = 0; pgf = FALSE; printf("\r%s\r--%s--", x_spc, prompt); /* Erase argument. */ goto getcmd; default: if (w_c >= '0' && w_c <= '9') { /* If w_c is a digit, */ if (!pgf) { /* If prompt is not gone, */ printf("\r%s\r",x_spc); /* erase it, */ pgf = 1; /* and set flag. */ } arg[arglen++] = w_c; /* add w_c to string, */ arg[arglen] = '\0'; /* terminate string properly, */ putchar(w_c); /* and put w_c on screen. */ if (arglen > 3) { /* If more than 3 digits long, */ printf("\r%s\rArgument too long.",x_spc); /* say so, */ arg[0] = '\0'; /* and start over. */ arglen = 0; pgf = FALSE; } /* if */ goto getcmd; } /* if */ /* Arg[] is limited to 3 digits because the largest integer which can be held in a int is 32767. Arg[] is multiplied by a number which can be as large as 24. 24 * 999 (the largest 3 digit number) = 23976, which is within the range of an int. 24 * 9999 (the largest 4 digit number) = 239976, which is too big to fit in an int. Therefore, it is a safety precaution not to allow any number larger than 3 digits to be entered as an argument. */ if (w_c == '\b' && arglen >= 1) { /* If w_c is a backspace, */ arg[--arglen] = '\0'; /* then delete the last char in */ fputs("\b \b",stdout); /* arg[] if there is one there */ goto getcmd; /* and erase it from the screen. */ } /* if */ putchar('\007'); /* If the above tests fail, then beep. */ goto getcmd; } /* switch */ printf("\r%s\r",x_spc); /* Erase prompt or message. */ } /* wait */ /* Now return to main(). */ help(prompt) /* Prints out help text and the prompt. */ char *prompt; { char *ht; ht = "\nPC-More Help:\n\n <sp> next screen\n <cr> next line\n\ h next half page\n r rewind current file\n\ e edit current file\n n go to next file\n\ p go to previous file \n f choose a new file\n\ ! push to shell\n ? print this text\n\ v print version\n ^G abort a command while entering text\n\ q quit\n\n"; cls(); printf("%s--%s--",ht,prompt); } cpi() /* Close stdin handle and reopen it to the console. */ { struct regval { int ax,bx,cx,dx,si,di,ds,es; } reg; int fr; /* fr contains the contents of the 8088 flag register, which sysint21() returns. */ /* Make duplicate of redirected stdin file handle. */ reg.ax = 0x4500; /* Call DOS function 0x45 (DUP) */ reg.bx = 0x0000; /* on file handle 0. */ fr = sysint21(®, ®); /* Issue the interrupt, get flags. */ if (fr & 0x001) /* If carry is set, error occured. */ abort("DOS Error %d occured on DOS function call 0x45.\n", reg.ax); x_siold = reg.ax; /* Store duplicate. */ /* Close the original stdin. The copy remains open. */ reg.ax = 0x3E00; /* Call DOS function 0x3E (Close file handle) */ reg.bx = 0x0000; /* on file handle 0. */ fr = sysint21(®, ®); /* Issue the interrupt, get flags. */ if (fr & 0x001) /* If carry is set, error occured. */ abort("DOS Error %d occured on DOS function call 0x3E.\n", reg.ax); /* Reopen the console. It is automagically assigned file handle 0. */ reg.ax = 0x3D00; /* Call DOS function 0x3D (Open file) */ reg.dx = "CON"; /* on the console. Must be uppercase, no ":". */ segread(®.si); /* Find the current value of DS. */ /* The above line is somewhat cryptic. segread() expects the address of a struct containing 4 ints. The structure reg can be used if setread() is passed the address of its last 4 elements, which start with reg.si. The purpose of this is to get the current value of DS into the reg structure before calling sysint21(). In the structure that segread() expects, DS is the third item. When ®.si is passed to segread(), DS is also the third item, so the proper assignment is made. */ fr = sysint21(®, ®); /* Issue the interrupt, get flags. */ if (fr & 0x001) /* If carry is set, error occured. */ abort("DOS Error %d occured on DOS function call 0x3D\n", reg.ax); } /* cpi */ opi() /* Reattach stdin file handle to pipe. */ { struct regval { int ax,bx,cx,dx,si,di,ds,es; } reg; int fr; /* Copy the file handle for the pipe back to the stdin file handle. */ reg.ax = 0x4600; /* Call DOS function 0x46 (DUP2) */ reg.bx = x_siold; /* on file handle x_siold. */ reg.cx = 0x0000; /* File handle 0 is the target. */ fr = sysint21(®, ®); /* Issue the interrupt and get flags. */ if (fr & 0x001) /* If carry is set, error occured. */ abort("DOS Error %d occured on DOS function call 0x46.\n", reg.ax); /* Close the duplicate pipe file handle. */ reg.ax = 0x3E00; /* Call DOS function 0x3E, (Close file handle) */ reg.bx = x_siold; /* on x_siold. */ fr = sysint21(®, ®); /* Issue the interrupt and get flags. */ if (fr & 0x001) /* If carry is set, error occured. */ abort("DOS Error %d occured on DOS function call 0x3E.\n", reg.ax); } /* opi */ bang(i,cmd,prompt) /* Bang() will push to an inferior shell if i == 0 or it will execute the command pointed to by cmd if i != 0. The command can be an internal DOS command or it can be a program to run. */ int i; /* Length of command to execute. */ char *cmd; /* Pointer to command to execute. */ char *prompt; /* Pointer to prompt to print when done. */ { int retrn; FILE *fopen(); long fseek(); if (!x_srf) /* If reading from a file, then */ fclose(x_fp); /* close file before push. */ if (!i) /* If no command was entered, */ retrn = system("command"); /* push to DOS. */ else /* If a command was entered, */ retrn = system(cmd); /* give DOS the command in cmd[]. */ if (retrn) printf("Push not successful, DOS error code = %d.", retrn); if (!x_srf) { /* If reading from a file, */ x_fp = fopen(x_file,"r"); /* reopen file, */ if (x_fp == 0) /* check to see if it was reopened, */ abort("Unable to reopen file after push to DOS.\n"); fseek(x_fp, x_rwp, 0); /* and reposition read/write pointer. */ } fputs("\n\nReturning to more...\n\n",stdout); printf("--%s--",prompt); } key_gets(string, len, msg) /* Key_gets() gets a string by reading one character at a time from the keyboard, not from stdin. It reads up to len-1 characters and puts them in string[]. If the user tries to backspace too far, then this is interpreted to mean "I really didn't want to do this after all," and key_gets() aborts, returning -1 to signal error. Key_gets() will read up until it receives a carriage return, a linefeed, or an end of file indication. It returns the number of characters actually read, or -1 if it was aborted. I can't use gets() to collect the string since it reads from stdin. If stdin is redirected, strange things will happen. That's why I wrote key_gets() to read from the keyboard. */ int len; /* How much to get. */ char string[]; /* Where to put it. */ char *msg; /* What to say when aborting. */ { int i, k_c; for (i = 0; i < len; i++) { /* Get len-1 characters for the string. */ k_c = (key_getc() & CMASK); /* Get char, mask scan code. */ if (k_c == '\r' || k_c == '\n' || k_c == EOF) { break; /* If 'Enter' or EOF found, quit getting characters. */ } /* if */ if (k_c == '\b') { /* If 'backspace', */ if (i > 0) { /* don't erase before start of command. */ string[--i] = '\0'; /* remove last char in string[], */ fputs("\b \b",stdout); /* erase it from screen. */ } /* if */ else { /* If user tries to erase too far, then abort. */ printf("\r%s",msg); /* Print aborting message. */ return (-1); /* Return with error. */ } /* else */ i--; /* Dec. i again since 'for' will increment it, */ continue; /* and go to end of for loop. */ } /* if */ if (k_c == '\007') { /* If 'bell', then abort: */ printf("\r%s\r%s", x_spc, msg); /* Erase anything, print msg, */ return (-1); /* and return with error. */ } /* if */ putchar(k_c); /* If not 'enter' or 'bs', then echo it, */ string[i] = k_c; /* and add it to the command string. */ } /* for */ string[i] = '\0'; /* Terminate the command string. */ return (i); } /* key_gets() */ nextfile(next) int next; /* Nextfile steps through the argument list on the command line, trying to open each argument as a file. If it succeeds, then x_fp points to the file and x_file points to a string which is the name of the file. If it fails, abort is called. Since where is a static variable, this function "remembers" where it was the last time it was called and moves on to the next argument on the command line each time it is called. Nextfile also sets x_rwp to point to the top of the file. Nextfile will return a value of 1 only if you try to go to the file which is before the first file on the command line. If no error occurs, then it returns 0. If any other error occurs, then it is fatal and execution is aborted. The only place where the return value is checked is "case 'p':" segment of the wait() subroutine. */ { long fseek(); static int where; FILE *fopen(); next: if (next) { /* If going to next file do this: */ if (++where == x_argc) /* Go to next file. Gone too far? */ exit(0); /* If so, exit. */ } /* if */ else { /* If going to previous file, do this: */ if (--where < 1) { /* Go to prev file. Gone too far? */ printf("\r%s\rAt first file.",x_spc); /* If so, say so, */ where++; /* put where back where it belongs, */ return(1); /* and return with an error code. */ } /* if */ } /* else */ if (x_fp != 0) { /* If x_fp != 0, then a file is open, so close it. */ /* The following if{} is the closing sequence for stdin. */ if ( !(strcmp(x_file, "stdin")) ) { /* If just-finish file is stdin: */ cpi(); /* then call cpi to reattach stdin to console. */ } /* The following else{} is the closing sequence for a file. */ else { /* If just-finished file isn't stdin: */ fclose(x_fp); /* then close it as a normal file. */ } } /* if */ /* The following if{} is the opening sequence for stdin. */ if ( !(strcmp(x_argv[where], "-")) ) { /* If upcoming file is "-" : */ if (x_srf) { /* If stdio is redirected: */ opi(); /* Reattach stdin to pipe. */ x_fp = stdin; /* Set file pointer to stdin. */ x_fs = 0L; /* Don't know the size of a pipe. */ strcpy(x_file,"stdin"); /* Set x_file to "stdin". */ } /* if */ else /* If stdio isn't redirected: */ goto next; /* Just go to next file. */ } /* if */ /* The following else{} is the opening sequence for a file. */ else { /* If upcoming file is not "-" then: */ x_fp = fopen(x_argv[where], "r"); /* Open next or (prev) file. */ if (x_fp == 0) /* If file pointer is bad, abort. */ abort("Could not open file %s.\n",x_argv[where]); x_fs = fseek(x_fp, 0L, 2); /* Get file size. */ fseek(x_fp, 0L, 0); /* Put file pointer back to start of file. */ strcpy(x_file, x_argv[where]); /* Set x_file to new filename. */ x_rwp = 0L; /* Reset !'s copy of rwp. */ } /* else */ cls(); /* Clear screen before going to the next file. */ return(0); /* For consistancy, return with an OK code. */ } /* nextfile */ getval(string) char *string; { int i; /* This function gets the number entered */ i = atoi(string); /* as an argument in wait(). If atoi() */ if (i == 0) /* returns 0, then it is assumed that no */ i = 1; /* argument was entered and that the */ /* default of 1 should be used. */ return(i); } cls() /* Clear the screen and set the curser to home */ /* This function was written by Harry McGavran at Los Alamos National Laboratory, hgm@lanl. */ { unsigned char cur_mode; struct regval {int ax, bx, cx, dx, si, di, ds, es; } reg; /* get current active display mode into al */ reg.ax = 0x0f00; sysint(0x10, ®, ®); cur_mode = reg.ax & 0xff; /* set blank line attribute bh, based on current display mode */ if ((cur_mode > 3) && (cur_mode != 7)) reg.bx = 0; else reg.bx = 0x0700; /* scroll active page up, bh = blank line attribute */ reg.ax = 0x0600; reg.cx = 0; reg.dx = 0x184f; sysint(0x10, ®, ®); /* put the cursor at home */ reg.ax = 0x0200; reg.bx = 0; reg.dx = 0; sysint(0x10, ®, ®); /* reset the display mode, if not done characters don't print */ reg.ax = cur_mode; sysint(0x10, ®, ®); } SHAR_EOF if test 35944 -ne "`wc -c pc-more.c`" then echo shar: error transmitting pc-more.c '(should have been 35944 characters)' fi echo shar: extracting pc-more.doc '(17867 characters)' cat << \SHAR_EOF > pc-more.doc PC-Write by Donald L. Nash December, 1985 Version 1.3 Section 1: Introduction PC-More is a pager program similar to the UNIX* more program. It is designed to work on the IBM Personal Computer, PC XT, and PC AT, as well as compatibles. The purpose of PC-More is to display a file one screenful at a time for easy viewing. The PC-DOS "type" command can do this, but the text scrolls too fast for most people to read. Beginning with version 2.0, PC-DOS supplied its own version of a more filter, but it is extremely limited in its usefulness, since it can only display one screenful at a time. People who are used to the UNIX version of more expect to be able to move through the file in any increment they choose, not just a screenful at a time. PC-More corrects this problem. Section 2: Invoking PC-More PC-More can be used to read from a file or to read from a pipe. To invoke PC-More to read from a file, simple type the following in responce to the PC- DOS prompt: A>more file1.ext [file2.ext ... ] The part in brackets is optional. It simply means that you can type any number of filenames after the word "more." When PC-More reaches the end of one file, it will automatically go on to the next one on the command line. Moving between files is explained below. If you want PC-More to read from a pipe, where it will read the output of some other command as its input, then you would invoke it like this: A>command | more [file1.exe - [file2.exe ... ] ] where "command" is some program or PC-DOS command which writes to the PC-DOS stdout device (usually the console screen). The hyphen is used to indicate "read from stdin." It is listed on the command line just as if it were a filename, and need not be the second item in the list, as indicated above. In fact, the hyphen doesn't need to be there at all if there are no other files on the command line. If there are other files on the command line, and you want PC-More to read from the pipe, then the hyphen is necessary. *UNIX is a trademark of ATT Bell Laboratories. - 1 - The command set for PC-More is the same regardless of whether it is reading from a pipe or from a file, with one exception: You cannot call up an editor to edit the pipe. Section 3: PC-More Commands Part 1: Motion Commands If you have used programs like PC-More before, then you should skip the first four parts of this section, since they are something of a tutorial description of the PC-More commands. Part 5 has a summary of all the commands which will probably be enough for you. Once PC-More has been invoked, it will clear the screen and display the first screenful of data. When the screen fills, the following message appears on the bottom line of the screen: --filename.ext-- where "filename.ext" is the name of the file from which PC-More is reading. If it is reading from a pipe, then "filename.ext" will be "stdin." You may now type any of the PC-More commands. To see the next screenful of data, simply type a space. The screen will clear and the next screenful will appear. PC-More will clear the screen every time it reaches the bottom with the following exceptions: 1. Advancing one line at a time will never clear the screen, even if it is full. This is a feature which allows you to display two lines which may be on different (but consecutive) screens. 2. If the screen is not full when the prompt appears and command is given which will fill the screen and cause scrolling, then PC-More will not clear the screen when it fills. An example of this would be the following situation: The screen is currently full. The user types 'h' to request the next half screen of data. The screen is cleared and the next half screen appears at the top of the screen. The user then types a space to see the next full screen. The text will scroll down until it hits the bottom of the screen. PC-More will not clear the screen to display the rest of the data. Instead, it will scroll up the text already on the screen. - 2 - Now that the issue of screen clearing is out of the way, the other two motion commands can be described. To advance only one line, hit the return key. The next line will appear and the prompt will reappear. To advance half a screen, which would be the next 12 lines, hit the 'h' key in responce to the prompt. The screen will be cleared if necessary and the next 12 lines will appear, followed by the prompt. These three commands can be preceded by a numeric argument up to three digits long. This argument will tell the following motion command to repeat itself the specified number of times. Note that when the "advance one line" command is given an argument, it will clear the screen when necessary. As an example of using arguments, the following command will show the next five screenfuls of data without pausing or clearing the screen when given to the prompt: 5<sp> Here, <sp> means "hit the space bar." Similarly, <cr> would mean "hit the enter key." Only the three motion commands will use the argument. The other commands will simply ignore the argument and clear it when they finish. The final motion command is 'r', for "rewind file." This will reset the read/write pointer to the beginning of the file. This is handy if you accidently pass up what you are looking for. You can rewind the file and start over at the beginning. While this is not as handy as backward paging commands would be, it is all that is available at the moment. Backward paging commands may come out in future versions of PC-More. Important Note: "rewind file" will not work if you are reading from a pipe! There is no way to tell PC-DOS to rewind the pipe. Part 2: File commands If you listed more than one filename on the command line which invoked PC- More, then you can move between them with the 'n' "next file" and 'p' "previous file" commands. When PC-More reaches the end of a file, it pauses and prints out the following prompt: --filename.ext [EOF]-- This means that there is no more data in the current file. Any of the forward motion commands described above will automatically move to the next file on the command line. You can go on to the next file at any time by simply typing 'n' - 3 - in responce to the prompt. The current file is closed and the next file is opened. If you are on the last file (or if you are reading from a pipe), then typing 'n' will cause PC-More to exit, since there is no next file. If you wish to go to the previous file on the command line, then simply type a 'p'. The current file is closed and the previous file is opened. If you are reading from the first file on the command line (or from a pipe), then 'p' will have no effect other than printing a message on the last line which says that you are already on the first file. If you wish to read from some file that is not listed on the command line, type 'f'. The prompt is replaced with the message: New file: You may now type the name of the file you wish to read from. You can also type a hyphen if you wish to read from stdin, but if stdin is not redirected, then this will have no effect. If you make a typo, use the backspace key to fix it. If you try to backspace over the prompt, then the command is aborted. Likewise, if you type a control-G at any time while entering the new filename, the command will be aborted. Control-G can be used at any time to erase either the numeric argument or any text arguments that some of the commands prompt for. You may use "open new file" at any time, even when you are reading from a pipe. The rest of the pipe is ignored. However, you will not be able to edit the new file or push to an inferior command interpreter. These commands and their restrictions are explained below in Part 3 of this section. Part 3: Running Other Programs Under PC-More If you wish to execute a PC-DOS command, run a program, or load in inferior command interpreter, then use the '!' "push to DOS" command. '!' may be followed by an optional command which PC-DOS is to execute. This command may an internal PC-DOS command or a program on disk. If the '!' is not followed by any text, then the DOS command interpreter is loaded. When a DOS command finishes, or when a program exits, or when you type "exit" to the inferior shell, control returns to PC-More and the last screen of data is redisplayed. As a special case of the above command, you can call up an editor on the current file by typing 'e', for "edit current file." The name of the editor to use is obtained by translating the environment variable EDITOR. If EDITOR is not set, then the PC-DOS line editor "edlin" is used. To set the environ- - 4 - ment variable EDITOR, type the following to PC-DOS before invoking PC-More: A>set editor=whatever The word "editor" does not need to be capitalized. However, there must be no spaces to the left of the = sign. Spaces are significant and will be part of the variable name. PC-More will NOT recognize the following: A>set editor = whatever If you type something like this, you will get "edlin" when you type 'e'. If you should type 'e' when the current file is a pipe, then you will be told that you may not edit stdin. Part 4: Other commands If you forget what the PC-More commands are, type '?', which is the help command. It will print a summary of the commands known to PC-More. Typing a 'v' will print the version number of your copy of PC-More. If you are entering a numeric argument for the motion commands or a text argument for the '!' or 'f' commands, then you can cancel the argument by typing control-G. This will also abort the '!' and 'f' commands and return you to the PC-More command level. Of course, there is a quit command for PC-More as well. Type 'q' and you will be returned to the process which called PC-More (usually PC-DOS). Part 5: Command Summary Here is a summary of all PC-More commands. If you have used programs like PC-More before (which most of you probably have), then this is probably all you will need to be able to use PC-More: <sp> next screen <cr> next line h next half screen r rewind the current file e edit the current file n go to the next file p go to the previous file - 5 - f open a new file ! push do DOS ^G clear argument or abort '!' or 'f' ? help v print the version number q quit to DOS Section 4: Source Notes and Portability Concerns PC-More is written in Computer Innovations C86 version 2.20G. The code is pretty straight-forward and heavily commented. It should not be very hard to determine what a piece of code does. I made extensive use of external variables in PC-More. There are 10 external variables in the program. This is necessary because they are used by several functions. Some of the external variables are used by only two functions, but one function does not always call the other one directly. Instead, funtion a() and funtion c() may both use a variable, but a() does not call c(). Rather, a() calls b() which then calls c(). This isn't the best style of programming, but PC-More is small and not very complicated. Besides, all external variables start with the characters "x_", to they are easy to spot. There are only four functions used in PC-More which may not be supplied with other C compilers. These are: key_getc() This function reads a character directly from the keyboard rather than from stdin. It returns an int with the ASCII code of the character typed in the lower byte and the scan code of the key struck in the upper byte. In PC-More, the scan code is masked off to zero. This function will wait for a key to be struck and the return key is not needed to make it return. sysint21() This function allows you to make calls to PC-DOS directly through the INT 21H instruction. The syntax of sysint21() is: int fr, sysint21(); struct regval {int ax,bx,cx,dx,si,di,ds,es; } sreg,rreg; fr = sysint21(&sreg, &rreg); - 6 - The regval structure contains elements for each of the 8088 registers except cs, ss, and bp. You set up the registers in sreg the way you want them before the call. The state of the registers after the call is returned in rreg. Note the '&' "address of" operator before the name of each structure in the sysint21() call. It is necessary to pass the address of the structures, since you cannot actually pass a structure as an argument. Note that the structures can overlap or even be the same structure entirely. The value of the 8088 flag register is returned by sysint21(). sysint() This function is exactly like sysint21(), except that you can specify which interrupt you want to use. The syntax is: int fr, intno, sysint(); struct regval {same struct as above} ssreg, rreg; fr = sysint(intno, &sreg, &rreg); where intno is the interrupt number to use. Note that sysint21() could be written as sysint(0x21, &sreg, &rreg), but using sysint21 is slightly more efficient. ltoa() This function takes a long integer and converts it into an ASCII string of equivalent digits. The syntax is: int ltoa(); long n, lenbuf; char *buffer; lenbuf = ltoa(n, buffer); where n is the number to be converted and buffer is a pointer to a place to put the resulting string. The number n is assumed to be signed. ltoa() returns the length of the string in buffer after the conversion takes place. This number is equivalent to: lenbuf = strlen(buffer); All the other functions I used in PC-More are available in the standard UNIX C libraries under 4.2 BSD. If your compiler does not come with some of these - 7 - functions, look them up in section 3 of the UNIX manual to find out what they do. History: Ver 1.3 New clear screen function installed, written by Harry McGavran. All references to crt_cls() and crt_mode() eliminated. This new clear screen function works on either a monochrome or color monitor. Nextfile() rewritten to understand that "-" on the command line represents stdin. The " case 'f': " part of wait() was modified in the same way. New functions cpi() and opi() added to allow stdin to be reopened to the console when it is redirected to a file or a pipe. This allows the user to execute a "!" or a "e" when a pipe is present. Of course, you still can't edit the pipe. The knowledge to implement cpi() and opi() was provided by Brandon S. Allbery. Nextfile() modified to find the file's size and put it in the external variable x_fs. Wait() also modified so that when it constructs the prompt, it uses x_fs to compute what percent of the file has been read. When the prompt is printed, this percentage is included as part of the prompt. Wait() modified to clear the screen when a file is rewound. Ver 1.21 This version fixed a bug which prevented PC-More from working on a color monitor. Under previous versions, only machines equipped with a monochrome monitor would run PC-More properly. The problem was a hardware-dependendent function call to crt_mode(). The problem was fixed by determining the type of monitor in use and using the correct function to clear the screen. Ver 1.2 This was the initial release to USENET. Other earlier versions were too buggy for a general release. Section 5: Conclusion - 8 - As a final note to add to the end of this manual, I'd like to say that PC-More is a public domain program. You can copy it, modify it chop it up, whatever you want to do, but please don't sell it. I welcome any comments, bug fixes, new features (searches and backward paging would be nice), etc. My e-mail address is: UUCP: ...!{ihnp4 | allegra | seismo!ut-sally}!ut-ngp!dlnash ARPA: dlnash@ngp.UTEXAS.EDU Enjoy! - 9 - SHAR_EOF if test 17867 -ne "`wc -c pc-more.doc`" then echo shar: error transmitting pc-more.doc '(should have been 17867 characters)' fi echo shar: extracting pc-more.uuencode '(22292 characters)' cat << \SHAR_EOF > pc-more.uuencode begin 666 pc-more.exe M35H< 2 P @ "\ ___P P !ND;_( '@ $ $R$ #8A #U*P M M M M M M M M M M M !5B^R#[""+1@2)!@ &,\")1NR+1NP[1@1]'HMV M!HM&[-'@ _"+-(T^C :+1NS1X /XB37_1NSKVK@ 1(E&\#/ B4;RC7;P5HUV M\%;H_Q&#Q 2+1O8E@ ")1NZX__^)!@(&BT;N"\!T NLWN $ B0;^!8%^! $ M=1J+!HX'B087!8T&1@!0C08,!E#H$1&#Q 3K#>@Y"+@! %#H] J#Q +K#S/ MB0;^!; !4.CC"H/$ K@8 (D&_ 4SP(E&Y+ 8B4;HN $ "\!U ^D3 8%^Z!@ M?!"!/OP% 0!T".A!##/ B4;H,\")1N:+1N8[!OP%? /IWP#_-A<%Z/L=@\0" MB4;@@_C_=16X 0!0Z-8 @\0",\")1NB)1N:)1N"+1N E_P")1N*!?N() '5# M@7[D20!^"+@* (E&XNLTN @ 4%"+1N1;F??[6"O"B4;J@7[J" !U!3/ B4;J MN $ B4;LBT;L.T;J?0C_1N3_1NSK\(%^Y$\ ?#*!?N(* '0K_T;F_T;H,\") M1N3_-I 'N H 4.@<'H/$!/\V%P7_=N+HH1B#Q 0SP(E&XH%^X@ =!#_-I ' M_W;BZ/8=@\0$_T;D@7[B"@!U"_]&YO]&Z#/ B4;DZ17_,\!0Z H @\0"Z>/^ MB^5=PU6+[('L!@&-!@P&4(V&=O]0Z*@/@\0$BP8(!HL6"@8+T'1TBT8$"\!T M NMKC09, %"-AG;_4.@3#X/$!(V&=O]0C89V_U#HG0^#Q )> _!6C089!5#H MJ0N+!@@&BQ8*!E)0Z)(2_S87!>A@#H/$ E)0Z(,2Z(P3Z,@2Z$816%I24.AB M#H/$!HT&3@!0C89V_U#HN Z#Q 2+1@0+P'00C090 %"-AG;_4.BA#H/$!(V& M=O]0C097 %#H10Z#Q 0SP(UV]H@$,\")AO[^B88 _^A8-"7_ (F&^OZ+AOK^ M4.ET!8M&! O = JX 0!0Z+\(@\0"NQ@ 4XU&]E#H&0J#Q ):]^J)!OP%_S87 M!>B^#8/$ HD&! :)%@8&Z9@%BT8$"\!T"K@! %#HA B#Q *-1O90Z.()@\0" MB0;\!?\V%P7HB@V#Q *)!@0&B18&!NED!8M&! O = JX 0!0Z% (@\0"NPP M4XU&]E#HJ@F#Q ):]^J)!OP%_S87!>A/#8/$ HD&! :)%@8&Z2D%_S87!>B2 M#8/$ K@8 (D&_ 4SP#/2B08$!HD6!@;HD0GI!@6X 0!0Z/D'@\0"N!@ B0;\ M!>GR!+@8 (D&_ 4SP%#HWP>#Q (+P'04,\"-=O:(!#/ B8;^_HF& /_IY?[I MQP3_-A4%C09> %#H!PV#Q 2-!FX 4+@- %"-A@+_4.C/!H/$!HF&_/Z!OOS^ M__]U%#/ C7;VB 0SP(F&_OZ)A@#_Z9_^C0:" %"-A@+_4.A"#8/$! O = +K M.8L&_@4+P'0,Z%0%BP:.!XE&_NLC_S85!8T&A !0Z)H,@\0$,\"-=O:(!#/ MB8;^_HF& /_I4O[K$XT&H@!0C88"_U#H*1F#Q 2)1OZ+1OZ#^ !U*(V& O]0 M_S85!8T&I !0Z%4,@\0&,\"-=O:(!#/ B8;^_HF& /_I#?Z-!KL 4(T&# 90 MZ+ ,@\0$"\!T NL%Z!$$ZPK_-A<%Z$\8@\0"BT;^B087!;@8 (D&_ 4SP#/2 MB08$!HD6!@:-!L$ 4(V& O]0Z'$,@\0$"\!T NL>C0;# %"-!@P&4.B8#(/$ M!#/ ,]*)!@@&B18*!NL]C88"_U"-!@P&4.AZ#(/$!+@" % SP#/24E#_-A<% MZ$4;@\0(B08(!HD6"@8SP% STE)0_S87!>@L&X/$".D_ _\V%06-!LD 4.A_ M"X/$!#/ 4.BH"8/$ HT&S@!0C08,!E#HY0N#Q 0+P'0"ZR/_-A4%C0;4 %#H M40N#Q 0SP(UV]H@$,\")AO[^B88 _^D)_8T&ZP!0Z% 2@\0"B4;\BT;\@_@ M=0>-!O( B4;\_W;\C88"_U#HS@N#Q 2-!O@ 4(V& O]0Z$X+@\0$C08,!E"- MA@+_4.@^"X/$!(T&^@!0_W;\Z&,+@\0$"\!T"?]V_.B!"8/$ HV&=O]0C88" M_U"-A@+_4.BH"X/$ E#HVP.#Q 8SP(UV]H@$,\")AO[^B88 _^ES_/\V%06- M!@ !4.B8"H/$!(T&!@%0N', 4(V& O]0Z& $@\0&B8;\_H&^_/[__W44,\"- M=O:(!#/ B8;^_HF& /_I,/R-!A0!4(T&# 90Z-,*@\0$"\!T NL#Z#0"C89V M_U"-A@+_4/^V_/[H5P.#Q 8SP(UV]H@$,\")AO[^B88 _XT&&@%0C08,!E#H ME0J#Q 0+P'0"ZP/HKP+IUOO_-A4%C08@ 5#H^PF#Q 2-AG;_4.BW 8/$ C/ M4/\V!@;_-@0&_S87!>AV&8/$"#/ C7;VB 0SP(F&_OZ)A@#_Z9/[_S85!8T& M) %0Z+@)@\0$,\"-=O:(!#/ B8;^_HF& /_I</LSP(UV]H@$,\")AO[^B88 M_XV&=O]0_S85!8T&-0%0Z'\)@\0&Z4C[@;[Z_C ?0/I?P"!OOK^.0!_=XN& M /\+P'0"ZQ;_-A4%C09 5#H4 F#Q 2X 0")A@#_BX;Z_HUV]HN6_O[_AO[^ M _*(!#/ C7;V [;^_H@$_S:0!_^V^O[HZ!>#Q 2!OO[^ P!^(/\V%06-!D4! M4.@&"8/$!#/ C7;VB 0SP(F&_OZ)A@#_Z;[Z@;[Z_@@ =2N!OO[^ 0!\(S/ MC7;V_X[^_HN6_OX#\H@$_S:0!XT&7 %0Z#('@\0$Z8OZ_S:0![@' %#H?!># MQ 3I>OKH3 H6 < 5@!V #\ (0!% &4 40!Q $8 9@!0 ' 3@!N %( <@!( M &@ #0 * " :0=!!QX''@?;!CX&;P5O!5<%5P7/ \\#I .D Y #D -M VT# M,@,R _X"_@+# O\V%06-!F !4.A "(/$!(OE7<-5B^R#[ *-!F4!B4;^Z&4$ M_W8$_W;^C0;J E#H&PB#Q :+Y5W#58OL@^P2N !%B4;N,\")1O"-=NY6C7;N M5NAC"8/$!(E&_HM&_B4! O = [_=NZ-!O,"4.@(!8/$!(M&[HD& @:X #Z) M1NXSP(E&\(UV[E:-=NY6Z"@)@\0$B4;^BT;^)0$ "\!T#O]V[HT&) -0Z,T$ M@\0$N ]B4;NC095 XE&](UV]E;HQ@>#Q *-=NY6C7;N5NCH"(/$!(E&_HM& M_B4! O = [_=NZ-!ED#4.B-!(/$!(OE7<-5B^R#[!*X $:)1NZ+!@(&B4;P M,\")1O*-=NY6C7;N5NBC"(/$!(E&_HM&_B4! O = [_=NZ-!HD#4.A(!(/$ M!+@ /HE&[HL& @:)1O"-=NY6C7;N5NAM"(/$!(E&_HM&_B4! O = [_=NZ- M!KH#4.@2!(/$!(OE7<-5B^R#[ *+!OX%"\!T NL*_S87!>C\$H/$ HM&! O M= +K$(T&ZP-0Z!$/@\0"B4;^ZPS_=@;H P^#Q *)1OZ+1OX+P'0._W;^C0;S M U#HCP:#Q 2+!OX%"\!T NL]C08=!%"-!@P&4.@J$X/$!(D&%P6+!A<%@_@ M=0N-!A\$4.B( X/$ C/ 4/\V!@;_-@0&_S87!>CC%8/$"/\VD >-!DD$4.BI M!(/$!/]V"(T&8@10Z"L&@\0$B^5=PU6+[(/L!#/ B4;\BT;\.T8&? /IJP#H M-2PE_P")1OZ!?OX- '4"ZP>!?OX* '4"ZP>!?O[__W4#Z88 @7[^" !U08%^ M_ ?B SP(MV!/]._(M6_ /RB 3_-I 'C09I!%#H, 2#Q 3K%?]V"(T&;010 MZ+ %@\0$N/__B^5=P_]._.LX@7[^!P!U&?]V"/\V%06-!G$$4.B+!8/$!KC_ M_XOE7</_-I '_W;^Z$(4@\0$BT;^BW8$ W;\B 3_1OSI2O\SP(MV! -V_(@$ MBT;\B^5=PU6+[(M&! O =!G_!HP'BP:,!SL& 9U"3/ 4.AF X/$ NLG_PZ, M!XL&C >#^ %]&O\V%06-!G@$4.@6!8/$!/\&C >X 0"+Y5W#BP87!8/X '0E MC0:+!%"-!@P&4.AQ!8/$! O = +K!>C2_.L*_S87!>@0$8/$ HT&D010C3:, M!HL&C ?1X /P_S3H0P6#Q 0+P'0"ZS>+!OX%"\!T*>A5_8L&C@>)!A<%,\ S MTHD&" :)%@H&C0:3!%"-!@P&4.A+!8/$!.L#Z3C_Z9$ C0:9!%"--HP&BP:, M!]'@ _#_-.@C$8/$!(D&%P6+!A<%@_@ =1F--HP&BP:,!]'@ _#_-(T&FP10 MZ',!@\0$N ( 4#/ ,])24/\V%P7HSQ.#Q B)!@@&B18*!C/ 4#/24E#_-A<% MZ+83@\0(C3:,!HL&C ?1X /P_S2-!@P&4.B^!(/$!#/ ,]*)!@0&B18&!N@L M #/ B^5=PU6+[(/L O]V!.A5 8/$ HE&_H%^_@ =0:X 0")1OZ+1OZ+Y5W# M58OL@^P2N /B4;OC7;O5HUV[U:X$ !0Z*@$@\0&BT;O)?\ B$;NBD;N)?\ M@_@#=A**1NXE_P"#^ =T!S/ B4;QZP:X >)1O&X :)1N\SP(E&\[A/&(E& M]8UV[U:-=N]6N! 4.A9!(/$!K@ HE&[S/ B4;QB4;UC7;O5HUV[U:X$ !0 MZ#D$@\0&BD;N)?\ B4;OC7;O5HUV[U:X$ !0Z!X$@\0&B^5=PU!345)65U6+ M[/]F#H]&#HOE75]>6EE;6,.#[ ;HX?^+1A:)1A"+=AB+1 :)1AB+1 2)1A:+ M1 *)1A2+!(E&$NC*_\-5B^R-!K0$4/\VD@?H(!F#Q 2-=@96_W8$_S:2!^@@ M'8/$ E"-!@@L4.B6$X/$"(T&O@10_S:2!^CT&(/$!+C_?U#HP@"#Q *+Y5W# M58OL@^P&BW8$B@28@_@@=0+K"XMV!(H$F(/X"74%_T8$Z^,SP(E&_HMV!(H$ MF(/X+74(N $ B4;^ZPZ+=@2*!)B#^"MT _].!/]&!#/ ,]*)1OJ)5OR+=@2* M!)B#^#!\.HMV!(H$F(/X.7\ON H ,])24/]V_/]V^NB\&UA:4E"+=@3_1@2* M!)B#Z#"96UD#V!/*B5[ZB4[\Z[N+1OX+P'0/BT;ZBU;\]]KWV(/: .L&BT;Z MBU;\B^5=PU6+[(/L C/ B4;^@7[^( !]'XTVF@>+1O[1X /PBS0+]G0)_W;^ MZ/8;@\0"_T;^Z]K_=@3H;QN#Q *+Y5W#58OL@^P"_W8$Z&H"@\0"B4;^_W;^ M_W8$_W8&Z-T;@\0"4.B1'(/$!CM&_G0'N/__B^5=PS/ B^5=PU6+[(/L!H%& M!/S_BT8$BW8$BQ0[T'09C0; !%"X"0!0Z&H;@\0$N(B 4.@!&X/$ HT&E@>) M1OR)1OZ+=OR+-(EV^@OV=!B+1@0[1OIW NL.BT;\B4;^BT;ZB4;\Z]R+1@0[ M1OIU NNOBW;\BS2+?@2)-8M&!(MV_(D$C0:6!SM&_'0TBT8$BU;\@\($BW;\ M U0".]!U(8MV_(M$ H/ !(MV! -$ HMV_(E$ HMV!(LTBW[\B37K#(M&_(E& M_HM&!(E&_(M&^@O =#*+1OJ+5OR#P@2+=OP#5 ([T'4?BW;\BT0"@\ $BW;Z M T0"BW;\B40"BW;ZBS2+?OR)-8L&^02+5OR#P@2+=OP#5 ([T'4.BT;\B0;Y M!#/ BW;^B02+Y5W#58OLN $ 4#/ ,])24/]V!.B\#X/$"(OE7<-5B^RX]O]0 M_W8(_W8&_W8$Z(06@\0(B^5=PU6+[(UV!E;_=@3_-I 'Z%H:@\0"4(T&""Q0 MZ- 0@\0(B^5=PU6+[#/ 4#/24E#_=@3H9P^#Q B+Y5W#B_2+= *,#(Q4 HQ< M!(Q$!L/\58OLC-^.QXM^!HOW,\ SR4GRKO?1B]&+?@0SR4GRKD^+RO;! 70" MK*K1Z?.EBT8$7</\58OLC-^.QXM^!C/ ,\E)\J[WT8M^!HMV!/;! 70#IG42 MT>GSIW03@^X"@^\"IG4#IG0'?P1(ZP*00%W#_%6+[(S?CL>+?@8SP#/)2?*N M]]&+=@:+?@3VP0%T JRJT>GSI8M&!%W#_%6+[(S?CL>+?@0SP#/)2?*N+0( M*\%=P_P>!E6+[(I>"(#[)70&@/LF= %0G%I2#N@ %@M_!$%+Q)0@.8,4C/; MCL.*7@C1X]'C)O]W B;_-XM>"KD( /\W0T/B^@<?7UY:65M8SXOLG 8>5U92 M45-0BUX.N0@ -H\'0T/B^5A=70<?P_P>!E6+[(M>"+D( /\W0T/B^@<?7UY: M65M8S2&+[)P&'E=64E%34(M>"KD( #:/!T-#XOE870<?PU^,R([ 6":+#8O9 MT>,#^T']\J^#QP0#^R;_-?R,V([ PU!345)65U6+[/]F#H]&#HOE75]>6EE; M6,/\C-".P/.EPU>Y! #^>CO_U^+10J+V"7P?XE% HO#)0" B06!XP\ @<L0 M (E="L-65[D$ /QZ,;_7UZ+1 HE#P +! M$ HE%!L.+100+108+10@+10IU M"(D%B44"ZS:0NQ N.#_A44*=!'1;0K170C170;1700!70+KZK@0 (5%"G41 MT64$T54&T54(T54**5T"Z^K#58OL]T8*\']T!(!V"X!=P^@]_X/L"KD$ (UV M$HO\Z$C_BT;\)0" ,4;\B4;^N#!#4#/ 4%!0Z' BT;VBU[^"]MT O?8B488 MZ!'_P@8 Z/_^@^P*N00 C782B_SH"O^+1OPE ( Q1OR)1OZX,$-0,\!04%#H M,@"+1O:+5OB+7OX+VW0']]KWV(/: (E&%HE6&.C(_L($ .BV_H!V(8#K#.BM M_H!V&8#K ^BD_KCP?X5&&'01A48@=0^Y! "-=A*-?AKHI/[I@P"#[!B-=A*+ M_.B>_HUV&HU^].B5_HOTC7[TBT0"*T4"=!QY!(?^]]@!10*Q!-/HB\B[!@#X MT5D$2TMY^>+SN00 B]F+!3,$> SXBP 1 4-#XOCK)9#XBP 9 4-#XOB+10H+ MP'D4,\"Y! "+V?GW$1$!0T/B^+2 ,057Z'#^7HU^&NA._O=&(/!_=07'1B M .@"_L(( (/L!.CM_8MV%(M&%HM6&.L.@^P&Z-S]BW86BT88,](SVU-3ZS"# M[ 3HR/V+=A2+1A:+5ACK#8/L!NBW_8MV%HM&&)DSVU-3"])Y"O?:]]B#V@" MSX")=A!24+@P0U!3B_SH\_V+](U^$NC0_>B0_</H@/VX\'^%1B!T$85&&'4/ MN00 C782C7X:Z(#]ZW:0@^P8C782B_SH>OV-=AJ-?O3H<?TSVU-34U-34XOT MZ 7X''OA6![V05N0T +HH=BP +P'08+HI= ?<@+HI= @$ 0T,1$',&0T/_ M '3Z@\<#XMJ+1O8M,$ #1NJ)1MZ+1O0S1NB)1MR+_.A;_8OTC7X:Z#C]Z/C\ MP@@ (A8*(!8((A0((!0&'A8&'A0$'A("(A(&(!($'!8$'!0"(A $(! "Z+_\ MN/!_A488=0ZY! "-=A*-?AKHQ/SK%X5&('45N/__B48:B48<B48>@.1_"48@ MZWZ0@^P,C782B_SHI?Q;63/ 4%!04%%3@^P,C78:B_SHD/RY-0!1N00 C7;J MC7[^BP0[!7((=QM.3D]/XO*Y! "-=N2-?OCXBP09!49&1T?B]OFY" "-=O#1 M%$9&XOI9XL2+1N(M\#\I1NZ+1N Q1NR-?NSH?_R-=NR-?AKH6_SH&_S"" #H M"?RX @+K)N@!_+@%!>L>Z/G[N 0!ZQ;H\?NX!@/K#NCI^[@!!.L&Z.'[N ,& MBFX9BG8ABLT*SGD.BLTRSGD&.O5]'>LABL2Y! "^& "+4@@Y$G4*3D[B]20" M=!#K#'<&) %T".L$) 1T K !,N0+P(E&(.BA^\(. .B/^XM^$HM&%(D%BT86 MB44"BT88B44$BT8:B44&Z'[[P@( @^P&Z&G[BT86B480BW88BT0"BQ0SV[D# M -'XT=K1V^+X)?^/=0:+V(O0ZP,% #B)1AB)5A:)7A3'1A( .@[^\/H*_N+ M?AJ!YP\ @486 !"#5A@ @]< ]\<0 '06@^\0T>_17AC17A;W1AH >'4]@T86 M$(%F&O#_"7X:BT8:)?!_+? _/? '?2,]$/A^*8M&&BT .'D#@,P0BU88BUX6 MN0, T>/1TM'0XOCK#HM&&@W_?[K__^L#,\"9BWX2B16)10+HMOK" @!5B^R# M[ B--@<%_S2X+ !0Z!,3@\0$B4;\,\")1O[_=OS_=O[H_Q*#Q 0E_P +P'4# MZ> BT8$B4;XBW;XB@0E_P +P'0EBW;XB@0E_P!0_W;\_W;^Z,X2@\0$)?\ M6CO"=0C_1O[_1OCKSXMV^(H$)?\ "\!T ^E^ /]V_(M&_O]&_E#HGQ*#Q 0E M_P"#^#UU9HM&_HE&^/]V_(M&^/]&^%#H@1*#Q 0E_P +P'0"Z^>+1OB+5OXK MPE#HX0^#Q *)1OH+P'0JBT;ZB4;X_W;\BT;^_T;^4.A,$H/$!"7_ (MV^/]& M^(@$)?\ "\!T NO<BT;ZB^5=P_]V_(M&_O]&_E#H(1*#Q 0E_P +P'0"Z^?I M"O\SP(OE7<-5B^R#[!"X #>)1O"-=O!6C7;P5N@<^8/$!(M&]B7_ (OE7<-5 MB^R![*( N/__B4;^_W8$Z'?X@\0"@_A[?@/IW "X $B)AE[_N/#_B89@_XVV M7O]6C;9>_U;HUOB#Q 0E 0 +P'0-BX9@_X'X0 1S ^FJ /]V!.@T^(/$ H/ M XVV?/^(!.AW_R7_ (VV??^(!(T&Q@10C89\_X/ E#HXO>#Q 3_=@2-AGS_ M@\ $4.C1]X/$!(T&R010C89\_U#H4?>#Q 2-MF;_5N@U]X/$ C/ B89N_XV& M?/^)AG#_BX9J_XF&<O^-!LL$4.CW_8/$ HE&_ O ="4SP%#_MFK_C;9N_U;_ MMFK__W;\Z)81@\0*B4;^_W;\Z%?U@\0"BT;^B^5=PU6+[+@( (MV!HL4"]") M%(M&!(MV!HA$ XM&!(OE7<-5B^R#[%B+!O4$"\!T NL9C0;3!%"X"0!0Z)\0 M@\0$N ^ 4.@V$(/$ HM&!(E&N(MVN/]&N(H$)?\ B4;\BT;\_T[\"\!T*(MV MN(H$)?\ @_@@=0+K#8MVN(H$)?\ @_@)=0<SP(MVN(@$_T:XZ\XSP(MVN(@$ MBT8$B4:XN $ B4;^BW:X_T:XB@0E_P"#P &)1OR+1OS_3OP+P'1$BW:XB@0E M_P +P'0"ZP+K+XM&N(UVNHM6_O]&_M'B _*)!(%^_B ? +K&8MVN(H$)?\ M"\!T"/]&N/]._.OL_T:XZ[(SP(UVNHM6_M'B _*)!($^(P4 @'8'N " B08C M!;B; %"P 5#H> N#Q 2--IH'B02)!HX'N!8 BS:.!XD$N(@ BS:.!XE$!(LV MC@>)1 PSP(LVC@>)1!"+-HX'B40.N !$B4:HN $ B4:JC7:H5HUVJ%;HF?:# MQ 2+1JXE@ +P'0[N!0 4+ !4.@3"X/$!(TVG >)!(D&D >X%0"+-I 'B02X M 0"+-I 'B40.BS:0!XE$!(LVD >)1 SIB "X $6)1JBX 0")1JJ-=JA6C7:H M5N@Z]H/$!(L&(P6#P!-0N $ 4.BY"H/$!(TVG >)!(D&D >X!0"+-I 'B02+ M!B,%BS:0!XE$!(L&(P4STE)0_S:0!^A9](/$ E)0Z*(-6%J+-I 'B40*BP8C M!8LVD >+5 HKPHLVD >)1 R+1JB+-I 'B40.N $ BS:0!XE$$+@4 %"P 5#H M1@J#Q 2--IX'B02)!I('N!4 BS:2!XD$N $ BS:2!XE$!(LVD@>)1 RX @"+ M-I('B400BS:2!XE$#H%^_B ?!VX#@!0C0;B!%"X @!0Z"$/@\0&N(* 4.C) M#8/$ HT&\02-=KJ)!(U&NE#_=O[H^>*#Q 10Z ;R@\0"B^5=PU6+[(/L$C/ MB4;^BW8$BP0E( +P'04_W8$Z$L.@\0"@_C_=0:X__^)1OXSP(TVF@>+?@2+ M51#1X@/RB02X #Z)1NZ+=@2+1 Z)1O#_=@3H)?*#Q *-=NY6C7;N5NC8](/$ M!"4! O =!&+1NXE_P")!I0'N/__B^5=PXM&_HOE7<-5B^R#[ @SP(E&^+C_ M_XE&^C/ B4;\BW8&B@0E_P +P'4#Z9( BW8&_T8&B@0E_P!0ZV:X P")1OKK MVXM&^ O = +K!K@! (E&^(%._ $ Z\6+1O@+P'0"ZP:X @")1OB+1O@+P'0" MZP:X P")1OB!3OP" .N@BT;\)0$ "\!T!X%._ ( ZP^+1OPE @ +P'0%@4[\ M 0#I??_H4_0% "L 80!W '( 8@!+'@T>]QWH'=(=RAWIH0"+1OA0ZTTSP%"+ M1OP#1OI0_W8$Z,D.@\0&B4;^@7[^__]T NL'@7[X 0!U NL(@3Z4!P( = +K M+K@ _U"+1OP#1OI0_W8$Z)8.@\0&B4;^ZQ7K3NCB\P, @ # $ GQZ&'E0> M5!Z!?O@# '4:@7[^__]T$[@" % SP#/24E#_=O[HB R#Q B!?O[__W03C3:: M!XM&_M'@ _"+-(O&B^5=PS/ B^5=PU6+[(M>!/8'"'4E]@<@=2R+1P8[1PA] M-8MW!HI $C+D_T<&/!IT43P-=%CXB^5=PX G]XI' S+DB^5=PU/H2 R#Q (] M__]TXXM>!.O#4[@ /XM/#(U7$HM?#LTA6W)+/0 =!R)1PBX ")1P:)1PJ+ M1P2)1PSKH/8'!'2J_T\&^>LN]@<$=*/V!X!UGH /@%/H;/^#Q (]__]TCX G M?SP*=(C_3P:P#>N!@ ] B$<"^+C__XOE7<-5B^S&1@4 BUX&@"?W]@<@=#N M?@0*=!B+=P:+1@2(0!+_1P:+3P8[3PQ]4(OE7</V!P1TXU.X#0!0Z,/_@\0$ M/?__=.> #R"+7@;KRX /((-_!@!TO( GW_8'$'0"ZV-3N $ 4+@ %!04^AB M (/$"#W__W106X /(.N6@W\. 74+C7<2BA2T LTAZQ53M$"+3P:-5Q*+7P[- M(5MR)3O!=1LSP(E'"(E'!HE'"HM'!(E'#( GWXM&!(OE7</&1P)WZP.(1P* M#T"X__^+Y5W#58OLBW8$]@00=6* )/?V!"!T#%;HZ0J#Q (]__]T2HM&"HM6 M!HM."#P!= H\ '09/ )T%>LWB]J+1 CWV -$!ID#V!/*B].P ;1"BUP.S2&+ MV#/)B4P(B4P&BTP$22/9B5P*02O+B4P,B^5=P\9$ GCK XA$ H ,0+C__XO0 MB^5=P^L.NOL$M G-(;C__U#HJPG;X_RX<@..V(P&!P4FH0( .P8G!7;<*P8G M!8S?@<< $#OX<P*+Q[[O SOP<\4KQCL&)05RO3L&(05V Z$A!0/PC-^+QBO' M/0 0=@>X ! K\(O^B_"Q!-/@G%GZCM>+X#/M58OL49T& _Y7M##-(0K =0,R MY%NC]01T%5M8CL KV(D>]P0&M$K-(7,$B1[W!(S;'Q8'OH B@R P0.!X?X M*^&+_/.DCMN+Q%".P[_\!;G:!RO/,\#SJNB3^%#HZPA5B^R![)X BW8(B@0E M_P +P'4#Z?4$BW8(B@0E_P"#^"5T1(M&"(E&XO]&XHMVXHH$)?\ "\!T#XMV MXHH$)?\ @_@E= +KXHM&XBM&"#/24/]V"/]V!HMV!/_6@\0&BT;BB48(Z:$$ MN $ B4;H_T8(BW8(B@0E_P"#^"VX 0!T O_(B4;J"\!T _]&"(MV"(H$)?\ MB4;L@7[L, !U!?]&".L&N" B4;LBW8(B@0E_P"#^"IU$HMV"H%&"@( BP2) M1N[_1@CK-C/ B4;NBW8(B@0E_P!0Z#03@\0""\!T'KL* (M&[O?CBW8(_T8( MBA2!XO\ @^HP \*)1N[KSXMV"(H$)?\ @_@NN $ = +_R(E&\ O =%K_1@B+ M=@B*!"7_ (/X*G42BW8*@48* @"+!(E&\O]&".LV,\")1O*+=@B*!"7_ %#H MPQ*#Q (+P'0>NPH BT;R]^.+=@C_1@B*%('B_P"#ZC #PHE&\NO/ZP4SP(E& M\HMV"(H$)?\ 4.C0$H/$ H/X;+@! '0"_\B)1O0+P'0#_T8(BW8(B@0E_P!0 MZ6("BT;P"\!T NL&N 8 B4;RBT8*B4;^BW8(B@0E_P!0_W;RC89B_XE&XE"+ M=OZ!1OX( %;H.NKH% R#Q Z)1O:+1OZ)1@KI7@*X @")1N;K'K@( (E&YNL6 MN H B4;FZPZX$ ")1N;K!KCV_XE&YHM&] O = +K18MV"(H$)?\ @_A!N $ M<P+_R O = .X 0 +P'0BBW8(B@0E_P"#^%JX 0!V O_("\!T [@! O = 6X M 0#K [@ (E&](M&] O ="&+1@J)1OB+=OB!1O@$ (L$BU0"B4;ZB5;\BT;X MB48*ZRR!?N8 'T3BW8*@48* @"+!)F)1OJ)5OSK$HMV"H%&"@( BP0STHE& M^HE6_/]VYHV&8O]0_W;\_W;ZZ,L"@\0(BT;P"\!U ^FW (V&8O^)1N*+1OJ+ M5OR#^@!_"G4%@_@ <P/_1N+_=N+H!>V#Q *)1O:+1O(+P'1,BT;R@\ !.T;V M=D&+1O:#P %0BT;BBU;R \*#P &+5O8KPE#_=N+H?A&#Q :X, !0BT;R@\ ! M*T;V4/]VXNB*$8/$!HM&\H/ 8E&]HM&\H/ 5"+1N*+5O8#PHM6\BO"@\ ! M4(M&XHM6]@/"BU;R*\)0Z#(1@\0&N"X BW;BBU;V*U;R _*(!(V&8O^)1N)0 MZ&7L@\0"B4;VZ:T BT8*B4;DBW;D@4;D @"+-(EVXE;H1>R#Q *)1O:+1N2) M1@J+1O +P'0.BT;R.T;V<P:+1O*)1O8SP(E&Z.MNBT8*@48* @")1N*X 0") M1O8SP(E&Z.M6BT8(B4;BN $ B4;V,\")1NCK0^BM[ \ 8P!S &0 1 !X %@ M=0!5 &\ 3P!B $( 9P!F &4 PR6K)6PEVR/;(],CTR/+(\LCPR/#([LCNR-T M(W0C=".+1NH+P'0"ZU^+1NX[1O9V5XM&Z O =#"+=N**!"7_ (/X+74C@7[L M, !U'+@! %"+1N+_1N)0_W8&BW8$_]:#Q ;_3O;_3NZ+1N[_3NX[1O9V%;@! M %"-=NQ6_W8&BW8$_]:#Q ;KX(M&[CM&]G8(BT;V*4;NZP4SP(E&[O]V]O]V MXO]V!HMV!/_6@\0&BT;J"\!T)HM&[@O =!^+1N[_3NX+P'05N $ 4(UV[%;_ M=@:+=@3_UH/$!NOA_T8(Z?SZB^5=PU6+[(/L!HM&!C/24E"+1@0STE)0Z)P# M6%J)1OR)5OZ+1OR+5OZ#^@!R#G4%@_CH=@<SP(E&^NL?_W;\Z((!@\0"B4;Z M"\!T#S/ 4/]V_/]V^NAH#X/$!HM&^HOE7<-5B^R-=@A6_W8&_W8$Z $$@\0" M4(T&""Q0Z'?Z@\0(B^5=PU6+[(/L*C/ B4;ZC5;6@\(AB5;XB_*(!(%^"@ M? /IAP"+1@2+5@:#^@!_#W4%@_@ <PBX 0")1OKK$XM&!(M6!O?:]]B#V@") M1@2)5@:--BL%N $ ,])24(M&"IE24/]V!O]V!.@R EA:]]KWV(/: %)0Z+L" M6%H#\(H$)?\ _T[XBW;XB 2+1@KWV)E24/]V!O]V!.CX 5A:B48$B58&"]!T M NNHZUR+1@2+5@:)1OR)5OZ--BL%N $ ,])24(M&"C/24E#_=O[_=OSHT %8 M6E)0Z%L"6%H#\(H$)?\ _T[XBW;XB 2+1@J94E#_=O[_=OSHGP%86HE&_(E6 M_@O0= +KL(M&^@O = NX+0#_3OB+=OB(!(U&UH/ (2M&^#/2B4;ZBT;Z@\ ! M4/]V"/]V^.CC#8/$!HM&^HOE7<-5B^R#[ B!?@0 _W8&,\"+Y5W#BT8$@\ ! M)?[_B4;^C0:6!XE&^(MV^(LTB7;Z"_9T;XMV^HM$ CM&_G);BT;^@\ $BW;Z MBU0".]!R-HMV^(LTBT;^ _"#Q@2)=OR+=OJ+-(M^_(DUBW;ZBT0"*T;^@^@$ MBW;\B40"BT;\BW;ZB03K"8MV^HM$ HE&_HMV^HLTBW[XB37K"8M&^HE&^.F% M_XM&^@O = +K%(M&_H/ !%#H2 "#Q *)1OH+P'0WBT;ZBW;ZB02+1OZ+=OJ) M1 *!1OH$ (M&_CM&!'89,\!0BT;^*T8$4(M&^HM6! /"4.@*#8/$!HM&^HOE M7<-5B^R#[ *!?@0 _G8&,\"+Y5W#BT8$@\ !)?[_B48$BP8I!0-&!%"-1@0K M!OD$,]):.\)S!C/ B^5=PXL&^02)1OZ+1@2+%OD$ ]")%OD$BT;^B^5=PU R MP.L-4+ !ZPA0L +K U"P U-14E95B^Q7F).+1@Z+5A"+=A*+?A3VPP%U&PO2 M>0GWVO?8@]H _L<+_WD*]]_WWH/? (#W U.Y( SVU.'3OK1X-'2T=/1T3OY M=PMR!#OS=P4KWAO/0(=.^N+A7EGVP0)T"Y.+UO;% G0#@/4!]L$!=0SVQ0%T M!_?:]]B#V@")1A*)5A1?75Y:65M8P@0 58OL4%*+1@KW9@2)1@J+1@;W9@@! M1@J+1@3W9@B)1@@!5@I:6%W"! !5B^R+1@2+'@L%"MMT*'@$"\!T(E"+5@*- M'@L%Z"D C18)!;0)S2$+[70*.6X =@6+;@#KX%B+'O4$"MMT!+1,S2&--@4% M_RR^! "*PK$$T^HD#P20)Q1 )TZ( '7MPU6+[(IF!(M6!LTA7<-5B^P&Q'8$ M)HL$!UW#58OLC3::!XM&!-'@ _#_-.C/\8/$ HOE7<-5B^R+=@2+1!"+Y5W# M58OL_W8*_W8(_W8&C3::!XM&!-'@ _#_-.@']8/$"(OE7<-5B^R+=@2T0(M< M#HM,!HU4$LTA<AH[P74;N0 B4P(B4P& 40**40,@"3?B^5=PXA$ NL$QD0" M=X ,0+C__XOE7<-5B^R,%CP%B28^!<56!,1>"(I&#+1+G%_ZT>W1[='MT>V# M[1&,U@/UCM:\ %7G<TA<@(SP+IR X[:G%KZCA8\!8LF/@52G5W#58OLBW8$ M@_X@<T31YHN<F@<>!PO;=#CV!P)U,_8'('4#Z<X BTX(XQ^+=@;\]@<$="\R MY*Q15E-0Z&GS@\0$/?__= =>6>+LBT8(B^5=P[@% %"X$ 50Z(L*N(Z 4.A1 M_HM'#"M'!CO!?\<KR)&-?Q(#?P;SI%!3M$"+3PR-5Q*+7P[-(5MR73O!=5-9 MXS*+5P0[RGP>B\%*(\(KR%!3M$"+7PZ+U@/QS2%;<C@[P74N6>,-B4\&@ \@ MC7\2\Z3K"( GW\='!@ N B4<(B4<*BT<$B4<,BT8(B^5=P\9' G?K!HA' M KC__X /0(OE7<. #R"#?P8 =0/I)O^ )]_V!Q!T NOC4[@! %"X !04%/H M7_.#Q @]__]TS5N #R#I__Y5B^R#["HSP(E&[(E&_O]V!.B'Y(/$ H/X!'5* MBW8$@\8#B@0E_P"#^#IU.C/ B4;6@7[6 P!]'XMV! -VUHH$)?\ 4.C8"(/$ M HUVX@-VUH@$_T;6Z]HSP(UVY8@$C4;BB4;@ZP:+1@2)1N"+!B,%"\!T NL" MZQ&+!B,%BQ8C!8/J 2/""\!T*;@! (E&Z(E&ZHM&ZCL&(P5S$(M&ZHE&Z(M& MZM'@B4;JZ^>+1NB)!B,%BT8(@< /8M6!H'B P #PHE&[C/ B4;RBT;@B4;T MC7;V5N@9XX/$ HUV[E:-=NY6Z#OD@\0$)0$ "\!T ^D\ ;@! (E&_HM&[HE& MYHE&\+@ 1(E&[HUV[E:-=NY6Z [D@\0$)0$ "\!T ^D/ 8M&]"6 O =&B+ M1@8E! +P'0XN %$B4;NBT;FB4;PBT;T)?\ #2 B4;TC7;N5HUV[E;HRN.# MQ 0E 0 +P'0#Z<L N $ B4;>ZR2+1@;WT"4! O =!*+1O0E 0 +P'0(N(@ MB4;>ZP:X 0")1M[K!XL&(P6)1MXSP(E&W(%^W" ?1J--IH'BT;<T> #\(LT M"_9T NL"ZP7_1MSKWX%^W" =0+K<;@! %"+1MZ#P!-0Z-SW@\0$B4;LBT;L M"\!T NL"ZU*+1@:#P 'WT"4' (MV[(D$BT;>BW;LB40$BW;LB40,BT;FBW;L MB40.BT;<BW;LB400BT;LC3::!XM6W-'B _*)!(M&W(OE7<.+1NXE_P")!I0' MBT8("\!T"_]VX.@]!X/$ NLRBT;^"\!T*[@ /HE&[HM&YHE&\(UV[E:-=NY6 MZ+CB@\0$)0$ "\!T"HM&[B7_ (D&E >+1NP+P'0)_W;LZ-;?@\0"N/__B^5= MPU6+[(/L"#/ 4(UV!%;H[0&#Q 2)1OB*1A E_P"#^&6X 0!T O_("\!U;XI& M$"7_ (/X9[@! '0"_\@+P'1(BT;X@_@%N $ ?0+_R O = .X 0 +P'4=BT;X M@_C[N $ ?@+_R O = .X 0 +P'4%N ZP.X 0 +P'0#N $ "\!T!;@! .L# MN "\!T [@! O =06X #K [@! O = .X 0 +P'4=BT;X@_@4N $ ?0+_ MR O = .X 0 +P'4%N ZP.X 0")1OJ+1OH+P'0(BT8.@\ "ZPF+1O@#1@Z# MP )0C78$5N@3 8/$!(M6^ /0B5;X@7[X% !\!K@! (E&^HM&#%#_=@Z+1OH+ MP'0%N $ ZP:+1OB#P %0_W8,C48$4.C]W.B; X/$#EX#\(EV_HM&^@O =0/I M? "X10"+=O[_1OZ(!(%^^ ?16X+0"+=O[_1OZ(!(M&^/?8B4;XZPNX*P"+ M=O[_1OZ(!+@* %#_=OZ+1OB94E#H(?:#Q B)1OR#^ -]+8M&_(/ 5"+1OZ# MP ,K1OQ0_W;^Z!<%@\0&N# 4+ #*T;\4/]V_N@G!8/$!NLXBD80)?\ @_AG M=2W_3OZ+=OZ*!"7_ (/X,'4),\"+=OZ(!.OGBW;^B@0E_P"#^"YU!S/ BW;^ MB 3_=@SH$N"#Q *+Y5W#58OL@^P:,\")1N:+=@16Z!3<C4;P4.@_Y8T&U 50 MZ 7<Z,KD6 O =!R-1O!0Z/;;Z&?AC4;P4.@>Y8/$"+@! (E&Z.L%,\")1NB- M1O!0Z-7;C0;4!5#HS=OH@N18"\!T NL'@7X& !]!C/ B^5=PXM&!@O =%R! M?@80 'X&N! B48&C0;L!5#HFMN-1OA0Z,7D@\0(_TX&BT8&"\!T&XT&] 50 MZ'[;C4;X4.AWV^BUXE#HHN2#Q CKVXU&^%#H9-N-1O!0Z%W;Z'?A4.B(Y(/$ M"(U&\%#H3-N-!N0%4.A$V^@AY%@+P'1KN D B4;JBT;J_T[J"\!T6+@! (M6 MYHO(T^*)5N:+-H@%BT;JT>#1X-'@ _!6Z S;C4;P4.@%V^C2XU@+P'0GBS;2 M!8M&ZM'@T>#1X /P5NCJVHU&\%#HX]KH(>)0Z [D@\0(_T;FZY[IM0"-1O!0 MZ,K:C0;<!5#HPMKHA^-8"\!U ^F; +@) (E&ZHM&ZO].Z@O =%BX 0"+5N:+ MR-/BB5;FBS;2!8M&ZM'@T>#1X /P5NB'VHU&\%#H@-KH5>-8"\!T)XLVB 6+ M1NK1X-'@T> #\%;H9=J-1O!0Z%[:Z)SA4.B)XX/$"/].YNN>C4;P4.A(VHT& MW 50Z$#:Z 7C6 O =!R-!N0%4.@PVHU&\%#H*=KH9^%0Z%3C@\0(_T[F,\"9 M4E#H"N&-1OA0Z#_C@\0(C4;XB4;NC4;PB4;LBW;L@\8&BP0E\'^!Z$ #BW;N M@\8&B02-1OA0Z.#9C4;P4.C9V>CSWU#H!..#Q B-1O!0Z,C9C0;D!5#HP-GH MG>)8"\!T NL7C4;P4.BOV8T&W 50Z*?9Z&SB6 O =!4SP%"-=O!6Z&_]@\0$ MBU;F ]")5N:+1N@+P'0,C4;P4.A\V>CMWNL'C4;P4.APV8MV!%;HF^*#Q B+ M1N:+Y5W#58OL@^P$BT8,B4;\C48$4.A,V8T&U 50Z$39Z GB6 O =!^-1@10 MZ#79Z*;>C48$4.A=XH/$"+@M (MV_/]&_(@$@7X. 0!]2+@P (MV_/]&_(@$ MN"X BW;\_T;\B 2+1@X!1A"!?A 'T+BT80*48.,\")1A"+1@[_1@Z#^ !] M#;@P (MV_/]&_(@$Z^CK8XU&!%#HQ]CHAMY86HE&_HM&_H/ ,(MV_/]&_(@$ MC0;D!5#HJ=B-1@10Z*+8BT;^F5)0Z(_?Z*K>Z-3?C48$4.B^X8/$"/].#HM& M#@O = +KKXM&$ O = NX+@"+=OS_1OR(!(M&$/].$ O =$>-1@10Z%K8Z!G> M6%J)1OZ+1OZ#P#"+=OS_1OR(!(T&Y 50Z#S8C48$4.@UV(M&_IE24.@BW^@] MWNAGWXU&!%#H4>&#Q CKKS/ BW;\B 2+1OPK1@PSTHOE7<-5B^R*1@0E_P"# M^#"X 0!S O_("\!T [@! O =""*1@0E_P"#^#FX 0!V O_("\!T [@! O M= 6X 0#K [@ (OE7<-5B^R*1@28@_A!?!>*1@28@_A:?PZX( !06HI&!)@# MPHA&!(I&!)B+Y5W#58OLBD8$F(/X87P7BD8$F(/X>G\.N.#_4%J*1@28 \*( M1@2*1@28B^5=PU6+[(S8CL"+=@2+?@:+3@@[]W(#_.L' _%. _E/_?.D7?S# M58OLC-B.P(M^!(M.!HI&"/SSJEW#58OL@^P0BT8$B4;VN !!B4;PC7;X5NA5 MVH/$ HUV\%:-=O!6Z'?;@\0$)0$ "\!T![C__XOE7<,SP(OE7<-5B^RT0+L" M (M.!HM6!,TA<@@[P74$B^5=P[C__^OW53+DS19=PP M (" @(" @(" @(" @(" @(" @(" @(" @(" @(" @ M(" @(" @(" @(" @(" @(" @(" @(" <W1D:6X ( E "!;14]&70 M+25S M+2T #25S#4YE=R!F:6QE.B @ $YE=R!F:6QE.B @06)O<G1E9"X +0 -)7,- M0V%N;F]T(')E860@9G)O;2!C;VYS;VQE+@!R TE<PU#;W5L9"!N;W0@;W!E M;B E<RX <W1D:6X +0!S=&1I;@ -)7,- '-T9&EN TE<PU#86YN;W0@961I M="!S=&1I;BX 141)5$]2 &5D;&EN " 961L:6X #25S#2$ 4'5S:"!A8F]R M=&5D+@!S=&1I;@!S=&1I;@ -)7, #25S#5!#+4UO<F4@=C$N,P -)7,-+2TE M<RTM TE<PT #25S#4%R9W5M96YT('1O;R!L;VYG+@ (( @ #25S#0 *4$,M M36]R92!(96QP.@H*(" @(#QS<#X@(" @;F5X="!S8W)E96X*(" @(#QC<CX@ M(" @;F5X="!L:6YE"B @("!H(" @(" @(&YE>'0@:&%L9B!P86=E"B @("!R M(" @(" @(')E=VEN9"!C=7)R96YT(&9I;&4*(" @(&4@(" @(" @961I="!C M=7)R96YT(&9I;&4*(" @(&X@(" @(" @9V\@=&\@;F5X="!F:6QE"B @("!P M(" @(" @(&=O('1O('!R979I;W5S(&9I;&4@"B @("!F(" @(" @(&-H;V]S M92!A(&YE=R!F:6QE"B @(" A(" @(" @('!U<V@@=&\@<VAE;&P*(" @(#\@ M(" @(" @<')I;G0@=&AI<R!T97AT"B @("!V(" @(" @('!R:6YT('9E<G-I M;VX*(" @(%Y'(" @(" @86)O<G0@82!C;VUM86YD('=H:6QE(&5N=&5R:6YG M('1E>'0*(" @('$@(" @(" @<75I= H* "5S+2TE<RTM $1/4R!%<G)O<B E M9"!O8V-U<F5D(&]N($1/4R!F=6YC=&EO;B!C86QL(#!X-#4N"@!$3U,@17)R M;W(@)60@;V-C=7)E9"!O;B!$3U,@9G5N8W1I;VX@8V%L;" P>#-%+@H 0T]. M $1/4R!%<G)O<B E9"!O8V-U<F5D(&]N($1/4R!F=6YC=&EO;B!C86QL(#!X M,T0* $1/4R!%<G)O<B E9"!O8V-U<F5D(&]N($1/4R!F=6YC=&EO;B!C86QL M(#!X-#8N"@!$3U,@17)R;W(@)60@;V-C=7)E9"!O;B!$3U,@9G5N8W1I;VX@ M8V%L;" P>#-%+@H 8V]M;6%N9 !0=7-H(&YO="!S=6-C97-S9G5L+"!$3U,@ M97)R;W(@8V]D92 ]("5D+@!R %5N86)L92!T;R!R96]P96X@9FEL92!A9G1E M<B!P=7-H('1O($1/4RX* H*4F5T=7)N:6YG('1O(&UO<F4N+BX*"@ M+25S M+2T "" ( TE<P -)7,-)7, #25S#4%T(&9I<G-T(&9I;&4N '-T9&EN "T M<W1D:6X <@!#;W5L9"!N;W0@;W!E;B!F:6QE("5S+@H "D%"3U)4.BT@ H M1E)%120 0R #0!#3TU34$5# $Y%1413($1/4R R+C D I43T\@34%.62!! M4D=3 &, 0 W <*#4Y/($-/4D4D H- "174DE411 M !90 0 0 @$ (P,3(S-#4V-S@Y04)#1$5& D M0 %E "(PT A->700" X#=YPT%#%VX%M;6XDT;V^3_I M T\X33,=,/E(=X):/[]S?]U/%75 !9J9F9F9F;D_>Q2N1^%ZA#\M0QSKXC8: M/SJ,,.*.>44^O(G8E[+2G#PRIZC5(_9).3RG]$3]#Z4RFI>,SPBZ6R5 ;ZQD M* ;("HH% #P/P "1 %$"8F9F9F9FY !/P;( end SHAR_EOF if test 22292 -ne "`wc -c pc-more.uuencode`" then echo shar: error transmitting pc-more.uuencode '(should have been 22292 characters)' fi # End of shell archive exit 0