/* Copyright 1994-2002: Fred Hutchinson Cancer Research Center, Seattle, WA USA
 LAMA.c Compare pairs of matrix blocks.
   Author: Shmuel Pietrokovski, pietro@bioinfo.weizmann.ac.il
   Reference: NAR (1996) 24:3836-3845.

-----------------------------------------------------------------------------
4/28/00 Update for longer ACs. Fix DBtype(); removed Prodom check since
	format has changed.
2/15/02 Fix bug with freeing matrix[1] too soon.
-----------------------------------------------------------------------------*/

#define EXTERN

#define SEARCH_TYPE_UNSET  -1

#define HELPLINES "\
Usage: \n\
LAMA inp_file1[,inp_file2] out_file [min_algn_wdth] [dbg_lvl] [scrn] [cutoff] [expected target]\n\
\n\
The program must have the names of one or two files with entry(ies) to compare\n\
and an output file name. These can be specified on the command line or\n\
interactively. On the command line the first argument is the entry(ies) file\n\
name(s), if two files are specified they should be separated by a comma\n\
with no spaces. Each file can be of either block, matrix, ProDom \n\
multiple alignment entry(ies). The second argument is the output file name,\n\
it will be overwritten if it already exists. Optional arguments are 3rd -\n\
minimal alignment width (0 for default), 4th - the debug level, 5th -\n\
screen output (0 to forbid, anything else to allow), 6th - score\n\
cutoff (in Z units [std's from mean], >=0, 0 for default), and 7th - for\n\
how many searched blocks to calculate the number a score is expected to appear\n\
(0 for default).\n"

#include <blocksprogs.h>
#include "LAMA.h"

/* variables set by the configuration file in blimps program */

int StrandsToSearch;
int NumberToReport;
int SearchType;
int GeneticCodeInitializer;
int SiteSpecificScoringMatrixType;
int BlockToMatrixConversionMethod; /* default method is two */
int SequenceMatrixScoringMethod;   /* default method is zero */

/*
 * Local variables and data structures
 */

int    getargs(), data_read() ;

void   set_defaults(), load_stats3(), SW_matrices() ;
void   fprint_matrix(), load_ZvsPrcntl1() ;

double cols_score(), ZtoPrcntl(), extrpltd_mean(), extrpltd_var() ;

char   DBtype() ;

Block  *read_a_prodom_entry() ;

int         alloctd_algnmnts, alloctd_zVsPrcntl ;
int         alignments_done = 0 ;
int         dbg_lvl = 0, min_algnmnt_width = NARROWEST_WIDTH ;
double      Z_cutoff ;
ZvsPRCNTL   *zVsPrcntl ;
Stat        stats[WIDTHS] ;
Boolean     screen_out = TRUE, WWW_FLAG = TRUE ;

/*=======================================================================*/
/*
 * main
 *   controls flow of program
 *   Parameters: argc, argv
 *   Error codes:
 */

int main(argc, argv)
     int argc;
     char *argv[];
{
  int           i1, inpfiles ;
  int           read_entries = 0, entries_compared = 0, hits = 0, persearches = PERSEARCHES ;
  FILE          *bfp[2], *out ;
  Block         *block[2] ;
  Matrix        *matrix[2] ;
  BlocksAlgnmnt *scorePrpo ;
  char          bdbname[2][MAXNAME], outname[MAXNAME] ;
  char          version[40], line[MAXLINELEN], db_type[2], significance[9];
  char		*blimps_dir;	/* BLIMPS_DIR environment variable */
  char		ctemp[MAXNAME];
  double        percentile, expected, Z_score, shfl_mean, shfl_var ;


             /* allocate memory for the structures which are only pointed-to */
  scorePrpo = (BlocksAlgnmnt *) malloc(sizeof(BlocksAlgnmnt)) ;

  scorePrpo->alignment = (algnmnt *) calloc(ALGNMNTS_ALLOC, sizeof(algnmnt)) ;
  alloctd_algnmnts = ALGNMNTS_ALLOC ;

  strcpy(version,"28 Apr 00") ;

         /* load the mean and variance values for scores of different widths */
  load_stats3() ;

       /* load the Z score vs shuffled and unbiassed score percentile values */
  load_ZvsPrcntl1() ;

  Z_cutoff = Z_CUTOFF ;     /* set the Z value for score cutoff. */

                /* If no parameters passed on command line show how to do it */
  if (argc == 1) printf("\n%s", HELPLINES) ;

                                      /* getting input and output file names */
  if ((getargs(argc,argv,bdbname,bfp,&inpfiles,outname,&out,&Z_cutoff, &persearches)) != OK) 
     exit(ERROR) ; 

                                                    /*set the default values */
  set_defaults();

                                    /* set the score reporting cutoff values */
                   /* (avoid negative values which won't show up in S matrix)*/
  for (i1=0; i1<WIDTHS; i1++)
      stats[i1].cutoff = 
                   max (0, stats[i1].mean + (Z_cutoff * stats[i1].variance)) ;

  printf("LAMA version %s.\n", version) ;
  if (WWW_FLAG) 
     fprintf(out,"LAMA version %s.\n", version) ;
                                                        /* find out DBs type */
  if ((db_type[0] = DBtype(&bfp[0])) == ERROR ||  
      (db_type[1] = DBtype(&bfp[1])) == ERROR) 
  {
     printf("Cannot determine type of input file\n");
     exit(ERROR);
  }

  if (db_type[0] != db_type[1])
     printf("\nNote - the two input files have different types of data.\n") ;


                             /* print parameters used and scores header line */

  percentile = ZtoPrcntl(Z_cutoff) ;

  sprintf(line,
"\nMinimal length of reported alignments %3d\n\
Score cutoff is %.1f Z score units (in the top %.1e percentile of chance scores)\n", 
         min_algnmnt_width, Z_cutoff, 1. - percentile) ;

  printf("%s\n",line) ;
  if (WWW_FLAG) fprintf(out,"%s\n",line) ;

  sprintf(line,"\n\
                                            alignment     Z-score  expected number for\n\
block 1     from:to       block 2     from:to   length                 searching %d blocks\n",
          persearches) ;

  if (screen_out && dbg_lvl == 0) printf("%s", line) ;
  if (WWW_FLAG   && dbg_lvl == 0) fprintf(out,"%s",line) ;

  blimps_dir = getenv("BLIMPS_DIR");
                   /* load the frequencies for converting blocks to matrices */
  if ( ! load_frequencies(AA_FREQUENCY_FNAME) )
  {
     if (blimps_dir != NULL)
     {
        sprintf(ctemp, "%s/docs/%s", blimps_dir, AA_FREQUENCY_FNAME);
	fprintf(stderr, "Trying %s...\n", ctemp);
        load_frequencies(ctemp) ;
     }
  }

                                      /* looping through all the entry pairs */
  while (data_read(&bfp[0],&block[0],&matrix[0],db_type[0]) == OK) 
     {

     read_entries++ ;

     /* skip reading entries to compare with first matrix if its width 
       is less than narrowest allowed allowed alignment (min_algnmnt_width). */

     if (matrix[0]->width < min_algnmnt_width)
        {
        if (screen_out)
           {
           printf("\nComparisons skipped !\n") ;
           printf(
           "Block matrix %s shorter (%d) than narrowest width allowed (%d)\n",
                  matrix[0]->number, matrix[0]->width,  
       	          min_algnmnt_width) ;
	   }
                                /* free memory allocated to structure */
        if (db_type[0] != MATRIX_DB) free_block(block[0]) ;
        free_matrix(matrix[0]) ;

        continue ;
        }

          /* if only one input files is used begin using second block/matrix 
                      from the block/matrix following the first block/matrix */
     if (inpfiles == 1) 
        for(i1 = 0; i1 < read_entries; i1++)
           {
           data_read(&bfp[1],&block[1],&matrix[1],db_type[1]) ;
                                      /* free memory allocated to structures */
           if (db_type[1] != MATRIX_DB) free_block(block[1]) ;
           free_matrix(matrix[1]) ;
           }

     while (data_read(&bfp[1],&block[1],&matrix[1],db_type[1]) == OK) 
        {
      
                 /* skip comparison if the width of second matrix is less than 
                    narrowest allowed allowed alignment (min_algnmnt_width). */
        if (matrix[1]->width < min_algnmnt_width)
           {
           if (screen_out)
              {
              printf("\nComparison skipped !\n") ;
              printf(
           "Block matrix %s shorter (%d) than narrowest width allowed (%d)\n",
                     matrix[1]->number, matrix[1]->width, 
       	             min_algnmnt_width) ;
	      }
                                /* free memory allocated to structure */
           if (db_type[1] != MATRIX_DB) free_block(block[1]) ;
           free_matrix(matrix[1]) ;

           continue ;
	   }

        if (dbg_lvl >= 7) /*-------------------------------------------------*/
           {
	   if (db_type[0] != MATRIX_DB) print_block(block[0]) ;
	   if (db_type[1] != MATRIX_DB) print_block(block[1]) ;
           printf("\n") ;
	   } /*--------------------------------------------------------------*/

        if (dbg_lvl >= 6) /*------------------------------------------------*/
           {
           printf("\n%s", matrix[0]->number) ;
           fprint_matrix(matrix[0],stdout) ;
           if (WWW_FLAG) 
              {
              fprintf(out,"\n%s", matrix[0]->number) ;
              fprint_matrix(matrix[0],out) ;
	      }

           printf("\n\n%s", matrix[1]->number) ;
           fprint_matrix(matrix[1],stdout) ;
           printf("\n") ;
           if (WWW_FLAG) 
              {
              fprintf(out,"\n\n%s", matrix[1]->number) ;
              fprint_matrix(matrix[1],out) ;
              fprintf(out,"\n") ;
	      }
           } /*--------------------------------------------------------------*/


                                                         /* compare matrices */
        SW_matrices (matrix[0], matrix[1], min_algnmnt_width, scorePrpo, &out) ;

        entries_compared++ ;

                                      /* free memory allocated to structures */
        if (db_type[1] != MATRIX_DB) free_block(block[1]) ;

        hits += scorePrpo->reported_alignments ;
                                                /* print reported alignments */
        for (i1=0; i1<scorePrpo->reported_alignments; i1++)
           {
/* If width of comparison is more than the longest width for which statistics 
   were scored - use mean and variance from extrapolation formulas.          */

           if (min(matrix[0]->width, matrix[1]->width) > WIDTHS-1)
	      {
              shfl_mean = 
                     extrpltd_mean(min(matrix[0]->width, matrix[1]->width)) ;
              shfl_var = 
                     extrpltd_var(min(matrix[0]->width, matrix[1]->width)) ;
	      }
           else
	      {
              shfl_mean = 
                        stats[min(matrix[0]->width, matrix[1]->width)].mean ;
              shfl_var = 
                    stats[min(matrix[0]->width, matrix[1]->width)].variance ;
	      }

                                           /* calculate the score's Z value. */
           Z_score = 
(scorePrpo->alignment[i1].score * scorePrpo->alignment[i1].complength / 100. -
                                                       shfl_mean) / shfl_var ;

           percentile = ZtoPrcntl(Z_score) ;
           if (percentile > 0)
              {
              expected = (1 - percentile) * (float) persearches ;
              sprintf(significance, "%.1e", expected) ;
	      }
           else
              {
              expected = -1 ;
              sprintf(significance,"-") ;
	      }


           sprintf (line,
"%-10s  %3d : %3d and %-10s  %3d : %3d (%2d) score %3.0f (%4.1f  %s)",
 scorePrpo->matrix0_number, 
 scorePrpo->alignment[i1].positionE0 - scorePrpo->alignment[i1].complength + 1,
 scorePrpo->alignment[i1].positionE0,
 scorePrpo->matrix1_number, 
 scorePrpo->alignment[i1].positionE1 - scorePrpo->alignment[i1].complength + 1,
 scorePrpo->alignment[i1].positionE1,
 scorePrpo->alignment[i1].complength, 
 scorePrpo->alignment[i1].score, Z_score, significance) ;

           if (screen_out) printf("%s\n",line) ;
           fprintf(out,"%s\n",line) ;
           }
        }

                                      /* free memory allocated to structures */
     if (db_type[0] != MATRIX_DB) free_block(block[0]) ;
     free_matrix(matrix[0]) ;
     free_matrix(matrix[1]) ;

     rewind(bfp[1]) ;
     }

  if (hits == 0) 
     {
     sprintf(line,"No hits found above score cutoff %.1f.", Z_cutoff) ;
     printf("%s\n",line) ;
     if (WWW_FLAG) fprintf(out,"%s\n",line) ;
     }


  fclose(bfp[0]); fclose(bfp[1]); fclose(out);               /* close files */

  printf ("Output written in file %s.\n", outname) ;
  exit(0);

}  /* end of main */


/*****************************************************************************
 * get input and output file names and other program parameters interactively
 * or from command line. 
 * WARNING: argv[] only expands ~s in first filename, so
	~btest/...,~btest/... works for the first first filename but
	not for the second filename
 *****************************************************************************/

int getargs(argc,argv,bdbname,bfp,inpfiles,outname,out,Z_cutoff, persearches)

int    argc;
char   *argv[];
char   bdbname[][MAXNAME], outname[] ;
FILE   *bfp[], **out;
int    *inpfiles, *persearches ;
double *Z_cutoff ;

{
   int i1, i2;

/* ------------1st arg = block file(s) --------------------------------------*/
   if (argc > 1)
      if (strstr(argv[1],",") == NULL)             /* if only one input file */
         {
         strcpy(bdbname[0], argv[1]);
         *inpfiles = 1 ;
         }
      else                             /* if two input files ("file1,file2") */
         {
         for(i1 = 0; argv[1][i1] != ',' && argv[1][i1] != '\0' && i1 < MAXNAME;
             bdbname[0][i1] = argv[1][i1++]) ;
         if (argv[1][i1] != ',') 
            {
            printf(
              "Error in reading first file name from first argument !\n") ;
            return(ERROR) ;
            }
         bdbname[0][i1] = '\0' ;

         for(i1 = i1++, i2 = 0; argv[1][i1] != '\0' && i2 < MAXNAME; 
             bdbname[1][i2++] = argv[1][i1++]) ;
         if (argv[1][i1] != '\0') 
            {
            printf(
              "Error in reading second file name from first argument !\n") ;
            return(ERROR) ;
            }
         bdbname[1][i2] = '\0' ;

         *inpfiles = 2 ;
         }
   else                                   /* get input file(s) interactively */
      {
      printf("\nEnter name of a file with blocks or block matrices: ");
      gets(bdbname[0]);

      printf("\nThe blocks/matrices in this file will be intercompared.\n");
      printf("If you wish to compare them against blocks/matrices in\n");
      printf("another file enter that file name (else just hit <ENTER>).\n");
      gets(bdbname[1]);

      if (bdbname[1][0] == '\0') *inpfiles = 1 ;
      else                       *inpfiles = 2 ;
      }

   if (*inpfiles == 1) strcpy(bdbname[1],bdbname[0]) ;

   for (i1 = 0; i1 < 2; i1++)                  /* opening input files */
      if ( (bfp[i1]=fopen(bdbname[i1], "r")) == NULL)
         {
         printf("\nCannot open file \"%s\"\n", bdbname[i1]);
         return(ERROR);
         }

/* ------------2nd arg = output file name -----------------------------------*/
   if (argc > 2)
      strcpy(outname, argv[2]);
   else
      {
      printf("\nEnter name of output file: ");
      gets(outname);
      }

   if ( (*out=fopen(outname, "w")) == NULL)
      {
      printf("\nCannot open file \"%s\"\n", outname);
      return(ERROR);
      }

/* ------------optional 3rd arg = minimal alignment width ------------------*/

   if (argc > 3) min_algnmnt_width = atoi(argv[3]) ;

   if (min_algnmnt_width == 0)
      min_algnmnt_width = NARROWEST_WIDTH ;
   else if (min_algnmnt_width < 0)
      {
      printf("\nMinimal alignment width can not be negative !\n") ;
      printf("The value given (%d) is out of range.\n", min_algnmnt_width) ;
      return(ERROR) ;
      }
   else if (min_algnmnt_width < NARROWEST_WIDTH)
      {
      printf("\nMinimal alignment width can not be less \n") ;
      printf("than narrowest allowed blocks (%d).\n", NARROWEST_WIDTH) ;
      return(ERROR) ;
      }

/* ------------optional 4th arg = debug level ------------------------------*/

   if (argc > 4) dbg_lvl = atoi(argv[4]) ;


/* ------------optional 5th arg = screen output ----------------------------*/

   if (argc > 5) screen_out = atoi(argv[5]) ;


/* -- optional 6th arg = Z score reporting level, 0 or less sets default ---*/
/*  If the Z cutoff wasn't given on the command line
    it would be been given a default value specified in the header file. */

   if (argc > 6) 
      if ((*Z_cutoff = atof(argv[6])) <= 0) *Z_cutoff = Z_CUTOFF ;


          /* If negative Z cutoff was passed print out why that was wrong. */

   if (argc > 6 && atof(argv[6]) < 0.)
      {
      printf("\nCutoff score should be specified as a Z score (mean+Z*std).\n") ;
      printf(
"The Z score must be positive (corresponding to the 50 percentile or higher).\n") ;
      printf(
        "A negative cutoff score (%f) was specified, default value (%.2f) used.\n",
         atof(argv[6]), (float) Z_CUTOFF) ;
      }

/* -- optional 7th arg = persearches number, the number of blocks for calculating the
   expected times a score would occur searching that number of blocks. */
/*  If it wasn't given on the command line or 0 or a non integer specified
    it would be been given a default value specified in the header file. */

   if (argc > 7) 
      if ((*persearches = atoi(argv[7])) <= 0) *persearches = PERSEARCHES ;


   return(OK) ;

}



/****************************************************************************
 * set the default values for some of the variables.
 ****************************************************************************/

void set_defaults()
{

  GeneticCodeInitializer = 0;           /* the standard genetic code */

  StrandsToSearch = 2;          /* == 2 if want to search both strands */
  NumberToReport  = 0;          /* <0 means all, 0 means judge, */
                                /* >0 means use that number */
  SearchType      = SEARCH_TYPE_UNSET;

  BlockToMatrixConversionMethod = 2; /* default method is two */
  SequenceMatrixScoringMethod   = 0; /* default method is zero */

  ErrorLevelReport = 5;		/* don't want to see BLIMPS errors */

}


/*****************************************************************************
 * SW_matrices
 * A modified (no gaps, alignments retained if they are above a cutoff value -
 * more than one alignment can be found for a pair of matrices) Smith Waterman 
 * optimal local alignment for matrices.
 *
 * Algorithm :
 * S matrix constructed. Highest score (=optimal alignment) found. For the
 * current score (starting with the highest) - while the score is above the 
 * minimal score cutoff (cutoff value for shortest allowed alignment) the 
 * following is done -
 *  The alignment and its width are found by doing a trace back along the
 *   diagonal in the S matrix from the score position,
 *  The S matrix is modified to remove the scores of the current alignment,
 *  The alignment is retained if its score is above the cutoff for its width
 *   (hence an alignment may be initially retained because of the score 
 *   (which might be significant for a short alignment) but later discarded 
 *   because it is not significant for its actual width), 
 *  The next best score is found in the modified S matrix.
 *
 * Dynamic programing algorithm based on Pearson & Miller,
 *  Meth. Enz. 210:575 92'.
 *****************************************************************************/

void SW_matrices(matrix0, matrix1, min_algnmnt_width, scorePrpo, out)

Matrix        *matrix0, *matrix1 ;
BlocksAlgnmnt *scorePrpo ;
int           min_algnmnt_width ;
FILE          **out;

{
  double  **s_matrix, *tmp_ptr1, Z_score, best_score, cutoff ;
  algnmnt *tmp_ptr2 ;
  int     i0, i1, i2, j, use_width ;

/* for cases where shortest block is longer the WIDTHS stat data will be 
   received by extrapolation formulas */

   use_width = min(matrix0->width, matrix1->width) ;

/* get cutoff score - from shuffled data for blocks <= 55 from extrapolation
   formulas for longer blocks */
  if (min(matrix0->width, matrix1->width) > WIDTHS-1)
     cutoff = max (0, 
                    extrpltd_mean(min(matrix0->width, matrix1->width)) + 
                     (Z_cutoff * 
                      extrpltd_var(min(matrix0->width, matrix1->width)) 
                     )) ;
  else
     cutoff = stats[use_width].cutoff ;


                                         /* allocate memory for score matrix */
                                              /* get memory for all elements */
  tmp_ptr1 = (double *) 
           calloc ((matrix0->width+1) * (matrix1->width+1), sizeof(double)) ;

	                                /* initialize the elements 2-d array */
  s_matrix = (double **) calloc (matrix0->width+1, sizeof(double *)) ;
  for (i0=0; i0 <= matrix0->width; i0++)
     s_matrix[i0] = &(tmp_ptr1[i0 * (matrix1->width+1)]) ;

                                 /* use j to simplify the way the code looks */
  j = scorePrpo->reported_alignments = 0 ;

  best_score = 0. ;

  strcpy(scorePrpo->matrix0_number, matrix0->number) ;
  strcpy(scorePrpo->matrix1_number, matrix1->number) ;

   /* initialize outer edges of S matrix to 0 and calculate rest of matrix and
      find best score.                                                       */
  for (i1=0; i1 <= matrix1->width; i1++)
     s_matrix[0][i1] = 0. ;

  for (i0=1; i0 <= matrix0->width; i0++)
     {
     s_matrix[i0][0] = 0. ;
     for (i1=1; i1 <= matrix1->width; i1++)
        {
        s_matrix[i0][i1] = max(0, s_matrix[i0-1][i1-1] + 
                     cols_score(matrix0->weights,i0-1,matrix1->weights,i1-1)) ;
        if (s_matrix[i0][i1] > best_score)
	   {
           best_score = s_matrix[i0][i1] ;
           scorePrpo->alignment[0].positionE0 = i0 ;
           scorePrpo->alignment[0].positionE1 = i1 ;
	   }
        }
     }

  if (dbg_lvl >= 5) /*-------------------------------------------------------*/
     {
     printf("Column scores for %s and %s -\n", 
            matrix0->number, matrix1->number) ;

     for (i0=1; i0 <= matrix0->width; i0++)
        {
        for (i1=1; i1 <= matrix1->width; i1++)
           printf("%6.3f ",
                  cols_score(matrix0->weights,i0-1,matrix1->weights,i1-1)) ;

        printf("\n") ;
        }

     printf("\n") ;
     }
  /*-------------------------------------------------------------------------*/


/* while best score is more than lowest possible score cutoff for this matrix 
   pair find the next best (sub optimal) scores found in decreasing values. */

  while (best_score > 0. && best_score > cutoff)
    {

/* Do a trace back along the S matrix to find the alignment's width.        */
/* trace-back procedure - go back along the diagonal from the best score's 
   position and stop when a value of 0 or an edge of the matrix is reached. */

    for (scorePrpo->alignment[j].complength = 1 ;
         (s_matrix[scorePrpo->alignment[j].positionE0 - 
                   scorePrpo->alignment[j].complength]
                  [scorePrpo->alignment[j].positionE1 - 
                   scorePrpo->alignment[j].complength] > 0.) &&
         (scorePrpo->alignment[j].positionE0 - 
          scorePrpo->alignment[j].complength > 0) &&
         (scorePrpo->alignment[j].positionE1 - 
          scorePrpo->alignment[j].complength > 0) ;
         scorePrpo->alignment[j].complength++) ;


    if (dbg_lvl >= 4) /*----------------------------------------------------*/
       {
       printf("S matrix for %s and %s -\n", 
              matrix0->number, matrix1->number) ;
       for (i0=1; i0 <= matrix0->width; i0++)
          {
          for (i1=1; i1 <= matrix1->width; i1++)
             printf("%6.3f ",s_matrix[i0][i1]) ;
          printf("\n") ;
          }

       printf("\n") ;
       }
    /*-----------------------------------------------------------------------*/

  if (dbg_lvl >= 3) /*-------------------------------------------------------*/
     {
     printf("\nColumn scores for optimal alignment of %s and %s -\n", 
            matrix0->number, matrix1->number) ;
     if (WWW_FLAG)  
        fprintf(*out,"\nColumn scores for optimal alignment of %s and %s -\n", 
                matrix0->number, matrix1->number) ;

     for (i2=0, 
          i0=scorePrpo->alignment[j].positionE0 - 
             scorePrpo->alignment[j].complength + 1, 
          i1=scorePrpo->alignment[j].positionE1 - 
             scorePrpo->alignment[j].complength + 1;
          i2 < scorePrpo->alignment[j].complength; i2++)
       {
       printf("%3d,%2d ",i0+i2, i1+i2) ;
       if (WWW_FLAG) fprintf(*out,"%3d,%2d ",i0+i2, i1+i2) ;
       }

     printf("\n") ;
     if (WWW_FLAG)  fprintf(*out,"\n") ;

     for (i2=0, 
          i0=scorePrpo->alignment[j].positionE0 - 
             scorePrpo->alignment[j].complength + 1, 
          i1=scorePrpo->alignment[j].positionE1 - 
             scorePrpo->alignment[j].complength + 1;
          i2 < scorePrpo->alignment[j].complength; i2++)
        {
        printf("%6.3f ",
              cols_score(matrix0->weights,i0-1+i2,matrix1->weights,i1-1+i2)) ;
        if (WWW_FLAG) fprintf(*out,"%6.3f ",
              cols_score(matrix0->weights,i0-1+i2,matrix1->weights,i1-1+i2)) ;
        }

     printf("\n") ;
     if (WWW_FLAG)  fprintf(*out,"\n") ;

     }

  /*-------------------------------------------------------------------------*/

    if (dbg_lvl >= 2) /*-----------------------------------------------------*/
       {
                                                        /* calculate Z value */
       if (min(matrix0->width, matrix1->width) > WIDTHS-1)
          Z_score = (best_score - 
                    extrpltd_mean(min(matrix0->width, matrix1->width))) /
                     extrpltd_var(min(matrix0->width, matrix1->width)) ;
       else
          Z_score = (best_score - stats[use_width].mean) / 
                    stats[use_width].variance ;

       printf("%-10s %3d %3d %-10s %3d %3d %2d Prpo %6.2f (%4.1f)\n",
           matrix0->number, 
   scorePrpo->alignment[j].positionE0 - scorePrpo->alignment[j].complength + 1,
           scorePrpo->alignment[j].positionE0, 
           matrix1->number, 
   scorePrpo->alignment[j].positionE1 - scorePrpo->alignment[j].complength + 1,
           scorePrpo->alignment[j].positionE1,
           scorePrpo->alignment[j].complength, 
           best_score * 100. / scorePrpo->alignment[j].complength,
           Z_score) ;
       }
    /*-----------------------------------------------------------------------*/

                                                     /* find next best score */

       /* change values of S matrix elements of current best alignment to 0s */
    for (i0 = scorePrpo->alignment[j].positionE0,
         i1 = scorePrpo->alignment[j].positionE1; 
         i0 >= scorePrpo->alignment[j].positionE0 -
               scorePrpo->alignment[j].complength + 1 ;
         i0--, i1--)
         s_matrix[i0][i1] = 0. ; 

/* recalculate  values of S matrix elements on the diagonal beyond the end of 
   the current best alignment alignment                                      */

    for (i0 = scorePrpo->alignment[j].positionE0 + 1, 
         i1 = scorePrpo->alignment[j].positionE1 + 1; 
         i0 <= matrix0->width && i1<= matrix1->width ;
         i0++, i1++)
        s_matrix[i0][i1] = max(0, s_matrix[i0-1][i1-1] + 
                     cols_score(matrix0->weights,i0-1,matrix1->weights,i1-1)) ;


  /* if the width of the alignment is more than the narrowest allowed 
     alignment save and normalize score and advance reported scores index.   */

    if (scorePrpo->alignment[j].complength >= min_algnmnt_width)
       {
         
/* Normalize the score by dividing it with the alignment width and multiplying 
   by 100. Since the score of each column pair ranges -1 to +1 this makes the 
   range of the normalized score -100 to +100.                               */

       scorePrpo->alignment[j].score = best_score * 100. / 
                                       scorePrpo->alignment[j].complength ;

       j = ++scorePrpo->reported_alignments ;        /* advance scores index */

      /* check if more memory needed for alignments array in score structure */
       if (scorePrpo->reported_alignments == alloctd_algnmnts)
         {
         alloctd_algnmnts += ALGNMNTS_ALLOC ;
         tmp_ptr2 = (algnmnt *) 
              realloc(scorePrpo->alignment, alloctd_algnmnts*sizeof(algnmnt)) ;
         scorePrpo->alignment = tmp_ptr2 ; 
         }

       }

                                /* find best score in the modified S matrix */
    best_score = 0. ;
    for (i0=1; i0 <= matrix0->width; i0++)
       for (i1=1; i1 <= matrix1->width; i1++)
          if (s_matrix[i0][i1] > best_score)
    	     {
             best_score = s_matrix[i0][i1] ;
             scorePrpo->alignment[j].positionE0 = i0 ;
             scorePrpo->alignment[j].positionE1 = i1 ;
             }
    }

  free(tmp_ptr1) ; free(s_matrix) ;                           /* free memory */
  return ;
}

/*****************************************************************************
 * cols_score
 * compare a pair of matrix columns (positions)
 ****************************************************************************/

double cols_score(mat1,col1,mat2,col2)

MatType *mat1[], *mat2[] ;
int     col1, col2 ;

{
   double score ;
   double p1=0.0, p2=0.0, p3a=0.0, p3b=0.0, p4a=0.0, p4b=0.0 ;
   int    aa ;

                 /* Calculate Pearson's r score between the 2 matrix columns */

   for (aa=0; aa<MATRIX_CMPRD_WIDTH; aa++)
      {
      p1  += mat1[aa][col1] * mat2[aa][col2] ;
      p3a += mat1[aa][col1] * mat1[aa][col1] ;
      p3b += mat1[aa][col1] ; 
      p4a += mat2[aa][col2] * mat2[aa][col2] ;
      p4b += mat2[aa][col2] ;
      }

   p2  = (double) p3b * p4b / MATRIX_CMPRD_WIDTH ;
   p3b = (double) p3b * p3b / MATRIX_CMPRD_WIDTH ;
   p4b = (double) p4b * p4b / MATRIX_CMPRD_WIDTH ;

   if ((p3a != p3b) && (p4a != p4b))
      score = (p1 - p2) / sqrt((p3a-p3b)*(p4a-p4b)) ;
   else    /* avoid dividing by 0 */
      score = 0 ;

   return(score) ;
}

/*****************************************************************************
 * ZtoPrcntl
 * Find the shuffled unbiassed blocks score percentile corresponding to a
 * Z score. Use observed data (in array zVsPrcntl) if possible, or else a
 * formula fitted to data (using program xvgr).
 ****************************************************************************/

double ZtoPrcntl(Zscore)

double Zscore ;

{
   int i1 ;

        /* if Zscore greater then highest noted Z score return percentile 1 */

   if (Zscore > zVsPrcntl[alloctd_zVsPrcntl-1].Z) return(1.0) ;

/* if Zscore larger then lowest noted Z score go down the array (whose values 
   are sorted) until reaching a Zscore smaller then the searched one. This is 
   conservative since we find a smaller value not the closest one. */

   if (Zscore >= zVsPrcntl[0].Z)
      {
      for (i1=alloctd_zVsPrcntl-1; i1 >= 0 && Zscore <= zVsPrcntl[i1].Z; i1--) ;
      return(zVsPrcntl[i1].prcntl) ;
      }

/* for very low scores return value for unknown percentile */

   if (Zscore < 0) return(-1.0) ;

/* else fit with a formula */

   if (Zscore < 2) return(1.0 - 0.473 * exp(-1.150*Zscore)) ;

   if (Zscore < 5) return(1.0 - 0.901 * exp(-1.582*Zscore)) ;

/* if this part reached something is probably wrong, return -1 */

   return(-1.0) ;
 }

/***************************************************************************
 * A procedure to give the extrapolated mean-of-suffled-PSSMs for a given
 * block width. The extrapolation was done by fitting the actual values 
 * found for widths 4-55 (see procedure load_stats) to a formula :
 * mean = A1 + A2 * sqrt(width), the values found are 
 * mean = -0.134758 + 0.702457*sqrt(width).
 * The use of this procedure is for approximating the mean for widths
 * longer than 55. */

double extrpltd_mean(blk_width)

int blk_width ;

{
   if (blk_width<min_algnmnt_width)
      {
      printf("Error ! Extrapolated mean of shuffled PSSMs requested for \n\
a block too narrow (%d).\n", blk_width) ;
      exit(ERROR) ;
      }
   else
      {
      return(-0.134578 + 0.702457 * sqrt((double) blk_width)) ;
      }
}

/***************************************************************************
 * A procedure to give the extrapolated variance-of-suffled-PSSMs for a given
 * block width. The extrapolation was done by fitting the actual values 
 * found for widths 4-55 (see procedure load_stats) to a formula :
 * mean = A1 + A2 * sqrt(width), the values found are 
 * mean = 0.226805 + 0.101760*sqrt(width).
 * The use of this procedure is for approximating the mean for widths
 * longer than 55. */

double extrpltd_var(blk_width)

int blk_width ;

{
   if (blk_width<min_algnmnt_width)
      {
      printf("Error ! Extrapolated variance of shuffled PSSMs requested for \n\
a block too narrow (%d).\n", blk_width) ;
      exit(ERROR) ;
      }
   else
      {
      return(0.226805 + 0.101760 * sqrt((double) blk_width)) ;
      }
}

/****************************************************************************
	Just checks for blocks or matrix input, prodom format has changed
	since 1996...
 ****************************************************************************/

char DBtype(dbfile)
FILE  **dbfile ;
{

   char    line[80];
   char    rc = '\0' ;

   rc = ERROR;
   while ((rc == ERROR) && fgets(line, sizeof(line), *dbfile) != NULL)
      {
            /* check if first entry has BL and MA lines */
            if ((strncmp(line,"BL   ", 5)) == 0) { rc = BLOCK_DB ; }
            else
            if ((strncmp(line,"MA   ", 5)) == 0) { rc = MATRIX_DB ; }
      }  /* end while */

   rewind(*dbfile);
   return(rc) ;

}  /* end of DBtype */

/****************************************************************************
 * Read entry from appropriate dbfile (block, ProDom or matrix) according to 
 * db_type. If entry is not a matrix read it into a block structure and 
 * transform it into a matrix. If can not read entry return error. 
 ****************************************************************************/

int data_read(dbfile,block,matrix,db_type)

FILE   **dbfile ;
Block  **block ;
Matrix **matrix ;
char   db_type ;

{
   if (db_type == BLOCK_DB)
      {
      if ((*block = read_a_block(*dbfile)) == NULL) return (ERROR) ;
      *matrix = block_to_matrix(*block,BlockToMatrixConversionMethod) ;
      }
   else if (db_type == ProDom_mul_DB)
      {
      if ((*block = read_a_prodom_entry(*dbfile)) == NULL) return (ERROR) ;
      *matrix = block_to_matrix(*block,BlockToMatrixConversionMethod) ;
      }
   else if (db_type == MATRIX_DB)
      {
      if ((*matrix = read_a_matrix(*dbfile)) == NULL) return (ERROR) ;
      }
   else
      {
      printf(
       "Error. variable db_type (%c) is of unknown type !\n",
       db_type) ;
      exit (ERROR) ;
      }

   return (OK) ;

}


/****************************************************************************
 * load the mean and variance values for scores of different widths. 
 * The widths are those of blocks in BLOCKS database - 4 to 55. The stored
 * values for higher widths are taken from the widest blocks - 55.
 * Values obtained by blkvblk version 42 (best local alignments, using 
 * correlation coefficient for comparing PSSM columns in the Smith Wateman 
 * algorithm). The compared data was BLOCKS 8.0 with a shuffled version of
 * itself. For each block the order of columns in its PSSM was randomly changed
 * and the resulting PSSM saved. This resulted in 8.2 million (8,233,820)
 * scores. These were purged from all scores that contained any one of 215
 * biassed blocks or their shuffled versions and from scores between blocks
 * and their own shuffled version. This resulted in 7,048,856 scores. 
 ****************************************************************************/

void load_stats3()
{
   stats[4].mean  = 1.32 ;
   stats[5].mean  = 1.48 ;
   stats[6].mean  = 1.60 ;
   stats[7].mean  = 1.82 ;
   stats[8].mean  = 1.86 ;
   stats[9].mean  = 1.95 ;
   stats[10].mean = 2.11 ;
   stats[11].mean = 2.22 ;
   stats[12].mean = 2.29 ;
   stats[13].mean = 2.40 ;
   stats[14].mean = 2.46 ;
   stats[15].mean = 2.59 ;
   stats[16].mean = 2.68 ;
   stats[17].mean = 2.75 ;
   stats[18].mean = 2.85 ;
   stats[19].mean = 2.91 ;
   stats[20].mean = 2.97 ;
   stats[21].mean = 3.02 ;
   stats[22].mean = 3.16 ;
   stats[23].mean = 3.16 ;
   stats[24].mean = 3.32 ;
   stats[25].mean = 3.35 ;
   stats[26].mean = 3.45 ;
   stats[27].mean = 3.50 ;
   stats[28].mean = 3.55 ;
   stats[29].mean = 3.62 ;
   stats[30].mean = 3.67 ;
   stats[31].mean = 3.71 ;
   stats[32].mean = 3.80 ;
   stats[33].mean = 3.89 ;
   stats[34].mean = 3.95 ;
   stats[35].mean = 4.00 ;
   stats[36].mean = 4.04 ;
   stats[37].mean = 4.12 ;
   stats[38].mean = 4.21 ;
   stats[39].mean = 4.25 ;
   stats[40].mean = 4.29 ;
   stats[41].mean = 4.37 ;
   stats[42].mean = 4.42 ;
   stats[43].mean = 4.49 ;
   stats[44].mean = 4.54 ;
   stats[45].mean = 4.56 ;
   stats[46].mean = 4.71 ;
   stats[47].mean = 4.71 ;
   stats[48].mean = 4.76 ;
   stats[49].mean = 4.80 ;
   stats[50].mean = 4.81 ;
   stats[51].mean = 4.92 ;
   stats[52].mean = 4.99 ;
   stats[53].mean = 4.99 ;
   stats[54].mean = 5.05 ;
   stats[55].mean = 5.14 ;

   stats[4].variance  = 0.378 ;
   stats[5].variance  = 0.415 ;
   stats[6].variance  = 0.435 ;
   stats[7].variance  = 0.477 ;
   stats[8].variance  = 0.490 ;
   stats[9].variance  = 0.506 ;
   stats[10].variance = 0.544 ;
   stats[11].variance = 0.558 ;
   stats[12].variance = 0.566 ;
   stats[13].variance = 0.580 ;
   stats[14].variance = 0.601 ;
   stats[15].variance = 0.608 ;
   stats[16].variance = 0.630 ;
   stats[17].variance = 0.638 ;
   stats[18].variance = 0.648 ;
   stats[19].variance = 0.652 ;
   stats[20].variance = 0.674 ;
   stats[21].variance = 0.695 ;
   stats[22].variance = 0.698 ;
   stats[23].variance = 0.712 ;
   stats[24].variance = 0.713 ;
   stats[25].variance = 0.733 ;
   stats[26].variance = 0.747 ;
   stats[27].variance = 0.754 ;
   stats[28].variance = 0.769 ;
   stats[29].variance = 0.775 ;
   stats[30].variance = 0.774 ;
   stats[31].variance = 0.780 ;
   stats[32].variance = 0.786 ;
   stats[33].variance = 0.800 ;
   stats[34].variance = 0.808 ;
   stats[35].variance = 0.818 ;
   stats[36].variance = 0.811 ;
   stats[37].variance = 0.829 ;
   stats[38].variance = 0.844 ;
   stats[39].variance = 0.838 ;
   stats[40].variance = 0.849 ;
   stats[41].variance = 0.862 ;
   stats[42].variance = 0.882 ;
   stats[43].variance = 0.865 ;
   stats[44].variance = 0.874 ;
   stats[45].variance = 0.896 ;
   stats[46].variance = 0.899 ;
   stats[47].variance = 0.891 ;
   stats[48].variance = 0.905 ;
   stats[49].variance = 0.905 ;
   stats[50].variance = 0.913 ;
   stats[51].variance = 0.935 ;
   stats[52].variance = 0.940 ;
   stats[53].variance = 0.915 ;
   stats[54].variance = 0.936 ;
   stats[55].variance = 0.954 ;
}

/****************************************************************************
 * Allocate memory to array of zVsPrcntl structures and load values for
 * Z scores and corresponding percentile of shuffled and unbiassed scores.
 * These values are of Z scores > 5 from the following score data -
 * The compared data was BLOCKS 8.0 with a shuffled version of itself.
 * For each block the order of columns in its PSSM was randomly changed
 * and the resulting PSSM saved. This resulted in 8.2 million (8,233,820)
 * scores. These were purged from all scores that contained any one of 215
 * biassed blocks or their shuffled versions and from scores between blocks
 * and their own shuffled version. This resulted in 7,048,856 scores. 
 ****************************************************************************/

void load_ZvsPrcntl1() 
{
            /* Allocate memory to array of structures according to the data */
   alloctd_zVsPrcntl = 471 ;
   zVsPrcntl = (ZvsPRCNTL *) calloc(alloctd_zVsPrcntl, sizeof(ZvsPRCNTL)) ;

   zVsPrcntl[0].Z = 5.000 ;  zVsPrcntl[0].prcntl = 0.9997645 ;
   zVsPrcntl[1].Z = 5.000 ;  zVsPrcntl[1].prcntl = 0.9997650 ;
   zVsPrcntl[2].Z = 5.000 ;  zVsPrcntl[2].prcntl = 0.9997655 ;
   zVsPrcntl[3].Z = 5.000 ;  zVsPrcntl[3].prcntl = 0.9997660 ;
   zVsPrcntl[4].Z = 5.000 ;  zVsPrcntl[4].prcntl = 0.9997665 ;
   zVsPrcntl[5].Z = 5.000 ;  zVsPrcntl[5].prcntl = 0.9997670 ;
   zVsPrcntl[6].Z = 5.000 ;  zVsPrcntl[6].prcntl = 0.9997675 ;
   zVsPrcntl[7].Z = 5.000 ;  zVsPrcntl[7].prcntl = 0.9997680 ;
   zVsPrcntl[8].Z = 5.006 ;  zVsPrcntl[8].prcntl = 0.9997685 ;
   zVsPrcntl[9].Z = 5.006 ;  zVsPrcntl[9].prcntl = 0.9997690 ;
   zVsPrcntl[10].Z = 5.007 ;  zVsPrcntl[10].prcntl = 0.9997695 ;
   zVsPrcntl[11].Z = 5.011 ;  zVsPrcntl[11].prcntl = 0.9997700 ;
   zVsPrcntl[12].Z = 5.012 ;  zVsPrcntl[12].prcntl = 0.9997705 ;
   zVsPrcntl[13].Z = 5.013 ;  zVsPrcntl[13].prcntl = 0.9997710 ;
   zVsPrcntl[14].Z = 5.013 ;  zVsPrcntl[14].prcntl = 0.9997715 ;
   zVsPrcntl[15].Z = 5.014 ;  zVsPrcntl[15].prcntl = 0.9997720 ;
   zVsPrcntl[16].Z = 5.016 ;  zVsPrcntl[16].prcntl = 0.9997725 ;
   zVsPrcntl[17].Z = 5.018 ;  zVsPrcntl[17].prcntl = 0.9997730 ;
   zVsPrcntl[18].Z = 5.018 ;  zVsPrcntl[18].prcntl = 0.9997735 ;
   zVsPrcntl[19].Z = 5.018 ;  zVsPrcntl[19].prcntl = 0.9997740 ;
   zVsPrcntl[20].Z = 5.019 ;  zVsPrcntl[20].prcntl = 0.9997745 ;
   zVsPrcntl[21].Z = 5.023 ;  zVsPrcntl[21].prcntl = 0.9997750 ;
   zVsPrcntl[22].Z = 5.025 ;  zVsPrcntl[22].prcntl = 0.9997755 ;
   zVsPrcntl[23].Z = 5.026 ;  zVsPrcntl[23].prcntl = 0.9997760 ;
   zVsPrcntl[24].Z = 5.026 ;  zVsPrcntl[24].prcntl = 0.9997765 ;
   zVsPrcntl[25].Z = 5.028 ;  zVsPrcntl[25].prcntl = 0.9997770 ;
   zVsPrcntl[26].Z = 5.031 ;  zVsPrcntl[26].prcntl = 0.9997775 ;
   zVsPrcntl[27].Z = 5.032 ;  zVsPrcntl[27].prcntl = 0.9997780 ;
   zVsPrcntl[28].Z = 5.033 ;  zVsPrcntl[28].prcntl = 0.9997785 ;
   zVsPrcntl[29].Z = 5.033 ;  zVsPrcntl[29].prcntl = 0.9997790 ;
   zVsPrcntl[30].Z = 5.034 ;  zVsPrcntl[30].prcntl = 0.9997795 ;
   zVsPrcntl[31].Z = 5.036 ;  zVsPrcntl[31].prcntl = 0.9997800 ;
   zVsPrcntl[32].Z = 5.036 ;  zVsPrcntl[32].prcntl = 0.9997805 ;
   zVsPrcntl[33].Z = 5.037 ;  zVsPrcntl[33].prcntl = 0.9997810 ;
   zVsPrcntl[34].Z = 5.040 ;  zVsPrcntl[34].prcntl = 0.9997815 ;
   zVsPrcntl[35].Z = 5.042 ;  zVsPrcntl[35].prcntl = 0.9997820 ;
   zVsPrcntl[36].Z = 5.042 ;  zVsPrcntl[36].prcntl = 0.9997825 ;
   zVsPrcntl[37].Z = 5.043 ;  zVsPrcntl[37].prcntl = 0.9997830 ;
   zVsPrcntl[38].Z = 5.045 ;  zVsPrcntl[38].prcntl = 0.9997835 ;
   zVsPrcntl[39].Z = 5.046 ;  zVsPrcntl[39].prcntl = 0.9997840 ;
   zVsPrcntl[40].Z = 5.047 ;  zVsPrcntl[40].prcntl = 0.9997845 ;
   zVsPrcntl[41].Z = 5.050 ;  zVsPrcntl[41].prcntl = 0.9997850 ;
   zVsPrcntl[42].Z = 5.051 ;  zVsPrcntl[42].prcntl = 0.9997855 ;
   zVsPrcntl[43].Z = 5.054 ;  zVsPrcntl[43].prcntl = 0.9997860 ;
   zVsPrcntl[44].Z = 5.055 ;  zVsPrcntl[44].prcntl = 0.9997865 ;
   zVsPrcntl[45].Z = 5.057 ;  zVsPrcntl[45].prcntl = 0.9997870 ;
   zVsPrcntl[46].Z = 5.059 ;  zVsPrcntl[46].prcntl = 0.9997875 ;
   zVsPrcntl[47].Z = 5.059 ;  zVsPrcntl[47].prcntl = 0.9997880 ;
   zVsPrcntl[48].Z = 5.060 ;  zVsPrcntl[48].prcntl = 0.9997885 ;
   zVsPrcntl[49].Z = 5.061 ;  zVsPrcntl[49].prcntl = 0.9997890 ;
   zVsPrcntl[50].Z = 5.061 ;  zVsPrcntl[50].prcntl = 0.9997895 ;
   zVsPrcntl[51].Z = 5.063 ;  zVsPrcntl[51].prcntl = 0.9997900 ;
   zVsPrcntl[52].Z = 5.064 ;  zVsPrcntl[52].prcntl = 0.9997905 ;
   zVsPrcntl[53].Z = 5.066 ;  zVsPrcntl[53].prcntl = 0.9997910 ;
   zVsPrcntl[54].Z = 5.068 ;  zVsPrcntl[54].prcntl = 0.9997915 ;
   zVsPrcntl[55].Z = 5.069 ;  zVsPrcntl[55].prcntl = 0.9997920 ;
   zVsPrcntl[56].Z = 5.069 ;  zVsPrcntl[56].prcntl = 0.9997925 ;
   zVsPrcntl[57].Z = 5.071 ;  zVsPrcntl[57].prcntl = 0.9997930 ;
   zVsPrcntl[58].Z = 5.071 ;  zVsPrcntl[58].prcntl = 0.9997935 ;
   zVsPrcntl[59].Z = 5.073 ;  zVsPrcntl[59].prcntl = 0.9997940 ;
   zVsPrcntl[60].Z = 5.074 ;  zVsPrcntl[60].prcntl = 0.9997945 ;
   zVsPrcntl[61].Z = 5.077 ;  zVsPrcntl[61].prcntl = 0.9997950 ;
   zVsPrcntl[62].Z = 5.077 ;  zVsPrcntl[62].prcntl = 0.9997955 ;
   zVsPrcntl[63].Z = 5.078 ;  zVsPrcntl[63].prcntl = 0.9997960 ;
   zVsPrcntl[64].Z = 5.078 ;  zVsPrcntl[64].prcntl = 0.9997965 ;
   zVsPrcntl[65].Z = 5.078 ;  zVsPrcntl[65].prcntl = 0.9997970 ;
   zVsPrcntl[66].Z = 5.080 ;  zVsPrcntl[66].prcntl = 0.9997975 ;
   zVsPrcntl[67].Z = 5.082 ;  zVsPrcntl[67].prcntl = 0.9997980 ;
   zVsPrcntl[68].Z = 5.086 ;  zVsPrcntl[68].prcntl = 0.9997985 ;
   zVsPrcntl[69].Z = 5.087 ;  zVsPrcntl[69].prcntl = 0.9997990 ;
   zVsPrcntl[70].Z = 5.089 ;  zVsPrcntl[70].prcntl = 0.9997995 ;
   zVsPrcntl[71].Z = 5.090 ;  zVsPrcntl[71].prcntl = 0.9998000 ;
   zVsPrcntl[72].Z = 5.090 ;  zVsPrcntl[72].prcntl = 0.9998005 ;
   zVsPrcntl[73].Z = 5.091 ;  zVsPrcntl[73].prcntl = 0.9998010 ;
   zVsPrcntl[74].Z = 5.093 ;  zVsPrcntl[74].prcntl = 0.9998015 ;
   zVsPrcntl[75].Z = 5.094 ;  zVsPrcntl[75].prcntl = 0.9998020 ;
   zVsPrcntl[76].Z = 5.095 ;  zVsPrcntl[76].prcntl = 0.9998025 ;
   zVsPrcntl[77].Z = 5.097 ;  zVsPrcntl[77].prcntl = 0.9998030 ;
   zVsPrcntl[78].Z = 5.100 ;  zVsPrcntl[78].prcntl = 0.9998035 ;
   zVsPrcntl[79].Z = 5.103 ;  zVsPrcntl[79].prcntl = 0.9998040 ;
   zVsPrcntl[80].Z = 5.104 ;  zVsPrcntl[80].prcntl = 0.9998045 ;
   zVsPrcntl[81].Z = 5.105 ;  zVsPrcntl[81].prcntl = 0.9998050 ;
   zVsPrcntl[82].Z = 5.107 ;  zVsPrcntl[82].prcntl = 0.9998055 ;
   zVsPrcntl[83].Z = 5.108 ;  zVsPrcntl[83].prcntl = 0.9998060 ;
   zVsPrcntl[84].Z = 5.110 ;  zVsPrcntl[84].prcntl = 0.9998065 ;
   zVsPrcntl[85].Z = 5.110 ;  zVsPrcntl[85].prcntl = 0.9998070 ;
   zVsPrcntl[86].Z = 5.110 ;  zVsPrcntl[86].prcntl = 0.9998075 ;
   zVsPrcntl[87].Z = 5.112 ;  zVsPrcntl[87].prcntl = 0.9998080 ;
   zVsPrcntl[88].Z = 5.113 ;  zVsPrcntl[88].prcntl = 0.9998085 ;
   zVsPrcntl[89].Z = 5.115 ;  zVsPrcntl[89].prcntl = 0.9998090 ;
   zVsPrcntl[90].Z = 5.117 ;  zVsPrcntl[90].prcntl = 0.9998095 ;
   zVsPrcntl[91].Z = 5.119 ;  zVsPrcntl[91].prcntl = 0.9998100 ;
   zVsPrcntl[92].Z = 5.121 ;  zVsPrcntl[92].prcntl = 0.9998105 ;
   zVsPrcntl[93].Z = 5.123 ;  zVsPrcntl[93].prcntl = 0.9998110 ;
   zVsPrcntl[94].Z = 5.124 ;  zVsPrcntl[94].prcntl = 0.9998115 ;
   zVsPrcntl[95].Z = 5.125 ;  zVsPrcntl[95].prcntl = 0.9998120 ;
   zVsPrcntl[96].Z = 5.125 ;  zVsPrcntl[96].prcntl = 0.9998125 ;
   zVsPrcntl[97].Z = 5.126 ;  zVsPrcntl[97].prcntl = 0.9998130 ;
   zVsPrcntl[98].Z = 5.127 ;  zVsPrcntl[98].prcntl = 0.9998135 ;
   zVsPrcntl[99].Z = 5.127 ;  zVsPrcntl[99].prcntl = 0.9998140 ;
   zVsPrcntl[100].Z = 5.128 ;  zVsPrcntl[100].prcntl = 0.9998145 ;
   zVsPrcntl[101].Z = 5.133 ;  zVsPrcntl[101].prcntl = 0.9998150 ;
   zVsPrcntl[102].Z = 5.134 ;  zVsPrcntl[102].prcntl = 0.9998155 ;
   zVsPrcntl[103].Z = 5.137 ;  zVsPrcntl[103].prcntl = 0.9998160 ;
   zVsPrcntl[104].Z = 5.137 ;  zVsPrcntl[104].prcntl = 0.9998165 ;
   zVsPrcntl[105].Z = 5.138 ;  zVsPrcntl[105].prcntl = 0.9998170 ;
   zVsPrcntl[106].Z = 5.141 ;  zVsPrcntl[106].prcntl = 0.9998175 ;
   zVsPrcntl[107].Z = 5.141 ;  zVsPrcntl[107].prcntl = 0.9998180 ;
   zVsPrcntl[108].Z = 5.142 ;  zVsPrcntl[108].prcntl = 0.9998185 ;
   zVsPrcntl[109].Z = 5.143 ;  zVsPrcntl[109].prcntl = 0.9998190 ;
   zVsPrcntl[110].Z = 5.143 ;  zVsPrcntl[110].prcntl = 0.9998195 ;
   zVsPrcntl[111].Z = 5.147 ;  zVsPrcntl[111].prcntl = 0.9998200 ;
   zVsPrcntl[112].Z = 5.147 ;  zVsPrcntl[112].prcntl = 0.9998205 ;
   zVsPrcntl[113].Z = 5.149 ;  zVsPrcntl[113].prcntl = 0.9998210 ;
   zVsPrcntl[114].Z = 5.150 ;  zVsPrcntl[114].prcntl = 0.9998215 ;
   zVsPrcntl[115].Z = 5.154 ;  zVsPrcntl[115].prcntl = 0.9998220 ;
   zVsPrcntl[116].Z = 5.155 ;  zVsPrcntl[116].prcntl = 0.9998225 ;
   zVsPrcntl[117].Z = 5.157 ;  zVsPrcntl[117].prcntl = 0.9998230 ;
   zVsPrcntl[118].Z = 5.157 ;  zVsPrcntl[118].prcntl = 0.9998235 ;
   zVsPrcntl[119].Z = 5.158 ;  zVsPrcntl[119].prcntl = 0.9998240 ;
   zVsPrcntl[120].Z = 5.158 ;  zVsPrcntl[120].prcntl = 0.9998245 ;
   zVsPrcntl[121].Z = 5.158 ;  zVsPrcntl[121].prcntl = 0.9998250 ;
   zVsPrcntl[122].Z = 5.159 ;  zVsPrcntl[122].prcntl = 0.9998255 ;
   zVsPrcntl[123].Z = 5.161 ;  zVsPrcntl[123].prcntl = 0.9998260 ;
   zVsPrcntl[124].Z = 5.162 ;  zVsPrcntl[124].prcntl = 0.9998265 ;
   zVsPrcntl[125].Z = 5.163 ;  zVsPrcntl[125].prcntl = 0.9998270 ;
   zVsPrcntl[126].Z = 5.166 ;  zVsPrcntl[126].prcntl = 0.9998275 ;
   zVsPrcntl[127].Z = 5.167 ;  zVsPrcntl[127].prcntl = 0.9998280 ;
   zVsPrcntl[128].Z = 5.169 ;  zVsPrcntl[128].prcntl = 0.9998285 ;
   zVsPrcntl[129].Z = 5.171 ;  zVsPrcntl[129].prcntl = 0.9998290 ;
   zVsPrcntl[130].Z = 5.175 ;  zVsPrcntl[130].prcntl = 0.9998295 ;
   zVsPrcntl[131].Z = 5.178 ;  zVsPrcntl[131].prcntl = 0.9998300 ;
   zVsPrcntl[132].Z = 5.179 ;  zVsPrcntl[132].prcntl = 0.9998305 ;
   zVsPrcntl[133].Z = 5.184 ;  zVsPrcntl[133].prcntl = 0.9998310 ;
   zVsPrcntl[134].Z = 5.184 ;  zVsPrcntl[134].prcntl = 0.9998315 ;
   zVsPrcntl[135].Z = 5.186 ;  zVsPrcntl[135].prcntl = 0.9998320 ;
   zVsPrcntl[136].Z = 5.186 ;  zVsPrcntl[136].prcntl = 0.9998325 ;
   zVsPrcntl[137].Z = 5.189 ;  zVsPrcntl[137].prcntl = 0.9998330 ;
   zVsPrcntl[138].Z = 5.191 ;  zVsPrcntl[138].prcntl = 0.9998335 ;
   zVsPrcntl[139].Z = 5.191 ;  zVsPrcntl[139].prcntl = 0.9998340 ;
   zVsPrcntl[140].Z = 5.192 ;  zVsPrcntl[140].prcntl = 0.9998345 ;
   zVsPrcntl[141].Z = 5.195 ;  zVsPrcntl[141].prcntl = 0.9998350 ;
   zVsPrcntl[142].Z = 5.198 ;  zVsPrcntl[142].prcntl = 0.9998355 ;
   zVsPrcntl[143].Z = 5.200 ;  zVsPrcntl[143].prcntl = 0.9998360 ;
   zVsPrcntl[144].Z = 5.201 ;  zVsPrcntl[144].prcntl = 0.9998365 ;
   zVsPrcntl[145].Z = 5.202 ;  zVsPrcntl[145].prcntl = 0.9998370 ;
   zVsPrcntl[146].Z = 5.203 ;  zVsPrcntl[146].prcntl = 0.9998375 ;
   zVsPrcntl[147].Z = 5.204 ;  zVsPrcntl[147].prcntl = 0.9998380 ;
   zVsPrcntl[148].Z = 5.206 ;  zVsPrcntl[148].prcntl = 0.9998385 ;
   zVsPrcntl[149].Z = 5.208 ;  zVsPrcntl[149].prcntl = 0.9998390 ;
   zVsPrcntl[150].Z = 5.209 ;  zVsPrcntl[150].prcntl = 0.9998395 ;
   zVsPrcntl[151].Z = 5.211 ;  zVsPrcntl[151].prcntl = 0.9998400 ;
   zVsPrcntl[152].Z = 5.214 ;  zVsPrcntl[152].prcntl = 0.9998405 ;
   zVsPrcntl[153].Z = 5.214 ;  zVsPrcntl[153].prcntl = 0.9998410 ;
   zVsPrcntl[154].Z = 5.215 ;  zVsPrcntl[154].prcntl = 0.9998415 ;
   zVsPrcntl[155].Z = 5.216 ;  zVsPrcntl[155].prcntl = 0.9998420 ;
   zVsPrcntl[156].Z = 5.217 ;  zVsPrcntl[156].prcntl = 0.9998425 ;
   zVsPrcntl[157].Z = 5.220 ;  zVsPrcntl[157].prcntl = 0.9998430 ;
   zVsPrcntl[158].Z = 5.222 ;  zVsPrcntl[158].prcntl = 0.9998435 ;
   zVsPrcntl[159].Z = 5.224 ;  zVsPrcntl[159].prcntl = 0.9998440 ;
   zVsPrcntl[160].Z = 5.225 ;  zVsPrcntl[160].prcntl = 0.9998445 ;
   zVsPrcntl[161].Z = 5.229 ;  zVsPrcntl[161].prcntl = 0.9998450 ;
   zVsPrcntl[162].Z = 5.230 ;  zVsPrcntl[162].prcntl = 0.9998455 ;
   zVsPrcntl[163].Z = 5.232 ;  zVsPrcntl[163].prcntl = 0.9998460 ;
   zVsPrcntl[164].Z = 5.237 ;  zVsPrcntl[164].prcntl = 0.9998465 ;
   zVsPrcntl[165].Z = 5.238 ;  zVsPrcntl[165].prcntl = 0.9998470 ;
   zVsPrcntl[166].Z = 5.239 ;  zVsPrcntl[166].prcntl = 0.9998475 ;
   zVsPrcntl[167].Z = 5.241 ;  zVsPrcntl[167].prcntl = 0.9998480 ;
   zVsPrcntl[168].Z = 5.241 ;  zVsPrcntl[168].prcntl = 0.9998485 ;
   zVsPrcntl[169].Z = 5.244 ;  zVsPrcntl[169].prcntl = 0.9998490 ;
   zVsPrcntl[170].Z = 5.247 ;  zVsPrcntl[170].prcntl = 0.9998495 ;
   zVsPrcntl[171].Z = 5.250 ;  zVsPrcntl[171].prcntl = 0.9998500 ;
   zVsPrcntl[172].Z = 5.252 ;  zVsPrcntl[172].prcntl = 0.9998505 ;
   zVsPrcntl[173].Z = 5.253 ;  zVsPrcntl[173].prcntl = 0.9998510 ;
   zVsPrcntl[174].Z = 5.254 ;  zVsPrcntl[174].prcntl = 0.9998515 ;
   zVsPrcntl[175].Z = 5.258 ;  zVsPrcntl[175].prcntl = 0.9998520 ;
   zVsPrcntl[176].Z = 5.260 ;  zVsPrcntl[176].prcntl = 0.9998525 ;
   zVsPrcntl[177].Z = 5.261 ;  zVsPrcntl[177].prcntl = 0.9998530 ;
   zVsPrcntl[178].Z = 5.263 ;  zVsPrcntl[178].prcntl = 0.9998535 ;
   zVsPrcntl[179].Z = 5.265 ;  zVsPrcntl[179].prcntl = 0.9998540 ;
   zVsPrcntl[180].Z = 5.265 ;  zVsPrcntl[180].prcntl = 0.9998545 ;
   zVsPrcntl[181].Z = 5.269 ;  zVsPrcntl[181].prcntl = 0.9998550 ;
   zVsPrcntl[182].Z = 5.271 ;  zVsPrcntl[182].prcntl = 0.9998555 ;
   zVsPrcntl[183].Z = 5.275 ;  zVsPrcntl[183].prcntl = 0.9998560 ;
   zVsPrcntl[184].Z = 5.275 ;  zVsPrcntl[184].prcntl = 0.9998565 ;
   zVsPrcntl[185].Z = 5.277 ;  zVsPrcntl[185].prcntl = 0.9998570 ;
   zVsPrcntl[186].Z = 5.280 ;  zVsPrcntl[186].prcntl = 0.9998575 ;
   zVsPrcntl[187].Z = 5.281 ;  zVsPrcntl[187].prcntl = 0.9998580 ;
   zVsPrcntl[188].Z = 5.284 ;  zVsPrcntl[188].prcntl = 0.9998585 ;
   zVsPrcntl[189].Z = 5.286 ;  zVsPrcntl[189].prcntl = 0.9998590 ;
   zVsPrcntl[190].Z = 5.288 ;  zVsPrcntl[190].prcntl = 0.9998595 ;
   zVsPrcntl[191].Z = 5.290 ;  zVsPrcntl[191].prcntl = 0.9998600 ;
   zVsPrcntl[192].Z = 5.293 ;  zVsPrcntl[192].prcntl = 0.9998605 ;
   zVsPrcntl[193].Z = 5.295 ;  zVsPrcntl[193].prcntl = 0.9998610 ;
   zVsPrcntl[194].Z = 5.296 ;  zVsPrcntl[194].prcntl = 0.9998615 ;
   zVsPrcntl[195].Z = 5.298 ;  zVsPrcntl[195].prcntl = 0.9998620 ;
   zVsPrcntl[196].Z = 5.300 ;  zVsPrcntl[196].prcntl = 0.9998625 ;
   zVsPrcntl[197].Z = 5.302 ;  zVsPrcntl[197].prcntl = 0.9998630 ;
   zVsPrcntl[198].Z = 5.305 ;  zVsPrcntl[198].prcntl = 0.9998635 ;
   zVsPrcntl[199].Z = 5.306 ;  zVsPrcntl[199].prcntl = 0.9998640 ;
   zVsPrcntl[200].Z = 5.308 ;  zVsPrcntl[200].prcntl = 0.9998645 ;
   zVsPrcntl[201].Z = 5.309 ;  zVsPrcntl[201].prcntl = 0.9998650 ;
   zVsPrcntl[202].Z = 5.310 ;  zVsPrcntl[202].prcntl = 0.9998655 ;
   zVsPrcntl[203].Z = 5.310 ;  zVsPrcntl[203].prcntl = 0.9998660 ;
   zVsPrcntl[204].Z = 5.313 ;  zVsPrcntl[204].prcntl = 0.9998665 ;
   zVsPrcntl[205].Z = 5.318 ;  zVsPrcntl[205].prcntl = 0.9998670 ;
   zVsPrcntl[206].Z = 5.318 ;  zVsPrcntl[206].prcntl = 0.9998675 ;
   zVsPrcntl[207].Z = 5.322 ;  zVsPrcntl[207].prcntl = 0.9998680 ;
   zVsPrcntl[208].Z = 5.322 ;  zVsPrcntl[208].prcntl = 0.9998685 ;
   zVsPrcntl[209].Z = 5.323 ;  zVsPrcntl[209].prcntl = 0.9998690 ;
   zVsPrcntl[210].Z = 5.324 ;  zVsPrcntl[210].prcntl = 0.9998695 ;
   zVsPrcntl[211].Z = 5.324 ;  zVsPrcntl[211].prcntl = 0.9998700 ;
   zVsPrcntl[212].Z = 5.327 ;  zVsPrcntl[212].prcntl = 0.9998705 ;
   zVsPrcntl[213].Z = 5.329 ;  zVsPrcntl[213].prcntl = 0.9998710 ;
   zVsPrcntl[214].Z = 5.329 ;  zVsPrcntl[214].prcntl = 0.9998715 ;
   zVsPrcntl[215].Z = 5.330 ;  zVsPrcntl[215].prcntl = 0.9998720 ;
   zVsPrcntl[216].Z = 5.331 ;  zVsPrcntl[216].prcntl = 0.9998725 ;
   zVsPrcntl[217].Z = 5.332 ;  zVsPrcntl[217].prcntl = 0.9998730 ;
   zVsPrcntl[218].Z = 5.333 ;  zVsPrcntl[218].prcntl = 0.9998735 ;
   zVsPrcntl[219].Z = 5.336 ;  zVsPrcntl[219].prcntl = 0.9998740 ;
   zVsPrcntl[220].Z = 5.337 ;  zVsPrcntl[220].prcntl = 0.9998745 ;
   zVsPrcntl[221].Z = 5.341 ;  zVsPrcntl[221].prcntl = 0.9998750 ;
   zVsPrcntl[222].Z = 5.343 ;  zVsPrcntl[222].prcntl = 0.9998755 ;
   zVsPrcntl[223].Z = 5.345 ;  zVsPrcntl[223].prcntl = 0.9998760 ;
   zVsPrcntl[224].Z = 5.346 ;  zVsPrcntl[224].prcntl = 0.9998765 ;
   zVsPrcntl[225].Z = 5.348 ;  zVsPrcntl[225].prcntl = 0.9998770 ;
   zVsPrcntl[226].Z = 5.349 ;  zVsPrcntl[226].prcntl = 0.9998775 ;
   zVsPrcntl[227].Z = 5.349 ;  zVsPrcntl[227].prcntl = 0.9998780 ;
   zVsPrcntl[228].Z = 5.351 ;  zVsPrcntl[228].prcntl = 0.9998785 ;
   zVsPrcntl[229].Z = 5.353 ;  zVsPrcntl[229].prcntl = 0.9998790 ;
   zVsPrcntl[230].Z = 5.355 ;  zVsPrcntl[230].prcntl = 0.9998795 ;
   zVsPrcntl[231].Z = 5.356 ;  zVsPrcntl[231].prcntl = 0.9998800 ;
   zVsPrcntl[232].Z = 5.358 ;  zVsPrcntl[232].prcntl = 0.9998805 ;
   zVsPrcntl[233].Z = 5.361 ;  zVsPrcntl[233].prcntl = 0.9998810 ;
   zVsPrcntl[234].Z = 5.362 ;  zVsPrcntl[234].prcntl = 0.9998815 ;
   zVsPrcntl[235].Z = 5.365 ;  zVsPrcntl[235].prcntl = 0.9998820 ;
   zVsPrcntl[236].Z = 5.367 ;  zVsPrcntl[236].prcntl = 0.9998825 ;
   zVsPrcntl[237].Z = 5.368 ;  zVsPrcntl[237].prcntl = 0.9998830 ;
   zVsPrcntl[238].Z = 5.368 ;  zVsPrcntl[238].prcntl = 0.9998835 ;
   zVsPrcntl[239].Z = 5.370 ;  zVsPrcntl[239].prcntl = 0.9998840 ;
   zVsPrcntl[240].Z = 5.371 ;  zVsPrcntl[240].prcntl = 0.9998845 ;
   zVsPrcntl[241].Z = 5.372 ;  zVsPrcntl[241].prcntl = 0.9998850 ;
   zVsPrcntl[242].Z = 5.376 ;  zVsPrcntl[242].prcntl = 0.9998855 ;
   zVsPrcntl[243].Z = 5.378 ;  zVsPrcntl[243].prcntl = 0.9998860 ;
   zVsPrcntl[244].Z = 5.381 ;  zVsPrcntl[244].prcntl = 0.9998865 ;
   zVsPrcntl[245].Z = 5.383 ;  zVsPrcntl[245].prcntl = 0.9998870 ;
   zVsPrcntl[246].Z = 5.385 ;  zVsPrcntl[246].prcntl = 0.9998875 ;
   zVsPrcntl[247].Z = 5.388 ;  zVsPrcntl[247].prcntl = 0.9998880 ;
   zVsPrcntl[248].Z = 5.389 ;  zVsPrcntl[248].prcntl = 0.9998885 ;
   zVsPrcntl[249].Z = 5.391 ;  zVsPrcntl[249].prcntl = 0.9998890 ;
   zVsPrcntl[250].Z = 5.394 ;  zVsPrcntl[250].prcntl = 0.9998895 ;
   zVsPrcntl[251].Z = 5.397 ;  zVsPrcntl[251].prcntl = 0.9998900 ;
   zVsPrcntl[252].Z = 5.397 ;  zVsPrcntl[252].prcntl = 0.9998905 ;
   zVsPrcntl[253].Z = 5.404 ;  zVsPrcntl[253].prcntl = 0.9998910 ;
   zVsPrcntl[254].Z = 5.407 ;  zVsPrcntl[254].prcntl = 0.9998915 ;
   zVsPrcntl[255].Z = 5.410 ;  zVsPrcntl[255].prcntl = 0.9998920 ;
   zVsPrcntl[256].Z = 5.413 ;  zVsPrcntl[256].prcntl = 0.9998925 ;
   zVsPrcntl[257].Z = 5.415 ;  zVsPrcntl[257].prcntl = 0.9998930 ;
   zVsPrcntl[258].Z = 5.416 ;  zVsPrcntl[258].prcntl = 0.9998935 ;
   zVsPrcntl[259].Z = 5.421 ;  zVsPrcntl[259].prcntl = 0.9998940 ;
   zVsPrcntl[260].Z = 5.424 ;  zVsPrcntl[260].prcntl = 0.9998945 ;
   zVsPrcntl[261].Z = 5.432 ;  zVsPrcntl[261].prcntl = 0.9998950 ;
   zVsPrcntl[262].Z = 5.436 ;  zVsPrcntl[262].prcntl = 0.9998955 ;
   zVsPrcntl[263].Z = 5.444 ;  zVsPrcntl[263].prcntl = 0.9998960 ;
   zVsPrcntl[264].Z = 5.445 ;  zVsPrcntl[264].prcntl = 0.9998965 ;
   zVsPrcntl[265].Z = 5.448 ;  zVsPrcntl[265].prcntl = 0.9998970 ;
   zVsPrcntl[266].Z = 5.449 ;  zVsPrcntl[266].prcntl = 0.9998975 ;
   zVsPrcntl[267].Z = 5.452 ;  zVsPrcntl[267].prcntl = 0.9998980 ;
   zVsPrcntl[268].Z = 5.453 ;  zVsPrcntl[268].prcntl = 0.9998985 ;
   zVsPrcntl[269].Z = 5.457 ;  zVsPrcntl[269].prcntl = 0.9998990 ;
   zVsPrcntl[270].Z = 5.460 ;  zVsPrcntl[270].prcntl = 0.9998995 ;
   zVsPrcntl[271].Z = 5.460 ;  zVsPrcntl[271].prcntl = 0.9999000 ;
   zVsPrcntl[272].Z = 5.464 ;  zVsPrcntl[272].prcntl = 0.9999005 ;
   zVsPrcntl[273].Z = 5.469 ;  zVsPrcntl[273].prcntl = 0.9999010 ;
   zVsPrcntl[274].Z = 5.473 ;  zVsPrcntl[274].prcntl = 0.9999015 ;
   zVsPrcntl[275].Z = 5.475 ;  zVsPrcntl[275].prcntl = 0.9999020 ;
   zVsPrcntl[276].Z = 5.477 ;  zVsPrcntl[276].prcntl = 0.9999025 ;
   zVsPrcntl[277].Z = 5.478 ;  zVsPrcntl[277].prcntl = 0.9999030 ;
   zVsPrcntl[278].Z = 5.483 ;  zVsPrcntl[278].prcntl = 0.9999035 ;
   zVsPrcntl[279].Z = 5.484 ;  zVsPrcntl[279].prcntl = 0.9999040 ;
   zVsPrcntl[280].Z = 5.487 ;  zVsPrcntl[280].prcntl = 0.9999045 ;
   zVsPrcntl[281].Z = 5.488 ;  zVsPrcntl[281].prcntl = 0.9999050 ;
   zVsPrcntl[282].Z = 5.489 ;  zVsPrcntl[282].prcntl = 0.9999055 ;
   zVsPrcntl[283].Z = 5.492 ;  zVsPrcntl[283].prcntl = 0.9999060 ;
   zVsPrcntl[284].Z = 5.501 ;  zVsPrcntl[284].prcntl = 0.9999065 ;
   zVsPrcntl[285].Z = 5.502 ;  zVsPrcntl[285].prcntl = 0.9999070 ;
   zVsPrcntl[286].Z = 5.509 ;  zVsPrcntl[286].prcntl = 0.9999075 ;
   zVsPrcntl[287].Z = 5.513 ;  zVsPrcntl[287].prcntl = 0.9999080 ;
   zVsPrcntl[288].Z = 5.514 ;  zVsPrcntl[288].prcntl = 0.9999085 ;
   zVsPrcntl[289].Z = 5.515 ;  zVsPrcntl[289].prcntl = 0.9999090 ;
   zVsPrcntl[290].Z = 5.520 ;  zVsPrcntl[290].prcntl = 0.9999095 ;
   zVsPrcntl[291].Z = 5.525 ;  zVsPrcntl[291].prcntl = 0.9999100 ;
   zVsPrcntl[292].Z = 5.526 ;  zVsPrcntl[292].prcntl = 0.9999105 ;
   zVsPrcntl[293].Z = 5.530 ;  zVsPrcntl[293].prcntl = 0.9999110 ;
   zVsPrcntl[294].Z = 5.533 ;  zVsPrcntl[294].prcntl = 0.9999115 ;
   zVsPrcntl[295].Z = 5.537 ;  zVsPrcntl[295].prcntl = 0.9999120 ;
   zVsPrcntl[296].Z = 5.538 ;  zVsPrcntl[296].prcntl = 0.9999125 ;
   zVsPrcntl[297].Z = 5.540 ;  zVsPrcntl[297].prcntl = 0.9999130 ;
   zVsPrcntl[298].Z = 5.545 ;  zVsPrcntl[298].prcntl = 0.9999135 ;
   zVsPrcntl[299].Z = 5.550 ;  zVsPrcntl[299].prcntl = 0.9999140 ;
   zVsPrcntl[300].Z = 5.551 ;  zVsPrcntl[300].prcntl = 0.9999145 ;
   zVsPrcntl[301].Z = 5.557 ;  zVsPrcntl[301].prcntl = 0.9999150 ;
   zVsPrcntl[302].Z = 5.557 ;  zVsPrcntl[302].prcntl = 0.9999155 ;
   zVsPrcntl[303].Z = 5.557 ;  zVsPrcntl[303].prcntl = 0.9999160 ;
   zVsPrcntl[304].Z = 5.561 ;  zVsPrcntl[304].prcntl = 0.9999165 ;
   zVsPrcntl[305].Z = 5.564 ;  zVsPrcntl[305].prcntl = 0.9999170 ;
   zVsPrcntl[306].Z = 5.567 ;  zVsPrcntl[306].prcntl = 0.9999175 ;
   zVsPrcntl[307].Z = 5.569 ;  zVsPrcntl[307].prcntl = 0.9999180 ;
   zVsPrcntl[308].Z = 5.571 ;  zVsPrcntl[308].prcntl = 0.9999185 ;
   zVsPrcntl[309].Z = 5.574 ;  zVsPrcntl[309].prcntl = 0.9999190 ;
   zVsPrcntl[310].Z = 5.580 ;  zVsPrcntl[310].prcntl = 0.9999195 ;
   zVsPrcntl[311].Z = 5.582 ;  zVsPrcntl[311].prcntl = 0.9999200 ;
   zVsPrcntl[312].Z = 5.585 ;  zVsPrcntl[312].prcntl = 0.9999205 ;
   zVsPrcntl[313].Z = 5.586 ;  zVsPrcntl[313].prcntl = 0.9999210 ;
   zVsPrcntl[314].Z = 5.588 ;  zVsPrcntl[314].prcntl = 0.9999215 ;
   zVsPrcntl[315].Z = 5.591 ;  zVsPrcntl[315].prcntl = 0.9999220 ;
   zVsPrcntl[316].Z = 5.596 ;  zVsPrcntl[316].prcntl = 0.9999225 ;
   zVsPrcntl[317].Z = 5.599 ;  zVsPrcntl[317].prcntl = 0.9999230 ;
   zVsPrcntl[318].Z = 5.601 ;  zVsPrcntl[318].prcntl = 0.9999235 ;
   zVsPrcntl[319].Z = 5.609 ;  zVsPrcntl[319].prcntl = 0.9999240 ;
   zVsPrcntl[320].Z = 5.613 ;  zVsPrcntl[320].prcntl = 0.9999245 ;
   zVsPrcntl[321].Z = 5.615 ;  zVsPrcntl[321].prcntl = 0.9999250 ;
   zVsPrcntl[322].Z = 5.619 ;  zVsPrcntl[322].prcntl = 0.9999255 ;
   zVsPrcntl[323].Z = 5.623 ;  zVsPrcntl[323].prcntl = 0.9999260 ;
   zVsPrcntl[324].Z = 5.625 ;  zVsPrcntl[324].prcntl = 0.9999265 ;
   zVsPrcntl[325].Z = 5.626 ;  zVsPrcntl[325].prcntl = 0.9999270 ;
   zVsPrcntl[326].Z = 5.632 ;  zVsPrcntl[326].prcntl = 0.9999275 ;
   zVsPrcntl[327].Z = 5.635 ;  zVsPrcntl[327].prcntl = 0.9999280 ;
   zVsPrcntl[328].Z = 5.638 ;  zVsPrcntl[328].prcntl = 0.9999285 ;
   zVsPrcntl[329].Z = 5.647 ;  zVsPrcntl[329].prcntl = 0.9999290 ;
   zVsPrcntl[330].Z = 5.649 ;  zVsPrcntl[330].prcntl = 0.9999295 ;
   zVsPrcntl[331].Z = 5.651 ;  zVsPrcntl[331].prcntl = 0.9999300 ;
   zVsPrcntl[332].Z = 5.659 ;  zVsPrcntl[332].prcntl = 0.9999305 ;
   zVsPrcntl[333].Z = 5.662 ;  zVsPrcntl[333].prcntl = 0.9999310 ;
   zVsPrcntl[334].Z = 5.664 ;  zVsPrcntl[334].prcntl = 0.9999315 ;
   zVsPrcntl[335].Z = 5.666 ;  zVsPrcntl[335].prcntl = 0.9999320 ;
   zVsPrcntl[336].Z = 5.669 ;  zVsPrcntl[336].prcntl = 0.9999325 ;
   zVsPrcntl[337].Z = 5.674 ;  zVsPrcntl[337].prcntl = 0.9999330 ;
   zVsPrcntl[338].Z = 5.675 ;  zVsPrcntl[338].prcntl = 0.9999335 ;
   zVsPrcntl[339].Z = 5.681 ;  zVsPrcntl[339].prcntl = 0.9999340 ;
   zVsPrcntl[340].Z = 5.684 ;  zVsPrcntl[340].prcntl = 0.9999345 ;
   zVsPrcntl[341].Z = 5.685 ;  zVsPrcntl[341].prcntl = 0.9999350 ;
   zVsPrcntl[342].Z = 5.690 ;  zVsPrcntl[342].prcntl = 0.9999355 ;
   zVsPrcntl[343].Z = 5.694 ;  zVsPrcntl[343].prcntl = 0.9999360 ;
   zVsPrcntl[344].Z = 5.698 ;  zVsPrcntl[344].prcntl = 0.9999365 ;
   zVsPrcntl[345].Z = 5.699 ;  zVsPrcntl[345].prcntl = 0.9999370 ;
   zVsPrcntl[346].Z = 5.708 ;  zVsPrcntl[346].prcntl = 0.9999375 ;
   zVsPrcntl[347].Z = 5.712 ;  zVsPrcntl[347].prcntl = 0.9999380 ;
   zVsPrcntl[348].Z = 5.718 ;  zVsPrcntl[348].prcntl = 0.9999385 ;
   zVsPrcntl[349].Z = 5.723 ;  zVsPrcntl[349].prcntl = 0.9999390 ;
   zVsPrcntl[350].Z = 5.725 ;  zVsPrcntl[350].prcntl = 0.9999395 ;
   zVsPrcntl[351].Z = 5.730 ;  zVsPrcntl[351].prcntl = 0.9999400 ;
   zVsPrcntl[352].Z = 5.735 ;  zVsPrcntl[352].prcntl = 0.9999405 ;
   zVsPrcntl[353].Z = 5.735 ;  zVsPrcntl[353].prcntl = 0.9999410 ;
   zVsPrcntl[354].Z = 5.740 ;  zVsPrcntl[354].prcntl = 0.9999415 ;
   zVsPrcntl[355].Z = 5.741 ;  zVsPrcntl[355].prcntl = 0.9999420 ;
   zVsPrcntl[356].Z = 5.746 ;  zVsPrcntl[356].prcntl = 0.9999425 ;
   zVsPrcntl[357].Z = 5.750 ;  zVsPrcntl[357].prcntl = 0.9999430 ;
   zVsPrcntl[358].Z = 5.752 ;  zVsPrcntl[358].prcntl = 0.9999435 ;
   zVsPrcntl[359].Z = 5.758 ;  zVsPrcntl[359].prcntl = 0.9999440 ;
   zVsPrcntl[360].Z = 5.762 ;  zVsPrcntl[360].prcntl = 0.9999445 ;
   zVsPrcntl[361].Z = 5.768 ;  zVsPrcntl[361].prcntl = 0.9999450 ;
   zVsPrcntl[362].Z = 5.771 ;  zVsPrcntl[362].prcntl = 0.9999455 ;
   zVsPrcntl[363].Z = 5.771 ;  zVsPrcntl[363].prcntl = 0.9999460 ;
   zVsPrcntl[364].Z = 5.777 ;  zVsPrcntl[364].prcntl = 0.9999465 ;
   zVsPrcntl[365].Z = 5.782 ;  zVsPrcntl[365].prcntl = 0.9999470 ;
   zVsPrcntl[366].Z = 5.784 ;  zVsPrcntl[366].prcntl = 0.9999475 ;
   zVsPrcntl[367].Z = 5.793 ;  zVsPrcntl[367].prcntl = 0.9999480 ;
   zVsPrcntl[368].Z = 5.795 ;  zVsPrcntl[368].prcntl = 0.9999485 ;
   zVsPrcntl[369].Z = 5.796 ;  zVsPrcntl[369].prcntl = 0.9999490 ;
   zVsPrcntl[370].Z = 5.799 ;  zVsPrcntl[370].prcntl = 0.9999495 ;
   zVsPrcntl[371].Z = 5.801 ;  zVsPrcntl[371].prcntl = 0.9999500 ;
   zVsPrcntl[372].Z = 5.806 ;  zVsPrcntl[372].prcntl = 0.9999505 ;
   zVsPrcntl[373].Z = 5.810 ;  zVsPrcntl[373].prcntl = 0.9999510 ;
   zVsPrcntl[374].Z = 5.813 ;  zVsPrcntl[374].prcntl = 0.9999515 ;
   zVsPrcntl[375].Z = 5.822 ;  zVsPrcntl[375].prcntl = 0.9999520 ;
   zVsPrcntl[376].Z = 5.824 ;  zVsPrcntl[376].prcntl = 0.9999525 ;
   zVsPrcntl[377].Z = 5.828 ;  zVsPrcntl[377].prcntl = 0.9999530 ;
   zVsPrcntl[378].Z = 5.838 ;  zVsPrcntl[378].prcntl = 0.9999535 ;
   zVsPrcntl[379].Z = 5.844 ;  zVsPrcntl[379].prcntl = 0.9999540 ;
   zVsPrcntl[380].Z = 5.845 ;  zVsPrcntl[380].prcntl = 0.9999545 ;
   zVsPrcntl[381].Z = 5.853 ;  zVsPrcntl[381].prcntl = 0.9999550 ;
   zVsPrcntl[382].Z = 5.857 ;  zVsPrcntl[382].prcntl = 0.9999555 ;
   zVsPrcntl[383].Z = 5.862 ;  zVsPrcntl[383].prcntl = 0.9999560 ;
   zVsPrcntl[384].Z = 5.871 ;  zVsPrcntl[384].prcntl = 0.9999565 ;
   zVsPrcntl[385].Z = 5.877 ;  zVsPrcntl[385].prcntl = 0.9999570 ;
   zVsPrcntl[386].Z = 5.882 ;  zVsPrcntl[386].prcntl = 0.9999575 ;
   zVsPrcntl[387].Z = 5.884 ;  zVsPrcntl[387].prcntl = 0.9999580 ;
   zVsPrcntl[388].Z = 5.893 ;  zVsPrcntl[388].prcntl = 0.9999585 ;
   zVsPrcntl[389].Z = 5.901 ;  zVsPrcntl[389].prcntl = 0.9999590 ;
   zVsPrcntl[390].Z = 5.905 ;  zVsPrcntl[390].prcntl = 0.9999595 ;
   zVsPrcntl[391].Z = 5.913 ;  zVsPrcntl[391].prcntl = 0.9999600 ;
   zVsPrcntl[392].Z = 5.917 ;  zVsPrcntl[392].prcntl = 0.9999605 ;
   zVsPrcntl[393].Z = 5.933 ;  zVsPrcntl[393].prcntl = 0.9999610 ;
   zVsPrcntl[394].Z = 5.942 ;  zVsPrcntl[394].prcntl = 0.9999615 ;
   zVsPrcntl[395].Z = 5.948 ;  zVsPrcntl[395].prcntl = 0.9999620 ;
   zVsPrcntl[396].Z = 5.955 ;  zVsPrcntl[396].prcntl = 0.9999625 ;
   zVsPrcntl[397].Z = 5.962 ;  zVsPrcntl[397].prcntl = 0.9999630 ;
   zVsPrcntl[398].Z = 5.974 ;  zVsPrcntl[398].prcntl = 0.9999635 ;
   zVsPrcntl[399].Z = 5.983 ;  zVsPrcntl[399].prcntl = 0.9999640 ;
   zVsPrcntl[400].Z = 5.990 ;  zVsPrcntl[400].prcntl = 0.9999645 ;
   zVsPrcntl[401].Z = 5.996 ;  zVsPrcntl[401].prcntl = 0.9999650 ;
   zVsPrcntl[402].Z = 6.003 ;  zVsPrcntl[402].prcntl = 0.9999655 ;
   zVsPrcntl[403].Z = 6.007 ;  zVsPrcntl[403].prcntl = 0.9999660 ;
   zVsPrcntl[404].Z = 6.014 ;  zVsPrcntl[404].prcntl = 0.9999665 ;
   zVsPrcntl[405].Z = 6.019 ;  zVsPrcntl[405].prcntl = 0.9999670 ;
   zVsPrcntl[406].Z = 6.026 ;  zVsPrcntl[406].prcntl = 0.9999675 ;
   zVsPrcntl[407].Z = 6.034 ;  zVsPrcntl[407].prcntl = 0.9999680 ;
   zVsPrcntl[408].Z = 6.048 ;  zVsPrcntl[408].prcntl = 0.9999685 ;
   zVsPrcntl[409].Z = 6.059 ;  zVsPrcntl[409].prcntl = 0.9999690 ;
   zVsPrcntl[410].Z = 6.069 ;  zVsPrcntl[410].prcntl = 0.9999695 ;
   zVsPrcntl[411].Z = 6.081 ;  zVsPrcntl[411].prcntl = 0.9999700 ;
   zVsPrcntl[412].Z = 6.096 ;  zVsPrcntl[412].prcntl = 0.9999705 ;
   zVsPrcntl[413].Z = 6.104 ;  zVsPrcntl[413].prcntl = 0.9999710 ;
   zVsPrcntl[414].Z = 6.115 ;  zVsPrcntl[414].prcntl = 0.9999715 ;
   zVsPrcntl[415].Z = 6.129 ;  zVsPrcntl[415].prcntl = 0.9999720 ;
   zVsPrcntl[416].Z = 6.139 ;  zVsPrcntl[416].prcntl = 0.9999725 ;
   zVsPrcntl[417].Z = 6.139 ;  zVsPrcntl[417].prcntl = 0.9999730 ;
   zVsPrcntl[418].Z = 6.158 ;  zVsPrcntl[418].prcntl = 0.9999735 ;
   zVsPrcntl[419].Z = 6.180 ;  zVsPrcntl[419].prcntl = 0.9999740 ;
   zVsPrcntl[420].Z = 6.187 ;  zVsPrcntl[420].prcntl = 0.9999745 ;
   zVsPrcntl[421].Z = 6.188 ;  zVsPrcntl[421].prcntl = 0.9999750 ;
   zVsPrcntl[422].Z = 6.194 ;  zVsPrcntl[422].prcntl = 0.9999755 ;
   zVsPrcntl[423].Z = 6.197 ;  zVsPrcntl[423].prcntl = 0.9999760 ;
   zVsPrcntl[424].Z = 6.206 ;  zVsPrcntl[424].prcntl = 0.9999765 ;
   zVsPrcntl[425].Z = 6.221 ;  zVsPrcntl[425].prcntl = 0.9999770 ;
   zVsPrcntl[426].Z = 6.235 ;  zVsPrcntl[426].prcntl = 0.9999775 ;
   zVsPrcntl[427].Z = 6.240 ;  zVsPrcntl[427].prcntl = 0.9999780 ;
   zVsPrcntl[428].Z = 6.251 ;  zVsPrcntl[428].prcntl = 0.9999785 ;
   zVsPrcntl[429].Z = 6.271 ;  zVsPrcntl[429].prcntl = 0.9999790 ;
   zVsPrcntl[430].Z = 6.276 ;  zVsPrcntl[430].prcntl = 0.9999795 ;
   zVsPrcntl[431].Z = 6.285 ;  zVsPrcntl[431].prcntl = 0.9999800 ;
   zVsPrcntl[432].Z = 6.297 ;  zVsPrcntl[432].prcntl = 0.9999805 ;
   zVsPrcntl[433].Z = 6.303 ;  zVsPrcntl[433].prcntl = 0.9999810 ;
   zVsPrcntl[434].Z = 6.310 ;  zVsPrcntl[434].prcntl = 0.9999815 ;
   zVsPrcntl[435].Z = 6.331 ;  zVsPrcntl[435].prcntl = 0.9999820 ;
   zVsPrcntl[436].Z = 6.342 ;  zVsPrcntl[436].prcntl = 0.9999825 ;
   zVsPrcntl[437].Z = 6.345 ;  zVsPrcntl[437].prcntl = 0.9999830 ;
   zVsPrcntl[438].Z = 6.362 ;  zVsPrcntl[438].prcntl = 0.9999835 ;
   zVsPrcntl[439].Z = 6.365 ;  zVsPrcntl[439].prcntl = 0.9999840 ;
   zVsPrcntl[440].Z = 6.395 ;  zVsPrcntl[440].prcntl = 0.9999845 ;
   zVsPrcntl[441].Z = 6.406 ;  zVsPrcntl[441].prcntl = 0.9999850 ;
   zVsPrcntl[442].Z = 6.424 ;  zVsPrcntl[442].prcntl = 0.9999855 ;
   zVsPrcntl[443].Z = 6.434 ;  zVsPrcntl[443].prcntl = 0.9999860 ;
   zVsPrcntl[444].Z = 6.453 ;  zVsPrcntl[444].prcntl = 0.9999865 ;
   zVsPrcntl[445].Z = 6.467 ;  zVsPrcntl[445].prcntl = 0.9999870 ;
   zVsPrcntl[446].Z = 6.473 ;  zVsPrcntl[446].prcntl = 0.9999875 ;
   zVsPrcntl[447].Z = 6.476 ;  zVsPrcntl[447].prcntl = 0.9999880 ;
   zVsPrcntl[448].Z = 6.525 ;  zVsPrcntl[448].prcntl = 0.9999885 ;
   zVsPrcntl[449].Z = 6.526 ;  zVsPrcntl[449].prcntl = 0.9999890 ;
   zVsPrcntl[450].Z = 6.575 ;  zVsPrcntl[450].prcntl = 0.9999895 ;
   zVsPrcntl[451].Z = 6.594 ;  zVsPrcntl[451].prcntl = 0.9999900 ;
   zVsPrcntl[452].Z = 6.600 ;  zVsPrcntl[452].prcntl = 0.9999905 ;
   zVsPrcntl[453].Z = 6.606 ;  zVsPrcntl[453].prcntl = 0.9999910 ;
   zVsPrcntl[454].Z = 6.635 ;  zVsPrcntl[454].prcntl = 0.9999915 ;
   zVsPrcntl[455].Z = 6.655 ;  zVsPrcntl[455].prcntl = 0.9999920 ;
   zVsPrcntl[456].Z = 6.676 ;  zVsPrcntl[456].prcntl = 0.9999925 ;
   zVsPrcntl[457].Z = 6.703 ;  zVsPrcntl[457].prcntl = 0.9999930 ;
   zVsPrcntl[458].Z = 6.741 ;  zVsPrcntl[458].prcntl = 0.9999935 ;
   zVsPrcntl[459].Z = 6.767 ;  zVsPrcntl[459].prcntl = 0.9999940 ;
   zVsPrcntl[460].Z = 6.801 ;  zVsPrcntl[460].prcntl = 0.9999945 ;
   zVsPrcntl[461].Z = 6.834 ;  zVsPrcntl[461].prcntl = 0.9999950 ;
   zVsPrcntl[462].Z = 6.891 ;  zVsPrcntl[462].prcntl = 0.9999955 ;
   zVsPrcntl[463].Z = 6.963 ;  zVsPrcntl[463].prcntl = 0.9999960 ;
   zVsPrcntl[464].Z = 7.064 ;  zVsPrcntl[464].prcntl = 0.9999965 ;
   zVsPrcntl[465].Z = 7.121 ;  zVsPrcntl[465].prcntl = 0.9999970 ;
   zVsPrcntl[466].Z = 7.151 ;  zVsPrcntl[466].prcntl = 0.9999975 ;
   zVsPrcntl[467].Z = 7.238 ;  zVsPrcntl[467].prcntl = 0.9999980 ;
   zVsPrcntl[468].Z = 7.252 ;  zVsPrcntl[468].prcntl = 0.9999985 ;
   zVsPrcntl[469].Z = 7.442 ;  zVsPrcntl[469].prcntl = 0.9999990 ;
   zVsPrcntl[470].Z = 7.837 ;  zVsPrcntl[470].prcntl = 0.9999995 ;

   return ;
}

Block *read_a_prodom_entry(db)

FILE   *db ;

{
   Block    *block ;
   char     line[MAXLINELEN], word[MAXLINELEN], entry_name[MAXLINELEN] ;
   char     *ptr, *iptr ;
   int      i1, i2, num_seqs, rc, max_pos, min_pos, temp ;
   Sequence *sequence_pointer ;
   Residue  *residue_pointer ;


                 /* read until a prodom entry first line - begins with a ">" */
   while((fgets(line, MAXLINELEN, db)) != NULL && line[0] != '>') ;

   if (line[0] != '>') return(NULL) ;

                                                /* allocate space for block */
     CheckMem(block = (Block *) malloc(sizeof(Block))) ;

/* process first line - the description line */

   line[0] = ' ' ;                                        /* get rid of '>' */
                                          /* get first word - sequence name */
   if ((ptr = get_token(line)) == NULL) 
      {
      printf("Error ! Problem in format of ProDom entry description -line\n") ;
      return(NULL) ;
      }

                            /* create accession prefix - "PD" + preceding 0s,
                                entry presumed not to be longer then 5 chars */
   word[0] = 'P' ;   word[1] = 'D' ; 
   i2 = 2 ;
   for(i1=0; i1<(5 - (int) strlen(ptr)); i1++) word[i2++] = '0' ;
   word[i2] = '\0' ;

   strcpy(entry_name, ptr) ;
                                       /* save first word in block accession */
   sprintf(block->ac, "%s%s;", word, entry_name) ;
   sprintf(block->number, "%s%s", word, entry_name) ;

                                              /* save first word in block ID */
   sprintf(block->id, "%s; ProDom_mul", entry_name) ;

                 /* get second word - number of sequences between parethesis */
   if ((ptr = get_token(NULL)) == NULL) 
      {
      printf("Error ! Problem in format of ProDom entry description-line\n") ;
      return(NULL) ;
      }

                                                        /* strip parenthesis */
   if (ptr[0] != '(')
      {
      printf("Error ! Problem in ProDom entry %s\n", entry_name) ;
      printf("second word in description line doesn't begin with a (\n") ;
      return(NULL) ;
      }
   else
      ptr[0] = '0' ;

   if (ptr[strlen(ptr)-1] != ')')
      {
      printf("Error ! Problem in ProDom entry %s\n", entry_name) ;
      printf("second word in description line doesn't end with a )\n") ;
      return(NULL) ;
      }
   else
      ptr[strlen(ptr)-1] = ' ' ;

               /* check that second word is composed of digits and copy it */
   for(iptr=ptr; *iptr != ' ' && isdigit(*iptr); iptr++) ;
   if (*iptr != ' ')
      {
      printf("Error ! Problem in format of ProDom entry %s\n", entry_name) ;
      printf("A non-digit in the number-of-sequences field \"%s\"\n", ptr) ;
      return(NULL) ;
      }

   block->num_sequences = atoi(ptr) ;

   if (block->num_sequences <= 1) 
      {
      printf(
       "Error ! Number of sequences in ProDom entry %s (%d) is less than 2\n",
       entry_name, block->num_sequences) ;
      return(NULL) ;
      }
   else 
      block->max_sequences = block->num_sequences ;

                                                        /* get rest of line */
   for(iptr=ptr; *iptr != '\0'; iptr++) ;       /* find end of current word */

                            /* get rid of leading and trailing white spaces */
   ptr = eat_whitespace(iptr+1) ;
   remove_trailing_whitespace(ptr) ;

                                   /* save string in block description line */
   strncpy(block->de, ptr, SMALL_BUFF_LENGTH) ;
                           /* in case word is longer than SMALL_BUFF_LENGTH 
                                      and thus the last char copied isnt \0 */ 
   block->de[SMALL_BUFF_LENGTH-1] = '\0' ;

   block->num_clusters = block->max_clusters = 1 ; 
   block->motif[0] = '\0';
   block->percentile = 0 ;
   block->strength = 0 ;

                                         /* allocate space for the clusters */
   CheckMem(block->clusters = (Cluster *) 
                             calloc(block->max_clusters, sizeof(Cluster))) ;

/* process next lines - the sequence lines */
  
          /* read all lines until a line starting with a space, EOL or '>' */
/* Note that if a line begining with '>' was read (the description line of 
   the next entry) it won't be read in fetching the next entry and that 
   entry will be lost */

   
   for(num_seqs=0;
       (fgets(line, MAXLINELEN, db)) != NULL && 
       line[0] != '\n' && line[0] != ' '  && line[0] != '>' ;
       num_seqs++)
      {
                                          /* get first word - sequence name */
      if ((ptr = get_token(line)) == NULL) 
         {
         printf(
            "Error ! Problem in format of ProDom entry %s sequence-line %d\n",
                entry_name, num_seqs+1) ;
         return(NULL) ;
         }

           /* temporarily store sequence name, if this is first sequence 
              the sequences length isn't known and no memory allocated yet, 
              place it in block sequence structure after memory is allocated */
      strcpy(word, ptr) ;

                               /* get second word - sequence start position */
      if ((ptr = get_token(NULL)) == NULL) 
         {
         printf(
            "Error ! Problem in format of ProDom entry %s sequence-line %d\n",
                entry_name, num_seqs+1) ;
         return(NULL) ;
         }

           /* temporarily store start position, if this is first sequence 
              the sequences length isn't known and no memory allocated yet, 
              place it in block sequence structure after memory is allocated */

      for(iptr=ptr; *iptr != '\0' && isdigit(*iptr); iptr++) ;
      if (*iptr != '\0')
         {
         printf(
            "Error ! Problem in format of ProDom entry %s sequence-line %d\n",
                entry_name, num_seqs+1) ;
         printf("A non-digit in the sequence start position %s\n", ptr) ;
         return(NULL) ;
         }

      temp = atoi(ptr) ;

                    /* get 3rd word - sequence end position (no use for it) */
      if ((ptr = get_token(NULL)) == NULL) 
         {
         printf(
            "Error ! Problem in format of ProDom entry %s sequence-line %d\n",
                entry_name, num_seqs+1) ;
         return(NULL) ;
         }

                                              /* get 4th word - the sequence */
      if ((ptr = get_token(NULL)) == NULL) 
         {
         printf(
            "Error ! Problem in format of ProDom entry %s sequence-line %d\n",
                entry_name, num_seqs+1) ;
         return(NULL) ;
         }


           /* should have arrived at the begining of 4th word - the sequence */
                /* find out from the first sequence the sequence length 
                   and use it to allocate memory for the sequence structures */
      if (num_seqs == 0)
	 {
         block->width = strlen(ptr) ;

                          /* following part adapted from 
                             blimps procedure read_block_body by Bill Alford */

         /* allocate space for all the Sequences of the block sequence array */
         CheckMem(
             sequence_pointer = 
                  (Sequence *) 
		  calloc(block->max_sequences,sizeof(Sequence))) ;

	                             /* initialize the block sequences array */
	 block->sequences = sequence_pointer ;

	                                  /* allocate space for all residues */
	 CheckMem(
             residue_pointer = 
                 (Residue *) 
                 calloc(block->width * block->max_sequences, 
			sizeof(Residue))) ;

	                                /* initialize the residues 2-d array */
	 CheckMem(
             block->residues = 
                 (Residue **) calloc(block->max_sequences, sizeof(Residue *))) ;

	                                /* initialize sequences and residues */
         for(i1=0; i1<block->max_sequences; i1++) 
            {
	    sequence_pointer[i1].length = block->width;
	    sequence_pointer[i1].sequence =
 		              &(residue_pointer[i1 * block->width]) ;
	    block->residues[i1] = 
                              &(residue_pointer[i1 * block->width]) ;
	    }
         }

                         /* memory now allocated to block sequence structure 
                                              copy name, position and length */
      strncpy(block->sequences[num_seqs].name, word, SMALL_BUFF_LENGTH) ;
                           /* in case word is longer than SMALL_BUFF_LENGTH 
                                      and thus the last char copied isnt \0 */ 
      block->sequences[num_seqs].name[SMALL_BUFF_LENGTH-1] = '\0' ; 

      block->sequences[num_seqs].position = temp ;

      block->sequences[num_seqs].length = block->width ;

/* process next word - the sequence, check length, change gap symbol "." to "-" */

      if (strlen(ptr) != block->width)
	 {
         printf(
            "Error ! Problem in format of ProDom entry sequence-line %d\n",
                num_seqs+1) ;
         printf("Sequence %s has length of %d instead of expected %d\n",
                block->sequences[num_seqs].name, strlen(ptr), 
	        block->width) ;
         return(NULL) ;
         }

      for(iptr=ptr; *iptr != '\0'; iptr++) if (*iptr == '.') *iptr = '-' ;

    /* next part adopted from blimps  procedure next_cluster by Bill Alford */
                     /* read the sequence from the string into the Sequence */

       rc = read_sequence(&(block->sequences[num_seqs]), AA_SEQ, 0, ptr) ; 
				   /* the Sequence, sequence type, starting */
   				   /* position, string with the sequence    */

                                      /* check to see if there was an error */    
       if (rc < 0) 
          {
                      /* Error, more residues in the sequence than expected */
          printf("Error reading sequence %s in block %s,", 
                 block->sequences[num_seqs].name, block->number) ;
          printf("%d more residues in the sequence than the expected %d.\n",
	         -rc, block->sequences[num_seqs].length) ;
          }
       else if (rc < block->sequences[num_seqs].length) 
          {
        /* Error, not enough residues for the sequence, filling with blanks */
          printf("Error reading sequence %s in block %s,", 
                 block->sequences[num_seqs].name, block->number) ;
          printf("not enough residues to fill the sequence.");
          printf("Filling the rest of the sequence with blanks.\n");

                                                     /* filling with blanks */
    	  for(i1=rc; i1<block->sequences[num_seqs].length; i1++) 
	     block->sequences[num_seqs].sequence[i1] = aa_atob['-'];
          }
       else if (rc > block->sequences[num_seqs].length) 
          {
              /* BIG Error, an undocumented return value from read_sequence */
          printf(
              "read_a_prodom_entry(): Error reading sequence %s in block %s,",
 	         block->sequences[num_seqs].name,
                 block->number) ;
          printf("Undocumented return value, %d, from read_sequence().\n",
                 rc) ;
          } /* else, ret_value == seq.length, OK */

                 /* sequences have no weights give all equal weights of 100 */
       block->sequences[num_seqs].weight =  100.0 ;

          /* assign the sequences to the cluster (space has been allocated) */

       block->clusters[0].num_sequences = block->num_sequences ;

       block->clusters[0].sequences = &(block->sequences[0]) ;

       }

      if (num_seqs < 2)
	 {
         printf("Error ! Not enough sequences (%d) in ProDom entry %s\n",
                num_seqs, block->number) ;
         return(NULL) ;
         }
      else if (num_seqs != block->num_sequences)
         {
         printf("Error ! Actual number of sequences in ProDom entry %s\n",
                block->number) ;
         printf("different than what the entry reports\n") ;
         return(NULL) ;
         }

      min_pos = 10000 ;  /* find min and max start positions of sequences */
      max_pos = 0 ;
      for(i1=0; i1<num_seqs; i1++)
	 {
         if (block->sequences[i1].position > max_pos) 
            max_pos = block->sequences[i1].position ;
         if (block->sequences[i1].position < min_pos) 
            min_pos = block->sequences[i1].position ;
	 }

/* add min and max distance from previous block (sequence start) to Ac line */
      sprintf(word, " distance from previous block=(%d,%d)", 
              min_pos, max_pos);
      strcat(block->ac, word) ;

      sprintf(block->bl, "adapted from ProDom entry; width=%d; seqs=%d;",
              block->width, block->num_sequences) ; 

   return(block) ;
}


/*
 * fprint_matrix
 *   Prints a Matrix data structure to a file.  Primarily for debugging purposes.
 * adapted from blimps3.0.0 print_matrix
 *   Parameters: 
 *     Matrix *matrix:  the matrix to print
 *     FILE   *omfp:   the output matrix file pointer
 *   Error Codes: none
 */

void fprint_matrix(matrix,omfp)
     Matrix *matrix;
     FILE *omfp;
{
  int pos;
  int low, high;
  char c;

  int MATRIX_PRINT_WIDTH ;

  if (WWW_FLAG)
     MATRIX_PRINT_WIDTH = 55 ;
  else
     MATRIX_PRINT_WIDTH = 18 ;

  high = MATRIX_PRINT_WIDTH;
  for (low=0; 
       low<high && low<matrix->width; 
       low = (high+=MATRIX_PRINT_WIDTH) - MATRIX_PRINT_WIDTH) {



  fprintf(omfp,"\n");

/* modified following statements to 
  print matrix column number starting from 1 not 0*/

  if (matrix->width > 99) {
    fprintf(omfp,"  |");
    for (pos=low; pos<high &&  pos<matrix->width; pos++) {
      if (pos+1 > 99) {
	fprintf(omfp,"% 4d", (pos+1)%100);
      }
      else {
	fprintf(omfp,"    ");
      }
    }
  }

  fprintf(omfp,"\n");
  if (matrix->width > 9) {
    fprintf(omfp,"  |");
    for (pos=low; pos<high &&  pos<matrix->width; pos++) {
      if (pos+1 > 9) {
	fprintf(omfp,"% 4d", (pos+1-(((pos+1)/100)*100)) / 10);
      }
      else {
	fprintf(omfp,"    ");
      }
    }
  }
  
  fprintf(omfp,"\n");
  fprintf(omfp,"  |");
  for (pos=low; pos<high &&  pos<matrix->width; pos++) {
    fprintf(omfp,"%4d", ((pos-((pos/10)*10))+1)%10);
  }
  
  fprintf(omfp,"\n");
  fprintf(omfp,"--+");
  for (pos=low; pos<high &&  pos<matrix->width; pos++) {
    fprintf(omfp,"----");
  }

  fprintf(omfp,"\n");
  
/* following part modified not to show B, J, O, U and Z */
  for (c='A'; c<='Y'; c++) {
    switch (c)
      {
      case 'B' : continue ;
      case 'J' : continue ;
      case 'O' : continue ;
      case 'U' : continue ;
      }
    fprintf(omfp,"%c |", c);
    for (pos=low; pos<high &&  pos<matrix->width; pos++) {
      fprintf(omfp,"% 4d", round(matrix->weights[aa_atob[c]][pos]));
    }
    fprintf(omfp,"\n");
  }

/* removed printing of c='*' */

  c = '-';
  fprintf(omfp,"%c |", c);
  for (pos=low; pos<high &&  pos<matrix->width; pos++) {
    fprintf(omfp,"% 4d", round(matrix->weights[aa_atob[c]][pos]));
  }
  fprintf(omfp,"\n");

  }

}

