glam2-1064/0000755007451300001540000000000011014153712012124 5ustar charlesgenomeglam2-1064/ChangeLog0000644007451300001540000000177711014153712013712 0ustar charlesgenome------------------------------------------------------------------------ r1063 | m.frith | 2008-05-19 10:02:05 +0900 (Mon, 19 May 2008) | 2 lines Use CFLAGS in Makefiles: requested for Debian packaging ------------------------------------------------------------------------ r1057 | t.bailey | 2008-01-22 10:35:08 +0900 (Tue, 22 Jan 2008) | 2 lines Fixed bug in usage message: z_def was out of orer ------------------------------------------------------------------------ r1053 | t.bailey | 2008-01-03 13:21:04 +0900 (Thu, 03 Jan 2008) | 2 lines Adjust glam2scan to print longer sequence names. ------------------------------------------------------------------------ r1050 | m.frith | 2007-11-30 12:27:20 +0900 (Fri, 30 Nov 2007) | 2 lines Fixed typo in purge usage message ------------------------------------------------------------------------ r1049 | m.frith | 2007-11-30 12:02:29 +0900 (Fri, 30 Nov 2007) | 2 lines Added purge README ------------------------------------------------------------------------ glam2-1064/README0000644007451300001540000000011710663252220013006 0ustar charlesgenomeFor installation and usage instructions, view doc/index.html in a web browser. glam2-1064/src/0000755007451300001540000000000011014153712012713 5ustar charlesgenomeglam2-1064/src/scan_output.c0000644007451300001540000000174310740564057015445 0ustar charlesgenome#include "util.h" #include "scan_output.h" void print_hit(FILE *fp, const alignment *aln, const alphabet *alph) { //const int name_width = 12; const int name_width = 24; // TLB const int coord1_width = digits(aln->coord1); int i; put_pad(' ', name_width + coord1_width + 2, fp); for (i = 0; i < aln->aln_size; ++i) if (aln->seq1[i] == 1) putc('*', fp); else putc('.', fp); putc('\n', fp); fprintf(fp, "%-*.*s", name_width, name_width, aln->name); fprintf(fp, " %d ", aln->coord1); for (i = 0; i < aln->aln_size; ++i) if (aln->seq2[i] < alph->size || aln->seq1[i] == 0) putc(alph->decode[aln->seq2[i]], fp); else putc('.', fp); fprintf(fp, " %d ", aln->coord2); fprintf(fp, "%c ", aln->strand); fprintf(fp, "%#.3g\n", aln->score / xlog(2)); } void print_hits(FILE *fp, const alignment *alns, const data *d) { int i; for (i = 0; i < d->hit_num; ++i) { print_hit(fp, &alns[i], &d->alph); putc('\n', fp); } } glam2-1064/src/column_sample.h0000644007451300001540000000022410653277534015741 0ustar charlesgenome#ifndef COLUMN_SAMPLE_H #define COLUMN_SAMPLE_H #include "glam2.h" void column_sample(glam2_aln *aln, data *d, const double temperature); #endif glam2-1064/src/util.c0000644007451300001540000003111110647604364014050 0ustar charlesgenome#include #include /* isspace */ #include #include #include #include #include #include #include "util.h" const char *prog_name = ""; int can_add_int(const int x, const int y) { if (x >= 0) return INT_MAX - x >= y; else return INT_MIN - x <= y; } /* Uses "div" because "/" is not well defined for negative operands */ int can_mul_int(const int x, const int y) { if (x > 0) { if (y >= 0) return y <= div(INT_MAX, x).quot; else return y >= div(INT_MIN, x).quot; } else if (x < 0) { if (y >= 0) return y <= div(INT_MIN, x).quot; else return y >= div(INT_MAX, x).quot; } else /* x == 0 */ return 1; } void memswap(void *s, void *t, size_t n) { char *a = s; char *b = t; while (n--) { /* if n > 0, do-while might be faster? */ const char tmp = *a; *a++ = *b; *b++ = tmp; } } /* Return the greatest common divisor of a and b: Euclidean algorithm */ static size_t gcd(size_t a, size_t b) { while (b) { size_t c = a % b; a = b; b = c; } return a; } void memrol(void *s, size_t n, size_t k) { size_t cycles; char *start; if (n == 0) /* prevent % 0 */ return; k %= n; /* allow rotations of size > n */ if (k == 0) return; assert(s != NULL); cycles = gcd(n, k); for (start = s; cycles != 0; ++start) { char *x = start + k; char tmp = *x; while (x != start) { char *next = x < (char *)s+n-k ? x+k : x-(n-k); *x = *next; x = next; } *start = tmp; --cycles; } } void memror(void *s, size_t n, size_t k) { size_t cycles; char *start; if (n == 0) /* prevent % 0 */ return; k %= n; /* allow rotations of size > n */ if (k == 0) return; assert(s != NULL); cycles = gcd(n, k); for (start = s; cycles != 0; ++start) { char *x = start + (n-k); char tmp = *x; while (x != start) { char *next = x < (char *)s+k ? x+(n-k) : x-k; *x = *next; x = next; } *start = tmp; --cycles; } } void set_int(int *ptr, const size_t size, const int value) { const int *end = ptr + size; assert(ptr != NULL || size == 0); for (; ptr != end; ++ptr) *ptr = value; } void set_dbl(double *ptr, const size_t size, const double value) { const double *end = ptr + size; assert(ptr != NULL || size == 0); for (; ptr != end; ++ptr) *ptr = value; } int *min_int(const int *ptr, const size_t size) { const int *end = ptr + size; const int *min = ptr; assert(ptr != NULL || size == 0); for (; ptr != end; ++ptr) if (*ptr < *min) min = ptr; return (int *)min; } int *max_int(const int *ptr, const size_t size) { const int *end = ptr + size; const int *max = ptr; assert(ptr != NULL || size == 0); for (; ptr != end; ++ptr) if (*ptr > *max) max = ptr; return (int *)max; } double *min_dbl(const double *ptr, const size_t size) { const double *end = ptr + size; const double *min = ptr; assert(ptr != NULL || size == 0); for (; ptr != end; ++ptr) if (*ptr < *min) min = ptr; return (double *)min; } double *max_dbl(const double *ptr, const size_t size) { const double *end = ptr + size; const double *max = ptr; assert(ptr != NULL || size == 0); for (; ptr != end; ++ptr) if (*ptr > *max) max = ptr; return (double *)max; } int sum_int(const int *ptr, const size_t size) { const int *end = ptr + size; int sum = 0; assert(ptr != NULL || size == 0); for (; ptr != end; ++ptr) { assert(can_add_int(sum, *ptr)); sum += *ptr; } return sum; } double sum_dbl(const double *ptr, const size_t size) { const double *end = ptr + size; double sum = 0; assert(ptr != NULL || size == 0); for (; ptr != end; ++ptr) sum += *ptr; return sum; } void add_int(int *ptr, const size_t size, const int x) { const int *end = ptr + size; assert(ptr != NULL || size == 0); for (; ptr != end; ++ptr) { assert(can_add_int(x, *ptr)); *ptr += x; } } void add_dbl(double *ptr, const size_t size, const double x) { const double *end = ptr + size; assert(ptr != NULL || size == 0); for (; ptr != end; ++ptr) *ptr += x; } void mul_dbl(double *ptr, const size_t size, const double x) { const double *end = ptr + size; assert(ptr != NULL || size == 0); for (; ptr != end; ++ptr) *ptr *= x; } void div_dbl(double *ptr, const size_t size, const double x) { const double *end = ptr + size; assert(ptr != NULL || size == 0); assert(x != 0 || size == 0); for (; ptr != end; ++ptr) *ptr /= x; } void pow_dbl(double *ptr, const size_t size, const double x) { const double *end = ptr + size; assert(ptr != NULL || size == 0); for (; ptr != end; ++ptr) *ptr = xpow(*ptr, x); } void normalize(double *ptr, const size_t size) { const double tot = sum_dbl(ptr, size); div_dbl(ptr, size, tot); } double log_sum(const double *ptr, const size_t size) { if (size == 1) /* do special case faster */ return *ptr; else { const double max = *max_dbl(ptr, size); const double *end = ptr + size; double sum = 0; assert(size > 0); for (; ptr != end; ++ptr) sum += xexp(*ptr - max); return xlog(sum) + max; } } int rand_int(const unsigned n) { /* from C FAQ */ unsigned d, threshold, r; assert(n > 0); assert(n <= RAND_MAX + 1u); d = (RAND_MAX + 1u) / n; threshold = d * n; do { r = rand(); } while(r >= threshold); return r / d; } double rand_dbl(const double n) { double r; assert(n == n); /* check for NaN */ assert(n > 0); assert(n <= DBL_MAX); /* check for inf */ do { r = rand() / (RAND_MAX + 1.0) * n; /* from C FAQ */ } while (r >= n); /* r can equal n when n is tiny (e.g. < DBL_MIN) */ return r; } double *pick_dbl(const double *ptr, const size_t size) { const double tot = sum_dbl(ptr, size); const double r = rand_dbl(tot); const double *end = ptr + size; double s = 0; for (; ptr != end; ++ptr) if ((s += *ptr) > r) break; assert(ptr != end); return (double *)ptr; /* strange that this cast is needed */ } void shuffle(void *base, size_t n, size_t size) { for (; n > 1; --n) { const int r = rand_int(n); memswap((char *)base + (n-1) * size, (char *)base + r * size, size); } } int digits(int n) { int d = 1; assert(n >= 0); while (n /= 10) ++d; return d; } void die(const char *fmt, ...) { va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); exit(EXIT_FAILURE); } void *xmalloc(size_t size) { void *p = malloc(size); if (p == NULL && size != 0) die("%s: error allocating %lu bytes: %s\n", prog_name, (unsigned long)size, strerror(errno)); return p; } void *xcalloc(size_t nmemb, size_t size) { void *p = calloc(nmemb, size); if (p == NULL && nmemb != 0 && size != 0) die("%s: error calculated-allocating %lu * %lu bytes: %s\n", prog_name, (unsigned long)nmemb, (unsigned long)size, strerror(errno)); return p; } void *xrealloc(void *p, size_t size) { void *q = realloc(p, size); if (q == NULL && size != 0) die("%s: error reallocating %lu bytes: %s\n", prog_name, (unsigned long)size, strerror(errno)); return q; } char *xstrdup(const char *cs) { char *t; assert(cs != NULL); t = xmalloc(strlen(cs) + 1); return strcpy(t, cs); } void *xmemdup(const void *cs, size_t n) { char *t; assert(cs != NULL); t = xmalloc(n); return memcpy(t, cs, n); } char *strtrunc(char *s, size_t n) { size_t i; assert(s != NULL); for (i = 0; i != n; ++i) if (s[i] == 0) return s; s[n] = 0; return s; } void *xmalloc2(size_t rows, size_t cols) { char **ptrs; size_t i; if (rows > (size_t)-1 / sizeof(char *)) die("%s: memory requirement too large: %lu * %lu bytes\n", prog_name, (unsigned long)rows, (unsigned long)sizeof(char *)); XMALLOC(ptrs, rows); for (i = 0; i < rows; ++i) ptrs[i] = xmalloc(cols); return ptrs; } void *xcalloc2(size_t rows, size_t cols, size_t size) { char **ptrs; size_t i; if (rows > (size_t)-1 / sizeof(char *)) die("%s: memory requirement too large: %lu * %lu bytes\n", prog_name, (unsigned long)rows, (unsigned long)sizeof(char *)); XMALLOC(ptrs, rows); for (i = 0; i < rows; ++i) ptrs[i] = xcalloc(cols, size); return ptrs; } void free2(void *p, size_t rows) { char **ptrs = p; size_t i; if (p == NULL) /* same behaviour as free (do we want this?) */ return; for (i = 0; i < rows; ++i) free(ptrs[i]); free(ptrs); } FILE *xfopen(const char *filename, const char *mode) { FILE *fp; assert(filename != NULL); assert(mode != NULL); if (strcmp(filename, "-") == 0) { if (strcmp(mode, "r") == 0) return stdin; else if (strcmp(mode, "w") == 0 || strcmp(mode, "a") == 0) return stdout; else assert(0); /* shouldn't get here (?) */ } fp = fopen(filename, mode); if (fp == NULL) die("%s: error opening file %s: %s\n", prog_name, filename, strerror(errno)); return fp; } int xfclose(FILE *stream) { int x = fclose(stream); if (x == EOF) die("%s: error closing file: %s\n", prog_name, strerror(errno)); return x; } int xungetc(int c, FILE *stream) { int x = ungetc(c, stream); if (x == EOF) die("%s: error reading file: %s\n", prog_name, strerror(errno)); return x; } size_t xgetline(char **lineptr, size_t *n, FILE *stream) { size_t i = 0; /* number of characters read so far */ int c; /* this character */ assert(lineptr != NULL); if (*lineptr == NULL || *n == 0) { *n = 1; /* should probably use a bigger starting size */ *lineptr = XREALLOC(*lineptr, *n); } while((c = getc(stream)) != EOF) { ++i; if (i == *n) { *n = *n * 2; if (*n <= i) /* overflow */ die("%s: line too long: >= %lu\n", prog_name, (unsigned long)i); *lineptr = XREALLOC(*lineptr, *n); } (*lineptr)[i-1] = c; /* int -> char! */ if (c == '\n') break; } if (ferror(stream)) die("%s: error reading file: %s\n", prog_name, strerror(errno)); assert(i < *n); (*lineptr)[i] = '\0'; return i; } size_t chomp(char *s, size_t n) { assert(s != NULL); if (n != 0 && s[n-1] == '\n') { --n; s[n] = '\0'; } return n; } char *skipws(const char *cs) { assert(cs != NULL); while (isspace((unsigned char)*cs)) ++cs; return (char *)cs; } char *skipnw(const char *cs) { assert(cs != NULL); while (!isspace((unsigned char)*cs) && *cs != '\0') ++cs; return (char *)cs; } #if 0 /* is this function useful? */ char *next_word(char **stringp) { unsigned char *beg; /* ??? isspace needs unsigned */ unsigned char *end; /* ??? isspace needs unsigned */ assert(stringp != NULL); if (*stringp == NULL) return NULL; for (beg = *stringp; isspace(*beg); ++beg) ; for (end = beg, !isspace(*end) && *end != '\0'; ++end) ; if (*beg == '\0') beg = NULL; if (end == '\0') end = NULL; else { *end = '\0'; ++end; /* end might now point to '\0' */ } *stringp = end; return beg; } #endif double xexp(double x) { double z; errno = 0; z = exp(x); if (errno != 0 && !(errno == ERANGE && z == 0)) /* allow underflow */ die("%s: error exponentiating %g: %s\n", prog_name, x, strerror(errno)); return z; } double xlog(double x) { double z; errno = 0; z = log(x); assert(!(errno == ERANGE && z == 0)); /* underflow should be impossible */ if (errno != 0) die("%s: error taking logarithm of %g: %s\n", prog_name, x, strerror(errno)); return z; } double xpow(double x, double y) { double z; errno = 0; z = pow(x, y); if (errno != 0 && !(errno == ERANGE && z == 0)) /* allow underflow */ die("%s: error raising %g to the power of %g: %s\n", prog_name, x, y, strerror(errno)); return z; } double xatof(const char *s) { double out; char *endp; errno = 0; out = strtod(s, &endp); if (endp == s || *endp != '\0' || errno == ERANGE) /* catches underflow */ die("%s: error converting %s to double\n", prog_name, s); return out; } int xatoi(const char *s) { long out; char *endp; errno = 0; out = strtol(s, &endp, 10); if (endp == s || *endp != '\0' || errno == ERANGE || out > INT_MAX || out < INT_MIN) die("%s: error converting %s to integer\n", prog_name, s); return out; } unsigned xatou(const char *s) { unsigned long out; char *endp; errno = 0; out = strtoul(s, &endp, 10); if (endp == s || *endp != '\0' || errno == ERANGE || out > UINT_MAX) die("%s: error converting %s to unsigned integer\n", prog_name, s); return (unsigned)out; } int put_pad(int c, int n, FILE *stream) { assert(n >= 0); while (n--) if (putc(c, stream) == EOF) return EOF; return (unsigned char)c; /* like fputc(?) */ } glam2-1064/src/site_sample.h0000644007451300001540000000043310653277354015412 0ustar charlesgenome#ifndef SITE_SAMPLE_H #define SITE_SAMPLE_H #include "glam2.h" void unalign(glam2_aln *aln, const int seq_pick, const fasta *f); void realign(glam2_aln *aln, const int seq_pick, const fasta *f); void site_sample(glam2_aln *aln, int seq_pick, data *d, double temperature); #endif glam2-1064/src/output.h0000644007451300001540000000036410653300077014435 0ustar charlesgenome#ifndef OUTPUT_H #define OUTPUT_H #include #include "glam2.h" void print_aln(FILE *fp, glam2_aln *aln, data *d); void print_aln_info(FILE *fp, glam2_aln *aln, data *d); void print_alns(FILE *fp, glam2_aln *alns, data *d); #endif glam2-1064/src/dna_prior.c0000644007451300001540000000022510647016166015047 0ustar charlesgenome#include "dna_prior.h" void dmix_dna(dirichlet_mix *m) { double a[] = { 0.4, 0.4, 0.4, 0.4 }; double w[] = { 1 }; dmix_init(m, 1, 4, w, a); } glam2-1064/src/version.h0000644007451300001540000000000711014153712014546 0ustar charlesgenome"1064" glam2-1064/src/util.h0000644007451300001540000001413710647604447014070 0ustar charlesgenome/* Useful, general-purpose functions */ #ifndef UTIL_H #define UTIL_H #include /* FILE */ #include /* qsort */ #include /* memcpy, memmove, memset */ #define COPY(s, t, n) memcpy(s, t, (n) * sizeof *(s)) #define MOVE(s, t, n) memmove(s, t, (n) * sizeof *(s)) #define ZERO(s, n) memset(s, 0, (n) * sizeof *(s)) #define XDUP(s, n) xmemdup(s, (n) * sizeof *(s)) #define SORT(base, n, cmp) qsort(base, n, sizeof *(base), cmp) #define ROL(s, n, k) memrol(s, (n) * sizeof *(s), (k) * sizeof *(s)) #define ROR(s, n, k) memror(s, (n) * sizeof *(s), (k) * sizeof *(s)) #define SHUFFLE(base, n) shuffle(base, n, sizeof *(base)) #define XREALLOC(p, n) xrealloc(p, (n) * sizeof *(p)) #define XMALLOC(p, n) ((p) = xmalloc((n) * sizeof *(p))) #define COUNTOF(a) (sizeof (a) / sizeof *(a)) extern const char *prog_name; /* set this to get nicer error messages */ /* Put some of these functions in the header so they may get inlined? */ /* Should some of these return their 1st argument rather than "void"? */ /* Return 1 if x and y can be added without overflow, 0 otherwise */ int can_add_int(const int x, const int y); /* Return 1 if x and y can be multiplied without overflow, 0 otherwise */ int can_mul_int(const int x, const int y); /* Swap memory blocks s and t of size n */ void memswap(void *s, void *t, size_t n); /* Rotate memory k bytes to the left. Works for all values of k */ void memrol(void *s, size_t n, size_t k); /* Rotate memory k bytes to the right. Works for all values of k */ void memror(void *s, size_t n, size_t k); /* Set an array of ints all to "value" */ void set_int(int *ptr, const size_t size, const int value); /* Set an array of doubles all to "value" */ void set_dbl(double *ptr, const size_t size, const double value); /* Get the minimum element of a set of ints */ /* In case of ties, it will return the first one */ /* If size=0, it will return ptr */ int *min_int(const int *ptr, const size_t size); /* Get the maximum element of a set of ints */ /* In case of ties, it will return the first one */ /* If size=0, it will return ptr */ int *max_int(const int *ptr, const size_t size); /* Get the minimum element of a set of doubles */ /* In case of ties, it will return the first one */ /* If size=0, it will return ptr */ double *min_dbl(const double *ptr, const size_t size); /* Get the maximum element of a set of doubles */ /* In case of ties, it will return the first one */ /* If size=0, it will return ptr */ double *max_dbl(const double *ptr, const size_t size); /* Get the sum of a set of ints */ int sum_int(const int *ptr, const size_t size); /* Get the sum of a set of doubles */ double sum_dbl(const double *ptr, const size_t size); /* Add x to each member of a set of ints */ void add_int(int *ptr, const size_t size, const int x); /* Add x to each member of a set of doubles */ void add_dbl(double *ptr, const size_t size, const double x); /* Multiply each member of a set of doubles by x */ void mul_dbl(double *ptr, const size_t size, const double x); /* Divide each member of a set of doubles by x */ void div_dbl(double *ptr, const size_t size, const double x); /* Raise each member of a set of doubles to the power of x */ void pow_dbl(double *ptr, const size_t size, const double x); /* Divide each member of a set of doubles by their sum, so they sum to 1 */ void normalize(double *ptr, const size_t size); /* Get the sum of a set of doubles, working in log space. size must be >0 */ double log_sum(const double *ptr, const size_t size); /* Random integer between 0 (inclusive) and n (exclusive) */ /* n must be > 0 and <= RAND_MAX+1 */ int rand_int(const unsigned n); /* Random double between 0 (inclusive) and n (exclusive) */ /* n must be > 0 */ double rand_dbl(const double n); /* Randomly pick a member of a set of doubles, weighted by their values */ double *pick_dbl(const double *ptr, const size_t size); /* Randomly shuffle an array */ void shuffle(void *base, size_t n, size_t size); /* Get the number of digits in an integer (must be >= 0) */ int digits(int n); /* Print message to stderr and exit */ void die(const char *fmt, ...); /* malloc or die */ void *xmalloc(size_t size); /* calloc or die */ void *xcalloc(size_t nmemb, size_t size); /* realloc or die */ void *xrealloc(void *p, size_t size); /* strdup or die */ char *xstrdup(const char *cs); /* memdup or die */ void *xmemdup(const void *cs, size_t n); /* If string s is longer than n, truncate it to length n */ char *strtrunc(char *s, size_t n); /* Allocate memory for a two-dimensional array or die */ void *xmalloc2(size_t rows, size_t cols); /* Allocate memory for a two-dimensional array with zero fill or die */ void *xcalloc2(size_t rows, size_t cols, size_t size); /* Free memory allocated by xmalloc2 */ /* Does nothing if p is NULL */ void free2(void *p, size_t rows); /* fopen or die */ /* if filename is "-", stdin or stdout is returned, and mode must be r|w|a */ FILE *xfopen(const char *filename, const char *mode); /* fclose or die */ int xfclose(FILE *stream); /* ungetc or die */ int xungetc(int c, FILE *stream); /* getline or die: returns the number of characters read */ size_t xgetline(char **lineptr, size_t *n, FILE *stream); /* Remove final newline, if any, from string s of length n */ /* Returns new length */ size_t chomp(char *s, size_t n); /* Skip whitespace: return pointer to 1st non-white character */ char *skipws(const char *cs); /* Skip non-white: return pointer to 1st whitespace character or '\0' */ /* (An alternative would be to return NULL if there's no whitespace) */ char *skipnw(const char *cs); /* exp or die */ double xexp(double x); /* log or die */ double xlog(double x); /* pow or die */ double xpow(double x, double y); /* The following functions convert strings to numbers, dying on failure */ /* Failure = non-numeric, extra chars after number, overflow, underflow */ /* Leading whitespace is allowed */ double xatof(const char *s); int xatoi(const char *s); /* Bizarrely, xatou allows -ve numbers, because so does strtoul */ unsigned xatou(const char *s); /* Writes c to stream n times (n must be >= 0): returns c or EOF on error */ int put_pad(int c, int n, FILE *stream); #endif glam2-1064/src/args.h0000644007451300001540000000175010714467561014043 0ustar charlesgenome/* data structure to hold command line arguments */ #ifndef ARGS_H #define ARGS_H #include typedef struct { int stop_after; int runs; const char *out_file; int two_strands; int min_width; int max_width; int min_seqs; /* minimum number of sequences in the alignment */ int init_width; /* initial width */ double delete_pseudo; double no_delete_pseudo; double insert_pseudo; double no_insert_pseudo; int profile; double column_sample_rate; int algorithm; /* 0 = fast, 1 = slow, 2 = FFT */ double temperature; double cool; double frozen; /* lowest allowed temperature, to avoid numerical problems */ const char *dirichlet_file; double bg_pseudo; /* "weight" of background pseudocounts */ unsigned seed; /* seed for random number generator */ const char *alph_name; /* "n" = nucleotide, "p" = protein */ const char *seq_file; } args; void printargs(FILE *fp, int argc, char **argv); void getargs(args *a, int argc, char **argv); #endif glam2-1064/src/output.c0000644007451300001540000001115210653300155014422 0ustar charlesgenome/* GLAM2 output functions */ #include /* free */ #include "util.h" #include "output.h" static const int name_width = 12; /* Get maximum insertion between columns col and col+1 */ static int max_right_insert(const glam2_aln *aln, const int col) { int max = 0; int i; for (i = 0; i < aln->seq_num; ++i) if (ALIGNED(aln, i)) { int ins = RIGHT_INSERT(aln, col, i); if (ins > max) max = ins; } return max; } /* Print an alignment in a nice format */ void print_aln(FILE *fp, glam2_aln *aln, data *d) { const int width = aln->width; const glam2_col *cols = aln->cols; const fasta *seqs = d->seqs.f; const int coord_width = digits(d->seqs.maxlen); int *max_insert = xmalloc(width * sizeof(int)); int i, j, k; /* get maximum insert size at each position: */ for (i = 0; i < width; ++i) max_insert[i] = max_right_insert(aln, i); put_pad(' ', name_width + coord_width + 2, fp); for (j = 0; j < width; ++j) { putc('*', fp); put_pad('.', max_insert[j], fp); } putc('\n', fp); for (i = 0; i < aln->seq_num; ++i) { const int strand = aln->strands[i]; const int *seq = strand == '+' ? seqs[i].seq : seqs[i].rcseq; const int start = LEFT_POS(&cols[0], i); /* zero-based coordinate */ const int end = RIGHT_POS(&cols[width-1], i); const int coord1 = strand == '+' ? start+1 : seqs[i].seqlen - start; const int coord2 = strand == '+' ? end : seqs[i].seqlen - end + 1; if (!ALIGNED(aln, i)) continue; fprintf(fp, "%-*.*s", name_width, name_width, seqs[i].title); fprintf(fp, " %*d ", coord_width, coord1); for (j = 0; j < width; ++j) { int pos = LEFT_POS(&cols[j], i); if (cols[j].matches[i]) putc(d->alph.decode[seq[pos++]], fp); else putc('.', fp); for (k = 0; k < RIGHT_INSERT(aln, j, i); ++k) putc(d->alph.decode[seq[pos++]], fp); put_pad('.', max_insert[j] - k, fp); } fprintf(fp, " %*d ", coord_width, coord2); fprintf(fp, "%c ", strand); fprintf(fp, "%#.3g\n", marginal_score(&d->scorer, aln, i, &seqs[i]) / xlog(2)); } free(max_insert); } /* Print a multilevel consensus sequence, like MEME */ void print_consensus(FILE *fp, const glam2_aln *aln, const data *d) { const int width = aln->width; const glam2_col *cols = aln->cols; const int alph_size = cols->alph_size; const int coord_width = digits(d->seqs.maxlen); int **counts = xmalloc2(width, alph_size * sizeof(int)); int *max_insert = xmalloc(width * sizeof(int)); int i, j; for (i = 0; i < width; ++i) COPY(counts[i], cols[i].emission_counts, alph_size); /* get maximum insert size at each position: */ for (i = 0; i < width; ++i) max_insert[i] = max_right_insert(aln, i); for (i = 0; i < alph_size; ++i) { int end_flag = 1; for (j = 0; j < width; ++j) { const int *m = max_int(counts[j], alph_size); if (*m * 5 >= cols[j].match_count && *m > 0) end_flag = 0; } if (end_flag) break; put_pad(' ', name_width + coord_width + 2, fp); for (j = 0; j < width; ++j) { int *m = max_int(counts[j], alph_size); if (*m * 5 >= cols[j].match_count && *m > 0) putc(d->alph.decode[m - counts[j]], fp); else putc(' ', fp); *m = 0; put_pad(' ', max_insert[j], fp); } putc('\n', fp); } free(max_insert); free2(counts, width); } /* Print residue counts, indel counts, and score for each column */ void print_col_scores(FILE *fp, glam2_aln *aln, data *d) { int i, j; for (j = 0; j < d->alph.size; ++j) fprintf(fp, "%2c ", d->alph.decode[j]); fputs("Del Ins Score\n", fp); for (i = 0; i < aln->width; ++i) { if (i != 0) { put_pad(' ', 3 * d->alph.size, fp); fprintf(fp, " %3d ", aln->insert_counts[i-1]); fprintf(fp, "% #.3g\n", insertion_score(&d->scorer, aln->insert_counts[i-1], aln->aligned_seq) / xlog(2)); } for (j = 0; j < d->alph.size; ++j) fprintf(fp, "%2d ", aln->cols[i].emission_counts[j]); fprintf(fp, "%3d ", aln->cols[i].delete_count); fprintf(fp, "% #.3g\n", column_score(&d->scorer, &aln->cols[i]) / xlog(2)); } } /* Print extended information about an alignment */ void print_aln_info(FILE *fp, glam2_aln *aln, data *d) { fprintf(fp, "Score: %#g Columns: %d Sequences: %d\n", aln->score / xlog(2), aln->width, aln->aligned_seq); putc('\n', fp); print_aln(fp, aln, d); putc('\n', fp); print_consensus(fp, aln, d); putc('\n', fp); print_col_scores(fp, aln, d); putc('\n', fp); } /* Print a list of alignments */ void print_alns(FILE *fp, glam2_aln *alns, data *d) { int i; for (i = 0; i < d->a.runs; ++i) print_aln_info(fp, &alns[i], d); } glam2-1064/src/glam2_aln.c0000644007451300001540000000333210653314110014713 0ustar charlesgenome#include #include "util.h" #include "glam2_aln.h" void col_init(glam2_col *col, int seq_num, int alph_size) { col->seq_num = seq_num; XMALLOC(col->positions, seq_num); XMALLOC(col->matches, seq_num); col->alph_size = alph_size; XMALLOC(col->emission_counts, alph_size + 1); } void aln_init(glam2_aln *aln, int seq_num, int max_width, int alph_size) { int i; aln->seq_num = seq_num; XMALLOC(aln->cols, max_width); for (i = 0; i < max_width; ++i) col_init(&aln->cols[i], seq_num, alph_size); XMALLOC(aln->strands, seq_num); XMALLOC(aln->insert_counts, max_width); /* back is unused */ } static void col_zero(glam2_col *col) { ZERO(col->emission_counts, col->alph_size + 1); col->match_count = 0; col->delete_count = 0; } void aln_zero(glam2_aln *aln) { int i; ZERO(aln->strands, aln->seq_num); /* set all sequences unaligned */ aln->aligned_seq = 0; ZERO(aln->insert_counts, aln->width); /* last element isn't really used */ for (i = 0; i < aln->width; ++i) col_zero(&aln->cols[i]); } void col_copy(glam2_col *a, const glam2_col *b) { assert(a->seq_num == b->seq_num); assert(a->alph_size == b->alph_size); COPY(a->positions, b->positions, b->seq_num); COPY(a->matches, b->matches, b->seq_num); COPY(a->emission_counts, b->emission_counts, b->alph_size+1); a->match_count = b->match_count; a->delete_count = b->delete_count; } void aln_copy(glam2_aln *a, const glam2_aln *b) { int i; assert(a->seq_num == b->seq_num); a->width = b->width; for (i = 0; i < b->width; ++i) col_copy(&a->cols[i], &b->cols[i]); COPY(a->strands, b->strands, b->seq_num); a->aligned_seq = b->aligned_seq; COPY(a->insert_counts, b->insert_counts, b->width); a->score = b->score; } glam2-1064/src/glam2mask.c0000644007451300001540000000454610647047220014755 0ustar charlesgenome/* Mask a glam2 motif in FASTA-format sequences */ #include #include /* free */ #include /* strcmp */ #include /* non-ANSI */ #include "util.h" #include "fasta.h" #include "alignment.h" void mask_seqs(const alignment *a, int mask_char, FILE *in, FILE *out) { static const int name_width = 12; /* max name width for glam2 */ static const int line_size = 60; /* line size for FASTA-format output */ fasta f; size_t i = 0; while (fasta_read(&f, in) != EOF) { const aligned_seq *s = &a->seqs[i]; /* mangle the title in the same way as glam2: */ char *title = xstrdup(f.title); first_word(title); strtrunc(title, name_width); if (i != a->seq_num && strcmp(title, s->name) == 0) { int pos = xatoi(s->start)-1; size_t j; for (j = 0; s->seq[j] != 0; ++j) { if (pos >= f.seqlen) break; /* die with error message? */ if (s->seq[j] != '.') { if (a->key_positions[j] == '*') f.seq[pos] = mask_char; ++pos; } } ++i; } free(title); put_fasta(&f, line_size, out); free_fasta(&f); } if (i != a->seq_num) die("%s: didn't find %s among the sequences\n", prog_name, a->seqs[i].name); } static void usage(void) { die("\ Usage: glam2mask [options] my_motif.glam2 my_seqs.fa\n\ Options (default settings):\n\ -o: output file (stdout)\n\ -x: mask character (x)\n\ "); } int main(int argc, char **argv) { const char *mot_file; const char *seq_file; const char *out_file = "-"; int mask_char = 'x'; FILE *in; FILE *out; alignment aln; int c; prog_name = "glam2mask"; /* for error messages */ while ((c = getopt(argc, argv, "o:x:")) != -1) { /* non-ANSI */ switch (c) { case 'o': out_file = optarg; break; case 'x': mask_char = *optarg; break; case '?': usage(); } } if (optind != argc-2) usage(); mot_file = argv[optind++]; seq_file = argv[optind++]; in = xfopen(mot_file, "r"); aln_read(&aln, in); xfclose(in); if (aln.key_positions == NULL) die("%s: no motif found in %s\n", prog_name, mot_file); if (!aln_same_lengths(&aln)) die("%s: unequal aligned lengths in %s\n", prog_name, mot_file); in = xfopen(seq_file, "r"); out = xfopen(out_file, "w"); mask_seqs(&aln, mask_char, in, out); xfclose(in); xfclose(out); aln_free(&aln); return 0; } glam2-1064/src/alphabet.c0000644007451300001540000000604710651003554014652 0ustar charlesgenome#include #include #include #include "util.h" #include "alphabet.h" /* almost general-purpose enough to go into util? */ static void counts2probs(double *probs, const int *counts, const size_t size) { const double tot = sum_int(counts, size); size_t i; for (i = 0; i < size; ++i) probs[i] = counts[i] / tot; } void alphabet_n(alphabet *a) { const char *string = "acgt"; const int counts[] = { 1, 1, 1, 1 }; int i; a->size = strlen(string); set_int(a->encode, UCHAR_MAX+1, a->size); for (i = 0; i < a->size; ++i) { const char x = string[i]; a->encode[tolower(x)] = i; a->encode[toupper(x)] = i; a->decode[i] = tolower(x); } a->encode['u'] = a->encode['t']; /* for RNA */ a->encode['U'] = a->encode['T']; /* for RNA */ a->decode[a->size] = 'N'; /* wildcard symbol */ XMALLOC(a->prob, a->size); counts2probs(a->prob, counts, a->size); } void alphabet_p(alphabet *a) { const char *string = "acdefghiklmnpqrstvwy"; const int counts[] = { 35155, 8669, 24161, 28354, 17367, 33229, 9906, 23161, 25872, 40625, 10101, 20212, 23435, 19208, 23105, 32070, 26311, 29012, 5990, 14488 }; int i; a->size = strlen(string); set_int(a->encode, UCHAR_MAX+1, a->size); for (i = 0; i < a->size; ++i) { const char x = string[i]; a->encode[tolower(x)] = i; a->encode[toupper(x)] = i; a->decode[i] = toupper(x); } a->decode[a->size] = 'x'; /* wildcard symbol */ XMALLOC(a->prob, a->size); counts2probs(a->prob, counts, a->size); } void alphabet_read(alphabet *a, FILE *fp) { int c; int state = 0; double tot; a->size = 0; set_int(a->encode, UCHAR_MAX+1, -1); a->prob = NULL; while((c = getc(fp)) != EOF) { if (c == '#') { /* start of comment */ fscanf(fp, "%*[^\n]"); /* skip line */ } else if (c == '\n') { state = 0; } else if (isspace(c)) { if (state == 1) { double p = 0; const int r = fscanf(fp, "%lf", &p); if (r == 1 && p <= 0) die("%s: error reading alphabet file: abundance %g should be > 0\n", prog_name, p); a->prob[a->size - 1] = p; fscanf(fp, "%*[^\n]"); /* skip line */ } } else { if (state == 0) { ++a->size; a->decode[a->size - 1] = c; a->prob = XREALLOC(a->prob, a->size); a->prob[a->size - 1] = 1; /* default abundance */ state = 1; } if (a->encode[c] != -1 && a->encode[c] != a->size - 1) die("%s: error reading alphabet file: found %c twice\n", prog_name, c); a->encode[c] = a->size - 1; } } if (ferror(fp)) die("%s: error reading alphabet file: %s\n", prog_name, strerror(errno)); if (a->size <= 1) /* disallow size zero alphabet */ die("%s: error reading alphabet file: no alphabet\n", prog_name); --a->size; /* last line has the wildcard symbol */ for (c = 0; c <= UCHAR_MAX; ++c) if (a->encode[c] == -1) a->encode[c] = a->size; tot = sum_dbl(a->prob, a->size); div_dbl(a->prob, a->size, tot); } void alphabet_free(alphabet *a) { assert(a != NULL); free(a->prob); } glam2-1064/src/init.h0000644007451300001540000000011710653313622014034 0ustar charlesgenome#ifndef INIT_H #define INIT_H #include "glam2.h" void init(data *d); #endif glam2-1064/src/scan.h0000644007451300001540000000206210647111034014012 0ustar charlesgenome/* Data structures for GLAM2 scanner */ #ifndef SCAN_H #define SCAN_H #include #include "alphabet.h" #include "fasta.h" #include "dirichlet.h" #include "motif.h" #include "scan_args.h" typedef struct { char *name; char strand; int coord1; int coord2; int aln_size; int *seq1; int *seq2; double score; } alignment; typedef struct { beta d_prior; /* prior for deletions */ beta i_prior; /* prior for insertions */ dirichlet_mix e_prior; /* prior for emissions */ } glam2_scorer; /* merge this with the one in glam2.h */ typedef struct { args a; FILE *out; alphabet alph; motif m; glam2_scorer scorer; double **match_scores; double *delete_scores; double *insert_scores; int dp_seqlen; /* sequence length that dp_mat is sized for */ double **dp_mat; char **forbidden; /* forbidden match positions in dp_mat */ fasta f; /* the sequence */ int *hit_positions; int *hit_matches; /* 0=deletion, 1=match */ alignment *hits; int hit_num; /* how many alignments are stored in hits so far */ } data; #endif glam2-1064/src/init.c0000644007451300001540000001245310714467571014050 0ustar charlesgenome/* Initialization done once only at program startup */ #include #include /* srand */ #include /* strcmp */ #include "util.h" #include "recode3_20comp.h" #include "dna_prior.h" #include "init.h" void init_alph(alphabet *alph, const char *name) { if (strcmp(name, "n") == 0) { /* nucleotide alphabet */ alphabet_n(alph); } else if (strcmp(name, "p") == 0) { /* protein alphabet */ alphabet_p(alph); } else { /* alphabet file */ FILE *fp = xfopen(name, "r"); alphabet_read(alph, fp); xfclose(fp); } } void init_seqs(mfasta *seqs, const data *d) { int i; FILE *fp = xfopen(d->a.seq_file, "r"); mfasta_read(seqs, fp); xfclose(fp); if (seqs->seqnum < 1) die("%s: no sequences found in %s\n", prog_name, d->a.seq_file); for (i = 0; i < seqs->seqnum; ++i) first_word(seqs->f[i].title); tr_mfasta(seqs, d->alph.encode); if (d->a.two_strands) rc_mfasta(seqs, d->alph.size); } void init_background(prob_vec *bg, const data *d) { const int alph_size = d->alph.size; const double bg_pseudo = d->a.bg_pseudo * alph_size; int *counts = xcalloc(alph_size+1, sizeof(int)); /* zero fill */ double *probs = xmalloc(alph_size * sizeof(double)); double *log_probs = xmalloc(alph_size * sizeof(double)); int tot; int i; count_mfasta(&d->seqs, counts); if (d->a.two_strands) for (i = 0; i < (alph_size+1)/2; ++i) counts[i] = counts[alph_size-i-1] = counts[i] + counts[alph_size-i-1]; tot = sum_int(counts, alph_size); for (i = 0; i < alph_size; ++i) probs[i] = (counts[i] + bg_pseudo * d->alph.prob[i]) / (tot + bg_pseudo); for (i = 0; i < alph_size; ++i) log_probs[i] = xlog(probs[i]); bg->dim = alph_size; bg->counts = counts; bg->probs = probs; bg->log_probs = log_probs; } void init_d_prior(beta *b, const data *d) { beta_init(b, d->a.delete_pseudo, d->a.no_delete_pseudo, d->seqs.seqnum); } void init_i_prior(beta *b, const data *d) { beta_init(b, d->a.insert_pseudo, d->a.no_insert_pseudo, d->seqs.seqnum); } void init_e_prior(dirichlet_mix *m, const data *d) { if (d->a.dirichlet_file) { FILE *fp = xfopen(d->a.dirichlet_file, "r"); dmix_read(m, fp); xfclose(fp); assert(m->comp_num > 0); if (m->components->dim != d->alph.size) die("%s: wrong alphabet size in %s\n", prog_name, d->a.dirichlet_file); } else if (strcmp(d->a.alph_name, "p") == 0) dmix_recode3(m); else if (strcmp(d->a.alph_name, "n") == 0) dmix_dna(m); else dmix_uniform(m, d->alph.size); dmix_precalc(m, d->seqs.seqnum); } void init_convolve(score_matrices *sm, const data *d) { const int max_seqlen = d->seqs.maxlen; XMALLOC(sm->convolver, max_seqlen + 1); if (d->a.algorithm == 2) { #ifdef FFT fft_init(&sm->fft, max_seqlen+1); #endif } else XMALLOC(sm->convolved, max_seqlen + 1); } void init_sm(score_matrices *sm, const data *d) { const int alph_size = d->alph.size; const int max_width = d->a.max_width; const int max_seqlen = d->seqs.maxlen; int i; sm->match_scores = xmalloc2(max_width, (alph_size+1) * sizeof(double)); XMALLOC(sm->delete_scores, max_width); XMALLOC(sm->insert_scores, max_width); for (i = 0; i < max_width; ++i) /* zero score for mask character */ sm->match_scores[i][alph_size] = 0; /* dp_mat needs one extra row and column: */ sm->dp_mat = xmalloc2(max_width+1, (max_seqlen+1) * sizeof(double)); /* boundary condition for short-in-long alignment: */ set_dbl(sm->dp_mat[0], max_seqlen+1, 1); if (d->a.two_strands) { sm->rc_match_scores = xmalloc2(max_width, (alph_size+1) * sizeof(double)); XMALLOC(sm->rc_delete_scores, max_width); for (i = 0; i < max_width; ++i) /* zero score for mask character */ sm->rc_match_scores[i][alph_size] = 0; sm->rc_mat = xmalloc2(max_width+1, (max_seqlen+1) * sizeof(double)); /* boundary condition for short-in-long alignment: */ set_dbl(sm->rc_mat[0], max_seqlen+1, 1); } } void init_del_probs(double *del_probs, const int max) { int i; assert(max > 0); del_probs[1] = xlog(2); for (i = 1; i < max; ++i) del_probs[i+1] = (i+1) * (1 - del_probs[i]) / i; } void init_col_sampler(column_sampler *s, const data *d) { const int seq_num = d->seqs.seqnum; const int max_width = d->a.max_width; const int max_seqlen = d->seqs.maxlen; s->seq_num = seq_num; XMALLOC(s->offsets, seq_num); XMALLOC(s->fits, max_width); col_init(&s->col, seq_num, d->alph.size); XMALLOC(s->scores, max_seqlen + max_width * 2); /* ? */ XMALLOC(s->del_probs, max_width + 1); init_del_probs(s->del_probs, max_width); } void init_seq_order(data *d) { const int seq_num = d->seqs.seqnum; int i; XMALLOC(d->seq_order, seq_num); for (i = 0; i < seq_num; ++i) d->seq_order[i] = i; } void init(data *d) { srand(d->a.seed); init_alph(&d->alph, d->a.alph_name); init_seqs(&d->seqs, d); #if 0 if (d->a.min_seqs == 0) /* OOPS model requested */ d->a.min_seqs = d->seqs.seqnum; #endif init_background(&d->scorer.bg, d); init_d_prior(&d->scorer.d_prior, d); init_i_prior(&d->scorer.i_prior, d); init_e_prior(&d->scorer.e_prior, d); aln_init(&d->aln, d->seqs.seqnum, d->a.max_width, d->alph.size); init_sm(&d->sm, d); if (d->a.algorithm > 0) init_convolve(&d->sm, d); init_col_sampler(&d->col_sampler, d); init_seq_order(d); d->out = xfopen(d->a.out_file, "w"); } glam2-1064/src/glam2.c0000644007451300001540000001226410653312507014075 0ustar charlesgenome/* GLAM2 */ #include #include /* DBL_MIN, DBL_EPSILON */ #include "util.h" #include "glam2.h" #include "init.h" #include "output.h" #include "site_sample.h" #include "column_sample.h" /* log probability of counts given probabilities */ double prob_vec_score(const prob_vec *p, const int *counts) { int i; double score = 0; for (i = 0; i < p->dim; ++i) score += counts[i] * p->log_probs[i]; return score; } double bg_score(const glam2_scorer *s, const int *counts) { return prob_vec_score(&s->bg, counts); } double emission_score(glam2_scorer *s, const int *counts) { return dmix_score(&s->e_prior, counts); } double deletion_score(glam2_scorer *s, int delete_count, int no_delete_count) { return beta_score(&s->d_prior, delete_count, no_delete_count); } double insertion_score(glam2_scorer *s, int insert_count, int no_insert_count) { return beta_score(&s->i_prior, insert_count, no_insert_count); } double column_score(glam2_scorer *s, const glam2_col *col) { return emission_score(s, col->emission_counts) + deletion_score(s, col->delete_count, col->match_count) - bg_score(s, col->emission_counts); } /* Calculate the score of an alignment */ double aln_score(glam2_scorer *s, const glam2_aln *aln) { double score = 0; int i; for (i = 0; i < aln->width; ++i) score += column_score(s, &aln->cols[i]); for (i = 1; i < aln->width; ++i) score += insertion_score(s, aln->insert_counts[i-1], aln->aligned_seq); return score; } /* Calculate one sequence's contribution to the alignment score */ double marginal_score(glam2_scorer *s, glam2_aln *aln, int seq, const fasta *f) { double score = aln->score; unalign(aln, seq, f); score -= aln_score(s, aln); realign(aln, seq, f); return score; } /* get a random starting alignment */ void start_aln(glam2_aln *aln, data *d) { int i; #if 0 aln->width = d->a.min_width; /* ?? initial number of columns */ aln->width = sqrt(d->a.max_width * d->a.min_width); /* geometric mean */ #endif aln->width = d->a.init_width; aln_zero(aln); SHUFFLE(d->seq_order, aln->seq_num); for (i = 0; i < aln->seq_num; ++i) site_sample(aln, d->seq_order[i], d, 1); aln->score = aln_score(&d->scorer, aln); } void update_aln(glam2_aln *aln, data *d, const double temperature) { assert(aln->seq_num > 0); if (rand_dbl(d->a.column_sample_rate + 1) < 1) { const int seq_pick = rand_int(aln->seq_num); if (d->a.profile) fprintf(d->out, "site sample: seq=%d\n", seq_pick); site_sample(aln, seq_pick, d, temperature); } else column_sample(aln, d, temperature); aln->score = aln_score(&d->scorer, aln); } void optimise_aln(glam2_aln *best, data *d) { glam2_aln *aln = &d->aln; int no_improvement = 0; int i; aln_copy(aln, best); if (d->a.profile) fputs("Temperature, Columns, Sequences, Score:\n", d->out); for (i = 0; no_improvement < d->a.stop_after; ++i) { double temperature = d->a.temperature / xpow(d->a.cool, (double)i / d->a.stop_after); if (temperature < d->a.frozen) temperature = d->a.frozen; if (d->a.profile) fprintf(d->out, "%g\t%d\t%d\t%g\n", temperature, aln->width, aln->aligned_seq, aln->score / xlog(2)); /* print_aln(d->out, aln, d); */ update_aln(aln, d, temperature); if (aln->score > best->score) { aln_copy(best, aln); no_improvement = 0; } else ++no_improvement; } if (d->a.profile) putc('\n', d->out); fprintf(stderr, "%d iterations\n", i); } void print_misc_info(FILE *fp, const data *d) { const int alph_size = d->alph.size; int i; fprintf(fp, "Sequences: %d\n", d->seqs.seqnum); fprintf(fp, "Greatest sequence length: %d\n", d->seqs.maxlen); fputs("Residue counts: ", fp); for (i = 0; i <= alph_size; ++i) fprintf(fp, "%c=%d%c", d->alph.decode[i], d->scorer.bg.counts[i], i < alph_size ? ' ' : '\n'); } /* Alignment comparison function for sorting */ int aln_cmp(const void *a, const void *b) { const double x = ((const glam2_aln *)a)->score; const double y = ((const glam2_aln *)b)->score; return x < y ? +1 : x > y ? -1 : 0; } int main(int argc, char **argv) { data d; glam2_aln *alns; int r; prog_name = "glam2"; /* for error messages */ getargs(&d.a, argc, argv); init(&d); fputs("GLAM2: Gapped Local Alignment of Motifs\nVersion " #include "version.h" "\n\n", d.out); printargs(d.out, argc, argv); print_misc_info(d.out, &d); putc('\n', d.out); XMALLOC(alns, d.a.runs); for (r = 0; r < d.a.runs; ++r) { glam2_aln *aln = &alns[r]; fprintf(stderr, "Run %d... ", r+1); fflush(stderr); aln_init(aln, d.seqs.seqnum, d.a.max_width, d.alph.size); d.sm.underflow_flag = 1; /* do we care about underflow in start_aln? */ start_aln(aln, &d); optimise_aln(aln, &d); if (d.sm.underflow_flag < (d.a.algorithm == 2 ? DBL_EPSILON : DBL_MIN)) fprintf(stderr, "%s: accuracy loss due to numeric underflow (%g)\nIf the alignment looks suspect, try rerunning with higher -u, or maybe lower -b\n", prog_name, d.sm.underflow_flag); if (d.a.profile) print_aln_info(d.out, aln, &d); } putc('\n', stderr); SORT(alns, d.a.runs, aln_cmp); if (!d.a.profile) print_alns(d.out, alns, &d); return 0; } glam2-1064/src/recode3_20comp.h0000644007451300001540000000017010647016166015602 0ustar charlesgenome#ifndef RECODE3_30COMP_H #define RECODE3_30COMP_H #include "dirichlet.h" void dmix_recode3(dirichlet_mix *m); #endif glam2-1064/src/args.c0000644007451300001540000001547210751741365014042 0ustar charlesgenome#include #include #include /* non-ANSI */ #include "util.h" #include "args.h" /* default values: */ static const int n_def = 10000; static const int r_def = 10; static const int a_def = 2; static const int b_def = 50; static const int z_def = 2; static const int w_def = 20; static const double D_def = 0.1; static const double E_def = 2; static const double I_def = 0.02; static const double J_def = 1; static const double m_def = 1; /* ??? */ static const int x_def = 0; static const double t_def = 1.2; /* seems to work well, so does 1.1 */ static const double c_def = 1.44; /* seems to work well, so does 1.21 */ static const double u_def = 0.1; static const double q_def = 1e99; static const unsigned s_def = 1; static void usage(void) { die("\ Usage: glam2 [options] alphabet my_seqs.fa\n\ Main alphabets: p = proteins, n = nucleotides\n\ Main options (default settings):\n\ -h: show all options and their default settings\n\ -o: output file (stdout)\n\ -r: number of alignment runs (%d)\n\ -n: end each run after this many iterations without improvement (%d)\n\ -2: examine both strands - forward and reverse complement\n\ -z: minimum number of sequences in the alignment (%d)\n\ -a: minimum number of aligned columns (%d)\n\ -b: maximum number of aligned columns (%d)\n\ -w: initial number of aligned columns (%d)\n\ ", r_def, n_def, z_def, a_def, b_def, w_def); } static void help(void) { die("\ Usage: glam2 [options] alphabet my_seqs.fa\n\ Alphabets: p = proteins, n = nucleotides, other = alphabet file\n\ Options (default settings):\n\ -h: show all options and their default settings\n\ -o: output file (stdout)\n\ -r: number of alignment runs (%d)\n\ -n: end each run after this many iterations without improvement (%d)\n\ -2: examine both strands - forward and reverse complement\n\ -z: minimum number of sequences in the alignment (%d)\n\ -a: minimum number of aligned columns (%d)\n\ -b: maximum number of aligned columns (%d)\n\ -w: initial number of aligned columns (%d)\n\ -d: Dirichlet mixture file\n\ -D: deletion pseudocount (%g)\n\ -E: no-deletion pseudocount (%.1f)\n\ -I: insertion pseudocount (%g)\n\ -J: no-insertion pseudocount (%.1f)\n\ -q: weight for generic versus sequence-set-specific residue abundances (%g)\n\ -t: initial temperature (%g)\n\ -c: cooling factor per n iterations (%g)\n\ -u: temperature lower bound (%g)\n\ -p: print progress information at each iteration\n\ -m: column-sampling moves per site-sampling move (%.1f)\n\ -x: site sampling algorithm: 0=FAST 1=SLOW 2=FFT (%d)\n\ -s: seed for pseudo-random numbers (%u)\n\ ", r_def, n_def, z_def, a_def, b_def, w_def, D_def, E_def, I_def, J_def, q_def, t_def, c_def, u_def, m_def, x_def, s_def); } void getargs(args *a, int argc, char **argv) { int c; a->stop_after = n_def; a->runs = r_def; a->out_file = "-"; a->two_strands = 0; a->min_width = a_def; a->max_width = b_def; a->min_seqs = z_def; a->init_width = w_def; a->delete_pseudo = D_def; a->no_delete_pseudo = E_def; a->insert_pseudo = I_def; a->no_insert_pseudo = J_def; a->profile = 0; a->column_sample_rate = m_def; a->algorithm = x_def; a->temperature = t_def; a->cool = c_def; a->frozen = u_def; a->dirichlet_file = NULL; a->bg_pseudo = q_def; a->seed = s_def; /* non-ANSI: */ while ((c = getopt(argc, argv, "hn:r:o:2a:b:z:w:D:E:I:J:pm:x:t:c:u:d:q:s:")) != -1) { switch (c) { case 'h': help(); case 'n': a->stop_after = xatoi(optarg); if (a->stop_after < 1) die("%s: option -n should be at least 1\n", prog_name); break; case 'r': a->runs = xatoi(optarg); if (a->runs < 1) die("%s: option -r should be at least 1\n", prog_name); break; case 'o': a->out_file = optarg; break; case '2': a->two_strands = 1; break; case 'a': a->min_width = xatoi(optarg); if (a->min_width < 2) die("%s: option -a should be at least 2\n", prog_name); break; case 'b': a->max_width = xatoi(optarg); if (a->max_width < 2) die("%s: option -b should be at least 2\n", prog_name); break; case 'z': a->min_seqs = xatoi(optarg); if (a->min_seqs < 0) die("%s: option -z should be at least 0\n", prog_name); break; case 'w': a->init_width = xatoi(optarg); if (a->init_width < 2) die("%s: option -w should be at least 2\n", prog_name); break; case 'D': a->delete_pseudo = xatof(optarg); if (a->delete_pseudo <= 0) die("%s: option -D should be > 0\n", prog_name); break; case 'E': a->no_delete_pseudo = xatof(optarg); if (a->no_delete_pseudo <= 0) die("%s: option -E should be > 0\n", prog_name); break; case 'I': a->insert_pseudo = xatof(optarg); if (a->insert_pseudo <= 0) die("%s: option -I should be > 0\n", prog_name); break; case 'J': a->no_insert_pseudo = xatof(optarg); if (a->no_insert_pseudo <= 0) die("%s: option -J should be > 0\n", prog_name); break; case 'p': a->profile = 1; break; case 'm': a->column_sample_rate = xatof(optarg); if (a->column_sample_rate < 0) die("%s: option -m should be at least 0\n", prog_name); break; case 'x': a->algorithm = xatoi(optarg); if (a->algorithm < 0 || a->algorithm > 2) die("%s: option -x should be 0, 1, or 2\n", prog_name); #ifndef FFT if (a->algorithm == 2) die("%s: recompile with FFT in order to use -x 2\n", prog_name); #endif break; case 't': a->temperature = xatof(optarg); if (a->temperature <= 0) die("%s: option -t should be > 0\n", prog_name); break; case 'c': a->cool = xatof(optarg); if (a->cool <= 0) die("%s: option -c should be > 0\n", prog_name); break; case 'u': a->frozen = xatof(optarg); if (a->frozen < 0) die("%s: option -u should be at least 0\n", prog_name); break; case 'd': a->dirichlet_file = optarg; break; case 'q': a->bg_pseudo = xatof(optarg); if (a->bg_pseudo <= 0) /* zero could lead to log(0) */ die("%s: option -q should be > 0\n", prog_name); break; case 's': a->seed = xatou(optarg); break; case '?': usage(); } } if (optind != argc-2) usage(); a->alph_name = argv[optind++]; a->seq_file = argv[optind++]; if (a->max_width < a->min_width) die("%s: option -a should be >= option -b\n", prog_name); else if (a->max_width == a->min_width) fprintf(stderr, "%s: warning: setting -a equal to -b is not recommended\n", prog_name); if (a->init_width < a->min_width) a->init_width = a->min_width; else if (a->init_width > a->max_width) a->init_width = a->max_width; } void printargs(FILE *fp, int argc, char **argv) { int i; for (i = 0; i < argc; ++i) { fputs(argv[i], fp); putc(i < argc-1 ? ' ' : '\n', fp); } } glam2-1064/src/motif.c0000644007451300001540000000357210631247117014213 0ustar charlesgenome#include #include /* INT_MAX */ #include "util.h" #include "alignment.h" #include "motif.h" /* Move to util? */ static size_t strcnt(const char *cs, int c) { size_t count = 0; assert(cs != NULL); for (; *cs != '\0'; ++cs) count += *cs == (char)c; /* same cast as strchr(?) */ return count; } void aln2mot(motif *m, const alignment *a, int alph_size, const int *encode) { const int columns = strlen(a->key_positions); const int width = strcnt(a->key_positions, '*'); int **residue_counts = xcalloc2(width, alph_size, sizeof(int)); /* zero */ int *delete_counts = xcalloc(width, sizeof(int)); /* zero fill */ int *insert_counts = xcalloc(width, sizeof(int)); /* zero fill */ int i, j, k; for (i = 0; i != a->seq_num; ++i) { const char *seq = a->seqs[i].seq; k = 0; for (j = 0; j < columns; ++j) { const int c = (unsigned char)seq[j]; /* is this OK? */ if (a->key_positions[j] == '*') { if (c != '.') { if (encode[c] == alph_size) die("%s: error reading motif file: ambiguous residue %c in aligned column\n", prog_name, c); ++residue_counts[k][encode[c]]; } delete_counts[k] += c == '.'; ++k; } else { assert(k > 0); assert(k < width); insert_counts[k-1] += c != '.'; } } } m->width = width; m->alph_size = alph_size; m->seq_num = a->seq_num; m->residue_counts = residue_counts; m->delete_counts = delete_counts; m->insert_counts = insert_counts; } void read_motif(motif *m, int alph_size, const int *encode, FILE *fp) { alignment aln; aln_read(&aln, fp); if (aln.seq_num == 0) die("%s: error reading motif file: no motif\n", prog_name); if (!aln_same_lengths(&aln)) die("%s: error reading motif file: unequal aligned lengths\n", prog_name); assert(strlen(aln.key_positions) <= INT_MAX); /* can fail */ aln2mot(m, &aln, alph_size, encode); aln_free(&aln); } glam2-1064/src/glam2_aln.h0000644007451300001540000000357210653314124014733 0ustar charlesgenome/* structs for GLAM2 alignments */ #ifndef GLAM2_ALN_H #define GLAM2_ALN_H typedef struct { /* one column in a glam2 alignment */ /* fudamental data: */ int seq_num; /* number of sequences */ int *positions; /* zero-based coordinates */ int *matches; /* 0=deletion, 1=match */ /* derived data: */ int alph_size; int *emission_counts; int match_count; int delete_count; } glam2_col; typedef struct { /* a glam2 alignment */ int seq_num; /* number of sequences */ int width; /* number of columns */ glam2_col *cols; int *strands; /* '+', '-', or 0 = unaligned */ /* derived data: */ int aligned_seq; /* number of strands != 0 */ int *insert_counts; double score; } glam2_aln; /* Is the s-th sequence of alignment "aln" aligned? */ #define ALIGNED(aln, s) ((aln)->strands[s]) #define LEFT_POS(col, seq) ((col)->positions[seq]) #define RIGHT_POS(col, seq) ((col)->positions[seq] + (col)->matches[seq]) #define INSERTS(col1, col2, seq) (LEFT_POS(col2, seq) - RIGHT_POS(col1, seq)) #define LEFT_INSERT(aln, col, seq)\ ((col) > 0 ?\ INSERTS(&(aln)->cols[(col)-1], &(aln)->cols[col], seq) : 0) #define RIGHT_INSERT(aln, col, seq)\ ((col) < (aln)->width-1 ?\ INSERTS(&(aln)->cols[col], &(aln)->cols[(col)+1], seq) : 0) /* Allocate memory for a glam2_col */ void col_init(glam2_col *col, int seq_num, int alph_size); /* Allocate memory for a glam2_aln */ void aln_init(glam2_aln *aln, int seq_num, int max_width, int alph_size); /* Set all sequences unaligned and all counts to zero */ /* Assumes width has been set */ void aln_zero(glam2_aln *aln); /* Copy column b into column a */ /* Assumes a's memory has already been allocated */ void col_copy(glam2_col *a, const glam2_col *b); /* Copy alignment b into alignment a */ /* Assumes a's memory has already been allocated */ void aln_copy(glam2_aln *a, const glam2_aln *b); #endif glam2-1064/src/column_sample.c0000644007451300001540000002747010653300356015735 0ustar charlesgenome/* This code seems a bit messy and complicated - can it be simplified? */ #include #include #include "util.h" #include "column_sample.h" int sample(double *ptr, int size, const double temperature) { const double max = *max_dbl(ptr, size); const double *end = ptr + size; double *i; assert(size > 0); for (i = ptr; i != end; ++i) *i = xexp(*i - max); pow_dbl(ptr, size, 1 / temperature); return pick_dbl(ptr, size) - ptr; } /* Set positions of new column to the left of old column */ void col_put_left(column_sampler *s, const glam2_aln *aln, const int col) { int i; assert(col < aln->width); for (i = 0; i < aln->seq_num; ++i) if (ALIGNED(aln, i)) s->col.positions[i] = LEFT_POS(&aln->cols[col], i) - s->offsets[i] - s->col.matches[i]; else s->col.positions[i] = 0; /* dummy value */ } /* Set positions of new column to the right of old column */ void col_put_right(column_sampler *s, const glam2_aln *aln, const int col) { int i; assert(col < aln->width); for (i = 0; i < aln->seq_num; ++i) if (ALIGNED(aln, i)) s->col.positions[i] = RIGHT_POS(&aln->cols[col], i) + s->offsets[i]; else s->col.positions[i] = 0; /* dummy value */ } /* Count residues in one column of an alignment */ void count_residues(glam2_col *col, const glam2_aln *aln, const mfasta *m) { int i; ZERO(col->emission_counts, col->alph_size+1); for (i = 0; i < col->seq_num; ++i) if (ALIGNED(aln, i) && col->matches[i]) { const int *seq = aln->strands[i] == '+' ? m->f[i].seq : m->f[i].rcseq; ++col->emission_counts[seq[col->positions[i]]]; } } /* Count insertions to the right of a column. Returns 0 for rightmost column */ int count_right_insert(const glam2_aln *aln, const int col) { int count = 0; int i; assert(col < aln->width); for (i = 0; i < aln->seq_num; ++i) if (ALIGNED(aln, i)) count += RIGHT_INSERT(aln, col, i); return count; } int sum_offsets(const int *offsets, const glam2_aln *aln) { int sum = 0; int i; for (i = 0; i < aln->seq_num; ++i) if (ALIGNED(aln, i)) sum += offsets[i]; return sum; } /* Get offsets between columns col-1 and col */ void get_offsets(int *offsets, const glam2_aln *aln, const int col) { int i; int min = INT_MAX; assert(col > 0 && col < aln->width); for (i = 0; i < aln->seq_num; ++i) if (ALIGNED(aln, i)) { offsets[i] = LEFT_INSERT(aln, col, i); if (offsets[i] < min) min = offsets[i]; } else offsets[i] = 0; /* dummy value */ add_int(offsets, aln->seq_num, -min); } /* Get the index of the first aligned sequence */ int first_aligned_seq(const glam2_aln *aln) { int i; for (i = 0; i < aln->seq_num; ++i) if (ALIGNED(aln, i)) break; assert(i != aln->seq_num); return i; } /* Check whether matches/deletions and right offsets are identical */ int col_comp_left(const column_sampler *s, const glam2_aln *aln, int col) { int i = first_aligned_seq(aln); int off = RIGHT_INSERT(aln, col, i) - s->offsets[i]; assert(col != aln->width-1); for (; i < aln->seq_num; ++i) if (ALIGNED(aln, i)) if (s->col.matches[i] != aln->cols[col].matches[i] || RIGHT_INSERT(aln, col, i) - s->offsets[i] != off) return 0; return 1; } /* Check whether matches/deletions and left offsets are identical */ int col_comp_right(const column_sampler *s, const glam2_aln *aln, int col) { int i = first_aligned_seq(aln); int off = LEFT_INSERT(aln, col, i) - s->offsets[i]; assert(col != 0); for (; i < aln->seq_num; ++i) if (ALIGNED(aln, i)) if (s->col.matches[i] != aln->cols[col].matches[i] || LEFT_INSERT(aln, col, i) - s->offsets[i] != off) return 0; return 1; } /* Count matching columns */ int col_count_left(const column_sampler *s, const glam2_aln *aln) { int count = 0; int i; for (i = 0; i < aln->width-1; ++i) count += col_comp_left(s, aln, i); return count; } /* Count matching columns */ int col_count_right(const column_sampler *s, const glam2_aln *aln) { int count = 0; int i; for (i = 1; i < aln->width; ++i) count += col_comp_right(s, aln, i); return count; } /* How many columns can we fit between columns col-1 and col */ int col_fit(const column_sampler *s, const glam2_aln *aln, const int col) { int i; int min = INT_MAX; assert(col > 0 && col < aln->width); for (i = 0; i < aln->seq_num; ++i) if (ALIGNED(aln, i)) { const int fit = LEFT_INSERT(aln, col, i) - s->offsets[i] - s->col.matches[i] + 1; if (fit < min) min = fit; } return min > 0 ? min : 0; } /* How many columns can we fit before the first column? */ int col_fit_left(const column_sampler *s, const glam2_aln *aln) { int i; int min = INT_MAX; for (i = 0; i < aln->seq_num; ++i) if (ALIGNED(aln, i)) { const int fit = LEFT_POS(&aln->cols[0], i) - s->offsets[i] - s->col.matches[i] + 1; if (fit < min) min = fit; } return min > 0 ? min : 0; } /* How many columns can we fit after the last column? */ int col_fit_right(const column_sampler *s, const glam2_aln *aln, const mfasta *m) { const int w = aln->width; int i; int min = INT_MAX; for (i = 0; i < aln->seq_num; ++i) if (ALIGNED(aln, i)) { const int fit = m->f[i].seqlen - RIGHT_POS(&aln->cols[w-1], i) - s->offsets[i] - s->col.matches[i] + 1; if (fit < min) min = fit; } return min > 0 ? min : 0; } void left_fits(column_sampler *s, const glam2_aln *aln) { int i; s->fits[0] = col_fit_left(s, aln); for (i = 1; i < aln->width; ++i) s->fits[i] = col_fit(s, aln, i); } void right_fits(column_sampler *s, const glam2_aln *aln, const mfasta *m) { int i; for (i = 1; i < aln->width; ++i) s->fits[i-1] = col_fit(s, aln, i); s->fits[aln->width-1] = col_fit_right(s, aln, m); } void col_scan_left(column_sampler *s, const glam2_aln *aln, data *d) { const int aligned_seq = aln->aligned_seq; const int off_tot = sum_offsets(s->offsets, aln); const int res_tot = off_tot + s->col.match_count; double *score_ptr = s->scores; int i, j; for (i = 0; i < aln->width; ++i) { const double old_score = i != 0 ? insertion_score(&d->scorer, aln->insert_counts[i-1], aligned_seq) : 0; int right_inserts = off_tot; int left_inserts = i != 0 ? aln->insert_counts[i-1] - res_tot : 0; col_put_left(s, aln, i); for (j = 0; j < s->fits[i]; ++j) { assert(score_ptr-s->scores < d->seqs.maxlen+d->a.max_width); count_residues(&s->col, aln, &d->seqs); *score_ptr = column_score(&d->scorer, &s->col) + insertion_score(&d->scorer, right_inserts, aligned_seq); if (i != 0) *score_ptr += insertion_score(&d->scorer, left_inserts, aligned_seq) - old_score; if (s->col.emission_counts[s->col.alph_size]) *score_ptr = -DBL_MAX; /* forbid ambiguous residues */ add_int(s->col.positions, aln->seq_num, -1); /* add -1 to positions */ right_inserts += aligned_seq; left_inserts -= aligned_seq; ++score_ptr; } } } void col_scan_right(column_sampler *s, const glam2_aln *aln, data *d) { const int aligned_seq = aln->aligned_seq; const int off_tot = sum_offsets(s->offsets, aln); const int res_tot = off_tot + s->col.match_count; double *score_ptr = s->scores; int i, j; for (i = 0; i < aln->width; ++i) { const double old_score = i != aln->width-1 ? insertion_score(&d->scorer, aln->insert_counts[i], aligned_seq) : 0; int left_inserts = off_tot; int right_inserts = i != aln->width-1 ? aln->insert_counts[i] - res_tot : 0; col_put_right(s, aln, i); for (j = 0; j < s->fits[i]; ++j) { assert(score_ptr-s->scores < d->seqs.maxlen+d->a.max_width); count_residues(&s->col, aln, &d->seqs); *score_ptr = column_score(&d->scorer, &s->col) + insertion_score(&d->scorer, left_inserts, aligned_seq); if (i != aln->width-1) *score_ptr += insertion_score(&d->scorer, right_inserts, aligned_seq) - old_score; if (s->col.emission_counts[s->col.alph_size]) *score_ptr = -DBL_MAX; /* forbid ambiguous residues */ add_int(s->col.positions, aln->seq_num, 1); /* add 1 to positions */ left_inserts += aligned_seq; right_inserts -= aligned_seq; ++score_ptr; } } } /* Rotate a column out of an alignment, and repair insert counts */ void rotate_out(glam2_aln *aln, const int col) { assert(col < aln->width); ROL(aln->cols + col, aln->width - col, 1); ROL(aln->insert_counts + col, aln->width - col, 1); --aln->width; if (col != 0) aln->insert_counts[col-1] = count_right_insert(aln, col-1); } /* Rotate a column back into an alignment, and repair insert counts */ void rotate_in(glam2_aln *aln, const int col) { ++aln->width; assert(col < aln->width); ROR(aln->cols + col, aln->width - col, 1); ROR(aln->insert_counts + col, aln->width - col, 1); if (col != 0) aln->insert_counts[col-1] = count_right_insert(aln, col-1); aln->insert_counts[col] = count_right_insert(aln, col); } int pick_new_col(column_sampler *s, int match_cols, double temperature) { const int tot_fit = sum_int(s->fits, s->width); int r, c; set_dbl(s->scores + tot_fit, match_cols, 0); /* printf("match_cols=%d tot_fit=%d scores=", match_cols, tot_fit); for (r = 0; r < tot_fit + match_cols; ++r) printf("%.3g ", s->scores[r]); printf("\n"); */ r = sample(s->scores, tot_fit + match_cols, temperature); for (c = 0; c < s->width; ++c) { if (r < s->fits[c]) break; r -= s->fits[c]; } if (c < s->width) add_int(s->offsets, s->seq_num, r); return c; } void sample_left(glam2_aln *aln, data *d, const double temperature) { column_sampler *s = &d->col_sampler; const int del_flag = rand_dbl(1) < s->del_probs[aln->width - 1]; const int col_pick = rand_int(aln->width - 1); int match_cols, new_col; if (d->a.profile) fprintf(d->out, "column sample: side=left, delete=%d, col=%d\n", del_flag, col_pick); get_offsets(s->offsets, aln, col_pick+1); col_copy(&s->col, &aln->cols[col_pick]); if (del_flag) rotate_out(aln, col_pick); /* Remove column & decrement width */ else if (aln->width == d->a.max_width) return; s->width = aln->width; left_fits(s, aln); col_scan_left(s, aln, d); match_cols = col_count_left(s, aln); if (aln->width < d->a.min_width) match_cols = 0; /* force column re-insertion */ new_col = pick_new_col(s, match_cols, temperature); if (new_col >= s->width) return; col_put_left(s, aln, new_col); count_residues(&s->col, aln, &d->seqs); col_copy(&aln->cols[aln->width], &s->col); rotate_in(aln, new_col); } void sample_right(glam2_aln *aln, data *d, const double temperature) { column_sampler *s = &d->col_sampler; const int del_flag = rand_dbl(1) < s->del_probs[aln->width - 1]; const int col_pick = rand_int(aln->width - 1) + 1; int match_cols, new_col; if (d->a.profile) fprintf(d->out, "column sample: side=right, delete=%d, col=%d\n", del_flag, col_pick); get_offsets(s->offsets, aln, col_pick); col_copy(&s->col, &aln->cols[col_pick]); if (del_flag) rotate_out(aln, col_pick); /* Remove column & decrement width */ else if (aln->width == d->a.max_width) return; s->width = aln->width; right_fits(s, aln, &d->seqs); col_scan_right(s, aln, d); match_cols = col_count_right(s, aln); if (aln->width < d->a.min_width) match_cols = 0; /* force column re-insertion */ new_col = pick_new_col(s, match_cols, temperature); if (new_col >= s->width) return; col_put_right(s, aln, new_col); count_residues(&s->col, aln, &d->seqs); col_copy(&aln->cols[aln->width], &s->col); rotate_in(aln, new_col+1); } void column_sample(glam2_aln *aln, data *d, double temperature) { assert(aln->width > 1); /* need at least 2 columns */ if (aln->aligned_seq == 0) /* need at least 1 aligned sequence */ return; if (rand_int(2)) sample_left(aln, d, temperature); else sample_right(aln, d, temperature); assert(aln->width >= d->a.min_width && aln->width <= d->a.max_width); } glam2-1064/src/dna_prior.h0000644007451300001540000000015210647016166015053 0ustar charlesgenome#ifndef DNA_PRIOR_H #define DNA_PRIOR_H #include "dirichlet.h" void dmix_dna(dirichlet_mix *m); #endif glam2-1064/src/fasta.c0000644007451300001540000001032110647047151014164 0ustar charlesgenome/* Functions for handling FASTA format sequences */ #include #include #include #include /* free */ #include "util.h" #include "fasta.h" char *first_word(char *s) { const char *beg = skipws(s); const char *end = skipnw(beg); MOVE(s, beg, end - beg); /* overflow danger? */ s[end - beg] = '\0'; /* overflow danger? */ return s; } void count_fasta(const fasta *f, int *counts) { int i; for (i = 0; i < f->seqlen; ++i) ++counts[f->seq[i]]; } void count_mfasta(const mfasta *m, int *counts) { int i; for (i = 0; i < m->seqnum; ++i) count_fasta(&m->f[i], counts); } void rc_fasta(fasta *f, const int alph_size) { const int seqlen = f->seqlen; /* might be zero */ const int *seq = f->seq; /* might be NULL */ int *rcseq = xmalloc(seqlen * sizeof(int)); /* might be NULL */ int i; for (i = 0; i < seqlen; ++i) rcseq[seqlen - i - 1] = seq[i] < alph_size ? alph_size - seq[i] - 1 : alph_size; f->rcseq = rcseq; } void rc_mfasta(mfasta *m, const int alph_size) { int i; for (i = 0; i < m->seqnum; ++i) rc_fasta(&m->f[i], alph_size); } void tr_fasta(fasta *f, const int *encode) { int i; for (i = 0; i < f->seqlen; ++i) f->seq[i] = encode[f->seq[i]]; } void tr_mfasta(mfasta *m, const int *encode) { int i; for (i = 0; i < m->seqnum; ++i) tr_fasta(&m->f[i], encode); } static int get_maxlen(const mfasta *m) { int i; int max = 0; for (i = 0; i < m->seqnum; ++i) if (m->f[i].seqlen > max) max = m->f[i].seqlen; return max; } void put_fasta(const fasta *f, int line_size, FILE *fp) { int i; assert(line_size > 0); fprintf(fp, ">%s\n", f->title); for (i = 0; i < f->seqlen; ++i) { putc(f->seq[i], fp); if ((i+1) % line_size == 0 || i+1 == f->seqlen) putc('\n', fp); } } /* double memory allocation or die */ static void *moremem(void *buf, int *mem) { if (!can_mul_int(*mem, 2)) die("%s: memory requirement too large: %d * 2 bytes\n", prog_name, *mem); *mem *= 2; return xrealloc(buf, *mem); } /* read FASTA title line */ static size_t get_title(char **title, FILE *fp) { char *buf = NULL; size_t mem = 0; size_t len = xgetline(&buf, &mem, fp); len = chomp(buf, len); buf = XREALLOC(buf, len+1); /* shrink-wrap */ *title = buf; return len; /* might be zero */ } /* read FASTA sequence */ static int get_seq(int **seq, FILE *fp) { int len = 0; /* sequence length so far */ int mem = sizeof(int); /* bytes allocated to sequence so far */ int *buf = xmalloc(mem); /* sequence */ register int c; while((c = getc(fp)) != EOF) { if (c == '>') break; else if (isspace(c)) /* we might want to read e.g. gap characters */ continue; if (len * sizeof(int) == mem) buf = moremem(buf, &mem); buf[len] = c; ++len; } if (ferror(fp)) die("%s: error reading fasta file: %s\n", prog_name, strerror(errno)); if (c == '>') xungetc(c, fp); buf = XREALLOC(buf, len); /* shrink-wrap */ *seq = buf; /* might be NULL */ return len; /* might be zero */ } int fasta_read(fasta *f, FILE *fp) { char *title; int *seq; size_t titlen; int seqlen; register int c; /* skip any junk before '>': */ while ((c = getc(fp)) != EOF) if (c == '>') break; if (ferror(fp)) die("%s: error reading fasta file: %s\n", prog_name, strerror(errno)); if (c == EOF) return EOF; titlen = get_title(&title, fp); seqlen = get_seq(&seq, fp); f->title = title; f->titlen = titlen; f->seq = seq; f->seqlen = seqlen; f->rcseq = NULL; /* so it can be freed */ return 0; } void mfasta_read(mfasta *m, FILE *fp) { int num = 0; /* number of fastas read so far */ int mem = sizeof(fasta); /* bytes allocated for fastas so far */ fasta *f = xmalloc(mem); /* fastas */ while (fasta_read(&f[num], fp) != EOF) { ++num; if (num * sizeof(fasta) == mem) f = moremem(f, &mem); } f = XREALLOC(f, num); /* shrink-wrap */ m->f = f; /* might be NULL */ m->seqnum = num; /* might be zero */ m->maxlen = get_maxlen(m); } void free_fasta(fasta *f) { free(f->title); free(f->seq); free(f->rcseq); } void free_mfasta(mfasta *m) { int i; for (i = 0; i < m->seqnum; ++i) free_fasta(&m->f[i]); free(m->f); } glam2-1064/src/recode3_20comp.c0000644007451300001540000001114710647016166015603 0ustar charlesgenome#include "recode3_20comp.h" void dmix_recode3(dirichlet_mix *m) { double a[] = { 0.668781, 0.072626, 1.08101, 0.930936, 0.1235, 0.982387, 0.366701, 0.0586812, 0.849019, 0.185073, 0.0648062, 0.979541, 0.519704, 0.555784, 0.636552, 1.04987, 0.60931, 0.129148, 0.0676805, 0.201772, 0.880009, 0.197393, 0.303744, 0.497357, 0.657492, 0.391988, 0.348159, 0.936094, 0.527206, 1.42844, 0.449302, 0.368825, 0.384576, 0.439775, 0.581516, 0.622624, 0.747064, 1.08007, 0.235012, 0.606928, 0.153384, 0.0520756, 0.0073824, 0.0158439, 0.428964, 0.025533, 0.0185789, 0.845361, 0.0282996, 2.42256, 0.424296, 0.0190716, 0.0313429, 0.0274578, 0.0252186, 0.028514, 0.0519217, 0.522946, 0.0279653, 0.0664755, 0.794007, 0.0130659, 0.624236, 1.85769, 0.0290214, 0.115707, 0.123504, 0.22099, 1.52605, 0.341371, 0.111114, 0.308302, 0.263545, 0.953727, 0.933444, 0.554741, 0.604551, 0.396451, 0.00823516, 0.0420054, 0.740015, 0.187165, 0.0213261, 0.0456854, 0.118944, 0.0633687, 0.0170331, 1.06684, 0.0380614, 0.733524, 0.138456, 0.0300644, 0.0718692, 0.0240143, 0.0301022, 0.0862989, 0.367283, 1.70735, 0.0113856, 0.045079, 0.15978, 0.0261585, 0.0505181, 0.125524, 0.0350331, 0.102549, 0.157461, 0.0795041, 1.26261, 0.189383, 0.0550608, 0.171028, 0.0844169, 0.290476, 1.44604, 0.129158, 0.138972, 0.0851144, 0.0159134, 0.0637679, 0.308434, 0.0137217, 1.69731, 1.92422, 0.0361113, 0.162357, 0.07232, 0.0487895, 0.236135, 0.0809074, 0.0286236, 0.213663, 0.181631, 0.320245, 0.104878, 0.218398, 0.141668, 0.0747719, 0.0141705, 0.0453433, 0.00260287, 9.99856e-06, 0.00631292, 0.00445502, 0.00274753, 1.03886e-05, 1.02839e-05, 0.000913052, 0.0029241, 0.00353485, 0.00105128, 0.00338172, 1.04172e-05, 0.00173574, 0.00459583, 0.00274255, 0.00247625, 0.00175366, 1.02411e-05, 0.00288489, 1.61043, 0.15522, 0.0378292, 0.0498243, 0.0406484, 0.529136, 0.0217524, 0.040597, 0.0413396, 0.100193, 0.0509779, 0.0357917, 0.0931204, 0.0367156, 0.0330646, 0.529587, 0.196607, 0.230878, 0.00909518, 0.0329275, 0.15525, 0.0136827, 0.0857138, 0.0508316, 0.0151451, 3.10555, 0.027169, 0.0140491, 0.0654038, 0.0257501, 0.00901049, 0.127437, 0.0423873, 0.0345064, 0.0477247, 0.12452, 0.0341196, 0.0230637, 0.00930115, 0.0187464, 0.225739, 0.0684326, 0.101072, 0.0813791, 0.0298832, 0.0915218, 0.0336807, 0.0833114, 0.0931673, 0.0731542, 0.0419314, 0.230216, 0.087446, 0.0694702, 0.0751969, 1.13857, 1.63158, 0.179083, 0.00912576, 0.0311963, 1.3431e-06, 0.0166656, 0.00743068, 1.34592e-06, 0.169076, 0.00407061, 0.00714122, 1.98221, 0.017522, 0.816669, 0.114773, 0.00678027, 0.0106392, 0.0100244, 0.0158968, 0.00879658, 0.0399043, 1.81043, 0.0150671, 0.0517801, 0.063525, 0.0288391, 1.09265, 0.0959581, 0.00965196, 0.216914, 0.0730986, 0.0207325, 0.08719, 0.0315107, 0.00960293, 0.752755, 0.059914, 0.0445321, 0.0312317, 0.287327, 0.116896, 0.0249446, 0.00701663, 0.0305859, 0.294281, 0.019271, 0.12293, 0.162747, 0.0373667, 0.145029, 0.0412349, 0.0815261, 0.157594, 0.151631, 0.021412, 0.0601581, 3.6966, 0.0809085, 0.101856, 0.23533, 0.135424, 0.140532, 0.00900473, 0.0321389, 0.0844832, 0.0584945, 0.0411628, 0.045719, 0.847822, 0.0590839, 0.250253, 0.0675757, 0.0562614, 0.168617, 0.0439737, 0.0794234, 0.028301, 0.0305672, 0.0598024, 0.0798202, 0.0585385, 0.0858243, 0.227395, 1.30336, 0.0634034, 0.0246167, 1.3443e-06, 0.00389272, 1.12953, 0.00796028, 1.35032e-06, 0.233395, 1.34466e-06, 0.541933, 0.101309, 1.36412e-06, 0.027467, 0.00704479, 0.00802297, 0.0248977, 0.0276933, 0.185467, 0.183309, 0.516892, 0.123696, 0.0454619, 0.0386434, 0.351847, 0.0560181, 0.0439442, 0.223229, 0.01302, 0.148699, 0.19001, 0.120964, 0.098734, 5.90055e-06, 0.554971, 0.219233, 0.0453885, 0.0564686, 0.0614792, 0.0410248, 0.0800036, 0.0212037, 3.18769, 0.00745627, 0.00382411, 0.00691924, 0.0126233, 1.34375e-06, 0.00724293, 0.00522979, 0.00785563, 0.00489521, 0.0105326, 0.0136265, 0.00505819, 0.00677712, 0.0251744, 0.0235516, 0.0371462, 0.00187667, 0.0038893, 0.0229376, 0.00427768, 0.00959934, 0.013608, 0.182277, 0.0227654, 0.0157344, 0.0226783, 0.011561, 0.0803491, 0.0154283, 0.00899225, 0.00980608, 0.00600945, 0.0342359, 0.0216842, 0.0189306, 0.0223176, 1.83914, 0.154565, 2.16602e-06, 2.16245e-06, 0.0198496, 2.17942e-06, 0.0246741, 2.47051e-06, 1.02563, 0.0131152, 2.16539e-06, 0.00637704, 2.1414e-06, 0.0839371, 0.0168135, 0.0438887, 0.0252951, 0.0235533, 0.0130626, 0.00797507, 2.16433e-06, 0.0545531 }; double w[] = { 0.176513, 0.207622, 0.0669246, 0.0868259, 0.0593123, 0.0358616, 0.03427, 0.0428319, 0.047875, 0.0466614, 0.0283695, 0.0301127, 0.0233828, 0.034662, 0.0270202, 0.0226822, 0.00898452, 0.00716226, 0.00710292, 0.00582299 }; dmix_init(m, 20, 20, w, a); } glam2-1064/src/site_sample.c0000644007451300001540000003464110653277517015416 0ustar charlesgenome/* Site sampling functions for GLAM2 */ #include #include #include #include "util.h" #include "site_sample.h" /* print vector of doubles: for debugging */ void print_vec(double *vec, int size) { int i; for (i = 0; i < size; ++i) printf("%.2g%c", vec[i], i < size-1 ? '\t' : '\n'); } /* print matrix of doubles: for debugging */ void print_mat(double **mat, int rows, int cols) { int i, j; for (i = 0; i < rows; ++i) for (j = 0; j < cols; ++j) printf("%.2g%c", mat[i][j], j < cols-1 ? '\t' : '\n'); } /* Remove one sequence from an alignment's count matrices */ void unalign(glam2_aln *aln, const int seq_pick, const fasta *f) { const int *seq = aln->strands[seq_pick] == '+' ? f->seq : f->rcseq; int i; if (!ALIGNED(aln, seq_pick)) /* the sequence is unaligned */ return; --aln->aligned_seq; for (i = 0; i < aln->width; ++i) { glam2_col *col = &aln->cols[i]; if (col->matches[seq_pick]) { const int pos = col->positions[seq_pick]; assert(seq[pos] < col->alph_size); --col->match_count; --col->emission_counts[seq[pos]]; } else --col->delete_count; aln->insert_counts[i] -= RIGHT_INSERT(aln, i, seq_pick); } } /* Add one sequence to an alignment's count matrices */ void realign(glam2_aln *aln, const int seq_pick, const fasta *f) { const int *seq = aln->strands[seq_pick] == '+' ? f->seq : f->rcseq; int i; if (!ALIGNED(aln, seq_pick)) /* the sequence is unaligned */ return; ++aln->aligned_seq; for (i = 0; i < aln->width; ++i) { glam2_col *col = &aln->cols[i]; if (col->matches[seq_pick]) { const int pos = col->positions[seq_pick]; assert(seq[pos] < col->alph_size); ++col->match_count; ++col->emission_counts[seq[pos]]; } else ++col->delete_count; aln->insert_counts[i] += RIGHT_INSERT(aln, i, seq_pick); } } static void get_score_matrices(score_matrices *sm, const glam2_aln *aln, glam2_scorer *s) { double **match_scores = sm->match_scores; double *delete_scores = sm->delete_scores; double *insert_scores = sm->insert_scores; int i, j; for (i = 0; i < aln->width; ++i) { /* loop over aligned columns */ const int alph_size = aln->cols[i].alph_size; /* should be in sm */ const int *residue_counts = aln->cols[i].emission_counts; const int match_count = aln->cols[i].match_count; const int delete_count = aln->cols[i].delete_count; const int insert_count = aln->insert_counts[i]; const int aligned_seq = aln->aligned_seq; const double ds = beta_ratio_a(&s->d_prior, delete_count, match_count); const double ms = beta_ratio_b(&s->d_prior, delete_count, match_count); const double is = beta_ratio_a(&s->i_prior, insert_count, aligned_seq); const double js = beta_ratio_b(&s->i_prior, insert_count, aligned_seq); assert(residue_counts[alph_size] == 0); /* no mask characters */ dmix_ratios(&s->e_prior, match_scores[i], residue_counts); if (i+1 < aln->width) { for (j = 0; j < alph_size; ++j) match_scores[i][j] *= js * ms / s->bg.probs[j]; delete_scores[i] = ds * js; insert_scores[i] = is; } else { /* no insertions after last column: special case */ for (j = 0; j < alph_size; ++j) match_scores[i][j] *= ms / s->bg.probs[j]; delete_scores[i] = ds; insert_scores[i] = 0; } } } static void heat_scores(score_matrices *sm, int width, int alph_size, double temperature) { int i; for (i = 0; i < width; ++i) pow_dbl(sm->match_scores[i], alph_size, 1 / temperature); pow_dbl(sm->delete_scores, width, 1 / temperature); pow_dbl(sm->insert_scores, width, 1 / temperature); /* back is 0 */ } static void copy_scores(score_matrices *sm, int width, int alph_size) { int i; for (i = 0; i < width; ++i) COPY(sm->rc_match_scores[i], sm->match_scores[i], alph_size); COPY(sm->rc_delete_scores, sm->delete_scores, width); } /* Stochastically choose a strand (or "unaligned"), using the DP matrix */ int pick_strand(const glam2_aln *aln, const int seq_pick, const data *d) { const int width = aln->width; const int seq_len = d->seqs.f[seq_pick].seqlen; double **dp_mat = d->sm.dp_mat; double **rc_mat = d->sm.rc_mat; const double dp_rescale = d->sm.dp_rescale; const double rc_rescale = d->sm.rc_rescale; double tot[3]; double log_scale[3]; double max; int i, r; tot[0] = sum_dbl(dp_mat[width], seq_len+1); assert(tot[0] > 0); log_scale[0] = dp_rescale; if (d->a.two_strands) { tot[1] = sum_dbl(rc_mat[width], seq_len+1); assert(tot[1] > 0); log_scale[1] = rc_rescale; } else { tot[1] = 0; log_scale[1] = dp_rescale; } if (aln->aligned_seq >= d->a.min_seqs) { tot[2] = 1; log_scale[2] = 0; } else { tot[2] = 0; log_scale[2] = dp_rescale; } /* puts("tot:"); print_vec(tot, 3); puts("log_scale:"); print_vec(log_scale, 3); */ max = *max_dbl(log_scale, 3); for (i = 0; i < 3; ++i) tot[i] *= xexp(log_scale[i] - max); r = pick_dbl(tot, 3) - tot; if (r == 0) return '+'; else if (r == 1) return '-'; else return 0; } /* Stochastically choose an alignment endpoint, using the DP matrix */ static int pick_endpoint(const score_matrices *sm, int width, int seq_len, int strand) { double **dp_mat = strand == '+' ? sm->dp_mat : sm->rc_mat; if (strand == 0) /* the sequence is unaligned */ return -1; /* dummy value, hopefully never used */ return pick_dbl(dp_mat[width], seq_len+1) - dp_mat[width]; } /* Stochastic traceback: */ void traceback(glam2_aln *aln, int seq_pick, int strand, int end, data *d) { const fasta *f = &d->seqs.f[seq_pick]; const int *seq = strand == '+' ? f->seq : f->rcseq; glam2_col *cols = aln->cols; double **ms = strand == '+' ? d->sm.match_scores : d->sm.rc_match_scores; double *ds = strand == '+' ? d->sm.delete_scores : d->sm.rc_delete_scores; double **dp_mat = strand == '+' ? d->sm.dp_mat : d->sm.rc_mat; int i = aln->width - 1; int j = end - 1; aln->strands[seq_pick] = strand; if (strand == 0) /* the sequence is unaligned */ return; while (i != -1 && j != -1) { const double r = rand_dbl(dp_mat[i+1][j+1]); const double match = ms[i][seq[j]] * dp_mat[i][j]; const double delete = ds[i] * dp_mat[i][j+1]; if (dp_mat[i+1][j+1] < d->sm.underflow_flag) d->sm.underflow_flag = dp_mat[i+1][j+1]; if (r < match) { /* match */ assert(seq[j] < d->alph.size); /* ambiguous residue forbidden */ cols[i].matches[seq_pick] = 1; cols[i].positions[seq_pick] = j; --i; --j; } else if (r < match + delete) { /* deletion */ cols[i].matches[seq_pick] = 0; cols[i].positions[seq_pick] = j+1; --i; } else { /* insertion */ assert(i+1 < aln->width); --j; } } for (; i != -1; --i) { if (dp_mat[i+1][j+1] < d->sm.underflow_flag) d->sm.underflow_flag = dp_mat[i+1][j+1]; cols[i].matches[seq_pick] = 0; cols[i].positions[seq_pick] = 0; } } /* Stochastic traceback with nonlinear insertion scores */ void traceback_slow(glam2_aln *aln, int seq_pick, int strand, int end, data *d, double temperature) { const fasta *f = &d->seqs.f[seq_pick]; const int *seq = strand == '+' ? f->seq : f->rcseq; glam2_col *cols = aln->cols; double **ms = strand == '+' ? d->sm.match_scores : d->sm.rc_match_scores; double *ds = strand == '+' ? d->sm.delete_scores : d->sm.rc_delete_scores; double **dp_mat = strand == '+' ? d->sm.dp_mat : d->sm.rc_mat; int i = aln->width - 1; int j = end - 1; aln->strands[seq_pick] = strand; if (strand == 0) /* the sequence is unaligned */ return; while (i != -1 && j != -1) { double r = rand_dbl(dp_mat[i+1][j+1]); int a_count = aln->insert_counts[i]; int b_count = aln->aligned_seq+1; /* +1 */ double insert_score = 1; if (dp_mat[i+1][j+1] < d->sm.underflow_flag) d->sm.underflow_flag = dp_mat[i+1][j+1]; for (; j != -1; --j) { const double is = xpow(insert_score, 1 / temperature); const double match = ms[i][seq[j]] * dp_mat[i][j] * is; const double delete = ds[i] * dp_mat[i][j+1] * is; if (r < match) { /* match */ assert(seq[j] < d->alph.size); /* ambiguous residue forbidden */ cols[i].matches[seq_pick] = 1; cols[i].positions[seq_pick] = j; --i; --j; break; } else if (r < match + delete) { /* deletion */ cols[i].matches[seq_pick] = 0; cols[i].positions[seq_pick] = j+1; --i; break; } assert(i+1 < aln->width); r -= match + delete; insert_score *= beta_ratio_a(&d->scorer.i_prior, a_count, b_count); ++a_count; } } for (; i != -1; --i) { if (dp_mat[i+1][j+1] < d->sm.underflow_flag) d->sm.underflow_flag = dp_mat[i+1][j+1]; cols[i].matches[seq_pick] = 0; cols[i].positions[seq_pick] = 0; } } /* Fill in the DP matrix, using the "forward algorithm" (sum of paths): */ void forward(const glam2_aln *aln, int seq_pick, int strand, data *d) { const fasta *f = &d->seqs.f[seq_pick]; const int *seq = strand == '+' ? f->seq : f->rcseq; const int *end = seq + f->seqlen; double **ms = strand == '+' ? d->sm.match_scores : d->sm.rc_match_scores; double *ds = strand == '+' ? d->sm.delete_scores : d->sm.rc_delete_scores; double *is = d->sm.insert_scores; double **dp_mat = strand == '+' ? d->sm.dp_mat : d->sm.rc_mat; double *rescale = strand == '+' ? &d->sm.dp_rescale : &d->sm.rc_rescale; double r = 1; /* rescaling factor for one row */ int i; assert(is[aln->width-1] == 0); *rescale = 0; for (i = 0; i < aln->width; ++i) { if (r <= 0) die("%s: underflow in alignment i=%d\n", prog_name, i); div_dbl(ms[i], d->alph.size, r); ds[i] /= r; *rescale += xlog(r); /* tried to optimize this inner loop as much as possible */ const int *s = seq; const double *msi = ms[i]; const double dsi = ds[i]; const double isi = is[i]; const double *mat1 = dp_mat[i]; double *mat2 = dp_mat[i+1]; double m1 = *mat1; double m2 = dsi * m1; *mat2 = m2; r = m2; while (s != end) { ++mat1; ++mat2; m2 *= isi; m2 += msi[*s] * m1; m1 = *mat1; m2 += dsi * m1; *mat2 = m2; if (m2 > r) r = m2; if (m2 >= DBL_MAX) /* this check doesn't seem to slow it down */ die("%s: overflow %g in alignment i=%d isi=%.3g dsi=%.3g msi=%.3g m1=%.3g\n", prog_name, m2, i, isi, dsi, msi[*s], m1); ++s; } } } /* Make vector of probabilities for different insertion sizes */ void beta_convolver_a(const beta *b, double *convolver, int size, int a_count, int b_count) { double x = 1; int i; for (i = 0; i < size; ++i) { convolver[i] = x; x *= beta_ratio_a(b, a_count, b_count); ++a_count; } } /* z = convolution of x and y */ void convolve(double *z, const double *x, const double *y, const int size) { int i, j; for (i = 0; i < size; ++i) { z[i] = 0; for (j = 0; j <= i; ++j) z[i] += x[j] * y[i-j]; } } /* Move this to util? */ void truncate_min_dbl(double *ptr, const size_t size, const double min) { const double *end = ptr + size; for (; ptr != end; ++ptr) if (*ptr < min) *ptr = min; } /* Fill in the DP matrix, using nonlinear insertion scores */ void forward_slow(const glam2_aln *aln, int seq_pick, int strand, data *d, double temperature) { const fasta *f = &d->seqs.f[seq_pick]; const int *seq = strand == '+' ? f->seq : f->rcseq; double **ms = strand == '+' ? d->sm.match_scores : d->sm.rc_match_scores; double *ds = strand == '+' ? d->sm.delete_scores : d->sm.rc_delete_scores; double **dp_mat = strand == '+' ? d->sm.dp_mat : d->sm.rc_mat; double *convolver = d->sm.convolver; double *convolved = d->sm.convolved; double *rescale = strand == '+' ? &d->sm.dp_rescale : &d->sm.rc_rescale; int i, j; *rescale = 0; for (i = 0; i < aln->width; ++i) { const double r = *max_dbl(dp_mat[i], f->seqlen+1); if (r <= 0) die("%s: underflow in alignment i=%d\n", prog_name, i); div_dbl(ms[i], d->alph.size, r); ds[i] /= r; *rescale += xlog(r); dp_mat[i+1][0] = ds[i] * dp_mat[i][0]; for (j = 0; j < f->seqlen; ++j) { dp_mat[i+1][j+1] = ms[i][seq[j]] * dp_mat[i][j] + ds[i] * dp_mat[i][j+1]; if (dp_mat[i+1][j+1] >= DBL_MAX) die("%s: overflow %g in alignment i=%d j=%d M=%.3g*%.3g D=%.3g*%.3g\n", prog_name, dp_mat[i+1][j+1], i, j, ms[i][seq[j]], dp_mat[i][j], ds[i], dp_mat[i][j+1]); } if (i+1 < aln->width) { /* no insertions after last column */ beta_convolver_a(&d->scorer.i_prior, convolver, f->seqlen+1, aln->insert_counts[i], aln->aligned_seq+1); /* +1 */ pow_dbl(convolver, f->seqlen+1, 1 / temperature); if (d->a.algorithm == 2) { #ifdef FFT fft_convolve(dp_mat[i+1], dp_mat[i+1], convolver, f->seqlen+1, &d->sm.fft); #endif /* set negative numbers produced by FFT to zero: big fat kludge */ truncate_min_dbl(dp_mat[i+1], f->seqlen+1, 0); } else { convolve(convolved, dp_mat[i+1], convolver, f->seqlen+1); COPY(dp_mat[i+1], convolved, f->seqlen+1); } } } } #define FORWARD(aln, seq_pick, strand, d, temperature)\ ((d)->a.algorithm == 0 ?\ forward(aln, seq_pick, strand, d) :\ forward_slow(aln, seq_pick, strand, d, temperature)) #define TRACEBACK(aln, seq_pick, strand, end, d, temperature)\ ((d)->a.algorithm == 0 ?\ traceback(aln, seq_pick, strand, end, d) :\ traceback_slow(aln, seq_pick, strand, end, d, temperature)) /* Stochastically re-align one sequence */ void site_sample(glam2_aln *aln, int seq_pick, data *d, double temperature) { int strand, end; const fasta *f = &d->seqs.f[seq_pick]; unalign(aln, seq_pick, f); get_score_matrices(&d->sm, aln, &d->scorer); heat_scores(&d->sm, aln->width, d->alph.size, temperature); if (d->a.two_strands) copy_scores(&d->sm, aln->width, d->alph.size); FORWARD(aln, seq_pick, '+', d, temperature); if (d->a.two_strands) FORWARD(aln, seq_pick, '-', d, temperature); strand = pick_strand(aln, seq_pick, d); end = pick_endpoint(&d->sm, aln->width, f->seqlen, strand); /* puts("Delete scores:"); print_vec(d->sm.delete_scores, aln->width); puts("Insert scores:"); print_vec(d->sm.insert_scores, aln->width); puts("Match scores:"); print_mat(d->sm.match_scores, aln->width, d->alph.size); puts("DP matrix:"); print_mat(d->sm.dp_mat, aln->width+1, f->seqlen+1); printf("strand=%c end=%d\n", strand ? strand : '0', end); */ TRACEBACK(aln, seq_pick, strand, end, d, temperature); realign(aln, seq_pick, f); } glam2-1064/src/convolve.h0000644007451300001540000000110210607311611014712 0ustar charlesgenome/* Convolve vectors using O(n log n) FFT algorithm */ /* Uses FFTW library */ #ifndef CONVOLVE_H #define CONVOLVE_H #include "fftw3.h" typedef struct { int size; double *x; /* 1st input */ double *y; /* 2nd input */ double *z; /* output */ fftw_plan x_plan; fftw_plan y_plan; fftw_plan z_plan; } fft_convolver; /* Setup to convolve vectors of size <= max_size */ void fft_init(fft_convolver *f, const int max_size); /* z = convolution of x and y */ void fft_convolve(double *z, const double *x, const double *y, const int size, fft_convolver *f); #endif glam2-1064/src/motif.h0000644007451300001540000000074710653314450014220 0ustar charlesgenome/* Data structure representing a motif found by GLAM2 */ /* Should probably replace this with glam2_aln */ #ifndef MOTIF_H #define MOTIF_H #include typedef struct { int width; /* number of aligned columns */ int alph_size; int seq_num; /* number of sequences in the alignment */ int **residue_counts; int *delete_counts; int *insert_counts; } motif; /* Read a motif from a file */ void read_motif(motif *m, int alph_size, const int *encode, FILE *fp); #endif glam2-1064/src/fasta.h0000644007451300001540000000357710647047053014211 0ustar charlesgenome/* Structs and functions for FASTA-format sequences */ #ifndef FASTA_H #define FASTA_H #include /* One FASTA sequence and its title */ typedef struct { char *title; /* FASTA title line (without newline; NUL terminated) */ size_t titlen; /* length of title line */ int *seq; /* should probably be char or unsigned char */ int seqlen; /* maybe use unsigned or size_t? */ int *rcseq; /* reverse-complemented sequence */ } fasta; /* Multiple FASTA sequences */ typedef struct { fasta *f; /* the fastas */ int seqnum; /* the number of fastas */ int maxlen; /* maximum sequence length */ } mfasta; /* Replace a string with its first word */ /* Often seems to be used with fasta titles */ char *first_word(char *s); /* For now, these functions succeed or die, because error recovery is harder */ /* Read a FASTA-format sequence and title line from a file */ int fasta_read(fasta *f, FILE *fp); /* Read multiple FASTA-format sequences from a file */ void mfasta_read(mfasta *m, FILE *fp); /* Write a FASTA-format title & sequence to a file */ void put_fasta(const fasta *f, int line_size, FILE *fp); /* Deallocate the memory buffers within the fasta object */ void free_fasta(fasta *f); /* Deallocate all the memory within the mfasta */ void free_mfasta(mfasta *m); /* Translate (encode) the sequence */ void tr_fasta(fasta *f, const int *encode); /* Translate (encode) each sequence */ void tr_mfasta(mfasta *m, const int *encode); /* Initialize rcseq */ void rc_fasta(fasta *f, const int alph_size); /* Initialize rcseqs */ void rc_mfasta(mfasta *m, const int alph_size); /* Count residue types */ /* Assumes counts has been suitably allocated and initialized */ void count_fasta(const fasta *f, int *counts); /* Count residue types in all sequences */ /* Assumes counts has been suitably allocated and initialized */ void count_mfasta(const mfasta *m, int *counts); #endif glam2-1064/src/alignment.h0000644007451300001540000000141510631233402015042 0ustar charlesgenome/* Structs and functions for reading glam2 alignments */ #ifndef ALIGNMENT_H #define ALIGNMENT_H #include typedef struct aligned_seq { char *name; /* sequence name */ char *seq; /* the aligned sequence with gaps */ char *start; /* start coordinate */ /* add end coordinate, strand, score if needed */ } aligned_seq; typedef struct alignment { /* could put alignment score, etc. here too */ size_t seq_num; aligned_seq *seqs; char *key_positions; } alignment; /* Return 1 if all sequences and key_positions have same length, else 0 */ int aln_same_lengths(const alignment *a); /* Read an alignment from a stream */ void aln_read(alignment *a, FILE *stream); /* Free all the memory allocated in an alignment */ void aln_free(alignment *a); #endif glam2-1064/src/dirichlet.c0000644007451300001540000002134710714467602015051 0ustar charlesgenome#include #include #include "util.h" #include "dirichlet.h" static void grow_lgamma_alpha(double *table, int old_max, int new_max, double alpha) { double tot = table[old_max]; while (old_max < new_max) { tot += xlog(old_max + alpha); ++old_max; table[old_max] = tot; } } static void start_lgamma_alpha(double *table, int max, double alpha) { assert(alpha > 0); /* not checked in dirichlet initialization */ table[0] = 0; grow_lgamma_alpha(table, 0, max, alpha); } static double get_lgamma_alpha(lgamma_alpha *look, int value) { assert(look != NULL); assert(value >= 0); if (value > look->max) { look->table = XREALLOC(look->table, value+1); grow_lgamma_alpha(look->table, look->max, value, look->alpha); look->max = value; } return look->table[value]; } static void init_lgamma_alpha(lgamma_alpha *look, double alpha, int max) { assert(look != NULL); assert(alpha > 0); assert(max >= 0); look->alpha = alpha; look->max = max; XMALLOC(look->table, max + 1); start_lgamma_alpha(look->table, max, alpha); } static void free_lgamma_alpha(lgamma_alpha *look) { assert(look != NULL); free(look->table); } void beta_init(beta *b, double alpha, double beta, int max_lookup) { assert(b != NULL); assert(alpha > 0); assert(beta > 0); assert(max_lookup >= 0); b->alpha = alpha; b->beta = beta; b->sum = b->alpha + b->beta; init_lgamma_alpha(&b->alpha_lookup, b->alpha, max_lookup); init_lgamma_alpha(&b->beta_lookup, b->beta, max_lookup); init_lgamma_alpha(&b->sum_lookup, b->sum, max_lookup); } double beta_score(beta *b, const int count1, const int count2) { assert(b != NULL); assert(count1 >= 0); assert(count2 >= 0); return get_lgamma_alpha(&b->alpha_lookup, count1) + get_lgamma_alpha(&b->beta_lookup, count2) - get_lgamma_alpha(&b->sum_lookup, count1 + count2); } double beta_ratio_a(const beta *b, const int a_count, const int b_count) { assert(b != NULL); assert(a_count >= 0); assert(b_count >= 0); return (a_count + b->alpha) / (a_count + b_count + b->sum); } double beta_ratio_b(const beta *b, const int a_count, const int b_count) { assert(b != NULL); assert(a_count >= 0); assert(b_count >= 0); return (b_count + b->beta) / (a_count + b_count + b->sum); } void beta_free(beta *b) { assert(b != NULL); free_lgamma_alpha(&b->alpha_lookup); free_lgamma_alpha(&b->beta_lookup); free_lgamma_alpha(&b->sum_lookup); } static void dirichlet_extra_init(dirichlet *d) { d->sum = sum_dbl(d->alpha, d->dim); d->lookup_size = 0; d->alpha_lookup = NULL; d->sum_lookup = NULL; } void dirichlet_init(dirichlet *d, int dim, const double *alpha) { assert(d != NULL); assert(dim > 0); assert(alpha != NULL); d->dim = dim; d->alpha = XDUP(alpha, dim); dirichlet_extra_init(d); } void dirichlet_uniform(dirichlet *d, int dim) { assert(d != NULL); assert(dim > 0); d->dim = dim; XMALLOC(d->alpha, dim); set_dbl(d->alpha, dim, 1); dirichlet_extra_init(d); } void dirichlet_precalc(dirichlet *d, int max_lookup) { int i; assert(d != NULL); assert(max_lookup >= 0); d->lookup_size = max_lookup + 1; XMALLOC(d->alpha_lookup, d->dim * d->lookup_size); XMALLOC(d->sum_lookup, d->lookup_size); for (i = 0; i < d->dim; ++i) start_lgamma_alpha(d->alpha_lookup + i * d->lookup_size, max_lookup, d->alpha[i]); start_lgamma_alpha(d->sum_lookup, max_lookup, d->sum); } void dirichlet_free(dirichlet *d) { assert(d != NULL); free(d->alpha); free(d->alpha_lookup); free(d->sum_lookup); } /* Sum elements of lookup table indicated by offsets */ static double dirichlet_lookup_sum(const dirichlet *d, const int *offsets) { const int *end = offsets + d->dim; const double *a = d->alpha_lookup; double sum = 0; while (offsets != end) { /* tried to make this loop fast */ a += *offsets; sum += *a; ++offsets; } return sum; } static void dmix_extra_init(dirichlet_mix *m) { int i; XMALLOC(m->log_weights, m->comp_num); XMALLOC(m->scratch, m->comp_num); XMALLOC(m->counts, m->components->dim); XMALLOC(m->offsets, m->components->dim); for (i = 0; i < m->comp_num; ++i) m->log_weights[i] = xlog(m->weights[i]); } void dmix_init(dirichlet_mix *m, int comp_num, int dim, const double *weights, const double *all_alpha) { int i; assert(m != NULL); assert(comp_num > 0); assert(dim > 0); assert(weights != NULL); assert(all_alpha != NULL); m->comp_num = comp_num; m->weights = XDUP(weights, comp_num); XMALLOC(m->components, comp_num); for (i = 0; i < comp_num; ++i) dirichlet_init(&m->components[i], dim, all_alpha + i * dim); dmix_extra_init(m); } void dmix_uniform(dirichlet_mix *m, int dim) { assert(m != NULL); assert(dim > 0); m->comp_num = 1; XMALLOC(m->weights, 1); m->weights[0] = 1; XMALLOC(m->components, 1); dirichlet_uniform(m->components, dim); dmix_extra_init(m); } void dmix_precalc(dirichlet_mix *m, int max_lookup) { int i; assert(m != NULL); assert(max_lookup >= 0); for (i = 0; i < m->comp_num; ++i) dirichlet_precalc(&m->components[i], max_lookup); } void dmix_free(dirichlet_mix *m) { int i; assert(m != NULL); for (i = 0; i < m->comp_num; ++i) dirichlet_free(&m->components[i]); free(m->weights); free(m->components); free(m->log_weights); free(m->scratch); free(m->counts); free(m->offsets); } /* Get offsets into lookup table from counts */ static void dmix_offsets(dirichlet_mix *m, const int *counts) { int extra_offset = 0; int i; for (i = 0; i < m->components->dim; ++i) { m->offsets[i] = extra_offset + counts[i]; extra_offset = m->components->lookup_size - counts[i]; } } /* if all the counts are 0, the result should be 0, but might be a bit off */ /* tried to make this FAST */ double dmix_score(dirichlet_mix *m, const int *counts) { const int tot = sum_int(counts, m->components->dim); int i; assert(tot < m->components->lookup_size); dmix_offsets(m, counts); /* get alpha_lookup offsets for speed */ for (i = 0; i < m->comp_num; ++i) m->scratch[i] = m->log_weights[i] + dirichlet_lookup_sum(&m->components[i], m->offsets) - m->components[i].sum_lookup[tot]; return log_sum(m->scratch, m->comp_num); } void dmix_ratios(dirichlet_mix *m, double *scores, const int *counts) { const int tot = sum_int(counts, m->components->dim); /* this call leaves values on m->scratch that we'll use: */ const double log_norm = dmix_score(m, counts); int i, j; set_dbl(scores, m->components->dim, 0); for (i = 0; i < m->components->dim; ++i) m->counts[i] = counts[i]; /* convert ints to doubles here for speed */ for (i = 0; i < m->comp_num; ++i) { const double part_calc = xexp(m->scratch[i] - log_norm) / (tot + m->components[i].sum); for (j = 0; j < m->components->dim; ++j) scores[j] += part_calc * (m->counts[j] + m->components[i].alpha[j]); } } void dmix_read(dirichlet_mix *m, FILE *stream) { char word[21]; /* allow for terminating NUL */ int mixture_num = 0; int alpha_num = 0; double *weights = NULL; dirichlet *components = NULL; double x; while (fscanf(stream, "%20s", word) == 1) { if (strcmp(word, "Mixture=") == 0) { const int r = fscanf(stream, "%lf", &x); if (r != 1) die("%s: error reading Dirichlet mixture file: Mixture= ???\n", prog_name); if (x <= 0) die("%s: error reading Dirichlet mixture file: 'Mixture=' values should be > 0\n", prog_name); ++mixture_num; weights = XREALLOC(weights, mixture_num); weights[mixture_num-1] = x; } else if (strcmp(word, "Alpha=") == 0) { int dim = 0; double *alpha = NULL; fscanf(stream, "%lf", &x); /* 1st number is sum of alphas: ignore */ while (fscanf(stream, "%lf", &x) == 1) { if (x <= 0) die("%s: error reading Dirichlet mixture file: 'Alpha=' values should be > 0\n"); ++dim; alpha = XREALLOC(alpha, dim); alpha[dim-1] = x; } if (dim == 0) die("%s: error reading Dirichlet mixture file: zero pseudocounts\n", prog_name); ++alpha_num; components = XREALLOC(components, alpha_num); dirichlet_init(&components[alpha_num-1], dim, alpha); free(alpha); if (dim != components->dim) die("%s: error reading Dirichlet mixture file: unequal number of values on 'Alpha=' lines\n", prog_name); } } if (ferror(stream)) die("%s: error reading Dirichlet mixture file: %s\n", prog_name, strerror(errno)); if (mixture_num != alpha_num) die("%s: error reading Dirichlet mixture file: unequal number of 'Mixture=' and 'Alpha=' lines\n", prog_name); if (alpha_num == 0) die("%s: error reading Dirichlet mixture file: zero components\n", prog_name); /* check that weights sum to 1? */ m->comp_num = alpha_num; m->weights = weights; m->components = components; dmix_extra_init(m); } glam2-1064/src/dirichlet.h0000644007451300001540000000724610714467600015056 0ustar charlesgenome/* structs and functions for Dirichlet mixture and Beta calculations */ #ifndef DIRICHLET_H #define DIRICHLET_H #include /* struct for storing values of log[ gamma(x + alpha) / gamma(alpha) ] */ typedef struct { double alpha; int max; /* maximum value in lookup table */ double *table; } lgamma_alpha; /* Beta distribution (special case of Dirichlet) with growable lookup tables */ typedef struct { /* basic data: */ double alpha; /* the 1st pseudocount */ double beta; /* the 2nd pseudocount */ /* stored calculations for fast lookup: */ double sum; /* alpha + beta */ lgamma_alpha alpha_lookup; lgamma_alpha beta_lookup; lgamma_alpha sum_lookup; } beta; /* Dirichlet distribution with fixed lookup tables for speed */ typedef struct { /* basic data: */ int dim; /* dimensionality: number of pseudocounts */ double *alpha; /* the pseudocounts */ /* stored calculations for fast lookup: */ double sum; /* sum of pseudocounts */ int lookup_size; /* number of entries in each lookup table */ double *alpha_lookup; /* 2D array stuffed into 1D array for speed(?) */ double *sum_lookup; } dirichlet; /* Dirichlet mixture */ typedef struct { /* basic data: */ int comp_num; /* number of components in the mixture */ double *weights; /* the weight of each component */ dirichlet *components; /* stored calculations for fast lookup: */ double *log_weights; /* probably unnecessary */ double *scratch; /* scratch space for doing log_sum calculations */ double *counts; /* holds counts converted from int to double for speed */ int *offsets; /* holds offsets into alpha_lookup for speed */ } dirichlet_mix; /* Initialize a Beta distribution */ void beta_init(beta *b, double alpha, double beta, int max_lookup); /* Calculate log posterior probability of the counts */ /* Allow for lookup tables to be extended */ double beta_score(beta *b, const int count1, const int count2); /* Calculate 1st ratio with pseudocounts */ double beta_ratio_a(const beta *b, const int a_count, const int b_count); /* Calculate 2nd ratio with pseudocounts */ double beta_ratio_b(const beta *b, const int a_count, const int b_count); /* Free the memory buffers in a Beta distribution */ void beta_free(beta *b); /* Initialize a Dirichlet distribution, without lookup tables */ void dirichlet_init(dirichlet *d, int dim, const double *alpha); /* Set up a uniform Dirichlet distribution (pseudocounts = 1) */ void dirichlet_uniform(dirichlet *d, int dim); /* Make lookup tables for the Dirichlet distribution */ void dirichlet_precalc(dirichlet *d, int max_lookup); /* No functions yet for calculations directly with a dirichlet */ /* Free the memory buffers in a Dirichlet distribution */ void dirichlet_free(dirichlet *d); /* Initialize a Dirichlet mixture, without lookup tables */ /* all_alpha has the alpha parameters for all components, concatenated */ /* the alphas are passed like this because passing 2D arrays is hard in C */ void dmix_init(dirichlet_mix *m, int comp_num, int dim, const double *weights, const double *all_alpha); /* Read a Dirichlet mixture from a stream */ void dmix_read(dirichlet_mix *m, FILE *stream); /* Set up a uniform Dirichlet mixture (1 component, pseudocounts = 1) */ void dmix_uniform(dirichlet_mix *m, int dim); /* Make lookup tables for each component */ void dmix_precalc(dirichlet_mix *m, int max_lookup); /* Calculate log posterior probability of the counts */ double dmix_score(dirichlet_mix *m, const int *counts); /* Calculate "posterior mean estimators" */ void dmix_ratios(dirichlet_mix *m, double *scores, const int *counts); /* Free the memory buffers in a Dirichlet mixture */ void dmix_free(dirichlet_mix *m); #endif glam2-1064/src/glam2.h0000644007451300001540000000375610653311026014103 0ustar charlesgenome/* Data structures for GLAM2 */ #ifndef GLAM2_H #define GLAM2_H #include #include "alphabet.h" #include "fasta.h" #include "dirichlet.h" #include "args.h" #include "glam2_aln.h" #ifdef FFT #include "convolve.h" #endif typedef struct { int dim; int *counts; double *probs; double *log_probs; } prob_vec; typedef struct { prob_vec bg; /* background residue probabilities */ beta d_prior; /* prior for deletions */ beta i_prior; /* prior for insertions */ dirichlet_mix e_prior; /* prior for emissions */ } glam2_scorer; typedef struct { double **match_scores; double *delete_scores; double *insert_scores; double **dp_mat; /* dynamic programming matrix */ double **rc_mat; /* dynamic programming matrix for reverse strand */ double dp_rescale; /* scale factor to prevent dp_mat overflow */ double rc_rescale; /* scale factor to prevent rc_mat overflow */ double **rc_match_scores; /* match scores for reverse strand */ double *rc_delete_scores; /* delete scores for reverse strand */ double underflow_flag; /* lowest value hit during traceback */ /* Data for nonlinear insertion probabilities: */ double *convolver; double *convolved; #ifdef FFT fft_convolver fft; #endif } score_matrices; /* used for site sampling */ typedef struct { int seq_num; int width; int *offsets; int *fits; glam2_col col; double *scores; /* probability of choosing a deletion move as a function of alignment width: */ double *del_probs; /* for width w, use del_probs[w-1] */ } column_sampler; typedef struct { args a; FILE *out; alphabet alph; mfasta seqs; glam2_scorer scorer; glam2_aln aln; score_matrices sm; column_sampler col_sampler; int *seq_order; /* sequence order for starting alignments */ } data; double insertion_score(glam2_scorer *s, int insert_count, int no_insert_count); double column_score(glam2_scorer *s, const glam2_col *col); double marginal_score(glam2_scorer *s, glam2_aln *aln, int seq, const fasta *f); #endif glam2-1064/src/scan_init.c0000644007451300001540000000754610647111064015047 0ustar charlesgenome/* Initialization done once only at program startup */ #include #include /* DBL_MAX */ #include /* strcmp */ #include "util.h" #include "recode3_20comp.h" #include "dna_prior.h" #include "scan_init.h" void init_alph(alphabet *alph, const char *name) { if (strcmp(name, "n") == 0) { /* nucleotide alphabet */ alphabet_n(alph); } else if (strcmp(name, "p") == 0) { /* protein alphabet */ alphabet_p(alph); } else { /* alphabet file */ FILE *fp = xfopen(name, "r"); alphabet_read(alph, fp); xfclose(fp); } } void init_motif(motif *m, const data *d) { FILE *fp = xfopen(d->a.motif_file, "r"); read_motif(m, d->alph.size, d->alph.encode, fp); xfclose(fp); } void init_d_prior(beta *b, const data *d) { beta_init(b, d->a.delete_pseudo, d->a.no_delete_pseudo, d->m.seq_num); } void init_i_prior(beta *b, const data *d) { beta_init(b, d->a.insert_pseudo, d->a.no_insert_pseudo, d->m.seq_num); } void init_e_prior(dirichlet_mix *m, const data *d) { if (d->a.dirichlet_file) { FILE *fp = xfopen(d->a.dirichlet_file, "r"); dmix_read(m, fp); xfclose(fp); assert(m->comp_num > 0); if (m->components->dim != d->alph.size) die("%s: wrong alphabet size in %s\n", prog_name, d->a.dirichlet_file); } else if (strcmp(d->a.alph_name, "p") == 0) dmix_recode3(m); else if (strcmp(d->a.alph_name, "n") == 0) dmix_dna(m); else dmix_uniform(m, d->alph.size); dmix_precalc(m, d->m.seq_num); } void init_scores(data *d) { const int alph_size = d->m.alph_size; const int width = d->m.width; const double *bg = d->alph.prob; glam2_scorer *s = &d->scorer; int i, j; d->match_scores = xmalloc2(width, (alph_size+1) * sizeof(double)); XMALLOC(d->delete_scores, width); XMALLOC(d->insert_scores, width); for (i = 0; i < width; ++i) { const int *residue_counts = d->m.residue_counts[i]; const int match_count = sum_int(residue_counts, alph_size); const int delete_count = d->m.delete_counts[i]; const int insert_count = d->m.insert_counts[i]; const int aligned_seq = match_count + delete_count; const double ds = beta_ratio_a(&s->d_prior, delete_count, match_count); const double ms = beta_ratio_b(&s->d_prior, delete_count, match_count); const double is = beta_ratio_a(&s->i_prior, insert_count, aligned_seq); const double js = beta_ratio_b(&s->i_prior, insert_count, aligned_seq); dmix_ratios(&s->e_prior, d->match_scores[i], residue_counts); if (i+1 < width) { for (j = 0; j < alph_size; ++j) d->match_scores[i][j] = xlog(js * ms * d->match_scores[i][j] / bg[j]); d->delete_scores[i] = xlog(ds * js); d->insert_scores[i] = xlog(is); } else { /* no insertions after last column: special case */ for (j = 0; j < alph_size; ++j) d->match_scores[i][j] = xlog(ms * d->match_scores[i][j] / bg[j]); d->delete_scores[i] = xlog(ds); d->insert_scores[i] = -DBL_MAX; /* overflow risk? */ } /* overflow risk? */ d->match_scores[i][alph_size] = -DBL_MAX; /* mask character forbidden */ } } void init_dp(data *d) { const int width = d->m.width; int i; d->dp_seqlen = 0; d->dp_mat = xmalloc2(width+1, 1 * sizeof(double)); d->forbidden = xmalloc2(width+1, 1); /* boundary conditions for short-in-long alignment: */ d->dp_mat[0][0] = 0; for (i = 0; i < width; ++i) d->dp_mat[i+1][0] = d->delete_scores[i] + d->dp_mat[i][0]; } void init_hit(data *d) { const int width = d->m.width; XMALLOC(d->hit_matches, width); XMALLOC(d->hit_positions, width); XMALLOC(d->hits, d->a.hit_num); d->hit_num = 0; } void init(data *d) { init_alph(&d->alph, d->a.alph_name); init_motif(&d->m, d); init_d_prior(&d->scorer.d_prior, d); init_i_prior(&d->scorer.i_prior, d); init_e_prior(&d->scorer.e_prior, d); init_scores(d); init_dp(d); init_hit(d); d->out = xfopen(d->a.out_file, "w"); } glam2-1064/src/alignment.c0000644007451300001540000000306510643204006015041 0ustar charlesgenome#include /* free */ #include /* strlen */ #include "util.h" #include "alignment.h" int aln_same_lengths(const alignment *a) { const size_t len = strlen(a->key_positions); size_t i; for (i = 0; i != a->seq_num; ++i) if (strlen(a->seqs[i].seq) != len) return 0; return 1; } static char *next_word(const char *cs) { return skipws(skipnw(cs)); } void aln_read(alignment *a, FILE *stream) { char *line = NULL; size_t line_size = 0; int state = 0; a->seq_num = 0; a->seqs = NULL; a->key_positions = NULL; while (xgetline(&line, &line_size, stream)) { if (state == 0) { char *beg = skipws(line); char *end = skipnw(beg); if (*beg == '*' && *(end-1) == '*') { *end = 0; a->key_positions = xstrdup(beg); state = 1; } } else { char *name = line; char *start = next_word(name); char *seq = next_word(start); if (*seq == 0) break; *skipnw(name) = 0; *skipnw(start) = 0; *skipnw(seq) = 0; ++a->seq_num; /* slow but simple linear reallocation for now: */ a->seqs = XREALLOC(a->seqs, a->seq_num); a->seqs[a->seq_num-1].name = xstrdup(name); a->seqs[a->seq_num-1].seq = xstrdup(seq); a->seqs[a->seq_num-1].start = xstrdup(start); } } free(line); } static void seq_free(aligned_seq *s) { free(s->name); free(s->seq); free(s->start); } void aln_free(alignment *a) { size_t i; for (i = 0; i != a->seq_num; ++i) seq_free(&a->seqs[i]); free(a->seqs); free(a->key_positions); } glam2-1064/src/glam2format.c0000644007451300001540000002324410647047275015320 0ustar charlesgenome/* Convert glam2 output to standard alignment formats */ #include #include /* tolower */ #include #include /* strlen, strcmp */ #include /* non-ANSI */ #include "util.h" #include "fasta.h" #include "alignment.h" /* Move to util? */ static char *lowercase(char *s) { /* better to use strcasecmp? */ unsigned char *t; assert(s != NULL); for (t = (unsigned char *)s; *t; ++t) *t = tolower(*t); return s; } /* Return count of characters in cs other than c */ static size_t strccnt(const char *cs, int c) { size_t count = 0; assert(cs != NULL); for (; *cs != '\0'; ++cs) count += *cs != (char)c; /* same cast as strchr(?) */ return count; } void seq_fasta_write(const aligned_seq *s, size_t line_size, FILE *stream) { const char *seq = s->seq; size_t i; assert(line_size > 0); fprintf(stream, ">%s\n", s->name); for (i = 0; seq[i] != 0; ++i) { putc(seq[i], stream); if ((i+1) % line_size == 0 || seq[i+1] == 0) putc('\n', stream); } } void aln_fasta_write(const alignment *a, FILE *stream) { static const size_t line_size = 60; size_t i; for (i = 0; i != a->seq_num; ++i) seq_fasta_write(&a->seqs[i], line_size, stream); } static size_t aln_max_len(const alignment *a) { size_t max = 0; size_t i; for (i = 0; i != a->seq_num; ++i) { const size_t len = strlen(a->seqs[i].seq); if (len > max) max = len; } return max; } void aln_msf_write(const alignment *a, FILE *stream) { static const size_t line_size = 50; static const size_t block_size = 10; const size_t max_len = aln_max_len(a); size_t i, j, k; fputs("PileUp\n\n", stream); /* is this needed? */ fprintf(stream, " MSF: %lu Type: X Check: 0 ..\n\n", (unsigned long)max_len); for (i = 0; i != a->seq_num; ++i) { const aligned_seq *s = &a->seqs[i]; fprintf(stream, " Name: %-10.10s Len: %lu Check: 0 Weight: 1.00\n", s->name, (unsigned long)strlen(s->seq)); } fputs("\n//\n\n", stream); for (i = 0; i < max_len; i += line_size) { /* theoretical overflow risk */ for (j = 0; j != a->seq_num; ++j) { const aligned_seq *s = &a->seqs[j]; const size_t len = strlen(s->seq); /* slow */ fprintf(stream, "%-10.10s", s->name); for (k = 0; k != line_size && i + k < len; ++k) { const int c = s->seq[i+k]; if (k % block_size == 0) putc(' ', stream); putc(c, stream); } putc('\n', stream); } putc('\n', stream); } } /* Calculate how many columns an alignment will have after extension */ static size_t aln_extended_size(const alignment *a) { size_t new_size = 0; size_t i, j; for (i = 0; a->key_positions[i] != 0; ++i) if (a->key_positions[i] == '*') ++new_size; else for (j = 0; j < a->seq_num; ++j) new_size += a->seqs[j].seq[i] != '.'; return new_size; } /* Put extension of b in a, assuming sufficient memory has been allocated */ static void aln_do_extend(alignment *a, const alignment *b) { const char *kp = b->key_positions; const size_t seqnum = b->seq_num; size_t apos = 0; size_t s, t, bpos, bend, boff; for (bpos = 0; ; bpos = bend) { for (s = 0; s != seqnum; ++s) /* fill in the key position */ a->seqs[s].seq[apos] = b->seqs[s].seq[bpos]; ++apos; ++bpos; if (kp[bpos] == 0) break; assert(strchr(kp + bpos, '*') != NULL); bend = strchr(kp + bpos, '*') - kp; /* next key position */ for (s = 0; s != seqnum; ++s) { /* fill in the insertions */ const char *bseq = b->seqs[s].seq; for (boff = bpos; boff != bend; ++boff) if (bseq[boff] != '.') { for (t = 0; t != seqnum; ++t) /* put gaps in all other sequences */ a->seqs[t].seq[apos] = t == s ? bseq[boff] : '.'; ++apos; } } } for (s = 0; s != seqnum; ++s) /* terminate the strings */ a->seqs[s].seq[apos] = 0; } /* Extend an alignment, by un-aligning inserted residues */ static void aln_extend(alignment *a) { const size_t new_size = aln_extended_size(a); alignment tmp; size_t s; XMALLOC(tmp.seqs, a->seq_num); for (s = 0; s != a->seq_num; ++s) tmp.seqs[s].seq = xmalloc(new_size + 1); /* space for final NUL */ aln_do_extend(&tmp, a); for (s = 0; s != a->seq_num; ++s) { free(a->seqs[s].seq); a->seqs[s].seq = tmp.seqs[s].seq; } free(tmp.seqs); } /* Copy an array of ints into an array of chars */ static void int2char(char *s, const int *v, const size_t size) { size_t i; for (i = 0; i != size; ++i) s[i] = v[i]; } /* Get either sum or maximum of left flanking sequence lengths */ static int aln_tot_left(const alignment *a, int want_sum) { int tot = 0; size_t i; for (i = 0; i != a->seq_num; ++i) { const aligned_seq *s = &a->seqs[i]; const int left = xatoi(s->start) - 1; /* zero-based coordinate */ if (want_sum) tot += left; else /* want maximum */ if (left > tot) tot = left; } return tot; } /* Get either sum or maximum of right flanking sequence lengths */ static int get_tot_right(const alignment *a, const mfasta *m, int want_sum) { int tot = 0; int i; size_t j = 0; for (i = 0; i < m->seqnum; ++i) { const fasta *f = &m->f[i]; const aligned_seq *s = &a->seqs[j]; if (j != a->seq_num && strcmp(f->title, s->name) == 0) { const int left = xatoi(s->start) - 1; /* zero-based coordinate */ const int seq_len = strccnt(s->seq, '.'); const int seq_end = left + seq_len; const int right = f->seqlen - seq_end; if (want_sum) tot += right; else /* want maximum */ if (right > tot) tot = right; ++j; } } return tot; } /* Stick flanking sequences onto the left and right of an alignment */ static void add_flanks(alignment *a, const mfasta *m, int want_extend) { const int left_tot = aln_tot_left(a, want_extend); const int right_tot = get_tot_right(a, m, want_extend); int left_cumu = 0; /* only used for extended alignments */ int right_cumu = 0; /* only used for extended alignments */ int i; size_t j = 0; for (i = 0; i < m->seqnum; ++i) { const fasta *f = &m->f[i]; aligned_seq *s = &a->seqs[j]; if (j != a->seq_num && strcmp(f->title, s->name) == 0) { const int left = xatoi(s->start) - 1; /* zero-based coordinate */ const int aln_len = strlen(s->seq); const int seq_len = strccnt(s->seq, '.'); const int aln_end = left_tot + aln_len; const int seq_end = left + seq_len; const int right = f->seqlen - seq_end; const int left_extra = left_tot - left_cumu - left; const int right_extra = right_tot - right_cumu - right; const int left_beg = left_extra; const int right_beg = aln_end + right_cumu; const int left_end = left_beg + left; const int right_end = right_beg + right; const int tot_len = aln_end + right_tot; char *new_seq = xmalloc(tot_len+1); /* space for the final 0 */ memset(new_seq, '.', left_extra); int2char(new_seq + left_beg, f->seq, left); memset(new_seq + left_end, '.', left_cumu); memcpy(new_seq + left_tot, s->seq, aln_len); memset(new_seq + aln_end, '.', right_cumu); int2char(new_seq + right_beg, f->seq + seq_end, right); memset(new_seq + right_end, '.', right_extra); new_seq[tot_len] = 0; /* terminate the string */ free(s->seq); s->seq = new_seq; left_cumu += left * want_extend; right_cumu += right * want_extend; ++j; } } if (j != a->seq_num) die("%s: didn't find %s among the sequences\n", prog_name, a->seqs[j].name); assert(left_cumu == left_tot * want_extend); assert(right_cumu == right_tot * want_extend); } /* Mangle sequence names in the same way as glam2 */ static void mangle_names(mfasta *m) { static const int name_width = 12; /* max name width for glam2 */ int i; for (i = 0; i < m->seqnum; ++i) { first_word(m->f[i].title); strtrunc(m->f[i].title, name_width); } } /* Read sequences and stick flanking bits onto an alignment */ static void get_flanks(alignment *a, const char *seq_file, int want_extend) { mfasta m; FILE *fp = xfopen(seq_file, "r"); mfasta_read(&m, fp); /* read the sequences */ xfclose(fp); mangle_names(&m); /* make sequence names match alignment names */ add_flanks(a, &m, want_extend); free_mfasta(&m); } static void usage(void) { die("\ Usage: glam2format [options] my_format my_motif.glam2\n\ Formats: fasta, msf\n\ Options (default settings):\n\ -o: output file (stdout)\n\ -c: make a compact alignment\n\ -f: sequence file for flanking sequences\n\ "); } int main(int argc, char **argv) { const char *format; const char *in_file; const char *out_file = "-"; const char *seq_file = NULL; int want_extend = 1; FILE *fp; alignment aln; int c; prog_name = "glam2format"; /* for error messages */ while ((c = getopt(argc, argv, "o:cf:")) != -1) { /* non-ANSI */ switch (c) { case 'o': out_file = optarg; break; case 'c': want_extend = 0; break; case 'f': seq_file = optarg; break; case '?': usage(); } } if (optind != argc-2) usage(); format = lowercase(argv[optind++]); in_file = argv[optind++]; fp = xfopen(in_file, "r"); aln_read(&aln, fp); xfclose(fp); if (want_extend) { if (aln.key_positions == NULL) die("%s: no motif found in %s\n", prog_name, in_file); if (!aln_same_lengths(&aln)) die("%s: unequal aligned lengths in %s\n", prog_name, in_file); aln_extend(&aln); } if (seq_file) get_flanks(&aln, seq_file, want_extend); fp = xfopen(out_file, "w"); if (strcmp(format, "fasta") == 0) aln_fasta_write(&aln, fp); else if (strcmp(format, "msf") == 0) aln_msf_write(&aln, fp); else usage(); xfclose(fp); aln_free(&aln); return 0; } glam2-1064/src/heap.h0000644007451300001540000000167410625011622014011 0ustar charlesgenome/* A heap is a partially sorted array, where, in one-based coordinates: array[i] >= array[i * 2] and array[i] >= array[i * 2 + 1] */ #ifndef HEAP_H #define HEAP_H #include #define PUSH_HEAP(base, n, cmp) push_heap(base, n, sizeof *(base), cmp) #define POP_HEAP(base, n, cmp) pop_heap(base, n, sizeof *(base), cmp) /* cmp should return negative if the 1st argument is less than the 2nd, zero if equal, and positive if greater */ /* Add base[n-1] into the heap, by re-ordering base[0] ... base[n-1] */ /* Assumes base[0] ... base[n-2] is initially a heap */ void push_heap(void *base, size_t n, size_t size, int (*cmp)(const void *, const void *)); /* Remove base[0] from the heap */ /* i.e. move it to base[n-1], leaving a heap in base[0] ... base[n-2] */ /* Assumes base[0] ... base[n-1] is initially a heap */ void pop_heap(void *base, size_t n, size_t size, int (*cmp)(const void *, const void *)); #endif glam2-1064/src/scan.c0000644007451300001540000001611410647047235014023 0ustar charlesgenome/* GLAM2 scanner */ #include #include /* DBL_MAX */ #include /* free */ #include "util.h" #include "heap.h" #include "scan.h" #include "scan_init.h" #include "scan_output.h" /* print vector of doubles: for debugging */ void print_vec(double *vec, int size) { int i; for (i = 0; i < size; ++i) printf("%.2g%c", vec[i], i < size-1 ? '\t' : '\n'); } /* print matrix of doubles: for debugging */ void print_mat(double **mat, int rows, int cols) { int i, j; for (i = 0; i < rows; ++i) for (j = 0; j < cols; ++j) printf("%.2g%c", mat[i][j], j < cols-1 ? '\t' : '\n'); } double max3(double x, double y, double z) { if (x > y) if (x > z) return x; else return z; else if (y > z) return y; else return z; } void init_alignment(alignment *aln, const data *d, int strand) { const int width = d->m.width; const int *seq = strand == '+' ? d->f.seq : d->f.rcseq; const int *hp = d->hit_positions; const int *hm = d->hit_matches; const int start = hp[0]; const int end = hp[width-1] + hm[width-1]; const int deletions = width - sum_int(hm, width); const int aln_size = end - start + deletions; char *name = xstrdup(d->f.title); int *seq1 = xmalloc(aln_size * sizeof(int)); int *seq2 = xmalloc(aln_size * sizeof(int)); int aln_pos = 0; int seq_pos = start; int mot_pos; for (mot_pos = 0; mot_pos < width; ++mot_pos) { while (seq_pos < hp[mot_pos]) { seq2[aln_pos] = seq[seq_pos++]; seq1[aln_pos++] = 0; } if (hm[mot_pos] == 1) { /* match */ assert(seq[seq_pos] < d->alph.size); /* ambiguous residue forbidden */ seq2[aln_pos] = seq[seq_pos++]; } else /* deletion */ seq2[aln_pos] = d->alph.size; seq1[aln_pos++] = 1; } aln->name = name; aln->strand = strand; aln->coord1 = strand == '+' ? start+1 : d->f.seqlen - start; aln->coord2 = strand == '+' ? end : d->f.seqlen - end + 1; aln->aln_size = aln_size; aln->seq1 = seq1; aln->seq2 = seq2; aln->score = d->dp_mat[width][end]; } void free_alignment(alignment *aln) { free(aln->name); free(aln->seq1); free(aln->seq2); } int cmp_alignment(const void *a, const void *b) { const alignment *x = a; const alignment *y = b; if (x->score < y->score) return +1; if (x->score > y->score) return -1; /* break ties by sequence name, so results don't depend on order of input */ return strcmp(x->name, y->name); } void reinit_dp(data *d, int seqlen) { const int width = d->m.width; int i; if (seqlen > d->dp_seqlen) { for (i = 0; i <= width; ++i) { d->dp_mat[i] = XREALLOC(d->dp_mat[i], seqlen+1); d->forbidden[i] = XREALLOC(d->forbidden[i], seqlen+1); } set_dbl(d->dp_mat[0], seqlen+1, 0); /* boundary condition */ d->dp_seqlen = seqlen; } for (i = 0; i <= width; ++i) ZERO(d->forbidden[i], seqlen+1); } void dyn_prog(data *d, int strand) { const int width = d->m.width; const int seqlen = d->f.seqlen; const int *seq = strand == '+' ? d->f.seq : d->f.rcseq; const int *end = seq + seqlen; int i; for (i = 0; i < width; ++i) { /* tried to optimize this inner loop as much as possible */ /* it seems surprisingly easy to beat gcc -O3 */ const int *s = seq; const double *ms = d->match_scores[i]; const double ds = d->delete_scores[i]; const double is = d->insert_scores[i]; const double *mat1 = d->dp_mat[i]; double *mat2 = d->dp_mat[i+1]; double m1 = *mat1; double m2 = *mat2; while (s != end) { ++mat1; ++mat2; const double match = ms[*s] + m1; m1 = *mat1; const double delete = ds + m1; m2 += is; if (match > m2) m2 = match; if (delete > m2) m2 = delete; *mat2 = m2; ++s; } } } int traceback(data *d, int end, int strand) { const int width = d->m.width; const int *seq = strand == '+' ? d->f.seq : d->f.rcseq; int i = width - 1; int j = end - 1; while (i != -1 && j != -1) { const double match = d->forbidden[i][j] == 0 ? d->match_scores[i][seq[j]] + d->dp_mat[i][j] : -DBL_MAX; const double delete = d->delete_scores[i] + d->dp_mat[i][j+1]; const double insert = d->insert_scores[i] + d->dp_mat[i+1][j]; if (match >= delete && match >= insert) { /* match */ assert(seq[j] < d->alph.size); /* ambiguous residue forbidden */ d->hit_matches[i] = 1; d->hit_positions[i] = j; d->forbidden[i][j] = 1; --i; --j; } else if (delete >= insert) { /* deletion */ d->hit_matches[i] = 0; d->hit_positions[i] = j+1; --i; } else { /* insertion */ assert(i+1 != width); --j; } } for (; i != -1; --i) { d->hit_matches[i] = 0; d->hit_positions[i] = 0; } return j+1; } void recalculate(data *d, int start, int strand) { const int width = d->m.width; const int seqlen = d->f.seqlen; const int *seq = strand == '+' ? d->f.seq : d->f.rcseq; int end = start; int i, j; for (i = 0; i < width; ++i) for (j = start; j < seqlen; ++j) { const double match = d->forbidden[i][j] == 0 ? d->match_scores[i][seq[j]] + d->dp_mat[i][j] : -DBL_MAX; const double delete = d->delete_scores[i] + d->dp_mat[i][j+1]; const double insert = d->insert_scores[i] + d->dp_mat[i+1][j]; const double new = max3(match, delete, insert); if (new != d->dp_mat[i+1][j+1]) { d->dp_mat[i+1][j+1] = new; if (end < j) end = j; } else if (j > end) break; } } void scan_seq(data *d, int strand) { const int width = d->m.width; const int seqlen = d->f.seqlen; reinit_dp(d, d->f.seqlen); dyn_prog(d, strand); while (1) { /* print_mat(d->dp_mat, width+1, seqlen+1); */ const double *last_row = d->dp_mat[width]; const int end = max_dbl(last_row, seqlen+1) - last_row; const int start = traceback(d, end, strand); /* require at least 1 match, to prevent infinite loop: */ if (sum_int(d->hit_matches, width) == 0) break; if (d->hit_num == d->a.hit_num) { if (d->hit_num == 0 || last_row[end] <= d->hits[0].score) break; POP_HEAP(d->hits, d->hit_num, cmp_alignment); --d->hit_num; free_alignment(d->hits + d->hit_num); } init_alignment(d->hits + d->hit_num, d, strand); ++d->hit_num; PUSH_HEAP(d->hits, d->hit_num, cmp_alignment); recalculate(d, start, strand); } } int main(int argc, char **argv) { data d; FILE *fp; prog_name = "glam2scan"; /* for error messages */ getargs(&d.a, argc, argv); init(&d); fputs("GLAM2scan\nVersion " #include "version.h" "\n\n", d.out); printargs(d.out, argc, argv); putc('\n', d.out); /* print_vec(d.delete_scores, d.m.width); print_vec(d.insert_scores, d.m.width); print_mat(d.match_scores, d.m.width, d.alph.size); */ fp = xfopen(d.a.seq_file, "r"); while (fasta_read(&d.f, fp) != EOF) { first_word(d.f.title); tr_fasta(&d.f, d.alph.encode); scan_seq(&d, '+'); if (d.a.two_strands) { rc_fasta(&d.f, d.alph.size); scan_seq(&d, '-'); } free_fasta(&d.f); } xfclose(fp); SORT(d.hits, d.hit_num, cmp_alignment); print_hits(d.out, d.hits, &d); return 0; } glam2-1064/src/heap.c0000644007451300001540000000201010636472757014013 0ustar charlesgenome#include "util.h" /* memswap */ #include "heap.h" void push_heap(void *base, size_t n, size_t size, int (*cmp)(const void *, const void *)) { while (n > 1) { const size_t n2 = n / 2; if ((*cmp)((const char *)base + (n-1) * size, (const char *)base + (n2-1) * size) <= 0) break; memswap((char *)base + (n-1) * size, (char *)base + (n2-1) * size, size); n = n2; } } void pop_heap(void *base, size_t n, size_t size, int (*cmp)(const void *, const void *)) { size_t hole = 1; if (n == 0) return; memswap(base, (char *)base + (n-1) * size, size); while (1) { size_t child1 = hole * 2; size_t child2 = hole * 2 + 1; if (child1 >= n) break; else if (child2 < n) if ((*cmp)((const char *)base + (child1-1) * size, (const char *)base + (child2-1) * size) < 0) child1 = child2; memswap((char *)base + (hole-1) * size, (char *)base + (child1-1) * size, size); hole = child1; } push_heap(base, hole, size, cmp); } glam2-1064/src/alphabet.h0000644007451300001540000000137410653304343014657 0ustar charlesgenome#ifndef ALPHABET_H #define ALPHABET_H #include #include typedef struct { int size; /* number of symbols in the alphabet, apart from wildcards */ int encode[UCHAR_MAX+1]; int decode[UCHAR_MAX+1]; /* could use unsigned char? */ double *prob; /* probability of each symbol */ } alphabet; /* Set up a nucleotide alphabet */ /* Uniform abundances */ void alphabet_n(alphabet *a); /* Set up a protein alphabet */ /* Abundances of AB Robinson & LR Robinson 1991: same as BLAST */ void alphabet_p(alphabet *a); /* Read an alphabet file in vmatch-like format */ /* Unspecified abundances are set to 1 */ void alphabet_read(alphabet *a, FILE *fp); /* Free the memory allocated in an alphabet */ void alphabet_free(alphabet *a); #endif glam2-1064/src/scan_init.h0000644007451300001540000000013010607311611015026 0ustar charlesgenome#ifndef SCAN_INIT_H #define SCAN_INIT_H #include "scan.h" void init(data *d); #endif glam2-1064/src/Makefile0000644007451300001540000000447611014150302014356 0ustar charlesgenome# This file holds commands for compiling programs in the GLAM2 package # These commands are customized for the gcc compiler, and may need to # be modified for other compilers # -Wall means turn on compiler warnings (optional) # -O3 means optimization level 3 (the maximum for gcc) # -lm means include the math library # Source files for glam2: GSRC = alphabet.c args.c column_sample.c dirichlet.c dna_prior.c \ fasta.c glam2.c glam2_aln.c init.c output.c recode3_20comp.c \ site_sample.c util.c # Source files for glam2scan: SSRC = alphabet.c scan_args.c dirichlet.c dna_prior.c fasta.c scan.c \ scan_init.c scan_output.c recode3_20comp.c util.c heap.c motif.c \ alignment.c # Source files for glam2format: FSRC = glam2format.c alignment.c fasta.c util.c # Source files for glam2mask: MSRC = glam2mask.c alignment.c fasta.c util.c # Compiler options: CFLAGS = -Wall -O3 # Default action: compile glam2, glam2scan, glam2format, and glam2mask all: glam2 glam2scan glam2format glam2mask # Command for compiling glam2: glam2: $(GSRC) *.h Makefile cc $(CFLAGS) -o glam2 $(GSRC) -lm # Command for compiling glam2scan: glam2scan: $(SSRC) *.h Makefile cc $(CFLAGS) -o glam2scan $(SSRC) -lm # Command for compiling glam2format: glam2format: $(FSRC) *.h Makefile cc $(CFLAGS) -o glam2format $(FSRC) -lm # Command for compiling glam2mask: glam2mask: $(MSRC) *.h Makefile cc $(CFLAGS) -o glam2mask $(MSRC) -lm # Here follow commands for compiling special versions of the programs # Compile glam2 including FFT algorithm (requires FFTW to be installed): glam2fft: $(GSRC) convolve.c *.h Makefile cc $(CFLAGS) -DFFT -o glam2fft $(GSRC) convolve.c -lm -lfftw3 # Compile for debugging with gdb or valgrind, with extra compiler warnings: glam2_d: $(GSRC) *.h Makefile cc -Wall -W -pedantic -g -o glam2_d $(GSRC) -lm glam2scan_d: $(SSRC) *.h Makefile cc -Wall -W -pedantic -g -o glam2scan_d $(SSRC) -lm glam2format_d: $(FSRC) *.h Makefile cc -Wall -W -pedantic -g -o glam2format_d $(FSRC) -lm glam2mask_d: $(MSRC) *.h Makefile cc -Wall -W -pedantic -g -o glam2mask_d $(MSRC) -lm # Compile for profiling with gprof, with extra compiler warnings: # Use -O2 to avoid function inlining glam2_p: $(GSRC) *.h Makefile cc -Wall -W -pedantic -O2 -pg -o glam2_p $(GSRC) -lm glam2scan_p: $(SSRC) *.h Makefile cc -Wall -W -pedantic -O2 -pg -o glam2scan_p $(SSRC) -lm glam2-1064/src/scan_args.c0000644007451300001540000000567110644356002015035 0ustar charlesgenome#include #include #include #include /* non-ANSI */ #include "util.h" #include "scan_args.h" /* default values: */ static const int n_def = 25; static const double D_def = 0.1; static const double E_def = 2; static const double I_def = 0.02; static const double J_def = 1; static void usage(void) { die("\ Usage: glam2scan [options] alphabet my_motif.glam2 my_seqs.fa\n\ Main alphabets: p = proteins, n = nucleotides\n\ Main options (default settings):\n\ -h: show all options and their default settings\n\ -o: output file (stdout)\n\ -n: number of alignments to report (%d)\n\ -2: examine both strands - forward and reverse complement\n\ ", n_def); } static void help(void) { die("\ Usage: glam2scan [options] alphabet my_motif.glam2 my_seqs.fa\n\ Alphabets: p = proteins, n = nucleotides, other = alphabet file\n\ Options (default settings):\n\ -h: show all options and their default settings\n\ -o: output file (stdout)\n\ -n: number of alignments to report (%d)\n\ -2: examine both strands - forward and reverse complement\n\ -D: deletion pseudocount (%g)\n\ -E: no-deletion pseudocount (%.1f)\n\ -I: insertion pseudocount (%g)\n\ -J: no-insertion pseudocount (%.1f)\n\ -d: Dirichlet mixture file\n\ ", n_def, D_def, E_def, I_def, J_def); } void getargs(args *a, int argc, char **argv) { int c; a->out_file = "-"; a->hit_num = n_def; a->two_strands = 0; a->delete_pseudo = D_def; a->no_delete_pseudo = E_def; a->insert_pseudo = I_def; a->no_insert_pseudo = J_def; a->dirichlet_file = NULL; /* non-ANSI: */ while ((c = getopt(argc, argv, "ho:n:2D:E:I:J:d:")) != -1) { switch (c) { case 'h': help(); case 'o': a->out_file = optarg; break; case 'n': a->hit_num = xatoi(optarg); if (a->hit_num < 0) /* let's allow 0, even though it's stupid */ die("%s: option -n should be at least 0\n", prog_name); break; case '2': a->two_strands = 1; break; case 'D': a->delete_pseudo = xatof(optarg); if (a->delete_pseudo <= 0) die("%s: option -D should be > 0\n", prog_name); break; case 'E': a->no_delete_pseudo = xatof(optarg); if (a->no_delete_pseudo <= 0) die("%s: option -E should be > 0\n", prog_name); break; case 'I': a->insert_pseudo = xatof(optarg); if (a->insert_pseudo <= 0) die("%s: option -I should be > 0\n", prog_name); break; case 'J': a->no_insert_pseudo = xatof(optarg); if (a->no_insert_pseudo <= 0) die("%s: option -J should be > 0\n", prog_name); break; case 'd': a->dirichlet_file = optarg; break; case '?': usage(); } } if (optind != argc-3) usage(); a->alph_name = argv[optind++]; a->motif_file = argv[optind++]; a->seq_file = argv[optind++]; } void printargs(FILE *fp, int argc, char **argv) { int i; for (i = 0; i < argc; ++i) { fputs(argv[i], fp); putc(i < argc-1 ? ' ' : '\n', fp); } } glam2-1064/src/convolve.c0000644007451300001540000000470210607311611014716 0ustar charlesgenome#include #include #include "util.h" #include "convolve.h" /* Return the lowest power of 2 that is >= x (and >= 1) */ static int next_pow2(const int x) { int y = 1; while (y < x) { assert(can_mul_int(y, 2)); y *= 2; } return y; } /* Multiplication of complex numbers */ /* Allows output to overwrite input */ static void multiply_complex(fftw_complex z, const fftw_complex x, const fftw_complex y) { const double a = x[0] * y[0] - x[1] * y[1]; const double b = x[0] * y[1] + x[1] * y[0]; z[0] = a; z[1] = b; } /* Dot product of complex vectors */ /* Can't use const for pointer-to-pointer */ static void dot_complex(fftw_complex *z, fftw_complex *x, fftw_complex *y, int size) { int i; for (i = 0; i < size; ++i) multiply_complex(z[i], x[i], y[i]); } /* malloc or die */ static void *fftw_xmalloc(size_t size) { void *p = fftw_malloc(size); if (p == NULL) die("%s: error allocating %lu bytes: %s\n", prog_name, (unsigned long)size, strerror(errno)); return p; } void fft_init(fft_convolver *f, const int max_size) { int zero_pad, size, mem; assert(max_size > 0); zero_pad = max_size - 1; /* padding to avoid wraparound convolution */ assert(can_add_int(max_size, zero_pad)); size = next_pow2(max_size + zero_pad); /* power-of-2 size is faster??? */ assert(can_mul_int(2, size / 2 + 1)); mem = 2 * (size / 2 + 1); /* padding for in-place transforms */ f->size = size; f->x = fftw_xmalloc(mem * sizeof(double)); f->y = fftw_xmalloc(mem * sizeof(double)); f->z = fftw_xmalloc(mem * sizeof(double)); f->x_plan = fftw_plan_dft_r2c_1d(size, f->x, (fftw_complex *)f->x, FFTW_MEASURE); f->y_plan = fftw_plan_dft_r2c_1d(size, f->y, (fftw_complex *)f->y, FFTW_MEASURE); f->z_plan = fftw_plan_dft_c2r_1d(size, (fftw_complex *)f->z, f->z, FFTW_MEASURE); } void fft_convolve(double *z, const double *x, const double *y, const int size, fft_convolver *f) { const int half_size = f->size / 2 + 1; const int pad_size = f->size - size; assert(size <= f->size / 2); COPY(f->x, x, size); COPY(f->y, y, size); set_dbl(f->x + size, pad_size, 0); /* pad with zeros */ set_dbl(f->y + size, pad_size, 0); /* pad with zeros */ fftw_execute(f->x_plan); fftw_execute(f->y_plan); dot_complex((fftw_complex *)f->z, (fftw_complex *)f->x, (fftw_complex *)f->y, half_size); fftw_execute(f->z_plan); mul_dbl(f->z, f->size, 1.0 / f->size); COPY(z, f->z, size); } glam2-1064/src/scan_args.h0000644007451300001540000000113310607311611015023 0ustar charlesgenome/* data structure to hold command line arguments for GLAM2 scanner */ #ifndef SCAN_ARGS_H #define SCAN_ARGS_H #include typedef struct { const char *out_file; int hit_num; /* number of alignments to report */ int two_strands; double delete_pseudo; double no_delete_pseudo; double insert_pseudo; double no_insert_pseudo; const char *dirichlet_file; const char *alph_name; /* "n" = nucleotide, "p" = protein */ const char *motif_file; const char *seq_file; } args; void printargs(FILE *fp, int argc, char **argv); void getargs(args *a, int argc, char **argv); #endif glam2-1064/src/scan_output.h0000644007451300001540000000023410607311611015430 0ustar charlesgenome#ifndef SCAN_OUTPUT_H #define SCAN_OUTPUT_H #include #include "scan.h" void print_hits(FILE *fp, const alignment *alns, const data *d); #endif glam2-1064/purge/0000755007451300001540000000000011014153712013246 5ustar charlesgenomeglam2-1064/purge/purge.c0000644007451300001540000000675510631405617014561 0ustar charlesgenome/* purge.c - homology purge program */ #include "purge.h" Boolean RmHomologs(long cutoff, char method, long minimum, Boolean query, ss_type P) /** Use block bit array for edges to save space **/ { long maxleng,i,k,entry,*lengs,*list; long item,item1,*hits,N; b_type *edges; FILE *fptr; dh_type H; gb_typ B = NULL; keytyp key; e_type E,E1,E2; char str[100]; Boolean made_file=FALSE,related; N = NSeqsSeqSet(P); H = dheap(N+2,3); NEW(edges,N+2,b_type); NEW(list,N+2,long); NEW(lengs,N+2,long); NEW(hits,N+2,long); for(maxleng=0,entry =1 ;entry <= N;entry++) { E=SeqSetE(entry,P); lengs[entry]=LenSeq(E); edges[entry] = Block(N+1); maxleng = tMAX(long,maxleng,LenSeq(E)); } maxleng *= 2; entry = 1; if(cutoff < 99999) { for(item =1 ;item <= N;item++) { E1=SeqSetE(item,P); if(method == 'b') B=MakeGBlast(11, E1, SeqSetA(P)); for(item1 =item+1 ;item1 <= N;item1++) { E2=SeqSetE(item1,P); if(method == 'h'){ /** fasta heuristic method **/ related = RelateSeqFastp(E1,E2,SeqSetA(P),cutoff); } else if(method == 'b'){ /** gblast heuristic method **/ related = FastMatcherGBlast(E2, B, cutoff); /***** if(item==3 && item1==40) MatcherGBlast(stderr,E2, B); *****/ } else related = RelatedSeqs(cutoff, E1, E2, SeqSetA(P)); if(related){ AddBlock(item,edges[item1]); AddBlock(item1,edges[item]); hits[item]++; hits[item1]++; } } if(method == 'b') NilGBlast(B); fprintf(stderr,"\r%ld",entry++); /**/ } } fprintf(stderr,"\n%ld items compared\n", entry-1); if(!query){ for(entry=1; entry <= N; entry++){ key = -(keytyp) hits[entry]; key += (keytyp)lengs[entry]/(keytyp)maxleng; /*if(hits[entry] > 0) fprintf(stdout,"#%d: %d hits; key = %f\n", entry,hits[entry],key);*/ insrtHeap(entry,key,H); } while(TRUE){ if(emptyHeap(H)) print_error("error in RmHomologs( )"); else if(minkeyHeap(H) >= 0) break; else { item=delminHeap(H); for(i=1;i <= N;i++){ if(MemberBlock(i,edges[item]) && memHeap(i,H)){ hits[i]--; key = - (keytyp) hits[i]; key += (keytyp)lengs[i]/(keytyp)maxleng; chkeyHeap(i,key,H); } } } } } else { /** don't purge #1 from set; i.e., don't put in heap. **/ for(entry=2; entry <= N; entry++){ key = -(keytyp) hits[entry]; key += (keytyp)lengs[entry]/(keytyp)maxleng; /*if(hits[entry] > 0) fprintf(stdout,"#%d: %d hits; key = %f\n", entry,hits[entry],key);*/ insrtHeap(entry,key,H); } while(TRUE){ if(emptyHeap(H) || minkeyHeap(H) >= 0) break; else { item=delminHeap(H); for(i=2;i <= N;i++){ if(MemberBlock(i,edges[item]) && memHeap(i,H)){ hits[i]--; key = - (keytyp) hits[i]; key += (keytyp)lengs[i]/(keytyp)maxleng; chkeyHeap(i,key,H); } } } } insrtHeap(1,-1e99,H); } if(ItemsInHeap(H) < N+1){ /* TLB; allow all seqs thru */ if(ItemsInHeap(H) >= minimum){ sprintf(str,"%s.%c%ld",NameSeqSet(P),method,cutoff); fptr = open_file(str,"","w"); for(entry=1,k=0; entry <= N; entry++){ E=SeqSetE(entry,P); if(memHeap(entry,H)) { PutSeqSetE(fptr,entry,P); k++; } } fclose(fptr); fprintf(stderr,"%ld sequences put into file: '%s'\n",k,str); made_file = TRUE; } else fprintf(stderr, "less than %ld sequences left (%ld); file not created\n", minimum,ItemsInHeap(H)); } else fprintf(stderr,"no sequences removed; file not created\n"); for(entry=1; entry <= N; entry++) { NilBlock(edges[entry]); } free(lengs); free(hits); free(list); free(edges); Nildheap(H); return made_file; } glam2-1064/purge/mheap.h0000644007451300001540000000253210631405545014523 0ustar charlesgenome#if !defined (MMHEAP) #define MMHEAP #include "afnio.h" #include "dheap.h" #include "stdinc.h" /*************************** ADT MMHEAP *************************** min-max heap **********************************************************************/ /*************************** MMHEAP type **************************/ typedef struct { dh_type heap; /* minheap */ dh_type maxheap; /* maxheap */ long hpsz; /* heap size */ long nfree; /* #items available */ long *avail; /* list of available item no */ } mheap_type; typedef mheap_type *mh_type; /******************************* private *****************************/ /******************************* Public ******************************/ /***************************** operations ****************************/ mh_type Mheap(long hpsz, long d); long DelMinMheap(mh_type H); long DelMaxMheap(mh_type H); long RmMheap(long i, mh_type H); long InsertMheap(keytyp key, mh_type H); mh_type NilMheap(mh_type H); /**************************** macro operations **********************/ #define ItemsInMheap(H) ItemsInHeap((H)->heap) #define MinKeyMheap(H) minkeyHeap((H)->heap) #define MinItemMheap(H) minItemHeap((H)->heap) #define MaxKeyMheap(H) (-minkeyHeap((H)->maxheap)) #define EmptyMheap(H) emptyHeap((H)->heap) #define SizeMheap(H) ((H)->hpsz) #define FullMheap(H) fullHeap((H)->heap) #endif glam2-1064/purge/stdinc.h0000644007451300001540000000401610631405734014714 0ustar charlesgenome/* tlb 11/10/06; changes made to NEW functions to comply with ANSII standard; changed MIN, MAX to remove conflicts with macros of same names elsewhere */ /* defines.h - generic codes and constants for afn biosequence programs. */ #include #include #include #include #include #include #include /* VALUES */ #define NIL -1 #define FALSE 0 #define TRUE 1 #define ILLEGAL -1.0 #define BELL ((char) 7) #define FILE_BEGIN 0 #define FILE_CURRENT 1 #define FILE_END 2 #define Boolean char /* CONSTANTS */ #define MAX_INTEGER LONG_MAX /* MACROS - standard macro definitions and static types */ #define MEW(x,n,t) if ( (x=(t*) malloc(((n)*sizeof(t))))==NULL) { \ fprintf(stderr,"Out of Memory."); exit(1); } #define NEW(x,n,t) if ( (x=(t*) calloc(n,sizeof(t)))==NULL ) { \ fprintf(stderr,"Out of Memory."); exit(1); } #define NEWP(x,n,t) if ( (x=(t**) calloc(n,sizeof(t*)))==NULL) { \ fprintf(stderr,"Out of Memory."); exit(1); } #define NEWPP(x,n,t) (( (x=(t***) calloc(n,sizeof(t**)))==NULL) ? \ (t***) (fprintf(stderr,"Out of Memory."),exit(1),0):x) #define NEWP3(x,n,t) (( (x=(t****) calloc(n,sizeof(t***)))==NULL) ? \ (t****) (fprintf(stderr,"Out of Memory."),exit(1),0):x) #define GETCHAR(m,C) do{ fprintf(stderr,"%s ", m); \ if(fscanf(stdin,"%c",(C)) == 1) { \ while(getchar()!='\n') if(feof(stdin)) exit(1);\ break;\ } while(getchar()!='\n') if(feof(stdin)) exit(1);\ } while(TRUE); #define GETINT(m,i) do{ fprintf(stderr,"%s ",m); \ if(fscanf(stdin,"%d",(i)) == 1) { \ while(getchar()!='\n') if(feof(stdin)) exit(1);\ break;\ } while(getchar()!='\n') if(feof(stdin)) exit(1);\ } while(TRUE); #define print_error(str) for(fprintf(stderr,"%s\n",str); TRUE; exit(1)) #define DIGIT2INT(c) ((int)(c - 48)) #define tMIN(t,x,y) (((t)(x) < (t)(y)) ? (t)(x) : (t)(y)) #define tMAX(t,x,y) (((t)(x) > (t)(y)) ? (t)(x) : (t)(y)) #define SUM(x) (((x) * (x+1)) / 2) glam2-1064/purge/README0000600007451300001540000001366110723676107014143 0ustar charlesgenomeWe obtained the public domain purge program from ftp://ftp.ncbi.nlm.nih.gov/pub/neuwald/gibbs9_95/. We modified purge to be ANSI standard C and improved the user interface (2007). Here is the original README: /* ========================================================================= * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software is freely available to the * public for use. The National Library of Medicine and the U.S. Government * have not placed any restriction on its use or reproduction. * * Although reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite * * Neuwald, Liu, & Lawrence (1995) "Gibbs motif sampling: * detection of bacterial outer membrane protein repeats" * Protein Science 4, 1618-1632. (for Gibbs site sampling, * Gibbs motif sampling, purge, and scan programs) * * and * * Lawrence, Altschul, Boguski, Liu, Neuwald & Wootton (1993) * "Detecting Subtle Sequence Signals: A Gibbs Sampling Strategy * for Multiple Alignment", Science 262:208-214. (for Gibbs * site sampling program) * * in any work or product based on this material. * * The data structures used in this program are part of a package * of C code for molecular biological applications being developed * by A. F. Neuwald. * * =========================================================================*/ Uncompress gibbs9_95.tar.Z by typing "uncompress gibbs9_95.tar.Z" Then extract the files by typing "tar -xvf gibbs9_95.tar". This will create a directory "gibbs9_95". Go into this directory. Compile by typing "./compile" on the command line. (You may need to reset the CC macro in code/makefile to correspond to your compiler; the default is CC = cc). This will create three executable files in the current directory: purge, gibbs, and scan. Type the program names to see the input syntax. Each of these programs requires fasta formated input files. The purge program removes closely related sequences from an input file prior to running gibbs. This is important in order to reduce input sequence redundancy. The command syntax for purge is: purge where determines the maximum blosum62 relatedness score between any two sequences in the output file (the output file is created with the name .b). A score less than about 150 to 200 is highly recommended. The Gibbs motif sampler stochastically examines candidate alignments in an effort to find the best alignment as measured by the maximum a posteriori (MAP) log-likelihood ratio. Note that, because it is a stochastic method, there will be variations between the best alignments found with different random seeds - especially for subtle motifs. Consequently, it is often helpful to first run the sampler several times to see whether it usually converges on the same alignment each time. If it does not, as is typically the case for very subtle motifs, it may be necessary to perform a large number of independent searches in conjunction with a sufficient number of "near-optimum" samples (specified by the -R option). For instance, the alignment of subtle porin repeats described in Neuwald, Liu & Lawrence was obtained as the best found out of 1000 independent searches - 100 runs of the Gibbs program each performing 10 independent searches (the number of distinct searches is specified using the gibbs -t<#runs> option). To see an example of an alignment of porin repeats obtained as the best run out of 100 runs (as well as other examples) type "./demo" at the command line in the directory gibbs9_95. While picking the best result out of many independent runs is no guarrantee of obtaining the optimum alignment, it will substantially increase the chance of finding the optimum (or a nearly optimum) alignment in such cases. In any case it should be noted that most suboptimum alignments found by the sampler are often closely related to the optimum alignment. The scan program scans a database for sequences that contain motifs detected by gibbs. The gibbs program will produce a "scan file" of the locally aligned segment blocks by using the -f option. The resulting scan file is given the name .sn. In order to run the Wilcoxon test you will need a statistics package to analyze the output from the Gibbs sampler (it is NOT built into the Gibbs program). The Wilcoxon.test code is an Splus function that can be use for this purpose. In order to run it you need to scan in the *.wc file that the Gibbs program outputs with the -w option. Here's an example: S-PLUS : Copyright (c) 1988, 1992 Statistical Sciences, Inc. Version 3.1 Release 1 for Sun SPARC, SunOS 4.x : 1992 > xxx_matrix(scan("4hb.b100.wc"),2,6) > xxx [,1] [,2] [,3] [,4] [,5] [,6] [1,] 0.00 0.00 0.00 0.00 0.00 26.17 [2,] 28.92 30.29 27.53 27.72 28.11 0.00 > wilcox.test(xxx[1,],xxx[2,],alternative="less",paired=T) Exact Wilcoxon signed-rank test data: xxx[1, ] and xxx[2, ] signed-rank statistic V = 1, n = 6, p-value = 0.0312 These programs have been successfully compiled under UNIX on both an SGI and a Sun. Since they were developed as research tools, however, no promise is made that they can be compiled on any particular system. glam2-1064/purge/afnio.c0000644007451300001540000000270610631405432014516 0ustar charlesgenome#include "afnio.h" FILE *open_file(char *fstring,char *subfile,char *cmnd) { FILE *fptr; char s[100]; while(fstring[0] == ' ') fstring++; strcpy(s,fstring); strcat(s,subfile); if((fptr = fopen(s,cmnd)) == NULL) { fprintf(stderr,"Could not open file \"%s\"\n",s); print_error("File does not exist!\n"); } return(fptr); } long ParseReals(char *str, double *values, char *msg) /** WARNING: index starts at 0 not 1 as for ParseIntegers() **/ { long n; double k; if(!isdigit(str[0])) print_error(msg); for(n=1; str[0] != 0; ){ if(str[0] == ',') { n++; str++; } else if(isdigit(str[0])){ if(sscanf(str,"%lf", &k) != 1){ print_error(msg); } else { values[n-1] = k; while(isdigit(str[0]) || str[0] == '.' ) str++; } } else print_error(msg); } return n; } long ParseIntegers(char *str, long *values, char *msg) { long n,k; if(!isdigit(str[0])) print_error(msg); for(n=1; str[0] != 0; ){ if(str[0] == ',') { n++; str++; } else if(isdigit(str[0])){ if(sscanf(str,"%ld", &k) != 1){ print_error(msg); } else { values[n] = k; while(isdigit(str[0])) str++; } } else print_error(msg); } return n; } char *String(char *s) { char *S; if((S=(char*) calloc((strlen(s)+1),sizeof(char)))==NULL) print_error("Out of Memory"); strcpy(S,s); return S; } glam2-1064/purge/random.h0000644007451300001540000000031710631405637014712 0ustar charlesgenome #if !defined(RANDOM) #define RANDOM #include #include /* Random no. seeder and generator */ void sRandom(long x); long Random(void); #define DIM(A) (sizeof(A)/sizeof((A)[0])) #endif glam2-1064/purge/alphabet.c0000644007451300001540000001157110631406205015201 0ustar charlesgenome#include "alphabet.h" a_type MkAlphabetC(char *map_s,char *R,char *prs,char *comp) /* plus complementary bases */ { a_type A; long i; char c,d; A = MkAlphabet(map_s,R,prs); NEW(A->C,nAlpha(A)+2,char); /** if not defined set to 0 **/ for(i=0;isalpha(comp[i]);i+=2){ if(!isalpha(comp[i+1])) break; else { c = AlphaCode(comp[i],A); d = AlphaCode(comp[i+1],A); A->C[(int)c]=d; A->C[(int)d]=c; } } return A; } a_type MkAlphabet(char *map_s,char *R,char *prs) /* plus relatedness matrix input as ordered pairs */ { a_type A; long i; A=MkAlpha(map_s,R); NEWP(A->pairs,nAlpha(A)+2,char); for(i=0;i<=nAlpha(A);i++) NEW(A->pairs[i],nAlpha(A)+2,char); DefAlphaP(prs,A); return A; } a_type DefAlphaP(char *prs,a_type A) { long i,j,n; char c,d; for(i=0;i<=nAlpha(A);i++) { A->paired[i]=FALSE; for(j=0;j<=nAlpha(A);j++) { if(i==j) A->pairs[i][j] = 0; else A->pairs[i][j] = 99; } } for(n=1,A->npairs=i=0;isalpha(prs[i]);i+=2){ if(!isalpha(prs[i+1])) break; else { c = AlphaCode(prs[i],A); d = AlphaCode(prs[i+1],A); A->pairs[(int)c][(int)d]=A->pairs[(int)d][(int)c]=n++; A->paired[(int)c]=A->paired[(int)d]=TRUE; A->npairs++; } } if(A->prs!=NULL) free(A->prs); NEW(A->prs,strlen(prs)+2,char); for(j=0,i=1;i<=A->npairs;i++) { A->prs[j]=prs[j];j++; A->prs[j]=prs[j];j++; } return A; } a_type MkAlpha(char *map_s,char *R) { a_type A; long n,i; char c; NEW(A,1,alphabet_type); for(n=0;(c=map_s[n])!= '\0';n++) /* Get # letters */ if(!isalpha(c)) alpha_error("Illegal alphabet string",A); A->n = n-1; NEW(A->alphabet,A->n+2,char); /* ALPHABET */ strncpy(A->alphabet,map_s,nAlpha(A)+1); NEW(A->code2let,(strlen(map_s)+1),char); /* CODE2LETTER */ strcpy(A->code2let,map_s); NEW(A->code2lower,(strlen(map_s)+1),char); /* LOWER*/ strcpy(A->code2lower,map_s); NEW(A->let2code,ALPHA_NUM_SYMBOLS,char); /* LETTER2CODE */ for(i=0;ilet2code[i]= 0; /* =error */ for(i=0;map_s[i]!=0;i++) { c = map_s[(int)i]; A->let2code[(int)c] = i; if(isupper(c)) { c = tolower(c); A->let2code[(int)c] = i; } else if(islower(c)) { c = toupper(c); A->let2code[(int)c] = i; } } for(i=0;map_s[i]!=0;i++) if(isupper(map_s[i])) A->code2lower[i]=tolower(map_s[i]); if(R==NULL) { A->R = NULL; } /* RELATION */ else { /* tlb 5-6-00; make R type int */ NEWP(A->R,A->n+2,int); for(i=0;i<=nAlpha(A);i++) NEW(A->R[i],A->n+2,int); A = DefAlphaR(R,A); } NEW(A->paired,nAlpha(A)+2,Boolean); for(i=0;i<=nAlpha(A);i++) A->paired[i]=FALSE; A->pairs = NULL; A->prs = NULL; A->C = NULL; return (A); } a_type DefAlphaR(char *R,a_type A) /* relatedness matrix */ { long i,j,value,lo,hi; if(strlen(R)==0) { A->R = NULL; return A; } for(lo=9999,hi=(-9999),i=0;i<=nAlpha(A);i++) { for(j=0;j<=nAlpha(A);j++) { while(R[0] != '-' && !isdigit(R[0])) { if(R[0]== 0) alpha_error("Illegal input in DefAlphaR()",A); else R++; } if(sscanf(R,"%ld",&value) != 1) alpha_error("Illegal input in DefAlphaR()",A); A->R[i][j] = value; lo = tMIN(long,value,lo); hi = tMAX(long,value,hi); while(R[0] == '-' || isdigit(R[0])) R++; } } A->loR = lo; A->hiR = hi; return (A); } a_type PutAlpha(FILE *fptr,a_type A) { long i; fprintf(fptr,"Alphabet: %s (n=%ld)\n", A->alphabet,nAlpha(A)); fprintf(fptr," Code:\n"); for(i=0;i<=nAlpha(A);i++) fprintf(fptr," %c",A->code2let[i]); fprintf(fptr,"\n"); for(i=0;i<=nAlpha(A);i++) fprintf(fptr,"%3ld",i); fprintf(fptr,"\n\n"); PutAlphaR(fptr,A); fprintf(fptr,"\n"); PutAlphaPairs(fptr,A); fprintf(fptr,"\n"); return A; } void PutAlphaPairs(FILE *fptr, a_type A) { long i,j; if(A->pairs != NULL) { fprintf(fptr, " ordered pairs:\n "); for(j=0,i=1; i<=A->npairs; i++){ fprintf(fptr,"%c", A->prs[j]); j++; fprintf(fptr,"%c ", A->prs[j]); j++; if(i%10==0 && i < A->npairs){ fprintf(fptr, "\n "); } } fprintf(fptr,"\n"); } else fprintf(fptr," ordered pairs: NULL\n"); fprintf(fptr,"\n"); } void PutAlphaR(FILE *fptr, a_type A) { long i,j; if(A->R != NULL) { fprintf(fptr, " relatedness matrix:\n "); for(i=0; i<=nAlpha(A); i++) fprintf(fptr,"%3c", AlphaChar(i,A)); for(i=0; i<=nAlpha(A); i++) { fprintf(fptr,"\n %c:",AlphaChar(i,A)); for(j=0; j<=nAlpha(A); j++) fprintf(fptr,"%3d", valAlphaR(i,j,A)); } fprintf(fptr,"\n"); } else fprintf(fptr," R: NULL\n"); fprintf(fptr,"\n"); } void NilAlpha(a_type A) { long i; if(A != NULL) { free(A->alphabet); free(A->code2let); free(A->code2lower); free(A->let2code); if(A->C != NULL) free(A->C); if(A->R != NULL) { for(i=0;i<=nAlpha(A);i++) free(A->R[i]); free(A->R); } if(A->pairs != NULL) { for(i=0;i<=nAlpha(A);i++) free(A->pairs[i]); free(A->pairs); } if(A->prs!=NULL) free(A->prs); free(A->paired); free(A); } } void alpha_error(char *s, a_type A) { fprintf(stderr,"%s\n",s); PutAlpha(stderr,A); exit(1); } glam2-1064/purge/mlist.h0000644007451300001540000000220510631405557014561 0ustar charlesgenome/************ mlist.h - multiple linked list abstract data type.***********/ #if !defined(MLIST) #define MLIST #include "stdinc.h" /************************** alphabet datatype *****************************/ typedef struct { long M; /* number of elements for lists */ long N; /* number of lists */ long *first; /* pointers to beginning of lists */ long *item; /* items on lists */ long *next; /* pointer to next element */ long free; /* pinter to free list */ } multi_list_type; typedef multi_list_type *ml_type; /******************************** PRIVATE **********************************/ void mlist_error(char *s); /******************************** PUBLIC ***********************************/ /**************************** mlist operations **************************/ ml_type MkMList(long M, long N); long Add2MList(register long i, register long n, register ml_type L); long GetListMList(register long *list, register long n, register ml_type L); void NilMList(ml_type L); /***************************************************************************/ #define EmptyMList(n,L) ((L)->first[(n)]==0) #endif glam2-1064/purge/gblast.h0000644007451300001540000000533210631406220014675 0ustar charlesgenome/* gblast.h - generic blast program. */ #if !defined (GBLAST) #define GBLAST #include #include "afnio.h" #include "random.h" #include "residues.h" #include "alphabet.h" #include "dheap.h" #include "sequence.h" #include "mlist.h" /*********************** Finite State Machine ************************ FSM = (Q,q0,A,Sigma,d) Q = States q0 e Q = start state A subset Q = accepting states Sigma = input alphabet d = function from Q x Sigma -> Q (transition function) if in an accepting state then execute appropriate action. - go to positions on list and try extending alignment input text T[1..n]; pattern to be found P[1..m] n = input string length; m = pattern length (note: lex is a FSM) input tokens = A-Y and '-' 'x' '*' '\0' if q = a then go to query sequence: pos[q][1..n][A...Y] = list of positions matching pattern in accepting state = NULL if not an accepting state. blast method: 1. compile list of high scoring words and make fsm. 2. scan database for hits. 3. extend hits. (for purge extend only until find that score >= cutoff.) QWL ..: -> S = R(Q,N) + R(W,Y) + R(L,L). NYL if(S > Threshold) then extend hit to find MSP. need drop-score. *********************************************************************/ /*************************** generic gblast type **************************/ typedef struct { long nQ; /** number of States **/ long **d; /** d[q][r] = function from Q x A -> Q **/ ml_type *pos; /* lists for accept */ long *tmp; /* temporary list */ long T; a_type A; /* alphabet */ e_type E; /* query sequence */ } gblast_type; typedef gblast_type *gb_typ; /*********************************************************************/ /******************************* private *******************************/ Boolean FastExtendGBlast(e_type E1, long i1, e_type E2, long i2, register int **R, long score); long gblast_error(char *s); /******************************* PUBLIC *******************************/ gb_typ MakeGBlast(long T, e_type E, a_type A) ; long MatcherGBlastOffset(e_type E, gb_typ B, long *os); void NilGBlast(gb_typ B); long MatcherGBlast(FILE *fptr, e_type E, gb_typ B); Boolean FastMatcherGBlast(e_type E, gb_typ B, long score); long ExtendGBlast(e_type E1, long i1, e_type E2, long i2, a_type A); /*********************************************************************/ /* CODES */ /* CONSTANTS */ #define USAGE2_START "USAGE: fsm seq1 seq2 [options]\n\ options:\n\ [-l] - eliminate low complexity sequences\n\ [-f] - create output file for sequence with repeats\n\ [-F] - create output file for sequence without repeats\n\ [-e] - E value cutoff for output of sequences\n" #endif glam2-1064/purge/sequence.h0000644007451300001540000000563310631406257015247 0ustar charlesgenome/* entity.h - entity data type. */ #if !defined(SEQUENCE) #define SEQUENCE #include "stdinc.h" #include "alphabet.h" #include "dheap.h" #include "random.h" /**************************** Sequence ADT *************************** E == 2-tuple I == sequence identification key S == biological sequence **********************************************************************/ /*************************** Sequence type *****************************/ typedef struct { unsigned short I; /* identifier for entity */ unsigned short n; /* length of entity sequence */ Boolean xnu; /* sequences xnu'ed */ char *S; /* sequence */ char *X; /* if !xnu'ed == S; else X'ed seq */ char *info; /* description of entity */ } sequence_type; typedef sequence_type *e_type; /******************************** private **********************************/ long get_diagonal_ends_seq(char *seq1, char *seq2, int **R, long n, long *begin, long *end); e_type EmptySeq(long I, long length); long seq_error(char *s); /******************************** PUBLIC **********************************/ e_type ReadSeq(FILE *fptr, long I, long size, a_type A); e_type ReadSeqFA(char *infile, long I, a_type A); e_type MergeSeqs(e_type *E); Boolean IdentSeqs(e_type E1, e_type E2); Boolean NonNullIdentSeqs(register e_type E1, register e_type E2); long CenterSeqHSP(long offset, e_type E1, e_type E2, a_type A); long GetFastaInfo(char *DBS_NAME, long max, long **pcounts, unsigned short **psize, a_type A); e_type NilSeq(e_type E); /* undefine entity */ double *FreqResSeq(e_type E, double *freq, a_type A); long *CountsSeq(e_type E, a_type A); void MaskSeq(long start, long end, e_type E); long *NumResSeq(e_type E,a_type A); void PutSeqID(FILE *fptr,e_type E); void PutSeqInfo(FILE *fptr,e_type E); void PutSeq(FILE *fptr,e_type E,a_type A); void PutXnuSeq(FILE *fptr,e_type E,a_type A); void ProcessSeq(e_type E,a_type A,double lambda,double K,double H); e_type CopySeq(e_type E); e_type ShuffleSeq(e_type E); e_type RandomSeq(long length, long I, double *freq, a_type A); e_type RtnShuffleSeq(e_type E); e_type RandomizeSeq(e_type E, double *freq, a_type A); void PutSeqRegion(FILE *fptr,long start, long length, e_type E, a_type A); void PutSeqRegion2(FILE *fptr,long start, long length, e_type E, long flank, a_type A); long PutDiagonalSeq(FILE *fptr, long offset, e_type E1, e_type E2, a_type A); char RandomResSeq(register e_type E); /**************************** Macros ********************************/ #define LenSeq(E) ((E)->n) #define ResSeq(i,E) ((E)->S[(i)]) #define XnuSeq(i,E) ((E)->X[(i)]) #define EqSeq(i,x,E) ((E)->S[(i)]=(char) (x)) #define EqSeqKey(x,E) ((E)->info=(x)) #define RmSeq(E) ((E)->I=NULL) #define EqSeqI(i,E) ((E)->I=(unsigned short) (i)) #define SeqI(E) ((E)->I) #define SeqKey(E) ((E)->info) #define SeqPtr(E) ((E)->S) #define XnuSeqPtr(E) ((E)->X) #endif glam2-1064/purge/block.h0000644007451300001540000000624110631405457014526 0ustar charlesgenome#if !defined(BLOCKS) #define BLOCKS #include #include #include "stdinc.h" /*************************** ADT Block ******************************* B = subset of { 0,...,n-1 } where n is an element of Postive integers. **********************************************************************/ typedef struct { unsigned short *list; /* list of non-zero words */ unsigned short *list2; /* 2nd list of non-zero words */ unsigned char *b; /* as bytes = 8 bits */ unsigned long *i; /* as long ints = 32 bits */ long N; /* maximum number in set */ long nbyte; /* number of bytes in array */ long nint; /* number of ints in array */ } block_type; typedef block_type *b_type; /*************************** Private *******************************/ extern unsigned char *CARDINALITY_BLOCKS; extern unsigned long *SET_BIT_BLOCKS; extern unsigned short *B1_list,*B2_list,*IB_list; extern unsigned char *B1_byte,*B2_byte,*IB_byte; void initialize_blocks(); void add_list_block(b_type B); void update_list_block(b_type B); void blockerror(char *s); /*************************** Public ********************************/ b_type Block(long N); /* create Null block */ b_type BlockL(long N); /* create Null block with list */ void CopyBlock(b_type B1,b_type B2); void CopyBlockL(b_type B1,b_type B2); void CopyBlockL2(b_type B1, b_type B2); void CopyBlockLL(register b_type B1,register b_type B2); void ClearBlock(b_type B); /* zero out a set in B */ void FillBlock(b_type B); void AddBlock(long element,b_type B); /* add an element to set B */ void DeleteBlock(long element,b_type B); unsigned long MemberBlock(register long element, register b_type B); b_type UnionBlock(b_type B1, b_type B2); void UnionBlock3(b_type B1, b_type B2, b_type UB); long UnionBlockCL(b_type B1, b_type B2); void UnionBlockL(b_type B1, b_type B2); void UnionBlockLF(b_type B1, b_type B2, b_type UB); void IntersectNotBlock(b_type B1, b_type B2); void IntersectBlock3(b_type B1, b_type B2); void IntersectBlock1(b_type B1, b_type B2,b_type IB); long IntersectBlockCF(b_type B1,b_type B2,b_type IB); void IntersectBlockF(b_type B1,b_type B2,b_type IB); void IntersectBlockL(b_type B1,b_type B2); long IntersectBlockList(long *L, b_type B1, b_type B2); long IntersectBlockLCXOR(b_type eB,b_type B, b_type IB); long CardBlock(b_type B); /* return cardinality of a set in B */ long CardBlockL(b_type B); long CardInterBlock(b_type B1,b_type B2); long CardInterBlockLF(b_type B1,b_type B2); void CardInterBlockLMult(register long *C, b_type *B1,b_type B2); long *ListBlock(b_type B); /* return list of members in B */ long *ListBlockL(b_type B); /* return list of members in B */ b_type PutBlock(FILE *fptr,b_type B); /* print block B */ b_type NilBlock(b_type B); /* destroy ISets */ /*************************** Macros **********************/ #define MAX_BLOCK_SIZE 524000 /* = list of 65500 */ #define BLOCK_BUFFER_SIZE 65505 /* for temp list */ #define END_BLOCK_LIST 65530 #define BlockN(B) ((B)->N) /* return max cardinality of sets */ #define EmptyBlockL(B) ((B)->list[0]==END_BLOCK_LIST) #define ClearBlockL(B) ((B)->list[0]=END_BLOCK_LIST) #endif glam2-1064/purge/karlin.c0000644007451300001540000001363210631405523014703 0ustar charlesgenome#include "karlin.h" /**************** Statistical Significance Parameter Subroutine **************** Version 1.0 February 2, 1990 Version 2.0 March 18, 1993 Program by: Stephen Altschul Address: National Center for Biotechnology Information National Library of Medicine National Institutes of Health Bethesda, MD 20894 Internet: altschul@ncbi.nlm.nih.gov See: Karlin, S. & Altschul, S.F. "Methods for Assessing the Statistical Significance of Molecular Sequence Features by Using General Scoring Schemes," Proc. Natl. Acad. Sci. USA 87 (1990), 2264-2268. Computes the parameters lambda and K for use in calculating the statistical significance of high-scoring segments or subalignments. The scoring scheme must be integer valued. A positive score must be possible, but the expected (mean) score must be negative. A program that calls this routine must provide the value of the lowest possible score, the value of the greatest possible score, and a pointer to an array of probabilities for the occurence of all scores between these two extreme scores. For example, if score -2 occurs with probability 0.7, score 0 occurs with probability 0.1, and score 3 occurs with probability 0.2, then the subroutine must be called with low = -2, high = 3, and pr pointing to the array of values { 0.7, 0.0, 0.1, 0.0, 0.0, 0.2 }. The calling program must also provide pointers to lambda and K; the subroutine will then calculate the values of these two parameters. In this example, lambda=0.330 and K=0.154. The parameters lambda and K can be used as follows. Suppose we are given a length N random sequence of independent letters. Associated with each letter is a score, and the probabilities of the letters determine the probability for each score. Let S be the aggregate score of the highest scoring contiguous segment of this sequence. Then if N is sufficiently large (greater than 100), the following bound on the probability that S is greater than or equal to x applies: P( S >= x ) <= 1 - exp [ - KN exp ( - lambda * x ) ]. In other words, the p-value for this segment can be written as 1-exp[-KN*exp(-lambda*S)]. This formula can be applied to pairwise sequence comparison by assigning scores to pairs of letters (e.g. amino acids), and by replacing N in the formula with N*M, where N and M are the lengths of the two sequences being compared. In addition, letting y = KN*exp(-lambda*S), the p-value for finding m distinct segments all with score >= S is given by: 2 m-1 -y 1 - [ 1 + y + y /2! + ... + y /(m-1)! ] e Notice that for m=1 this formula reduces to 1-exp(-y), which is the same as the previous formula. long low; * Lowest score (must be negative) * long high; * Highest score (must be positive) * double *pr; * Probabilities for various scores * double *lambda; * Pointer to parameter lambda * double *K; * Pointer to parmeter K * double *H; * Pointer to parmeter H * *******************************************************************************/ Boolean karlin(long low,long high,double *pr,double *lambda,double *K,double *H) { long i,j,range,lo,hi,first,last; double up,new,sum,Sum,av,beta,oldsum,ratio,ftemp; double *p,*P,*ptrP,*ptr1,*ptr2; /* Check that scores and their associated probabilities are valid */ if (low>=0) { fprintf(stderr,"Lowest score must be negative.\n"); return FALSE; } for (i=range=high-low;i> -low && !pr[i];--i); if (i<= -low) { fprintf(stderr,"A positive score must be possible.\n"); return FALSE; } for (sum=i=0;i<=range;sum+=pr[i++]) if (pr[i]<0) { fprintf(stderr,"Negative probabilities not allowed.\n"); return FALSE; } if (sum<0.99995 || sum>1.00005) fprintf(stderr,"Probabilities sum to %.4f. Normalizing.\n",sum); NEW(p,range+1,double); for (Sum=low,i=0;i<=range;++i) Sum+=i*(p[i]=pr[i]/sum); if (Sum>=0) { fprintf(stderr,"Invalid (non-negative) expected score: %.3f\n",Sum); free(p); return FALSE; } /* Calculate the parameter lambda */ up=0.5; do { up*=2; ptr1=p; beta=exp(up); ftemp=exp(up*(low-1)); for (sum=i=0;i<=range;++i) sum+= *ptr1++ * (ftemp*=beta); } while (sum<1.0); for (*lambda=j=0;j<25;++j) { new=(*lambda+up)/2.0; beta=exp(new); ftemp=exp(new*(low-1)); ptr1=p; for (sum=i=0;i<=range;++i) sum+= *ptr1++ * (ftemp*=beta); if (sum>1.0) up=new; else *lambda=new; } /* Calculate the pamameter K */ ptr1=p; ftemp=exp(*lambda*(low-1)); for (av=0,i=low;i<=high;++i) av+= *ptr1++ *i*(ftemp*=beta); *H= *lambda*av/log(2.0); Sum=lo=hi=0; NEW(P,KARLINMAXIT*range+1,double); for (*P=sum=oldsum=j=1;j<=KARLINMAXIT && sum>0.001;Sum+=sum/=j++) { first=last=range; for (ptrP=P+(hi+=high)-(lo+=low);ptrP>=P;*ptrP-- =sum) { ptr1=ptrP-first; ptr2=p+first; for (sum=0,i=first;i<=last;++i) sum+= *ptr1-- * *ptr2++; if (first) --first; if (ptrP-P<=range) --last; } ftemp=exp(*lambda*(lo-1)); for (sum=0,i=lo;i;++i) sum+= *++ptrP * (ftemp*=beta); for (;i<=hi;++i) sum+= *++ptrP; ratio=sum/oldsum; oldsum=sum; } for (;j<=200;Sum+=oldsum/j++) oldsum*=ratio; for (i=low;!p[i-low];++i); for (j= -i;i1;) if (p[++i-low]) j=karlin_gcd(j,i); *K = (j*exp(-2*Sum))/(av*(1.0-exp(- *lambda*j))); free(p); free(P); return TRUE; /* Parameters calculated successfully */ } double ExpectedInformation(a_type A, double lambda, double *freq) { long i,j; double sum,tot,fij,eij,mij; sum = tot = 0.0; for (i=1; i<=20; i++){ for (j=1; j<=20; j++) { mij = valAlphaR(i,j,A); fij = freq[i]*freq[j]; tot += fij; eij = mij*fij*exp(lambda*mij); sum += eij; } } return(lambda*sum/tot); } long karlin_gcd(long a,long b) { long c; if (b<0) b= -b; if (b>a) { c=a; a=b; b=c; } for (;b;b=c) { c=a%b; a=b; } return a; } glam2-1064/purge/mheap.c0000644007451300001540000000250110631405542014507 0ustar charlesgenome#include "mheap.h" mh_type Mheap(long hpsz, long d) { mh_type H; long i; NEW(H,1,mheap_type); NEW(H->avail,hpsz+1,long); H->heap=dheap(hpsz,d); H->maxheap=dheap(hpsz,d); H->hpsz = hpsz; H->nfree = hpsz; for(i=1; i<=hpsz; i++) H->avail[i] = i; return H; } mh_type NilMheap(mh_type H) { if(H==NULL) return (mh_type) NULL; Nildheap(H->heap); Nildheap(H->maxheap); free(H->avail); free(H); return (mh_type) NULL; } long DelMinMheap(mh_type H) { long i; if((i=delminHeap(H->heap))!=(long)NULL){ rmHeap(i,H->maxheap); H->nfree++; H->avail[H->nfree] = i; return i; } else return (long)NULL; } long DelMaxMheap(mh_type H) { long i; if((i=delminHeap(H->maxheap))!=(long)NULL){ rmHeap(i,H->heap); H->nfree++; H->avail[H->nfree] = i; return i; } else return (long)NULL; } long RmMheap(long i, mh_type H) { if(rmHeap(i,H->heap) == (long)NULL) return (long)NULL; rmHeap(i,H->maxheap); H->nfree++; H->avail[H->nfree] = i; return i; } long InsertMheap(keytyp key, mh_type H) /* NULL == not inserted; -1 == inserted but none deleted */ { long i; if(H->nfree > 0){ i = H->avail[H->nfree]; H->nfree--; } else if(minkeyHeap(H->maxheap) < -key) { i=delminHeap(H->maxheap); rmHeap(i,H->heap); } else return (long)NULL; insrtHeap(i,key,H->heap); insrtHeap(i,-key,H->maxheap); return i; } glam2-1064/purge/seqset.h0000644007451300001540000000623710631405700014734 0ustar charlesgenome/***************** seqset.h - sequence set data type. ********************/ /*************************** Sequence Set ADT ****************************** Define: P = where S is a set of sequences A is the sequence alphabet **************************************************************************/ #if !defined (SEQSET) #define SEQSET #include "stdinc.h" #include "afnio.h" #include "alphabet.h" #include "karlin.h" #include "sequence.h" #include "random.h" /******************************* PRIVATE ***********************************/ /****************************** seqset type ****************************/ typedef struct { char *name; /* input filename for entities */ e_type *entity; /* array of sequence entities */ long nent; /* number of input entities */ long max_leng; /* sequence entity maximumlength */ long min_leng; /* sequence entity minimum length */ Boolean xnu; /* has data been xnu'ed? */ long *counts; /* number of b residues */ long total; /* total # residues */ double *tfreq; /* residue total freqs for seqs */ a_type A; /* sequence alphabet */ } seqset_type; typedef seqset_type *ss_type; /******************************* private *************************************/ void seqset_error(char *s); ss_type calcseqsetfreq(ss_type P); ss_type xnu_seqset(ss_type P); long count_seqset_entities(FILE *fptr, ss_type P,long nsize[]); FILE *OpenSeqSetFile(ss_type P); ss_type seqset(char *filename,a_type A); ss_type fptr_seqset(FILE *fptr,a_type A); ss_type SeqSet_fptr(FILE *fptr,a_type A); ss_type MkXnuSeqSet_fptr(FILE *fptr,a_type A); /******************************* PUBLIC *************************************/ /************************** seqset operations ***************************/ ss_type SeqSet(char *name,a_type A); ss_type SeqSet1(char *filename,e_type E,a_type A); ss_type MkXnuSeqSet(char *filename,a_type A); ss_type MkXnuSeqSet1(char *filename,e_type E,a_type A); ss_type RmSeqSet(e_type E, ss_type P); ss_type NilSeqSet(ss_type P); double SeqSetEntropy(ss_type P); long *LengthsSeqSet(ss_type P); ss_type PutSeqSet(FILE *fptr,ss_type P); /* show seqset data */ ss_type PutSeqSetPIDs(FILE *fptr, ss_type P); ss_type PutSeqSetEs(FILE *fptr,ss_type P); ss_type PutSeqSetE(FILE *fptr,long i, ss_type P); ss_type PutSeqSettFreqs(FILE *fptr,ss_type P); ss_type ShuffleSeqSet(ss_type P); /* shuffle seqset */ ss_type ShuffleSeqSet2(ss_type P); double LogL0SeqSet(ss_type P); /************************** sequence set defines ***************************/ #define MAX_NUMBER_SEQS 15000 #define SeqSetA(P) (P->A) #define nLetSeqSet(P) (nAlpha(P->A)) #define CountsSeqSet(r,P) ((P)->counts[(r)]) #define TotalSeqSet(P) ((P)->total) #define tFreqSeqSet(P) ((P)->tfreq) #define SeqP(n,i,P) ResSeq(i,(P)->entity[(n)]) #define NSeqsSeqSet(P) ((P)->nent) #define SqLenSeqSet(n,P) LenSeq((P)->entity[(n)]) #define SeqSeqSet2(n,P) SeqPtr((P)->entity[(n)]) #define SeqSeqSet(n,P) XnuSeqPtr((P)->entity[(n)]) #define SeqSetE(n,P) ((P)->entity[(n)]) #define NameSeqSet(P) ((P)->name) #define MinSeqSeqSet(P) ((P)->min_leng) #define MaxSeqSeqSet(P) ((P)->max_leng) #define CntsSeqSet(P) ((P)->counts) #define XnuSeqSet(P) xnu_seqset(P) #endif glam2-1064/purge/block.c0000644007451300001540000003160410631405454014517 0ustar charlesgenome#include "block.h" unsigned long *SET_BIT_BLOCKS=NULL; unsigned char *CARDINALITY_BLOCKS=NULL; unsigned char *BIT_NUMBER_BLOCKS=NULL; unsigned short *B1_list,*B2_list,*IB_list; unsigned char *B1_byte,*B2_byte,*IB_byte; void initialize_blocks(void) /* initialize lookup tables used for bitwise operations */ { long i,b,n; unsigned char bit; NEW(SET_BIT_BLOCKS,32,unsigned long); for(i=0,b=31;i<32;b--,i++) { SET_BIT_BLOCKS[i] = 1 << b; } NEW(CARDINALITY_BLOCKS,256,unsigned char); for(i=0;i<256;i++){ for(b=n=0;b<8;b++){ if(i & (1<=0;bit=(bit<<1),b--) BIT_NUMBER_BLOCKS[b]=bit; } /***************** List operations for blocks *********************/ void add_list_block(b_type B) /* add a list to block B */ { MEW(B->list,(B->nbyte+1),unsigned short); B->list[0] = END_BLOCK_LIST; } void update_list_block(b_type B) /* set all bytes in block B not on the list to zero */ { long i,a; for(i=0,a=0;inbyte;i++) { if(i==B->list[a]) a++; else B->b[i]=0; } } /*************** Create and Copy operations for blocks ********************/ b_type Block(long N) /* create and return the null Block B */ { b_type B; if(N > MAX_BLOCK_SIZE) blockerror("Too many segments."); if(CARDINALITY_BLOCKS == NULL) initialize_blocks(); MEW(B,1,block_type); B->list = NULL; B->N = N; B->list2 = NULL; B->nint = (long) ceil((double)N/(double)32.0); B->nbyte= 4*B->nint; NEW(B->i,B->nint,unsigned long); B->b = (unsigned char*) B->i; return (B); } b_type BlockL(long N) /* create and return a null block B with a list */ { b_type B; B=Block(N); MEW(B->list,(B->nbyte+1),unsigned short); B->list[0] = END_BLOCK_LIST; return (B); } void CopyBlock(b_type B1,b_type B2) /* copy block B2 into block B1 - block B2 is modified */ { long j; if(B1->N != B2->N) { fprintf(stderr,"N1=%ld N2=%ld\t",B1->N,B2->N); blockerror("incompatible sets!"); } if(B2->list != NULL) update_list_block(B2); for(j=0;jnint;j++) B1->i[j] = B2->i[j]; } void CopyBlockL(b_type B1,b_type B2) /* copy block B2 into block B1 maintaining a list - B1 is modified */ { long j,k; if(B2->N != B1->N) { fprintf(stderr,"N1=%ld N2=%ld\t",B1->N,B2->N); blockerror("incompatible sets!"); } if(B2->list != NULL) update_list_block(B2); if(B1->list == NULL) add_list_block(B1); for(j=0,k=0;jnbyte;j++) if((B1->b[j] = B2->b[j])) B1->list[k++]=j; B1->list[k]=END_BLOCK_LIST; } void CopyBlockL2(b_type B1, b_type B2) /* copy block B2 into block B1 maintaining a list - B1 is modified */ { register unsigned char *b1=B1->b,*b2=B2->b; register unsigned short *list1=B1->list,*list2=B2->list; register long i; for( ;(i= *list1= *list2) != END_BLOCK_LIST; list1++,list2++){ b1[i] = b2[i]; } } void CopyBlockLL(register b_type B1,register b_type B2) { register long i,e; for(i=0;(e=B1->list[i]=B2->list[i]) != END_BLOCK_LIST; i++){ B1->b[e] = B2->b[e]; } } /**************** Modify operations for blocks ********************/ void ClearBlock(b_type B) /* set block B equal to the empty set */ { long j; for(j=0;jnint;j++) B->i[j] = (unsigned long) 0; } void FillBlock(b_type B) /* set block B equal to the set of integers from 0 to N-1 */ { long j; for(j=0;jnbyte;j++) B->b[j] = (unsigned char) 0xff; for(j=B->N;j<8*B->nbyte;j++) DeleteBlock(j,B); } void DeleteBlock(long element,b_type B) /* delete an element from block B */ { long nbit,nint; if(element >= B->nbyte*8) blockerror("input numbers too large"); nbit = element & 0x1f; /* element mod 32 */ nint = element >> 5; /* element / 32 */ if(MemberBlock(element,B)) B->i[nint] ^= SET_BIT_BLOCKS[nbit]; } void AddBlock(long element,b_type B) /* add an element to block B */ { long nbit,nint; if(element >= B->N) blockerror("input numbers too large"); nbit = element & 0x1f; /* element mod 32 */ nint = element >> 5; /* element / 32 */ B->i[nint] |= SET_BIT_BLOCKS[nbit]; } unsigned long MemberBlock(register long element, register b_type B) /* return 0 if element is not a member of B; else return non-zero */ { register long nbit,nint; if(element >= B->nbyte*8) blockerror("input numbers too large"); nbit = element & 0x1f; nint = element >> 5; return (B->i[nint] & SET_BIT_BLOCKS[nbit]); } /**************** Union operations for blocks ********************/ void UnionBlock3(b_type B1, b_type B2, b_type UB) /* modifies B1 to equal B1 U B2; B1 is returned */ { long j; for(j=0;jnint;j++) UB->i[j] = B1->i[j] | B2->i[j]; } b_type UnionBlock(b_type B1, b_type B2) /* modifies B1 to equal B1 U B2; B1 is returned */ { long j; if(B1->N != B2->N) { fprintf(stderr,"N1=%ld, N2=%ld\n",B1->N,B2->N); blockerror("N1!=N2 for Union operation"); } if(B1->list != NULL) update_list_block(B1); if(B2->list != NULL) update_list_block(B2); for(j=0;jnint;j++) B1->i[j] = B1->i[j] | B2->i[j]; return B1; } long UnionBlockCL(b_type B1, b_type B2) /* modifies B1 to equal B1 U B2; B1 is returned; B1 uses a list */ { long b,k,n=0; unsigned short *list; if(B1->list2==NULL) MEW(B1->list2,(B1->nbyte+1),unsigned short); list = B1->list2; B1_byte = B1->b; B2_byte = B2->b; B2_list = B2->list; B1_list = B1->list; for(k=0; TRUE ; ){ if(*B1_list < *B2_list){ b= *B1_list; B1_list++; } else if(*B1_list > *B2_list){ b= *B2_list; B2_list++; B1_byte[b] = B2_byte[b]; } else if(*B1_list==END_BLOCK_LIST){ break; /* b1 == b2 */ } else { b= *B1_list; B1_list++; B2_list++; B1_byte[b] = B1_byte[b] | B2_byte[b]; } n+=CARDINALITY_BLOCKS[(B1_byte[b])]; list[k++]=b; } list[k]= END_BLOCK_LIST; B1->list2 = B1->list; B1->list = list; return n; } void UnionBlockLF(b_type B1, b_type B2, b_type UB) /* modifies UB to equal B1 U B2; B1 is returned; all use a list */ { register unsigned short *list=UB->list; register unsigned short *list1=B1->list; register unsigned short *list2=B2->list; register long b; register unsigned char *b1=B1->b,*b2=B2->b,*ub=UB->b; while(TRUE){ if(*list1 < *list2){ b= *list1; list1++; ub[b] = b1[b]; } else if(*list1 > *list2){ b= *list2; list2++; ub[b] = b2[b]; } else { /* b1 == b2 */ if(*list1==END_BLOCK_LIST) break; b= *list1; list1++; list2++; ub[b] = b1[b] | b2[b]; } *list=b; list++; } *list= END_BLOCK_LIST; } void UnionBlockL(b_type B1, b_type B2) /* modifies B1 to equal B1 U B2; B1 is returned; B1 uses a list */ { long b,k; unsigned short *list; if(B1->list2==NULL) MEW(B1->list2,(B1->nbyte+1),unsigned short); list = B1->list2; B1_byte = B1->b; B2_byte = B2->b; B2_list = B2->list; B1_list = B1->list; for(k=0; TRUE ; ){ if(*B1_list < *B2_list){ b= *B1_list; B1_list++; } else if(*B1_list > *B2_list){ b= *B2_list; B2_list++; B1_byte[b] = B2_byte[b]; } else if(*B1_list==END_BLOCK_LIST){ break; /* b1 == b2 */ } else { b= *B1_list; B1_list++; B2_list++; B1_byte[b] = B1_byte[b] | B2_byte[b]; } list[k++]=b; } list[k]= END_BLOCK_LIST; B1->list2 = B1->list; B1->list = list; } /*************** Intersect operations **********************/ void IntersectNotBlock(b_type B1, b_type B2) /* modifies B1 to equal B1 intersect not B2 */ { long j; if(B1->N != B2->N) blockerror("N1!=N2 for Intersection operation"); for(j=0;jnint;j++) B1->i[j] = B1->i[j] & ~(B2->i[j]); } void IntersectBlock1(b_type B1, b_type B2,b_type IB) /* modifies IB to equal B1 intersect B2 */ { long j; if(B1->N != B2->N || B1->N != IB->N) blockerror("N1!=N2 for Intersection operation"); for(j=0;jnint;j++) { IB->i[j] = B1->i[j] & B2->i[j]; } } long IntersectBlockList(long *L, b_type B1, b_type B2) /* returns a list of the elements in the intersect of B1 and B2 */ { long C,j,b,bit; unsigned char s; for(C=j=0; (b=B2->list[j]) != END_BLOCK_LIST; j++) { if((s=B1->b[b] & B2->b[b])) { for(bit=0;bit<8;bit++) { if(s & BIT_NUMBER_BLOCKS[bit]) { L[C++] = (b*8 + bit); } } } } L[C]= -1; return C; } void IntersectBlock3(b_type B1, b_type B2) /* modifies B1 to equal B1 intersect B2 */ { long j; if(B1->N != B2->N) blockerror("N1!=N2 for Intersection operation"); for(j=0;jnint;j++) B1->i[j] = B1->i[j] & B2->i[j]; } void IntersectBlockL(b_type B1, b_type B2) /* modifies B2 to equal B1 intersect B2 */ { long i,k,e; if(B1->list != NULL) update_list_block(B1); for(i=k=0;(e=B2->list[i]) != END_BLOCK_LIST; i++){ if((B2->b[e] = B1->b[e]) & B2->b[e]) {B2->list[k++]=e; } } B2->list[k]=END_BLOCK_LIST; } long IntersectBlockCF(b_type B1, b_type B2,b_type IB) /* modifies IB to equal B1 intersect B2; returns cardinality of IB */ { register unsigned char *b1=B1->b,*b2=B2->b,*ib=IB->b; register unsigned short *list=B2->list; register unsigned short *newlist=IB->list; register unsigned char *card = CARDINALITY_BLOCKS; register long i,k,a,n=0; /**if(B1->N != B2->N || B1->N != IB->N) { fprintf(stderr,"N1=%d, N2=%d; NIB=%d\n",B1->N,B2->N,IB->N); blockerror("N1!=N2 for Intersection operation"); } DEBUG*/ for(n=a=k=0; (i=list[a]) != END_BLOCK_LIST; a++){ if((ib[i]=b1[i]) & b2[i]) { newlist[k++]=i; n+=card[(ib[i])]; } } newlist[k]= END_BLOCK_LIST; return n; } void IntersectBlockF(b_type B1, b_type B2,b_type IB) /* modifies IB to equal B1 intersect B2 */ { register unsigned char *b1=B1->b,*b2=B2->b,*ib=IB->b; register unsigned short *list=B2->list; register unsigned short *newlist=IB->list; register long e; while((e= *list) != END_BLOCK_LIST){ if((ib[e] = b1[e]) & b2[e]) {*newlist=e; newlist++; } list++; } *newlist=END_BLOCK_LIST; } /*************** Cardinality operations **********************/ long CardInterBlockLF(b_type B1,b_type B2) /* return cardinality of the intersection of B1 and B2 - using lists */ { register unsigned char *b1=B1->b,*b2=B2->b; register unsigned short *list=B2->list; register unsigned char *card = CARDINALITY_BLOCKS; register long i,n=0; while((i= *list) != END_BLOCK_LIST) { n+=card[(b1[i] & b2[i])]; list++; } return n; } long CardInterBlock(b_type B1,b_type B2) /* return cardinality of the intersection of B1 and B2 */ { long i,b,byte,n=0; if(B1->N != B2->N) { fprintf(stderr,"N1=%ld; N2=%ld\n",B1->N,B2->N); blockerror("N1!=N2 for CardIntersect operation"); } for(i=0,byte=0; i < B1->nint; i++,byte+=4) { if(B1->i[i] & B2->i[i]) for(b=0;b<4;b++) { n+=CARDINALITY_BLOCKS[(B1->b[byte+b])& (B2->b[byte+b])]; } } return n; } long CardBlockL(b_type B) { register unsigned char *b=B->b, *card = CARDINALITY_BLOCKS; register unsigned short *list=B->list; register long i,n=0; while((i= *list) != END_BLOCK_LIST) { n+=card[b[i]]; list++; } return n; } long CardBlock(b_type B) /* return cardinality of block B */ { long i,b,byte,n=0; if(B->list != NULL) update_list_block(B); for(i=0,byte=0; i < B->nint; i++,byte+=4) { if(B->i[i]) for(b=0;b<4;b++) n+=CARDINALITY_BLOCKS[(B->b[byte+b])]; } return n; } /******************* List operations **********************/ long *ListBlock(b_type B) /* return list of elements in block B; list is terminated by -1 */ { long C,i,j=0,*L; if(B->list != NULL) update_list_block(B); C=CardBlock(B); NEW(L,C+1,long); for(i=0;iN;i++) if(MemberBlock(i,B)) { L[j]=i; j++; } L[j]= -1; return L; } long *ListBlockL(b_type B) /* return list of elements in block B; list is terminated by -1 */ { long C,p,b,bit,j=0,*L; C=CardBlockL(B); NEW(L,C+1,long); for(p=0,b=B->list[p]; b != END_BLOCK_LIST; p++,b=B->list[p]){ for(bit=0;bit<8;bit++) { if(B->b[b] & BIT_NUMBER_BLOCKS[bit]){ L[j]=b*8+bit;j++; } } } L[j]= -1; return L; } /******************* Output operations **********************/ b_type PutBlock(FILE *fptr,b_type B) /* print block B to file pointed to by fptr */ { long i,j=0,*m; if(B->list != NULL) update_list_block(B); m = ListBlock(B);/**/ /* m = ListBlockL(B);*/ fprintf(fptr," {"); for(i=0;m[i] != -1; i++) { if(m[i+1] != -1) fprintf(fptr,"%5ld,",m[i]); else fprintf(fptr,"%5ld",m[i]); if(i%10==9 && m[i+1] != -1) fprintf(fptr,"\n "); } if(j>0) fprintf(fptr,"%5ld }\n",m[i]); else fprintf(fptr," }\n"); free(m); return B; } b_type NilBlock(b_type B) /* destroy block B */ { if(B != NULL) { if(B->list !=NULL) free(B->list); if(B->list2 !=NULL) free(B->list2); free(B->i); free(B); } return (b_type) NULL; } void blockerror(char *s) { fprintf(stderr,"Block Error: %s\n",s); exit(1); } /*************** operations **********************/ long IntersectBlockLCXOR(b_type eB,b_type B, b_type IB) /* Sets IIB = eB intersect B and sets EOB = B xor IB */ { register unsigned char *eb=eB->b,*b=B->b,*ib=IB->b; register unsigned short *list=B->list,*eolist=B->list; register unsigned short *newlist=IB->list; register unsigned char *card = CARDINALITY_BLOCKS; register long e,k,ik,n; for(n=ik=k=0; (e= *list) != END_BLOCK_LIST; list++){ if((ib[e]=eb[e]) & b[e]) { newlist[ik++]=e; n+=card[(ib[e])]; if(b[e]^ib[e]){ eolist[k++] = e; } } else { eolist[k++] = e; } } eolist[k] = newlist[ik] = END_BLOCK_LIST; return n; } glam2-1064/purge/gblast.c0000644007451300001540000002234210631405504014674 0ustar charlesgenome/* gblast.c - */ #include "gblast.h" gb_typ MakeGBlast(long T, e_type E, a_type A) { gb_typ B; long n,q,q0,q1,q2,r0,r1,r2,s,t; long c,d,e,i,x,y,z,hits,nlet; char **best,*b0,*b1,*b2; /** letters ordered by decreasing score **/ /* 5-6-00 tlb; make R int */ int **R; keytyp key; dh_type H; long time1; NEW(B,1,gblast_type); B->A = A; B->E = E; /***** order letters by decreasing score *****/ NEWP(best,nAlpha(A)+2,char); H = dheap(nAlpha(A)+3,3); for(i=0,c=0; c <= nAlpha(A); c++){ NEW(best[c],nAlpha(A)+2,char); for(d=0; d <= nAlpha(A); d++){ key = (keytyp) -valAlphaR(c,d,A); insrtHeap(d+1,key, H); } /*** fprintf(stderr,"%c: ", AlphaChar(c,A)); **/ for(i=0; (d = delminHeap(H)) != 0; i++){ best[c][i] = d - 1; /** fprintf(stderr,"%c ", AlphaChar(d-1,A)); ***/ } /*** fprintf(stderr,"\n"); **/ } Nildheap(H); /***** create finite automaton *****/ /*** create transition function d(r,q). ***/ n = nAlpha(A) +1; n = 1 + n + n*n; NEWP(B->d,nAlpha(A)+2,long); for(c=0; c <= nAlpha(A); c++) NEW(B->d[c],n+2,long); for(q=0, c=0; c <= nAlpha(A); c++){ q++; B->d[c][0] = q; q0=q; /** q0 = state "^c" **/ for(d=0; d <= nAlpha(A); d++){ q++; B->d[d][q0] = q; /** q1 = state "cd" **/ } } B->nQ = q; /** nQ = #states **/ for(q=0, c=0; c <= nAlpha(A); c++){ q0 = B->d[c][0]; /** q = state "^c" **/ for(d=0; d <= nAlpha(A); d++){ q1 = B->d[d][q0]; /** q = state "cd" **/ q2 = B->d[d][0]; /** q2 = state "^d" **/ for(e=0; e <= nAlpha(A); e++){ q = B->d[e][q2]; /** q2 = state "de" **/ B->d[e][q1] = q; /** "cde" = "^de" = "de" **/ } } } /*** create acceptance states & positions pos[q][r][1..] ***/ time1=time(NULL); nlet = nAlpha(A) +1; MEW(B->pos,nlet+2,ml_type); n = B->nQ; for(c=0; c <= nAlpha(A); c++) B->pos[c] = MkMList(30*LenSeq(E),n); /*** fprintf(stderr,"\nallocation time: %ld seconds\n", time(NULL)-time1); ****/ time1=time(NULL); n = LenSeq(E) - 1; NEW(B->tmp,n+3,long); c = XnuSeq(1,E); q = B->d[c][0]; /** q = state "^c" **/ R = AlphaR(A); for(hits=0,i=2; i <= n; c=d, i++){ d = XnuSeq(i,E); q = B->d[d][q]; /** q = state "xd" **/ e = XnuSeq(i+1,E); /**** fprintf(stderr,"%c%c%c: (q=%d; d(%c,q)=%d)", AlphaChar(c,A),AlphaChar(d,A),AlphaChar(e,A), q,AlphaChar(e,A),B->d[e][q]); ** look through related 3-words for "matches". **/ b0 = best[c]; b1 = best[d]; b2 = best[e]; for(x=0; x <= nAlpha(A); x++){ r0 = b0[x]; q0 = B->d[r0][0]; s = T - (long) valAlphaR(c,r0,A); for(y=0; y <= nAlpha(A); y++){ r1 = b1[y]; q1 = B->d[r1][q0]; t = s - (long) valAlphaR(d,r1,A); for(z=0; z <= nAlpha(A); z++){ r2 = b2[z]; if(t <= (long)valAlphaR(e,r2,A)){ Add2MList(i-1, q1, B->pos[r2]); hits++; /**** fprintf(stderr," %c%c%c(%d)", AlphaChar(r0,A), AlphaChar(r1,A), AlphaChar(r2,A),s+t+u); ** add to acceptor states **/ } else { break; } } if(z==0) break; } if(y==0) break; } /*** fprintf(stderr,"\n"); ****/ } /*** fprintf(stderr,"\nneighborhood time: %ld seconds\n", time(NULL)-time1); ****/ for(c=0; c <= nAlpha(A); c++) free(best[c]); free(best); /** fprintf(stderr,"hits = %d\n",hits); fprintf(stderr,"\tcreate time: %ld seconds\n", time(NULL)-time1); ****/ return B; } long WinExtendGBlast(e_type E1, long i1, e_type E2, long i2, a_type A, long flank) /** extend only flank residues in either direction **/ { long n,n1,n2; register char *p1,*p2; register long k,score,max; n1 = LenSeq(E1); n2 = LenSeq(E2); p1 = XnuSeqPtr(E1); p2=XnuSeqPtr(E2); for(score=k=0, p1+=i1, p2+=i2; k<3; k++,p1++,p2++) { score += valAlphaR(*p1,*p2,A); } n = tMIN(long,n2-i2,n1-i1); /** TEST **/ n = tMIN(long,n,k+flank); /** TEST **/ for(max=score; k <= n; k++,p1++,p2++) { score += valAlphaR(*p1,*p2,A); if(score > max) max = score; /** else if(score < (max-40)) break; ***/ /**/ else if(score <= (max-40) || score < 0) break; /****/ } n = tMIN(long,i1,i2); /** TEST **/ n = tMIN(long,n,flank); /** TEST **/ p1 = XnuSeqPtr(E1)+i1-1; p2=XnuSeqPtr(E2)+i2-1; for(score=max, k=1; k < n; k++,p1--,p2--){ score += valAlphaR(*p1,*p2,A); if(score > max) max = score; /** else if(score < (max-40)) return max; ***/ /**/ else if(score < (max-40) || score < 0) return max; /****/ } return max; } long MatcherGBlastOffset(e_type E, gb_typ B, long *os) { long num,n,q,score,s,c,d,e,i,j,hits=0,max,*tmp=B->tmp,maxoff=0; a_type A=B->A; /** TEST **/ long flank = *os; /** TEST **/ n = LenSeq(E) - 1; c = XnuSeq(1,E); q = B->d[c][0]; /** q = state "^c" **/ for(max=0, i=2; i <= n; c=d, i++){ d = XnuSeq(i,E); q = B->d[d][q]; /** q = state "xd" **/ e = XnuSeq(i+1,E); /** e = next token (mealy model) **/ if(!EmptyMList(q,B->pos[e])){ /** then q + e signals acceptance **/ num=GetListMList(tmp, q, B->pos[e]); for(j=0; j < num; j++){ s = tmp[j]; /** TEST **/ score=WinExtendGBlast(B->E, s, E, i-1, A, flank); if(score > max){ max = score; maxoff = s+1; } /** TEST **/ /****** score=ExtendGBlast(B->E, s, E, i-1, A); if(score > max){ max = score; maxoff = s-i+1; } ******/ } hits+=j; } } *os = maxoff; return max; } long MatcherGBlast(FILE *fptr, e_type E, gb_typ B) { long num,n,q,score,s,c,d,e,i,j,hits=0,max,*tmp=B->tmp,maxoff=0; a_type A=B->A; long time1; time1=time(NULL); n = LenSeq(E) - 1; c = XnuSeq(1,E); q = B->d[c][0]; /** q = state "^c" **/ for(max=0, i=2; i <= n; c=d, i++){ d = XnuSeq(i,E); q = B->d[d][q]; /** q = state "xd" **/ e = XnuSeq(i+1,E); /** e = next token (mealy model) **/ if(!EmptyMList(q,B->pos[e])){ /** then q + e signals acceptance **/ num=GetListMList(tmp, q, B->pos[e]); for(j=0; j < num; j++){ s = tmp[j]; score=ExtendGBlast(B->E, s, E, i-1, A); if(score > max){ max = score; maxoff = s-i+1; } /*** DEBUG *** if(score == 47) fprintf(stderr, "%d - %c%c%c: s=%d\n", i-1,AlphaChar(c,A), AlphaChar(d,A), AlphaChar(e,A), s); *** DEBUG ***/ } hits+=j; } } if(max > 0 && fptr != NULL) { fprintf(fptr,"hits = %ld; max score = %ld\n",hits,max); fprintf(fptr,"score = %ld; offset = %ld\n", max,maxoff); PutDiagonalSeq(fptr, maxoff, B->E, E, A); fprintf(fptr,"\tmatcher time: %ld seconds\n", time(NULL)-time1); } return max; } long ExtendGBlast(e_type E1, long i1, e_type E2, long i2, a_type A) { long n,n1,n2; register char *p1,*p2; register long k,score,max; n1 = LenSeq(E1); n2 = LenSeq(E2); p1 = XnuSeqPtr(E1); p2=XnuSeqPtr(E2); for(score=k=0, p1+=i1, p2+=i2; k<3; k++,p1++,p2++) { score += valAlphaR(*p1,*p2,A); } n = tMIN(long,n2-i2,n1-i1); for(max=score; k <= n; k++,p1++,p2++) { score += valAlphaR(*p1,*p2,A); if(score > max) max = score; /** else if(score < (max-40)) break; ****/ /**/ else if(score <= (max-40) || score < 0) break; /****/ } n = tMIN(long,i1,i2); p1 = XnuSeqPtr(E1)+i1-1; p2=XnuSeqPtr(E2)+i2-1; for(score=max, k=1; k < n; k++,p1--,p2--){ score += valAlphaR(*p1,*p2,A); if(score > max) max = score; /** else if(score < (max-40)) return max; ****/ /**/ else if(score < (max-40) || score < 0) return max; /****/ } return max; } void NilGBlast(gb_typ B) { long c; for(c=0; c <= nAlpha(B->A); c++) { NilMList(B->pos[c]); free(B->d[c]); } free(B->tmp); free(B->d); free(B->pos); free(B); } Boolean FastMatcherGBlast(e_type E, gb_typ B, long score) { long num,n,q,s,c,d,e,i,j,*tmp=B->tmp; n = LenSeq(E) - 1; c = XnuSeq(1,E); q = B->d[c][0]; /** q = state "^c" **/ for(i=2; i <= n; c=d, i++){ d = XnuSeq(i,E); q = B->d[d][q]; /** q = state "xd" **/ e = XnuSeq(i+1,E); /** e = next token (mealy model) **/ if(!EmptyMList(q,B->pos[e])){ /** then q + e signals acceptance **/ num=GetListMList(tmp, q, B->pos[e]); for(j=0; j < num; j++){ s = tmp[j]; /***** if(score <= ExtendGBlast(B->E, s, E, i-1, B->A)) return TRUE; *****/ if(FastExtendGBlast(B->E, s, E, i-1, AlphaR(B->A),score)) return TRUE; /*****/ } } } return FALSE; } /* 5-6-00 tlb; make R int */ Boolean FastExtendGBlast(e_type E1, long i1, e_type E2, long i2, register int **R, long score) /**************************************************************** ****************************************************************/ { register long s,max; register char *p1,*p2,*end; p1 = XnuSeqPtr(E1)+i1; p2=XnuSeqPtr(E2)+i2; if((max=LenSeq(E2)-i2) > (s=LenSeq(E1)-i1)) end = p1 + s; else end = p1 + max; s = R[(int)p1[0]][(int)p2[0]] + R[(int)p1[1]][(int)p2[1]] + R[(int)p1[2]][(int)p2[2]]; for(max=s, p1+=3, p2+=3; p1 <= end; p1++,p2++) { if((s += R[(int)*p1][(int)*p2]) > max){ if(s >= score) return TRUE; max = s; } /** else if(s <= (max-40)) break; ****/ /**/ else if(s <= (max-40) || s < 0) break; /****/ } p1 = XnuSeqPtr(E1)+i1; p2=XnuSeqPtr(E2)+i2; if(i1 <= i2) end = p1 - i1; else end = p1 - i2; for(s=max, p1--, p2--; p1 > end; p1--,p2--){ if((s += R[(int)*p1][(int)*p2]) > max){ if(s >= score) return TRUE; max = s; } /** else if(s <= (max-40)) return FALSE; ****/ /**/ else if(s <= (max-40) || s < 0) return FALSE; /****/ } return FALSE; } /******************************* private *******************************/ long gblast_error(char *s) { fprintf(stderr,"gblast: %s\n",s); exit(1); } glam2-1064/purge/sequence.c0000644007451300001540000004203310631405720015227 0ustar charlesgenome#include "sequence.h" e_type ReadSeq(FILE *fptr, long I, long size, a_type A) { char *id,*seq; long length,i,c='x'; e_type E; while(c != EOF){ if((c=fgetc(fptr)) == '>') break; } if(c==EOF) return NULL; NEW(id,80,char); for(i=0; (c=fgetc(fptr))!=EOF; i++){ if(c=='\n') { if(i<80)id[i]= '\0'; break; } else if(i<79) id[i] = c; else if(i==79) id[i] = '\0'; } NEW(seq,size+1, char); for(length=1; (c=fgetc(fptr))!=EOF; ){ if(c == '>') { ungetc(c,fptr); break; } else if(isalpha(c)) { if(islower(c)) c = toupper(c); seq[length++] = AlphaCode(c,A); } } length--; if(length > size) seq_error("size and length inconsistency"); NEW(E,1,sequence_type); E->info=id; E->n = (unsigned short) length; E->I = (unsigned short) I; E->S = seq; E->X = seq; E->xnu = FALSE; return E; } Boolean NonNullIdentSeqs(register e_type E1, register e_type E2) /** If E1 has the same sequence as E2 return TRUE; else return FALSE **/ { register long s,r1,r2; if(E1->n != E2->n) return FALSE; for(s=1; s<= (long) E1->n; s++){ r1 = E1->X[s]; r2 = E2->X[s]; if(r1 != 0 && r2 != 0 && r1 != r2) return FALSE; } return TRUE; } Boolean IdentSeqs(e_type E1, e_type E2) /** If E1 has the same sequence as E2 return TRUE; else return FALSE **/ { long s; if(E1->n != E2->n) return FALSE; for(s=1; s<= (long) E1->n; s++){ if(E1->X[s] != E2->X[s]) return FALSE; } return TRUE; } e_type MergeSeqs(e_type *E) /** merge array of sequences into one long sequence **/ { e_type mE; long length,s,i,n; unsigned short I; if(E[0]==NULL) return NULL; for(I=length=n=0; E[n] != NULL; n++){ length += E[n]->n; I = tMAX(unsigned short,I,E[n]->I); } I++; if(n==1) return CopySeq(E[0]); mE = EmptySeq(I,length); NEW(mE->info,80,char); for(i=0; i<80; i++) mE->info[i] = E[0]->info[i]; for(s=1,n=0; E[n] != NULL; n++){ for(i=1; i<= (long) E[n]->n; i++,s++){ mE->S[s] = E[n]->S[i]; } } return mE; } e_type EmptySeq(long I, long length) /* create and return an empty sequence of length */ { char *seq; e_type E; NEW(seq,length+1, char); NEW(E,1,sequence_type); E->info=NULL; E->n = (unsigned short) length; E->I = (unsigned short) I; E->S = seq; E->X = seq; E->xnu = FALSE; return E; } long GetFastaInfo(char *DBS_NAME, long max, long **pcounts, unsigned short **psize, a_type A) /***************************************************************** Get information on the number of sequences, lengths (=size) and residue compositions for a fasta file *****************************************************************/ { long i,length; long *counts; unsigned short *size; /* 5-6-00 tlb; make c int */ int c; FILE *fptr; if((fptr = fopen(DBS_NAME,"r")) == NULL) { fprintf(stderr,"Could not open file \"%s\"\n",DBS_NAME); print_error("File does not exist."); } NEW(size,max+2,unsigned short); NEW(counts,nAlpha(A)+3,long); while((c=fgetc(fptr))!=EOF){ if(c=='>') break; } if(c==EOF) print_error("File not in fasta format!"); /*** fprintf(stderr,"Determining database composition...");****/ for(i=1,length=0;c!=EOF;length=0,i++) { if(c=='>') while((c=fgetc(fptr))!=EOF){ if(c=='\n') break; } while(c!='>') { if(isalpha(c)) { length++; counts[(int)(AlphaCode(c,A))]++; } else if(!isspace(c)) { fprintf(stderr,"sequence %ld: %c undefined ",i,c); /**** fprintf(stderr," (ignored)\n"); ****/ fprintf(stderr," (replaced with null character: %c)\n", AlphaChar(UndefAlpha(A),A)); length++; counts[UndefAlpha(A)]++; } if((c=fgetc(fptr))==EOF) break; } if(i > max) print_error("too many sequences; reset maximum"); size[i] = length; } i--; fclose(fptr); /*** fprintf(stderr," (%d sequences)\n",i); ***/ *pcounts = counts; *psize = size; return i; } long *CountsSeq(e_type E, a_type A) { long j,r,*cnts; NEW(cnts,nAlpha(A)+3,long); for(j=1; j <= (long)E->n; j++){ r=E->S[j]; cnts[r]++; } return cnts; } double *FreqResSeq(e_type E, double *freq, a_type A) { long j,r; for(r = 0; r <= nAlpha(A); r++) freq[r] = 0.0; for(j=1; j <= (long)E->n; j++) { r=E->S[j]; freq[r]+=1.0; } for(r = 0; r <= nAlpha(A); r++) freq[r] /= (double) E->n; return freq; } long *NumResSeq(e_type E,a_type A) /** return residue frequencies **/ { long j,r; long *num; NEW(num,nAlpha(A)+3,long); for(j=1; (long)j <= (long)E->n; j++) { r = E->S[j]; num[r]++; } return num; } e_type CopySeq(e_type E) { e_type E2; long i,len; NEW(E2,1,sequence_type); if(E==NULL) seq_error("CopySeq( ) can't copy null sequence."); if(E->info != NULL){ len = strlen(E->info); NEW(E2->info,len + 2,char); for(i=0;i<=len; i++) E2->info[i]= E->info[i]; } E2->n = E->n; E2->I = E->I; E2->xnu = E->xnu; NEW(E2->S, E->n + 2, char); for(i=1;i<=(long)E->n; i++) E2->S[i]= E->S[i]; if(E->xnu){ NEW(E2->X, E->n + 2, char); for(i=1;i<=(long)E->n; i++) E2->X[i]= E->X[i]; } else { E2->X = E2->S; } return E2; } /************************* Randomization Routines ***********************/ e_type RandomSeq(long length, long I, double *freq, a_type A) /* return a randomly generated new sequence of length with residue frequency " freq" */ { long i,c; double r; e_type E; E = EmptySeq(I, length); for(i=1;i<=(long)E->n; i++) { r = (double) Random()/(double) LONG_MAX; /* 0 <= r <= 1 */ for(E->S[i]=0,c=1; c <= nAlpha(A); c++){ r=r-freq[c]; if(r <= 0.0){ E->S[i]=c; break; } } } return E; } e_type RandomizeSeq(e_type E, double *freq, a_type A) /* destroy E and return a randomly generated new sequence of same length with residue frequency " freq" */ { long i,c; double r; if(E->xnu) {free(E->X); E->xnu=FALSE; E->X=E->S;} for(i=1;i<=(long)E->n; i++) { r = (double) Random()/(double) LONG_MAX; /* 0 <= r <= 1 */ for(E->S[i]=0,c=1; c <= nAlpha(A); c++){ r=r-freq[c]; if(r <= 0.0){ E->S[i]=c; break; } } } if(E->info!=NULL)free(E->info); E->info = NULL; return E; } char RandomResSeq(register e_type E) /* return a randomly obtained residue in sequence E */ { register long i; register double r; do { r = (double) Random()/(double) LONG_MAX; /* 0 <= r <= 1 */ i = (long) (r*E->n + 1); } while(i < 1 && i > (long) E->n); return E->S[i]; } e_type RtnShuffleSeq(e_type E) /* randomly permute the sequence E.S using a heap */ { e_type rE; long i,n; dh_type H; NEW(rE,1,sequence_type); rE->xnu=FALSE; rE->I = 0; n = rE->n = E->n; NEW(rE->S,n+1,char); H = dheap(n+1,4); for(i=1;i<=n;i++){ insrtHeap(i,((keytyp)Random()),H);} for(i=1;i<=n;i++) rE->S[i] = E->S[delminHeap(H)]; Nildheap(H); rE->info=NULL; rE->X = rE->S; return rE; } e_type ShuffleSeq(e_type E) /* randomly permute the sequence E.S using a heap; don't move 'X's. */ { char *S; long i; dh_type H; if(E->xnu) {free(E->X); E->xnu=FALSE; } NEW(S,E->n+1,char); H = dheap(E->n+1,4); for(i=1;i<=(long)E->n; i++){ S[i]=E->S[i]; if(S[i] != 0){ insrtHeap(i,((keytyp)Random()),H); } } for(i=1;i<=(long)E->n; i++){ if(E->S[i] != 0){ E->S[i] = S[delminHeap(H)]; } } Nildheap(H); free(S); if(E->info!=NULL)free(E->info); E->info = NULL; E->X = E->S; return E; } e_type ShuffleSeq2(e_type E) /* randomly permute the sequence E.S using a heap */ { char *S; long i; dh_type H; if(E->xnu) {free(E->X); E->xnu=FALSE; } NEW(S,E->n+1,char); H = dheap(E->n+1,4); for(i=1;i<=(long)E->n; i++) { S[i]=E->S[i];insrtHeap(i,((keytyp)Random()),H);} for(i=1;i<=(long)E->n; i++) E->S[i] = S[delminHeap(H)]; Nildheap(H); free(S); if(E->info!=NULL)free(E->info); E->info = NULL; E->X = E->S; return E; } /************************* Print Routines ***********************/ void PutSeqInfo(FILE *fptr,e_type E) { if(E->info !=NULL) fprintf(fptr,"%s\n", E->info); else fprintf(fptr,"random%ld\n",(long)E->I);} void PutSeqID(FILE *fptr,e_type E) { long k; if(E->info !=NULL) { for(k=0; !isspace(E->info[k]); k++){ if(E->info[k]==0) break; fprintf(fptr,"%c", E->info[k]); } } else fprintf(fptr,"random%ld ",(long)E->I); } void PutXnuSeq(FILE *fptr,e_type E,a_type A) { long j; fprintf(fptr,">"); PutSeqInfo(fptr,E); for(j=1; (long)j <= (long)E->n; j++) { fprintf(fptr,"%c",AlphaChar(E->X[j],A)); if(j%10 == 0) fprintf(fptr," "); if(j%50 == 0) fprintf(fptr,"\n"); } fprintf(fptr,"\n\n"); } void PutSeq(FILE *fptr,e_type E,a_type A) { long j; fprintf(fptr,">"); PutSeqInfo(fptr,E); for(j=1; (long)j <= (long)E->n; j++) { fprintf(fptr,"%c",AlphaChar(E->S[j],A)); if(j%10 == 0) fprintf(fptr," "); if(j%50 == 0) fprintf(fptr,"\n"); } fprintf(fptr,"\n\n"); } void MaskSeq(long start, long end, e_type E) /** set the region from start to end to "null" residues (0) **/ { long i; char *s; if(start < 1 || start > end || end > (long) LenSeq(E)){ seq_error("MaskSeq( ) - out of range."); } if(E->xnu) s = E->X; else s = E->S; for(i=start; i <= end; i++) s[i] = 0; } void PutSeqRegion(FILE *fptr,long start, long length, e_type E, a_type A) { PutSeqRegion2(fptr,start, length, E, 10, A); } void PutSeqRegion2(FILE *fptr,long start, long length, e_type E, long flank, a_type A) { long e,end,i; fprintf(fptr,"%4ld ",start); e = start + length - 1; end = e + flank; for(i=start-flank; i <= end; i++){ if(i < 1 || i > (long) E->n) fprintf(fptr," "); else if(i == e) { fprintf(fptr,"%c ", AlphaChar(E->S[i],A)); } else if(i == start) { fprintf(fptr," %c", AlphaChar(E->S[i],A)); } else { fprintf(fptr,"%c", AlphaChar(E->S[i],A)); } } e = tMIN(long,e,LenSeq(E)); fprintf(fptr," %4ld",e); } /** a_type ALPHABETA=NULL; ** DEBUG **/ /* 5-6-00 tlb; change R to int */ long get_diagonal_ends_seq(char *seq1, char *seq2, int **R, long n, long *begin, long *end) { register long min=LONG_MAX, sum=0,score=-9999; long min_n=0; if(n <= 0) { *begin = n+1; *end = n; return 0; } score = min = sum = R[(int)seq1[n]][(int)seq2[n]]; *begin = *end = min_n = n; n--; while(n > 0){ if(min > (sum += R[(int)seq1[n]][(int)seq2[n]])){ min = sum; min_n = n-1; } if(score < (sum-min)){ score = (sum-min); *end = min_n; *begin = n; } /***** fprintf(stderr,"%4d: %c-%c (%d (sum = %d): %d..%d)\n", n,AlphaChar(seq2[n],ALPHABETA), AlphaChar(seq1[n],ALPHABETA),score, sum, *begin,*end); *****/ n--; }; /*** printf("\tEND\n\n"); ****/ return score; } long CenterSeqHSP(long offset, e_type E1, e_type E2, a_type A) /* return the center of the high scoring pair with offset **/ { long v,n,n1,n2,score=0,e,start,end; char *seq1,*seq2; long center; n1 = LenSeq(E1); n2 = LenSeq(E2); v = offset; if(v < (1-n2) || v >= n1) seq_error("offset out of range"); seq1 = XnuSeqPtr(E1); seq2 = XnuSeqPtr(E2); if(v > 0){ /** case 1: offset **/ n = tMIN(long,n1-v,n2); score=get_diagonal_ends_seq(seq1+v,seq2,AlphaR(A),n,&start,&e); start = v+start; end = v+e-1; } else { n = tMIN(long,n2+v,n1); score=get_diagonal_ends_seq(seq2-v,seq1,AlphaR(A),n,&start,&e); end = e - 1; } n = (end - start + 1)/2; center = start + n; return center; } long PutDiagonalSeq(FILE *fptr, long offset, e_type E1, e_type E2, a_type A) /******************************************************************* print the MSP for diagonal at offset between seq1 and seq2. *******************************************************************/ { long v,i,j,n,n1,n2,score=0,b,e,start,end,w=40; char *seq1,*seq2; /** ALPHABETA=A; *****/ n1 = LenSeq(E1); n2 = LenSeq(E2); v = offset; if(v < (1-n2) || v >= n1) seq_error("offset out of range"); seq1 = XnuSeqPtr(E1); seq2 = XnuSeqPtr(E2); if(v > 0){ n = tMIN(long,n1-v,n2); score=get_diagonal_ends_seq(seq1+v,seq2,AlphaR(A),n,&start,&e); fprintf(fptr,"\n\n"); for(b=start; b <= e; b+=w){ end = tMIN(long,e,b+w-1); fprintf(fptr,"%4ld ",v+b); for(i=v+b,j=b; j <= end; i++,j++) fprintf(fptr,"%c",AlphaChar(seq1[i],A)); fprintf(fptr," %4ld ",v+end); PutSeqID(fptr,E1); fprintf(fptr,"\n "); for(i=v+b,j=b; j <= end; i++,j++) if(seq1[i]==seq2[j]) fprintf(fptr,":"); else if(valAlphaR(seq1[i],seq2[j],A) >= 0) fprintf(fptr,"."); else fprintf(fptr," "); fprintf(fptr,"\n%4ld ",b); for(j=b; j <= end; j++) fprintf(fptr,"%c", AlphaChar(seq2[j],A)); fprintf(fptr," %4ld ",end); PutSeqID(fptr,E2); fprintf(fptr,"\n\n"); } fprintf(fptr," score = %ld\n\n",score); } else { n = tMIN(long,n2+v,n1); score=get_diagonal_ends_seq(seq2-v,seq1,AlphaR(A),n,&start,&e); fprintf(fptr,"\n\n"); for(b=start; b <= e; b+=w){ end = tMIN(long,e,b+w-1); fprintf(fptr,"%4ld ",b); for(j=b; j <= end; j++) fprintf(fptr,"%c",AlphaChar(seq1[j],A)); fprintf(fptr," %4ld ",end); PutSeqID(fptr,E1); fprintf(fptr,"\n "); for(i=b-v,j=b; j <= end; i++,j++) if(seq2[i]==seq1[j]) fprintf(fptr,":"); else if(valAlphaR(seq2[i],seq1[j],A) >= 0) fprintf(fptr,"."); else fprintf(fptr," "); fprintf(fptr,"\n%4ld ",b-v); for(i=b-v,j=b; j <= end; i++,j++) fprintf(fptr,"%c", AlphaChar(seq2[i],A)); fprintf(fptr," %4ld ",end-v); PutSeqID(fptr,E2); fprintf(fptr,"\n\n"); } fprintf(fptr," score = %ld\n\n",score); } return score; } /******************************************************************** ** C program to read in sequences in Fasta format ** test them for internal repeats ** and print them out with the internal repeats flagged Usage: xnu fasta-sequences-file\n [-60] [-120] [-250] PAM matrix to use\n"); [-p probability-cut] default 0.01\n"); [-s score-cut]\n"); [-n search-width] default 10, 0->all diagonals\n"); [-a] [-d] ascending or descending\n"); [-.] [-x] [-o] output options\n"); (argv[i],"-p")==0) { pcut = atof(argv[++i]); } (argv[i],"-n")==0) { ncut = atoi(argv[++i]); } (argv[i],"-s")==0) { scut = atoi(argv[++i]); } (argv[i],"-60")==0) { m = pam60; lambda = lambda60;} (argv[i],"-250")==0) { m = pam250; lambda = lambda250;} (argv[i],"-a")==0) { ascend = 1; descend = 0;} (argv[i],"-d")==0) { ascend = 0; descend = 1;} *********************************************************************/ void ProcessSeq(e_type E,a_type A,double lambda,double K,double H) { long i,j,k,off,sum,beg,end,top,noff; long topcut,fallcut,len; char *is,*hit; double s0; long ascend=1; long descend=1; long ncut=4; long mcut=1; double pcut=0.001; long scut=0; if(E->xnu) return; /* already done */ if ((len=LenSeq(E)) == 0) return; NEW(E->X,len+2,char); E->xnu = TRUE; is = E->S +1; hit = E->X +1; for (i=0; i0) noff=ncut; if(scut!=0) topcut = scut; else { s0 = - log( pcut*H / (noff*K) ) / lambda; if (s0>0) topcut = floor(s0 + log(s0)/lambda + 0.5); else topcut = 0; } fallcut = (long)log(K/0.001)/lambda; for (off=mcut; off<=noff; off++) { sum=top=0; beg=off; end=0; for(i=off; itop) { top=sum; end=i; } if (top>=topcut && top-sum>fallcut) { for (k=beg; k<=end; k++) { if (ascend) hit[k] = TRUE; if (descend) hit[k-off] = TRUE; } sum=top=0; beg=end=i+1; } else if (top-sum>fallcut) { sum=top=0; beg=end=i+1; } if (sum<0) { beg=end=i+1; sum=top=0; } } if (top>=topcut) { for (k=beg; k<=end; k++) { if (ascend) hit[k] = TRUE; if (descend) hit[k-off] = TRUE; } } } for (i=0; i') break; } if(c=='>') while((c=fgetc(fptr))!=EOF){ if(c=='\n') break; } while(c!='>') { if(isalpha(c)) length++; else if(!isspace(c)) { fprintf(stderr,"seq %ld: illegal character -> %c",I,c); while((c=fgetc(fptr)) != EOF) { fprintf(stderr,"%c",c); if(c == '\n') break; } fprintf(stderr,"\n"); seq_error("fatal error."); } if((c=fgetc(fptr))==EOF) break; } fclose(fptr); if((fptr = fopen(infile,"r")) == NULL) { fprintf(stderr,"Could not open file \"%s\"\n",infile); seq_error("File does not exist!"); } E = ReadSeq(fptr, I, length, A); fclose(fptr); return E; } e_type NilSeq(e_type E) { if(E!=NULL){ free(E->S); if(E->info!=NULL)free(E->info); if(E->xnu) free(E->X); free(E); } return NULL; } long seq_error(char *s){fprintf(stderr,"Seq: %s\n",s);exit(1);} glam2-1064/purge/pairaln.h0000644007451300001540000000232710631406244015056 0ustar charlesgenome/* pairaln.h - pairwise alignment methods . */ #if !defined(PAIRALN) #define PAIRALN #include "stdinc.h" #include "alphabet.h" #include "sequence.h" #include "mheap.h" /******************************** private **********************************/ /* 5-6-00 tlb; make R int */ Boolean relate_seq(register char *seq1, register char *seq2, register int **R, register long n, register long cutoff); /* 5-6-00 tlb; make R int */ long diagonal_score_seq(register char *seq1, register char *seq2, register int **R, register long n); /* 5-6-00 tlb; make R int */ long get_diagonal_ends_seq(char *seq1, char *seq2, int **R, long n, long *begin, long *end); /* 5-6-00 tlb; make R int */ long repeat_score_seq(register char *seq, register int **R, register long o, register long n); /******************************** PUBLIC **********************************/ long PutDiagonalSeq(FILE *fptr, long offset, e_type E1, e_type E2, a_type A); Boolean RelatedSeqs(long cutoff, e_type E1, e_type E2, a_type A); long AlignSeqFastp(e_type E1, e_type E2, a_type A); Boolean RelateSeqFastp(e_type E1, e_type E2, a_type A,long score); long RepeatScoreSeq(e_type E, a_type A, long *offset); #endif glam2-1064/purge/random.c0000644007451300001540000000273610631405634014711 0ustar charlesgenome#include "random.h" /* Additive random number generator Modelled after "Algorithm A" in Knuth, D. E. (1981). The art of computer programming, volume 2, page 27. 7/26/90 WRG */ static long state[33] = { (long)0xd53f1852, (long)0xdfc78b83, (long)0x4f256096, (long)0xe643df7, (long)0x82c359bf, (long)0xc7794dfa, (long)0xd5e9ffaa, (long)0x2c8cb64a, (long)0x2f07b334, (long)0xad5a7eb5, (long)0x96dc0cde, (long)0x6fc24589, (long)0xa5853646, (long)0xe71576e2, (long)0xdae30df, (long)0xb09ce711, (long)0x5e56ef87, (long)0x4b4b0082, (long)0x6f4f340e, (long)0xc5bb17e8, (long)0xd788d765, (long)0x67498087, (long)0x9d7aba26, (long)0x261351d4, (long)0x411ee7ea, (long)0x393a263, (long)0x2c5a5835, (long)0xc115fcd8, (long)0x25e9132c, (long)0xd0c6e906, (long)0xc2bc5b2d, (long)0x6c065c98, (long)0x6e37bd55 }; #define r_off 12 static long *rJ = &state[r_off], *rK = &state[DIM(state)-1]; void sRandom(long x) { register long i; state[0] = x; /* linear congruential initializer */ for (i=1; i>1)&0x7fffffff; /* discard the least-random bit */ } glam2-1064/purge/dheap.c0000644007451300001540000000514110631405467014507 0ustar charlesgenome#include "dheap.h" dh_type dheap(long N,long D) /* Initialize a heap to store items in {1,...,N}.*/ { dh_type H; long i; NEW(H,1,dheap_type); H->N = N; H->d = D; H->n = 0; NEW(H->h,N+1,long); NEW(H->pos,N+1,long); NEW(H->kvec,N+1,keytyp); for (i=1; i<= N; i++) H->pos[i] = 0; return H; } void Nildheap(dh_type H) { free(H->h); free(H->pos); free(H->kvec); free(H); } void insrtHeap(long i,keytyp k, dh_type H) /* insert item i with specified key */ { if(i<1) dheap_error("fatal! item to insert is < 1"); if(H->pos[i]!=0) rmHeap(i,H); H->kvec[i] = k; H->n++; siftupHeap(i,H->n,H); } long rmHeap(long i,dh_type H) /* Remove item i from heap. */ { long j; if(H->pos[i]==0) return 0; j = H->h[H->n--]; if (i != j && H->kvec[j] <= H->kvec[i]) siftupHeap(j,H->pos[i],H); else if (i != j && H->kvec[j]>H->kvec[i]) siftdownHeap(j,H->pos[i],H); H->pos[i] = 0; return i; } long delminHeap(dh_type H) /* delete and return item with smallest key */ { long i; if (H->n == 0) return 0; i = H->h[1]; rmHeap(H->h[1],H); return i; } void siftupHeap(long i ,long x,dh_type H) /* Shift i up from position x to restore heap order.*/ { long px = pHeap(x,H); while (x > 1 && H->kvec[H->h[px]] > H->kvec[i]) { H->h[x] = H->h[px]; H->pos[H->h[x]] = x; x = px; px = pHeap(x,H); } H->h[x] = i; H->pos[i] = x; } void siftdownHeap(long i,long x,dh_type H) /* Shift i down from position x to restore heap order.*/ { long cx = minchildHeap(x,H); while (cx != 0 && H->kvec[H->h[cx]] < H->kvec[i]) { H->h[x] = H->h[cx]; H->pos[H->h[x]] = x; x = cx; cx = minchildHeap(x,H); } H->h[x] = i; H->pos[i] = x; } long minchildHeap(long x,dh_type H) /* Return the position of the child of the item at position x having minimum key. */ { long y, minc; if ((minc = leftHeap(x,H)) > H->n) return 0; for (y = minc + 1; y <= rightHeap(x,H) && y <= H->n; y++) { if (H->kvec[H->h[y]] < H->kvec[H->h[minc]]) minc = y; } return minc; } void chkeyHeap(long i,keytyp k, dh_type H) /* Change the key of i and restore heap order.*/ { keytyp ki; if(H->pos[i]==0) return; ki = H->kvec[i]; H->kvec[i] = k; if (k < ki) siftupHeap(i,H->pos[i],H); else if (k > ki) siftdownHeap(i,H->pos[i],H); } void PutHeap(FILE *fptr,dh_type H) /* Print the contents of the heap. */ { long x; fprintf(fptr," h:"); for (x = 1; x <= H->n; x++) fprintf(fptr," %2ld",H->h[x]); fprintf(fptr,"\nkvec:"); for (x = 1; x <= H->n; x++) fprintf(fptr," %3f",H->kvec[H->h[x]]); fprintf(fptr,"\n pos:"); for (x = 1; x <= H->n; x++) fprintf(fptr," %2ld",H->pos[H->h[x]]); fprintf(fptr,"\n"); } void dheap_error(char *s){fprintf(stderr,"dheap: %s\n",s);exit(1);} glam2-1064/purge/pairaln.c0000644007451300001540000002162710631405575015063 0ustar charlesgenome#include "pairaln.h" /**************************************************************** first: (seq2=1) from s1 = 1 v DSIMVNPPY s1 = s2 = 1; IATNPPYVGHIKG s1++; ^ to s1 = n1-3; v DSIMVNPPY s1 = n1 - 3 = 9 - 3 = 6 IATNPPYVGHIKG (s1...s1+end && s2...end) ^ s2 = 1; second: v v IATNPPYVGHIKG IATNPPYVGHIKG DSIMVNPPY to DSIMVNPPY ^ ^ ******************************************************************/ /* 5-6-00 tlb; make R int */ Boolean relate_seq(register char *seq1, register char *seq2, register int **R, register long n, register long cutoff) { register long min=0,sum=0; while(n > 0){ if(min < (sum += R[(int)seq1[n]][(int)seq2[n]])){ if(sum-min >= cutoff) return TRUE; } else min = sum; n--; }; return FALSE; } Boolean RelatedSeqs(long cutoff, e_type E1, e_type E2, a_type A) /********************************************************************* Compare all diagonals of E1 and E2 to see if the two have an MSP with score > cutoff. *********************************************************************/ { long i,s,n1,n2,end,w; char *seq1,*seq2; w = cutoff/highAlphaR(A); n1 = LenSeq(E1); seq1 = XnuSeqPtr(E1); n2 = LenSeq(E2); seq2 = XnuSeqPtr(E2); for(end = n1 - w, s=0; s < end; s++,i--) { i = tMIN(long,n1-s,n2); if(relate_seq(seq1+s, seq2, AlphaR(A),i,cutoff)) return TRUE; } for(end = n2 - w, s=1; s <= end; s++) { i = tMIN(long,n2-s,n1); if(relate_seq(seq2+s, seq1, AlphaR(A),i,cutoff)) return TRUE; } return FALSE; } /* 5-6-00 tlb; make R int */ long repeat_score_seq(register char *seq, register int **R, register long o, register long n) /******************************************************************** /ptr=seq1+s seq1: MQNKSQKETGDILGISQMHVSRL seq2: MPPLFVMNNEILMHLRALKKTKKDVS |...... n .......| ********************************************************************/ { register long min=0,sum=0,score=-9999; for(seq++; n > o; seq++){ if(min > (sum += R[(int)seq[0]][(int)seq[o]])){ min = sum; } else if(score < (sum-min)) score = (sum-min); n--; }; return score; } long RepeatScoreSeq(e_type E, a_type A, long *offset) /** look for internal repeats **/ { long i,best,s,n,score; char *seq; n = LenSeq(E); seq = XnuSeqPtr(E); for(score= -9999,best=i=1; i < n; i++) { s = repeat_score_seq(seq,AlphaR(A),i,n); if(s > score) { best = i; score = s; } } *offset = best; return score; } /* 5-6-00 tlb; make R int */ long diagonal_score_seq(register char *seq1, register char *seq2, register int **R, register long n) /******************************************************************** /ptr=seq1+s seq1: MQNKSQKETGDILGISQMHVSRL seq2: MPPLFVMNNEILMHLRALKKTKKDVS |...... n .......| ********************************************************************/ { register long min=0,sum=0,score=-9999; while(n > 0){ if(min > (sum += R[(int)seq1[n]][(int)seq2[n]])){ min = sum; } else if(score < (sum-min)) score = (sum-min); n--; }; return score; } long AlignSeqFastp(e_type E1, e_type E2, a_type A) /******************************************************************* Align two sequences using the fastp algorithm. see W.R. Pearson & D.J. Lipman PNAS (1988) 85:2444-2448 and Wilbur WJ; Lipman DJ (1983) Rapid similarity searches of nucleic acid and protein data banks. Proc Natl Acad Sci U S A 80: 726-730. *******************************************************************/ { long i,v,x,s,*D,**Q,*nQ,nsave=10; char *seq1,*seq2; long n,r,n1,n2,score=0,item; mh_type H; Boolean hits=FALSE; long *off,*off0; /** may want to remove spacer stuff - doesn't seem to help **/ keytyp *key,*key0; /** freq. of 1to5-spaces between matches **/ long *lastpos,*lastpos0,maxspace=10; n1 = LenSeq(E1); n2 = LenSeq(E2); seq1 = XnuSeqPtr(E1); seq2 = XnuSeqPtr(E2); /** Construct a lookup table for the query sequence (n1) using k=1 words with positions of all words in seq1. **/ NEW(nQ,nAlpha(A)+3,long); MEW(Q,nAlpha(A)+3,long*); for(i=0; i<= nAlpha(A); i++) NEW(Q[i],n1+3,long); for(s=1; s <= n1; s++) { r = seq1[s]; Q[r][nQ[r]] = s; nQ[r]++; } /** For each residue in a database sequence look up positions for all identical residues in the table & calculate the difference in position for all matches. (Store all matches with the same offset in a second table). ***/ v = n1 + n2; NEW(off0,v+4,long); off = off0 + n2 + 2; NEW(lastpos0,v+4,long); lastpos = lastpos0 + n2 + 2; NEW(key0,v+4,keytyp); key = key0 + n2 + 2; for(s=1; s <= n2; s++) { r = seq2[s]; for(i=0; i< nQ[r]; i++){ x = Q[r][i] - s; /** find offset **/ off[x]++; if(lastpos[x]!=0){ n = s - lastpos[x]; /** get spacer **/ if(n <= maxspace) key[x]+=4.0/(keytyp)n; } else lastpos[x] = s; } } /** locate regions of similarity using offsets with high # matches **/ H = Mheap(nsave,3); NEW(D,nsave+1,long); for(i = 1-n2; i < n1; i++){ if(i < 0) v = n2 + i; /** get length of diagonal **/ else v = n1 - i; key[i] += (keytyp)off[i] - (keytyp)v/(keytyp)nAlpha(A); /**/ if(key[i] > 3.0) { item=InsertMheap(-key[i],H); D[item] = i; /**** printf("key[%d]=%g (v=%d; percent = %g)\n", i,key[i],v, 100.0*(double)key[i]/(double)v); **/ /**** printf("off[%d]=%d (O-E=%f; v=%d; ave=%g)\n", i,off[i],(keytyp)v/(keytyp)nAlpha(A), v, (double)off[i]/(double)v); **/ } } /** compute the score for the ten offsets of highest similarity **/ /*** printf("\nn1 = %d; n2 = %d\n",n1,n2);**/ while((item=DelMinMheap(H))!=0){ i = D[item]; /*** fprintf(stderr,"key[%d] = %g; s[i] = ",i,key[i]); **/ if(i > 0){ /** -> start at seq1[i] **/ n = tMIN(long,n1-i,n2); s = diagonal_score_seq(seq1+i, seq2, AlphaR(A),n); } else { /** -> start at seq2[i] **/ n = tMIN(long,n2+i,n1); s= diagonal_score_seq(seq2-i, seq1, AlphaR(A),n); } if(s > score) { score = s; v = i; } /*** fprintf(stderr,"%d; score = %d\n",s,score); **/ /*** PutDiagonalSeq(stdout, i, E1, E2, A); TEST **/ hits=TRUE; } /** output high scoring segment **/ if(hits) PutDiagonalSeq(stdout, v, E1, E2, A); else printf("no match\n"); /** deallocate memory **/ NilMheap(H); free(D); for(i=0; i<= nAlpha(A); i++) free(Q[i]); free(Q); free(nQ); free(lastpos0); free(key0); free(off0); return score; } Boolean RelateSeqFastp2(e_type E1, e_type E2, a_type A,long score) /** use this to test fastp alignment, etc. **/ { if(score <= AlignSeqFastp(E1, E2, A)) return TRUE; else return FALSE; } Boolean RelateSeqFastp(e_type E1, e_type E2, a_type A,long score) /******************************************************************* See if two sequences are related with at or above a cutoff score using the fastp algorithm. *******************************************************************/ { long i,x,*D,**Q,*nQ,r,s,n,n1,n2,item,nsave=10; char *seq1,*seq2; mh_type H; long *off,*off0,*lastpos,*lastpos0; keytyp *key,*key0; long maxspace=10; n1 = LenSeq(E1); n2 = LenSeq(E2); seq1 = XnuSeqPtr(E1); seq2 = XnuSeqPtr(E2); NEW(nQ,nAlpha(A)+3,long); MEW(Q,nAlpha(A)+3,long*); for(i=0; i<= nAlpha(A); i++) MEW(Q[i],n1+3,long); for(i=1; i <= n1; i++) { r = seq1[i]; Q[r][nQ[r]] = i; nQ[r]++; } n = n1 + n2; NEW(off0,n+4,long); off = off0 + n2 + 2; NEW(lastpos0,n+4,long); lastpos = lastpos0 + n2 + 2; NEW(key0,n+4,keytyp); key = key0 + n2 + 2; for(i=1; i <= n2; i++) { r = seq2[i]; for(n=0; n < nQ[r]; n++){ x = Q[r][n] - i; /** find offset **/ off[x]++; if(lastpos[x]!=0){ s = i - lastpos[x]; /** get spacer **/ if(s <= maxspace) key[x]+=4.0/(keytyp)s; } else lastpos[x] = i; } } /** locate regions of similarity using offsets with high # matches **/ H = Mheap(nsave,3); MEW(D,nsave+2,long); for(i = 1-n2; i < n1; i++){ if(i < 0) n = n2 + i; /** get length of diagonal **/ else n = n1 - i; key[i] += (keytyp)off[i] - (keytyp)n/(keytyp)nAlpha(A); if(key[i] > 3.0) { item=InsertMheap(-key[i],H); D[item] = i; } } /** compute the score for the ten offsets of highest similarity **/ for(i=0; i<= nAlpha(A); i++) free(Q[i]); free(Q); free(nQ); free(lastpos0); free(key0); free(off0); while((item=DelMinMheap(H))!=0){ i = D[item]; if(i > 0){ /** -> start at seq1[i] **/ n = tMIN(long,n1-i,n2); if(relate_seq(seq1+i,seq2,AlphaR(A),n,score)){ NilMheap(H); free(D); return TRUE; } } else { /** -> start at seq2[i] **/ n = tMIN(long,n2+i,n1); if(relate_seq(seq2-i,seq1,AlphaR(A),n,score)){ NilMheap(H); free(D); return TRUE; } } } NilMheap(H); free(D); return FALSE; } glam2-1064/purge/alphabet.h0000644007451300001540000000550110631406143015203 0ustar charlesgenome/****************** alphabet.h - alphabet abstract data type.***************/ /* ident: Alpha/ field: A/ File: alphabet.h/ FileId: ALPHA/ type a_type *************************** alphabet datastructure ********************** char: X A C D E F G H I K L M N P Q R S T V W Y code: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 *************************************************************************/ #if !defined(ALPHA) #define ALPHA #include "stdinc.h" #include /************************** alphabet datatype *****************************/ /* 5-6-00 tlb; make R int */ typedef struct { long n; /* number of LETTERS */ char *alphabet; /* ALPHABET */ char *code2let; /* CODE2LETTER */ char *code2lower; /* CODE2LETTER lower case */ char *let2code; /* LETTER2CODE */ /* 5-6-00 tlb; make R int */ int **R; /* relatedness scoring matrix */ char *C; /* complementary bases */ long loR; /* lowest value in R */ long hiR; /* highest value in R */ char *prs; /* pairs string */ char **pairs; /* residue pairs */ Boolean *paired; /* is residue r paired? */ long npairs; /* number of pairs */ } alphabet_type; typedef alphabet_type *a_type; /******************************** PRIVATE **********************************/ void alpha_error(char *s,a_type A); /******************************** PUBLIC ***********************************/ /**************************** alphabet operations **************************/ a_type MkAlpha(char *map_S,char *R); /* define alphabet */ a_type MkAlphabet(char *map_s,char *R,char *prs); a_type MkAlphabetC(char *map_s,char *R,char *prs,char *comp); a_type DefAlphaR(char *R,a_type A); /* redefine R */ a_type DefAlphaP(char *prs,a_type A); a_type PutAlpha(FILE *fptr,a_type A); /* output alphabet A to file */ void PutAlphaR(FILE *fptr,a_type A);/* output alphabet Pairs to file */ void PutAlphaPairs(FILE *fptr, a_type A); void NilAlpha(a_type A); /* make alphabet A undefined */ /**************************** alphabet defines ****************************/ #define nAlpha(A) ((A)->n) #define UndefAlpha(A) 0 #define AlphaR(A) ((A)->R) #define valAlphaR(c,d,A) ((A)->R[(int)(c)][(int)(d)]) #define lowAlphaR(A) ((A)->loR) #define highAlphaR(A) ((A)->hiR) #define valAlphaP(c,d,A) ((A)->pairs[(c)][(d)]) #define AlphaChar(i,A) ((A)->code2let[(int)(i)]) #define AlphaCharLow(i,A) ((A)->code2lower[(int)(i)]) #define AlphaCode(c,A) ((A)->let2code[(int)(c)]) #define MapAlphaCode(A) ((A)->let2code) #define MapCodeAlpha(A) ((A)->code2let) #define MemAlpha(c,A) ((long) (A)->let2code[(int)(c)]) #define NPairsAlpha(A) ((A)->npairs) #define PairedAlpha(c,A) ((A)->paired[(int)(c)]) #define AlphaComplement(i,A) (((A)->C != NULL)?(A)->C[(int)(i)]:0) /************ CONSTANTS *****************/ #define ALPHA_NUM_SYMBOLS 127 #endif glam2-1064/purge/afnio.h0000644007451300001540000000036010631405440014514 0ustar charlesgenome#include #include "stdinc.h" FILE *open_file(char *fstring,char *subfile,char *cmnd); long ParseIntegers(char *str, long *values, char *msg); long ParseReals(char *str, double *values, char *msg); char *String(char *s); glam2-1064/purge/purge.h0000644007451300001540000000226210723701273014552 0ustar charlesgenome/* purge.h - codes and constants for purge program. */ #if !defined (PURGE) #define PURGE #include #include "afnio.h" #include "block.h" #include "residues.h" #include "seqset.h" #include "pairaln.h" #include "dheap.h" #include "gblast.h" Boolean RmHomologs(long cutoff, char method, long minimum, Boolean query, ss_type P); /********* N A C T G *******/ #define DNA_MTRX "-4 -4 -4 -4 -4 \ -4 5 -4 -4 -4 \ -4 -4 5 -4 -4 \ -4 -4 -4 5 -4 \ -4 -4 -4 -4 5 " #define PURGE_USAGE "\nusage: purge file score \n\ options:\n\ [-n] - sequences are DNA (default: protein)\n\ [-b] - use blast heuristic method (default for protein)\n\ [-e] - use an exhaustive method (default for DNA)\n\ [-q] - keep first sequence in the set\n\ [-x] - use xnu to mask protein tandem repeats\n\ \n\ Purge creates an output file from the input file such that\n\ no two sequences have local alignment score greater than .\n\ The output file is named ..\n\ Substitution matrices: BLOSUM62 (protein), +5/-1 (DNA).\n\ \n" #endif glam2-1064/purge/Makefile0000644007451300001540000000017611014150212014702 0ustar charlesgenome# Compiler options: CFLAGS = -Wall -O3 # Command for compiling purge: purge: *.c *.h Makefile cc $(CFLAGS) -o purge *.c -lm glam2-1064/purge/karlin.h0000644007451300001540000000054610631406232014706 0ustar charlesgenome#if !defined(KARLIN) #define KARLIN #include #include "stdinc.h" #include "alphabet.h" #define KARLINMAXIT 50 /* Max. # iterations used in calculating K */ Boolean karlin(long low,long high,double *pr,double *lambda,double *K,double *H); double ExpectedInformation(a_type A, double lambda, double *freq); long karlin_gcd(long a,long b); #endif glam2-1064/purge/residues.h0000644007451300001540000000736510631405662015265 0ustar charlesgenome/****************** residues.h .***************/ /*************************** for alphabet datastructure ***************** *************************************************************************/ #if !defined(RESIDUES) #define RESIDUES /******************************* PROTEIN ******************************/ /* PROTEIN: macro definitions and static types for amino acid alphabet. */ #define AMINO_ACIDS "XCGASTNDEQKRHWYFVILMP" /******* ordering of closely related amino acids. *******/ /* . . . . 5 . . . .10 . . . .15 . . . .20 . . . .25 .*/ #define SREL26_BLSM62 "FYIVYWRKLMQEHYILDESTQKNDMIASRQFWLVEKMVNSNHQHFLAGMFNQ" /* . . . . . . . . . . . . . . . . . . . . . . . . . . */ #define SRELATE_BLSM62 "FYIVYWRKLMQEHYILDESTQKNDMIASRQFWLVEKMVNSNHQHFLAGMFNQTATNVTSQ" #define PROT_BLOSUM62 "\ X -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 \ C -9 9 -3 0 -1 -1 -3 -3 -4 -3 -3 -3 -3 -2 -2 -2 -1 -1 -1 -1 -3 \ G -9 -3 6 0 0 -2 0 -1 -2 -2 -2 -2 -2 -2 -3 -3 -3 -4 -4 -3 -2 \ A -9 0 0 4 1 0 -2 -2 -1 -1 -1 -1 -2 -3 -2 -2 0 -1 -1 -1 -1 \ S -9 -1 0 1 4 1 1 0 0 0 0 -1 -1 -3 -2 -2 -2 -2 -2 -1 -1 \ T -9 -1 -2 0 1 5 0 -1 -1 -1 -1 -1 -2 -2 -2 -2 0 -1 -1 -1 -1 \ N -9 -3 0 -2 1 0 6 1 0 0 0 0 1 -4 -2 -3 -3 -3 -3 -2 -2 \ D -9 -3 -1 -2 0 -1 1 6 2 0 -1 -2 -1 -4 -3 -3 -3 -3 -4 -3 -1 \ E -9 -4 -2 -1 0 -1 0 2 5 2 1 0 0 -3 -2 -3 -2 -3 -3 -2 -1 \ Q -9 -3 -2 -1 0 -1 0 0 2 5 1 1 0 -2 -1 -3 -2 -3 -2 0 -1 \ K -9 -3 -2 -1 0 -1 0 -1 1 1 5 2 -1 -3 -2 -3 -2 -3 -2 -1 -1 \ R -9 -3 -2 -1 -1 -1 0 -2 0 1 2 5 0 -3 -2 -3 -3 -3 -2 -1 -2 \ H -9 -3 -2 -2 -1 -2 1 -1 0 0 -1 0 8 -2 2 -1 -3 -3 -3 -2 -2 \ W -9 -2 -2 -3 -3 -2 -4 -4 -3 -2 -3 -3 -2 11 2 1 -3 -3 -2 -1 -4 \ Y -9 -2 -3 -2 -2 -2 -2 -3 -2 -1 -2 -2 2 2 7 3 -1 -1 -1 -1 -3 \ F -9 -2 -3 -2 -2 -2 -3 -3 -3 -3 -3 -3 -1 1 3 6 -1 0 0 0 -4 \ V -9 -1 -3 0 -2 0 -3 -3 -2 -2 -2 -3 -3 -3 -1 -1 4 3 1 1 -2 \ I -9 -1 -4 -1 -2 -1 -3 -3 -3 -3 -3 -3 -3 -3 -1 0 3 4 2 1 -3 \ L -9 -1 -4 -1 -2 -1 -3 -4 -3 -2 -2 -2 -3 -2 -1 0 1 2 4 2 -3 \ M -9 -1 -3 -1 -1 -1 -2 -3 -2 0 -1 -1 -2 -1 -1 0 1 1 2 5 -2 \ P -9 -3 -2 -1 -1 -1 -2 -1 -1 -1 -1 -2 -2 -4 -3 -4 -2 -3 -3 -2 7" /* X C G A S T N D E Q K R H W Y F V I L M P */ #define PAM_AMINO_ACIDS "XARNDCQEGHILKMFPSTWYV" #define PROT_PAM120 "\ X -2 -1 -2 -1 -2 -4 -1 -1 -2 -2 -1 -2 -2 -2 -3 -2 -1 -1 -5 -3 -1 \ A -1 3 -3 -1 0 -3 -1 0 1 -3 -1 -3 -2 -2 -4 1 1 1 -7 -4 0 \ R -2 -3 6 -1 -3 -4 1 -3 -4 1 -2 -4 2 -1 -5 -1 -1 -2 1 -5 -3 \ N -1 -1 -1 4 2 -5 0 1 0 2 -2 -4 1 -3 -4 -2 1 0 -4 -2 -3 \ D -2 0 -3 2 5 -7 1 3 0 0 -3 -5 -1 -4 -7 -3 0 -1 -8 -5 -3 \ C -4 -3 -4 -5 -7 9 -7 -7 -4 -4 -3 -7 -7 -6 -6 -4 0 -3 -8 -1 -3 \ Q -1 -1 1 0 1 -7 6 2 -3 3 -3 -2 0 -1 -6 0 -2 -2 -6 -5 -3 \ E -1 0 -3 1 3 -7 2 5 -1 -1 -3 -4 -1 -3 -7 -2 -1 -2 -8 -5 -3 \ G -2 1 -4 0 0 -4 -3 -1 5 -4 -4 -5 -3 -4 -5 -2 1 -1 -8 -6 -2 \ H -2 -3 1 2 0 -4 3 -1 -4 7 -4 -3 -2 -4 -3 -1 -2 -3 -3 -1 -3 \ I -1 -1 -2 -2 -3 -3 -3 -3 -4 -4 6 1 -3 1 0 -3 -2 0 -6 -2 3 \ L -2 -3 -4 -4 -5 -7 -2 -4 -5 -3 1 5 -4 3 0 -3 -4 -3 -3 -2 1 \ K -2 -2 2 1 -1 -7 0 -1 -3 -2 -3 -4 5 0 -7 -2 -1 -1 -5 -5 -4 \ M -2 -2 -1 -3 -4 -6 -1 -3 -4 -4 1 3 0 8 -1 -3 -2 -1 -6 -4 1 \ F -3 -4 -5 -4 -7 -6 -6 -7 -5 -3 0 0 -7 -1 8 -5 -3 -4 -1 4 -3 \ P -2 1 -1 -2 -3 -4 0 -2 -2 -1 -3 -3 -2 -3 -5 6 1 -1 -7 -6 -2 \ S -1 1 -1 1 0 0 -2 -1 1 -2 -2 -4 -1 -2 -3 1 3 2 -2 -3 -2 \ T -1 1 -2 0 -1 -3 -2 -2 -1 -3 0 -3 -1 -1 -4 -1 2 4 -6 -3 0 \ W -5 -7 1 -4 -8 -8 -6 -8 -8 -3 -6 -3 -5 -6 -1 -7 -2 -6 12 -2 -8 \ Y -3 -4 -5 -2 -5 -1 -5 -5 -6 -1 -2 -2 -5 -4 4 -6 -3 -3 -2 8 -3 \ V -1 0 -3 -3 -3 -3 -3 -3 -2 -3 3 1 -4 1 -3 -2 -2 0 -8 -3 5" #endif glam2-1064/purge/dheap.h0000644007451300001540000000371010631405472014510 0ustar charlesgenome#if !defined(DHEAP) #define DHEAP /* Header file for d-heap data structure. Maintains a subset * of items in {1,...,m}, where item has a key.*/ #include "stdinc.h" typedef double keytyp; typedef struct { long N; /* max number of items in heap */ long n; /* number of items in heap */ long d; /* base of heap */ long *h; /* {h[1],...,h[n]} is set of items */ long *pos; /* pos[i] gives position of i in h */ keytyp *kvec; /* kvec[i] is key of item i */ } dheap_type; typedef dheap_type *dh_type; /************************ private operations ***************************/ /* parent of item, leftmost and rightmost children */ #define pHeap(x,H) (((x)+((H)->d-2))/(H)->d) #define leftHeap(x,H) ((H)->d*((x)-1)+2) #define rightHeap(x,H) ((H)->d*(x)+1) #define MAX_KEY DBL_MAX long minchildHeap(long i,dh_type H); /* returm smallest child of item */ void siftupHeap(long i ,long x,dh_type H); /* move item up to restore heap order */ void siftdownHeap(long i,long x,dh_type H); /* move item down to restore heap order */ void dheap_error(char *s); /************************ public operations ***************************/ dh_type dheap(long N,long D); void Nildheap(dh_type H); void insrtHeap(long i,keytyp k, dh_type H); /* insert item with specified key */ long rmHeap(long i,dh_type H); /* remove item from heap */ long delminHeap(dh_type H); /* delete and return smallest item */ void chkeyHeap(long i,keytyp k, dh_type H); /* change the key of an item */ void PutHeap(FILE *fptr, dh_type H); /* print the heap */ /************************* macros definitions **************************/ #define minHeap(H) ((H)->n==0?NULL:(H)->h[1]) #define ItemsInHeap(H) ((H)->n) #define minkeyHeap(H) ((H)->kvec[(H)->h[1]]) #define minItemHeap(H) ((H)->h[1]) #define keyHeap(i,H) ((H)->kvec[(i)]) #define memHeap(i,H) ((H)->pos[(i)]!=0?TRUE:FALSE) #define emptyHeap(H) ((H)->n==0) #define fullHeap(H) ((H)->n >= (H)->N) #endif glam2-1064/purge/seqset.c0000644007451300001540000002342110631405675014734 0ustar charlesgenome#include "seqset.h" ss_type MkXnuSeqSet1(char *filename, e_type E, a_type A) /** return NULL if can't xnu **/ { return xnu_seqset(SeqSet1(filename, E, A)); } ss_type MkXnuSeqSet(char *filename,a_type A) /** return NULL if can't xnu **/ { return xnu_seqset(seqset(filename,A)); } ss_type MkXnuSeqSet_fptr(FILE *fptr,a_type A) /** return NULL if can't xnu **/ { return xnu_seqset(fptr_seqset(fptr,A)); } ss_type SeqSet1(char *filename, e_type E,a_type A) /* create a seqset of one sequence E */ { ss_type P; e_type E2 = CopySeq(E); long s,r; NEW(P,1,seqset_type); P->name = String(filename); P->A = A; P->nent = 1; NEW(P->entity,2,e_type); NEW(P->counts,nAlpha(A)+1,long); P->entity[1]=E2; for(s=1; s<= (long) LenSeq(E2); s++){ r = ResSeq(s,E2); P->counts[r]++; } P->max_leng = P->min_leng = P->total = LenSeq(E2); P->tfreq = NULL; calcseqsetfreq(P); P->xnu = FALSE; return (P); } ss_type RmSeqSet(e_type E, ss_type P) /** remove all sequences in P that are identical to E **/ { e_type E2; long s,r,n,k; for(n=1;n<=P->nent;){ E2 = P->entity[n]; if(IdentSeqs(E2, E)){ for(s=1; s<= (long) LenSeq(E2); s++){ r = ResSeq(s,E2); P->counts[r]--; } NilSeq(E2); P->entity[n] = P->entity[P->nent]; P->nent--; } else n++; } P->total = P->max_leng = 0; P->min_leng = LONG_MAX; for(n=1;n<=P->nent;){ E2 = P->entity[n]; k = LenSeq(E2); if(P->max_leng < k) P->max_leng = k; if(P->min_leng > k) P->min_leng = k; P->total += LenSeq(E2); } calcseqsetfreq(P); return P; } ss_type SeqSet(char *filename,a_type A) { return seqset(filename,A); } ss_type SeqSet_fptr(FILE *fptr,a_type A) { return fptr_seqset(fptr,A); } ss_type fptr_seqset(FILE *fptr,a_type A) /* create a seqset from the input file with segment length k and */ /* alphabet A. */ { ss_type P; long i,s,r,nsize[MAX_NUMBER_SEQS+1]; e_type E; NEW(P,1,seqset_type); NEW(P->name,25,char); strcpy(P->name,"temp_file"); P->A = A; P->nent = count_seqset_entities(fptr,P,nsize); NEW(P->entity,P->nent+1,e_type); NEW(P->counts,nAlpha(A)+1,long); P->total = 0; rewind(fptr); for(i=1; i<=P->nent; i++){ E = ReadSeq(fptr,i,nsize[i],A); P->entity[i]=E; for(s=1;s<=(long)LenSeq(E);s++){r=ResSeq(s,E);P->counts[r]++;} P->total += LenSeq(E); } P->tfreq = NULL; calcseqsetfreq(P); P->xnu = FALSE; return (P); } ss_type seqset(char *filename,a_type A) /* create a seqset from the input file with segment length k and */ /* alphabet A. */ { ss_type P; FILE *fptr; long i,s,r,nsize[MAX_NUMBER_SEQS+1]; e_type E; NEW(P,1,seqset_type); NEW(P->name,strlen(filename)+2,char); strcpy(P->name,filename); P->A = A; fptr = OpenSeqSetFile(P); P->nent = count_seqset_entities(fptr,P,nsize); fclose(fptr); NEW(P->entity,P->nent+1,e_type); NEW(P->counts,nAlpha(A)+1,long); P->total = 0; fptr = OpenSeqSetFile(P); for(i=1; i<=P->nent; i++){ E = ReadSeq(fptr,i,nsize[i],A); P->entity[(int)i]=E; for(s=1;s<=(long)LenSeq(E);s++){r=ResSeq(s,E);P->counts[r]++;} P->total += LenSeq(E); } fclose(fptr); P->tfreq = NULL; calcseqsetfreq(P); P->xnu = FALSE; return (P); } FILE *OpenSeqSetFile(ss_type P) { FILE *fptr; if((fptr = fopen(P->name,"r")) == NULL) { fprintf(stderr,"Could not open file \"%s\"\n",P->name); seqset_error("File does not exist!\n"); } return fptr; } ss_type NilSeqSet(ss_type P) { long i; for(i=1; i<=P->nent; i++){ if(P->entity[i] != NULL) NilSeq(P->entity[i]); } free(P->name); free(P->entity); free(P->counts); if(P->tfreq != NULL) free(P->tfreq); free(P); return (ss_type) NULL; } ss_type xnu_seqset(ss_type P) /*** return NULL if can't xnu SeqSet ***/ { long s,i,j,low,high,len,v; double *pr,lambda,K,H; char r,r1,r2; e_type E; double *freq; a_type A=P->A; char xnualpha[] = {"ARNDCQEGHILKMFPSTWYVBZX*-"}; double xnufreq[20] = { 0.081, 0.057, 0.045, 0.054, 0.015, 0.039, 0.061, 0.068, 0.022, 0.057, 0.093, 0.056, 0.025, 0.040, 0.049, 0.068, 0.058, 0.013, 0.032, 0.067 }; freq = tFreqSeqSet(P); if(P->xnu) return P; else P->xnu = TRUE; low = lowAlphaR(A); high = highAlphaR(A); len = high - low + 1; NEW(pr,len+1,double); for(i=0; i<=nAlpha(A); i++){ P->counts[i]=0; for(j=0; j<=nAlpha(A); j++){ v = valAlphaR(i,j,A) - low; pr[v] += freq[i] * freq[j]; } } if(!karlin(low,high,pr,&lambda,&K,&H)) { fprintf(stderr,"\nusing blast amino acid frequencies\n"); if(nAlpha(A) == 20) { for(i=0; i<= len; i++) pr[i] = 0.0;/****/ for(i=0; i<20; i++){ r1 = AlphaCode(xnualpha[i],A); for(j=0; j<20; j++){ r2 = AlphaCode(xnualpha[j],A); v = valAlphaR(r1,r2,A) - low; pr[v] += xnufreq[i] * xnufreq[j]; } } if(!karlin(low,high,pr,&lambda,&K,&H)) { seqset_error("this should not happen."); } } else seqset_error("fatal error in xnu_seqset( )."); } else H=ExpectedInformation(A, lambda, freq); for(i=1;i<=NSeqsSeqSet(P);i++){ E = P->entity[i]; if (LenSeq(E) != 0) { ProcessSeq(E,A,lambda,K,H); for(s=1; s<= (long) LenSeq(E); s++){ r = XnuSeq(s,E); P->counts[(int)r]++; } } } free(pr); calcseqsetfreq(P); return P; } double LogL0SeqSet(ss_type P) { double *freq,L0,n,r; long b; freq = tFreqSeqSet(P); for(L0=0.0, b=1; b<= nAlpha(P->A); b++){ if(CountsSeqSet(b,P) > 0){ n = (double) CountsSeqSet(b,P); r = freq[b]; L0 += n * log(r); } } return (1.4427*L0); } long *LengthsSeqSet(ss_type P) /* returns an array containing the sequence lengths */ { long *len_seq,n; NEW(len_seq,NSeqsSeqSet(P) +1,long); for(n=1; n<= NSeqsSeqSet(P); n++)len_seq[n]=SqLenSeqSet(n,P); return len_seq; } /******************** Counting and Numbering Operations *******************/ long count_seqset_entities(FILE *fptr,ss_type P, long nsize[]) { long i=0,j,length,c; P->max_leng = 0; P->min_leng = 1000000; while((c=fgetc(fptr))!=EOF){ if(c=='>') break; } for(i=1,length=0;c!=EOF;length=0,i++) { if(c=='>') while((c=fgetc(fptr))!=EOF){ if(c=='\n') break; } while(c!='>') { if(isalpha(c)) length++; else if(!isspace(c)) { fprintf(stderr,"seq %ld: illegal character -> %c",i, (char)c); for(j=0; (c=fgetc(fptr)) != EOF; j++) { if(c == '\n') break; fprintf(stderr,"%c",(char)c); if(j > 10 || isspace(c)) break; } fprintf(stderr,"\n"); seqset_error("input file error - fatal."); } if((c=fgetc(fptr))==EOF) break; } if(i >= MAX_NUMBER_SEQS) seqset_error("too many sequences; reset MAX_NUMBER_SEQS"); P->max_leng = tMAX(long,P->max_leng,length); P->min_leng = tMIN(long,P->min_leng,length); nsize[i] = length; } i--; return i; } ss_type PutSeqSet(FILE *fptr,ss_type P) { fprintf(fptr,"\n input file:\n"); fprintf(fptr,"\tname: \"%s\"\n\ttotal sequences: %ld", P->name,P->nent); fprintf(fptr,"\n\tsequence lengths: %ld-%ld residues\n", P->min_leng,P->max_leng); return P; } /*********************** Put SeqSet Entities Operations **********************/ ss_type PutSeqSetEs(FILE *fptr,ss_type P) /* print all sequence entities in seqset using fasta format */ { long i; for(i=1;i<=P->nent; i++) { if(SeqI(P->entity[i]) != 0) PutSeqSetE(fptr, i,P); } fprintf(fptr,"\n\n"); return P; } ss_type PutSeqSetE(FILE *fptr, long i, ss_type P) /* print the ith entity */ { e_type E; if(i <= P->nent && i > 0) { E = P->entity[i]; PutSeq(fptr,E,P->A); } return P; } ss_type PutSeqSetPIDs(FILE *fptr, ss_type P) /* print entity ids for selected entities */ { e_type E; long i; for(i=1;i<=P->nent;i++) { E = P->entity[i]; if(SeqI(E) != 0){ fprintf(fptr,"#%-3ld ",(long)SeqI(E)); PutSeqInfo(fptr,E); } } fprintf(fptr,"\n\n"); return P; } /********************** Frequency Operations ********************/ ss_type calcseqsetfreq(ss_type P) /* calculate the residue frequencies for seqset */ { long s; a_type A=P->A; if(P->tfreq==NULL) NEW(P->tfreq,nAlpha(A)+1,double); for(s=0;s<=(long) nAlpha(A);s++) { P->tfreq[s] = (double) P->counts[s]/(double) P->total; } return P; } double SeqSetEntropy(ss_type P) { long i; double *freq,H; freq = tFreqSeqSet(P); for(H=0.0,i = 1; i <= nAlpha(P->A); i++){ if(freq[i] > 0.0) H += freq[i] * log(freq[i]); } return (-1.442695041*H); } ss_type PutSeqSettFreqs(FILE *fptr,ss_type P) { long i; double T=0.0; fprintf(fptr,"RES %-6s %-s\n","NUM","FREQ"); for(i=0;i<=nAlpha(P->A);T+=P->tfreq[i],i++) fprintf(fptr,"%c(%2ld): %-6ld %-2.3f\n", AlphaChar(i,P->A),i,P->counts[i],P->tfreq[i]); fprintf(fptr,"TOTAL: %-6ld %-2.3f\n\n", P->total, T); return P; } /************************* Randomization Routines ***********************/ ss_type ShuffleSeqSet2(ss_type P) { long r,s,i,n,item; dh_type H; e_type E; char *S; for(n=0,i=1;i<=P->nent;i++) { E=P->entity[i]; n += LenSeq(E); } H = dheap(n+2,4); NEW(S,n+2,char); for(item=i=1;i<=P->nent;i++) { E=P->entity[i]; for(s=1; s<= (long) LenSeq(E); s++){ r = ResSeq(s,E); insrtHeap(item,((keytyp)Random()),H); S[item++]=r; } } for(i=1;i<=P->nent;i++) { E=P->entity[i]; for(s=1; s<= (long) LenSeq(E); s++){ item=delminHeap(H); if(item==0) seqset_error("shuffleSeqSet2 error"); r=S[item]; EqSeq(s,r,E); } EqSeqI(i,P->entity[i]); } Nildheap(H); free(S); return P; } ss_type ShuffleSeqSet(ss_type P) { long i; for(i=1;i<=P->nent;i++) { ShuffleSeq(P->entity[i]); EqSeqI(i,P->entity[i]); } return P; } void seqset_error(char *s) {fprintf(stderr,"Seq_Set: %s\n",s); exit(1);} glam2-1064/purge/pmain.c0000644007451300001540000000256610631405607014536 0ustar charlesgenome#include "purge.h" int main(int argc,char *argv[]) { int i,cutoff_score = 200,minimum=0,arg; char score[100],*DBS_NAME,c=' '; ss_type P = NULL; a_type A; Boolean success=FALSE,DNA=FALSE,xnu=FALSE,query=FALSE; if(argc < 3) print_error(PURGE_USAGE); DBS_NAME = argv[1]; if(sscanf(argv[2],"%d",&i)!=1) print_error(PURGE_USAGE); cutoff_score = tMAX(int,1,i); sprintf(score,".%c%d",c,cutoff_score); for(arg = 3; arg < argc; arg++){ if(argv[arg][0] != '-') print_error(PURGE_USAGE); switch(argv[arg][1]) { case 'b': c = 'b'; break; case 'e': c = 'e'; break; case 'f': c = 'f'; break; case 'q': query=TRUE; break; case 'x': xnu=TRUE; break; case 'n': DNA=TRUE; xnu=FALSE; break; default: print_error(PURGE_USAGE); } } if(c=='b' && DNA == TRUE) print_error("-b option is not allowed with -n option"); if(xnu==TRUE && DNA == TRUE) print_error("-x option is not allowed with -n option"); if(DNA) A = MkAlpha("NACGT",DNA_MTRX); else A = MkAlpha(AMINO_ACIDS,PROT_BLOSUM62); if(xnu) P = MkXnuSeqSet(DBS_NAME,A); else P = SeqSet(DBS_NAME,A); if (c==' ') { if (DNA) c = 'e'; else c = 'b'; } success = RmHomologs(cutoff_score, c, minimum, query, P); NilAlpha(A); NilSeqSet(P); if(success) return 0; else return 1; } glam2-1064/purge/mlist.c0000644007451300001540000000336110631405554014555 0ustar charlesgenome#include "mlist.h" ml_type MkMList(long M, long N) /****************************************************************** N = number of lists; M = number of elements. sets all N lists to empty and creates the list of free cells. ******************************************************************/ { ml_type L; long i; MEW(L,1,multi_list_type); L->M = M; L->N = N; NEW(L->first,N+2,long); /* all set to zero = empty lists */ MEW(L->item,M+2,long); MEW(L->next,M+2,long); for(L->free=1, i=1; i < M; i++){ L->next[i]=i+1; } L->next[i] = 0; return L; } long Add2MList(register long i, register long n, register ml_type L) /****************************************************************** add item i to the nth list. ******************************************************************/ { register long new,t; if(n > L->N || n <= 0) mlist_error("list number out of range"); if((new = L->free) == 0) mlist_error("out of memory"); L->free = L->next[new]; t = L->first[n]; /* first[n] = t[?:?]-> */ L->item[new] = i; L->next[new] = t; /** new[item:t]-> t[?:?]-> **/ L->first[n] = new; /** first[n] = new[i:t]-> t[?:?]-> */ return 0; } long GetListMList(register long *list, register long n, register ml_type L) /****************************************************************** convert list to contain the nth list in L; returns list length. WARNING: assumes list[ ] is long enough. ******************************************************************/ { register long i,c; for(i=0, c = L->first[n] ; c != 0; c=L->next[c]){ list[i++] = L->item[c]; } return i; } void NilMList(ml_type L) { free(L->first); free(L->item); free(L->next); free(L); } void mlist_error(char *s){ fprintf(stderr,"mlist: %s\n",s); exit(1); } glam2-1064/examples/0000755007451300001540000000000011014153712013742 5ustar charlesgenomeglam2-1064/examples/glam_tfbs.1comp0000644007451300001540000000054710607311611016650 0ustar charlesgenomecomment= This is a simple Dirichlet mixture with just one component, suitable comment= for transcription factor binding sites in DNA. It was obtained by comment= fitting to motifs in the TRANSFAC database, as described in: MC comment= Frith, U Hansen, JL Spouge, Z Weng Nucleic Acids Research 2004 comment= 32:189-200. Mixture= 1 Alpha= 1.6 0.4 0.4 0.4 0.4 glam2-1064/examples/lipocalin.s0000644007451300001540000000172110633675033016114 0ustar charlesgenome>ICYA_MANSE GDIFYPGYCPDVKPVNDFDLSAFAGAWHEIAKLPLENENQGKCTIAEYKYDGKKASVYNSFVSNGVKEYMEGDLEIAPDA KYTKQGKYVMTFKFGQRVVNLVPWVLATDYKNYAINYNCDYHPDKKAHSIHAWILSKSKVLEGNTKEVVDNVLKTFSHLI DASKFISNDFSEAACQYSTTYSLTGPDRH >LACB_BOVIN MKCLLLALALTCGAQALIVTQTMKGLDIQKVAGTWYSLAMAASDISLLDAQSAPLRVYVEELKPTPEGDLEILLQKWENG ECAQKKIIAEKTKIPAVFKIDALNENKVLVLDTDYKKYLLFCMENSAEPEQSLACQCLVRTPEVDDEALEKFDKALKALP MHIRLSFNPTQLEEQCHI >BBP_PIEBR NVYHDGACPEVKPVDNFDWSNYHGKWWEVAKYPNSVEKYGKCGWAEYTPEGKSVKVSNYHVIHGKEYFIEGTAYPVGDSK IGKIYHKLTYGGVTKENVFNVLSTDNKNYIIGYYCKYDEDKKGHQDFVWVLSRSKVLTGEAKTAVENYLIGSPVVDSQKL VYSDFSEAACKVN >RETB_BOVIN ERDCRVSSFRVKENFDKARFAGTWYAMAKKDPEGLFLQDNIVAEFSVDENGHMSATAKGRVRLLNNWDVCADMVGTFTDT EDPAKFKMKYWGVASFLQKGNDDHWIIDTDYETFAVQYSCRLLNLDGTCADSYSFVFARDPSGFSPEVQKIVRQRQEELC LARQYRLIPHNGYCDGKSERNIL >MUP2_MOUSE MKMLLLLCLGLTLVCVHAEEASSTGRNFNVEKINGEWHTIILASDKREKIEDNGNFRLFLEQIHVLEKSLVLKFHTVRDE ECSELSMVADKTEKAGEYSVTYDGFNTFTIPKTDYDNFLMAHLINEKDGETFQLMGLYGREPDLSSDIKERFAKLCEEHG ILRENIIDLSNANRCLQARE glam2-1064/examples/dna.alph0000644007451300001540000000007510607311611015355 0ustar charlesgenome# This is the standard nucleotide alphabet. aA cC gG tTuU N glam2-1064/examples/robinson.alph0000644007451300001540000000056110607311611016444 0ustar charlesgenome# This is the standard protein alphabet. The abundances are taken # from from: AB Robinson & LR Robinson Proc Natl Acad Sci 1991 # 88:8880-4, which is cited in publications on NCBI BLAST. Aa 35155 Cc 8669 Dd 24161 Ee 28354 Ff 17367 Gg 33229 Hh 9906 Ii 23161 Kk 25872 Ll 40625 Mm 10101 Nn 20212 Pp 23435 Qq 19208 Rr 23105 Ss 32070 Tt 26311 Vv 29012 Ww 5990 Yy 14488 x glam2-1064/examples/crp0.s0000644007451300001540000000407210633675033015010 0ustar charlesgenome>ce1cg 17 61 TAATGTTTGTGCTGGTTTTTGTGGCATCGGGCGAGAATAGCGCGTGGTGTGAAAGACTGTTTTTTTGATCGTTTTCACAA AAATGGAAGTCCACAGTCTTGACAG >ara 17 55 GACAAAAACGCGTAACAAAAGTGTCTATAATCACGGCAGAAAAGTCCACATTGATTATTTGCACGGCGTCACACTTTGCT ATGCCATAGCATTTTTATCCATAAG >bglr1 76 ACAAATCCCAATAACTTAATTATTGGGATTTGTTATATATAACTTTATAAATTCCTAAAATTACACAAAGTTAATAACTG TGAGCATGGTCATATTTTTATCAAT >crp 63 CACAAAGCGAAAGCTATGCTAAAACAGTCAGGATGCTACAGTAATACATTGATGTACTGCATGTATGCAAAGGACGTCAC ATTACCGTGCAGTACAGTTGATAGC >cya 50 ACGGTGCTACACTTGTATGTAGCGCATCTTTCTTTACGGTCAATCAGCAAGGTGTTAAATTGATCACGTTTTAGACCATT TTTTCGTCGTGAAACTAAAAAAACC >deop2 7 60 AGTGAATTATTTGAACCAGATCGCATTACAGTGATGCAAACTTGTAAGTAGATTTCCTTAATTGTGATGTGTATCGAAGT GTGTTGCGGAGTAGATGTTAGAATA >gale 42 GCGCATAAAAAACGGCTAAATTCTTGTGTAAACGATTCCACTAATTTATTCCATGTCACACTTTTCGCATCTTTGTTATG CTATGGTTATTTCATACCATAAGCC >ilv 39 GCTCCGGCGGGGTTTTTTGTTATCTGCAATTCAGTACAAAACGTGATCAACCCCTCAATTTTCCCTTTGCTGAAAAATTT TCCATTGTCTCCCCTGTAAAGCTGT >lac 9 80 AACGCAATTAATGTGAGTTAGCTCACTCATTAGGCACCCCAGGCTTTACACTTTATGCTTCCGGCTCGTATGTTGTGTGG AATTGTGAGCGGATAACAATTTCAC >male 14 ACATTACCGCCAATTCTGTAACAGAGATCACACAAAGCGACGGTGGGGCGTAGGGGCAAGGAGGATGGAAAGAGGTTGCC GTATAAAGAAACTAGAGTCCGTTTA >malk 29 61 GGAGGAGGCGGGAGGATGAGAACACGGCTTCTGTGAACTAAACCGAGGTCATGTAAGGAATTTCGTGATGTTGCTTGCAA AAATCGTGGCGATTTTATGTGCGCA >malt 41 GATCAGCGTCGTTTTAGGTGAGTTGTTAATAAAGATTTGGAATTGTGACACAGTGCAAATTCAGACACATAAAAAAACGT CATCGCTTGCATTAGAAAGGTTTCT >ompa 48 GCTGACAAAAAAGATTAAACATACCTTATACAAGACTTTTTTTTCATATGCCTGACGGAGTTCACACTTGTAAGTTTTCA ACTACGTTGTAGACTTTACATCGCC >tnaa 71 TTTTTTAAACATTAAAATTCTTACGTAATTTATAATCTTTAAAAAAAGCATTTAATATTGCTCCCCGAACGATTGTGATT CGATTCACATTTAAACAATTTCAGA >uxu1 17 CCCATGAGAGTGAAATTGTTGTGATGTGGTTAACCCAATTAGAATTCGGGATTGACATGTCTTACCAAAAGGTAGAACTT ATACGCCATCTCATCCGATGCAAGC >pbr322 53 CTGGCTTAACTATGCGGCATCAGAGCAGATTGTACTGAGAGTGCACCATATGCGGTGTGAAATACCGCACAGATGCGTAA GGAGAAAATACCGCATCAGGCGCTC >trn9cat 1 84 CTGTGACGGAAGATCACTTCGCAGAATAAATAAATCCTGGTGTCCCTGTTGATACCGGGAAGCCCTGGGCCAACTTTTGG CGAAAATGAGACGTTGATCGGCACG >tdc 78 GATTTTTATACTTTAACTTGTTGATATTTAAAGGTATTTAATTGTAATAACGATACTCTGGAAAGTATTGAAAGTTAATT TGTGAGTGGTCGCACATATCCTGTT glam2-1064/examples/recode3.20comp0000644007451300001540000001416110607311611016314 0ustar charlesgenomeClassName = DirichletReg Name = recode3.20comp Alphabet = ExtAA Order = A C D E F G H I K L M N P Q R S T V W Y AlphaChar= 20 NumDistr= 20 Number= 0 Mixture= 0.176513 Alpha= 10.1329 0.668781 0.072626 1.08101 0.930936 0.1235 0.982387 0.366701 0.0586812 0.849019 0.185073 0.0648062 0.979541 0.519704 0.555784 0.636552 1.04987 0.60931 0.129148 0.0676805 0.201772 Comment= N , D S Q H K E G R T P >< A Y , W C F M , L V , I Number= 1 Mixture= 0.207622 Alpha= 11.6836 0.880009 0.197393 0.303744 0.497357 0.657492 0.391988 0.348159 0.936094 0.527206 1.42844 0.449302 0.368825 0.384576 0.439775 0.581516 0.622624 0.747064 1.08007 0.235012 0.606928 Comment= M Y L F I W V H T Q >< R A C S K N P E , G D Number= 2 Mixture= 0.0669246 Alpha= 5.22319 0.153384 0.0520756 0.0073824 0.0158439 0.428964 0.025533 0.0185789 0.845361 0.0282996 2.42256 0.424296 0.0190716 0.0313429 0.0274578 0.0252186 0.028514 0.0519217 0.522946 0.0279653 0.0664755 Comment= L , M I , F V >< C , A Y W , T H Q P , R K S N G , E , D Number= 3 Mixture= 0.0868259 Alpha= 9.82176 0.794007 0.0130659 0.624236 1.85769 0.0290214 0.115707 0.123504 0.22099 1.52605 0.341371 0.111114 0.308302 0.263545 0.953727 0.933444 0.554741 0.604551 0.396451 0.00823516 0.0420054 Comment= E K Q , R T D A >< S N P V H M , L I , G , Y C F , W Number= 4 Mixture= 0.0593123 Alpha= 5.54386 0.740015 0.187165 0.0213261 0.0456854 0.118944 0.0633687 0.0170331 1.06684 0.0380614 0.733524 0.138456 0.0300644 0.0718692 0.0240143 0.0301022 0.0862989 0.367283 1.70735 0.0113856 0.045079 Comment= V , I , C A L T M >< F , P S , Y G W E H , N K Q R D Number= 5 Mixture= 0.0358616 Alpha= 4.66847 0.15978 0.0261585 0.0505181 0.125524 0.0350331 0.102549 0.157461 0.0795041 1.26261 0.189383 0.0550608 0.171028 0.0844169 0.290476 1.44604 0.129158 0.138972 0.0851144 0.0159134 0.0637679 Comment= R K ,, Q H >< N T M , S L A E P Y C G I V , W D F Number= 6 Mixture= 0.03427 Alpha= 5.9237 0.308434 0.0137217 1.69731 1.92422 0.0361113 0.162357 0.07232 0.0487895 0.236135 0.0809074 0.0286236 0.213663 0.181631 0.320245 0.104878 0.218398 0.141668 0.0747719 0.0141705 0.0453433 Comment= E D ,, Q >< N K A P S , H T G R , M Y V W L F I C Number= 7 Mixture= 0.0428319 Alpha= 0.0441636 0.00260287 9.99856e-06 0.00631292 0.00445502 0.00274753 1.03886e-05 1.02839e-05 0.000913052 0.0029241 0.00353485 0.00105128 0.00338172 1.04172e-05 0.00173574 0.00459583 0.00274255 0.00247625 0.00175366 1.02411e-05 0.00288489 Comment= D R , Y N E F K M Q T S >< L A V , I ,,,,, W C H , P , G Number= 8 Mixture= 0.047875 Alpha= 3.87573 1.61043 0.15522 0.0378292 0.0498243 0.0406484 0.529136 0.0217524 0.040597 0.0413396 0.100193 0.0509779 0.0357917 0.0931204 0.0367156 0.0330646 0.529587 0.196607 0.230878 0.00909518 0.0329275 Comment= A , S C , G >< T V M P , L Q F , Y H N E K I R D W Number= 9 Mixture= 0.0466614 Alpha= 4.02936 0.15525 0.0136827 0.0857138 0.0508316 0.0151451 3.10555 0.027169 0.0140491 0.0654038 0.0257501 0.00901049 0.127437 0.0423873 0.0345064 0.0477247 0.12452 0.0341196 0.0230637 0.00930115 0.0187464 Comment= G ,,,>< N S A , D K H , R Q P E C T W Y , M F V L , I Number= 10 Mixture= 0.0283695 Alpha= 4.37516 0.225739 0.0684326 0.101072 0.0813791 0.0298832 0.0915218 0.0336807 0.0833114 0.0931673 0.0731542 0.0419314 0.230216 0.087446 0.0694702 0.0751969 1.13857 1.63158 0.179083 0.00912576 0.0311963 Comment= T S ,, N >< C A V , M Q P D K R I H E G , Y L F W Number= 11 Mixture= 0.0301127 Alpha= 5.10487 1.3431e-06 0.0166656 0.00743068 1.34592e-06 0.169076 0.00407061 0.00714122 1.98221 0.017522 0.816669 0.114773 0.00678027 0.0106392 0.0100244 0.0158968 0.00879658 0.0399043 1.81043 0.0150671 0.0517801 Comment= I V ,, L M >< F , Y , W C T ,, R K H Q P , N S D , G ,,,,,,,,,,, E , A Number= 12 Mixture= 0.0233828 Alpha= 3.08488 0.063525 0.0288391 1.09265 0.0959581 0.00965196 0.216914 0.0730986 0.0207325 0.08719 0.0315107 0.00960293 0.752755 0.059914 0.0445321 0.0312317 0.287327 0.116896 0.0249446 0.00701663 0.0305859 Comment= D N ,, S >< H G T C , K E P Q Y A , R W M , V L I F Number= 13 Mixture= 0.034662 Alpha= 5.72698 0.294281 0.019271 0.12293 0.162747 0.0373667 0.145029 0.0412349 0.0815261 0.157594 0.151631 0.021412 0.0601581 3.6966 0.0809085 0.101856 0.23533 0.135424 0.140532 0.00900473 0.0321389 Comment= P ,,,>< S A , K E T Q D R V G H L , N I C M Y F , W Number= 14 Mixture= 0.0270202 Alpha= 3.67648 0.0844832 0.0584945 0.0411628 0.045719 0.847822 0.0590839 0.250253 0.0675757 0.0562614 0.168617 0.0439737 0.0794234 0.028301 0.0305672 0.0598024 0.0798202 0.0585385 0.0858243 0.227395 1.30336 Comment= Y , F W , H ,>< C M L , N S V R I A T K , Q G E D P Number= 15 Mixture= 0.0226822 Alpha= 3.08684 0.0634034 0.0246167 1.3443e-06 0.00389272 1.12953 0.00796028 1.35032e-06 0.233395 1.34466e-06 0.541933 0.101309 1.36412e-06 0.027467 0.00704479 0.00802297 0.0248977 0.0276933 0.185467 0.183309 0.516892 Comment= F , Y , W , L M I >< V , C A , P T S ,, Q R G , E ,,,,,,,,,, H , N K , D Number= 16 Mixture= 0.00898452 Alpha= 2.51284 0.123696 0.0454619 0.0386434 0.351847 0.0560181 0.0439442 0.223229 0.01302 0.148699 0.19001 0.120964 0.098734 5.90055e-06 0.554971 0.219233 0.0453885 0.0564686 0.0614792 0.0410248 0.0800036 Comment= Q , H E M , R W K >< C N Y L A F , T V S D , G , I ,,,,,,,,,,, P Number= 17 Mixture= 0.00716226 Alpha= 3.39257 0.0212037 3.18769 0.00745627 0.00382411 0.00691924 0.0126233 1.34375e-06 0.00724293 0.00522979 0.00785563 0.00489521 0.0105326 0.0136265 0.00505819 0.00677712 0.0251744 0.0235516 0.0371462 0.00187667 0.0038893 Comment= C ,,,,,><,, V T , S P A N M , G F Q R D W I Y , K L E ,,,,,,,,,, H Number= 18 Mixture= 0.00710292 Alpha= 2.51689 0.0229376 0.00427768 0.00959934 0.013608 0.182277 0.0227654 0.0157344 0.0226783 0.011561 0.0803491 0.0154283 0.00899225 0.00980608 0.00600945 0.0342359 0.0216842 0.0189306 0.0223176 1.83914 0.154565 Comment= W ,,,,, F Y ><, L M R H , I S T , V G A C E P N K D Q Number= 19 Mixture= 0.00582299 Alpha= 1.35874 2.16602e-06 2.16245e-06 0.0198496 2.17942e-06 0.0246741 2.47051e-06 1.02563 0.0131152 2.16539e-06 0.00637704 2.1414e-06 0.0839371 0.0168135 0.0438887 0.0252951 0.0235533 0.0130626 0.00797507 2.16433e-06 0.0545531 Comment= H ,,,, N Y >< Q , F R S P D , T I , V , L ,,,,,,,,, W C M ,, K E G A EndClassName = DirichletReg glam2-1064/doc/0000755007451300001540000000000011014153712012671 5ustar charlesgenomeglam2-1064/doc/glam2_ref.html0000644007451300001540000001301510663267423015433 0ustar charlesgenome glam2 Reference

glam2 Reference

Usage

glam2 [options] alphabet my_seqs.fa

An alphabet other than p or n is interpreted as the name of an alphabet file.

Options that determine which alignments are possible

-2
Search both strands.
-z
Specify the minimum number sequences that must participate in the alignment. If greater than the number of input sequences, then all the sequences must participate.
-a
Specify the minimum number of key positions (aligned columns) in the alignment.
-b
Specify the maximum number of key positions (aligned columns) in the alignment.

Options that affect the scoring scheme

These options specify parameters in the formula for calculating alignment scores. See GLAM2 methods (PDF) for details.

-d
Specify a Dirichlet mixture file, which describes residues' tendencies to align with one another.
-D
Specify the deletion pseudocount.
-E
Specify the 'no-deletion' pseudocount.
-I
Specify the insertion pseudocount.
-J
Specify the 'no-insertion' pseudocount.
-q
Specify the weight for generic versus sequence-set-specific residue abundances. The residue abundances are estimated by counting the residue types in all the input sequences, and adding pseudocounts. The total number of pseudocounts is equal to the alphabet size mutiplied by the -q parameter. The allocation of pseudocounts among the residue types depends on the alphabet.

Options that affect the search algorithm

glam2 uses a simulated annealing algorithm, with a temperature parameter. At high temperatures, glam2 only slightly favours changes that increase the alignment's score, and at low temperatures it strongly favours such changes. Thus, at high temperatures the score will be optimized too slowly, but at low temperatures the algorithm will get frozen in a local optimum. The strategy, then, is to start with a high temperature and reduce it as slowly as possible.

-r
Specify the number of alignment runs.
-n
Specify how many iterations should pass since the highest-scoring alignment seen so far before ending each alignment run.
-w
Specify the initial number of key positions (aligned columns) in the alignment. If less than the minimum (-a) or greater than the maximum (-b), it is increased to the minimum or reduced to the maximum.
-t
Specify the initial temperature.
-c
Specify the cooling factor per n iterations. The temperature is multiplied by a constant factor after each iteration, such that after n iterations, it has dropped by this amount. 'n' is the number specified with the -n option.
-u
Specify the minimum temperature. The temperature never drops below this level, to avoid numerical problems.
-m
Specify the rate of column sampling relative to site sampling. On each iteration, glam2 randomly decides to try either realigning a sequence or adjusting an aligned column (key position). This parameter sets the probabilities for this decision.
-x
Specify the site sampling algorithm: 0=FAST, 1=SLOW, 2=FFT. See GLAM2 methods (PDF) for details. In summary, the FAST algorithm deviates slightly from the strict definition of simulated annealing, but works well in practice. The SLOW algorithm implements strict simulated annealing, but is much slower, especially for longer sequences. The FFT algorithm also implements strict simulated annealing, and has intermediate speed, but carries greater risk of numerical roundoff error. In order to use the FFT algorithm, it is necessary to install the FFTW library, and re-compile glam2 with 'make glam2fft'.
-s
Specify the seed for pseudo-random number generation. Change this to avoid getting identical results each time the program is run.

Cosmetic options

-h
Show all options and their default settings.
-o
Specify an output file name.
-p
Print information about the algorithm's state before each iteration. The following information is printed: the temperature, the number of key positions in the alignment, the number of sequences in the alignment, and the alignment's score. In addition, some information about each move is printed: for site sampling moves, which sequence is picked, and for column sampling moves, which column is picked, whether or not it is deleted, and whether the direction is left or right.

Warnings

glam2 might occasionally issue this warning: 'accuracy loss due to numeric underflow'. If this happens, its ability to optimise the alignment may be harmed: see GLAM2 methods (PDF) for details. To fix this, try increasing -u, or possibly decreasing -b. Increasing -u somewhat should be harmless, as long as it stays well below 1.

glam2-1064/doc/index.html0000644007451300001540000000717110745003547014706 0ustar charlesgenome GLAM2 Manual

GLAM2 Manual

Summary: GLAM2 is a software package for finding motifs in sequences, typically amino-acid or nucleotide sequences. A motif is a re-occurring sequence pattern: typical examples are the TATA box and the CAAX prenylation motif. The main innovation of GLAM2 is that it allows insertions and deletions in motifs.

Family: GLAM2 is a child of GLAM and a sibling of A-GLAM. If you are looking for nucleotide motifs without insertions or deletions, A-GLAM is probably better. 'GLAM' used to stand for Gapless Local Alignment of Multiple sequences, but it now stands for Gapped Local Alignment of Motifs.

Inventory: The package includes these programs:

  • glam2 - for discovering motifs shared by a set of sequences.
  • glam2scan - for finding matches, in a sequence database, to a motif discovered by glam2.
  • glam2format - for converting glam2 motifs to standard alignment formats.
  • glam2mask - for masking glam2 motifs out of sequences, so that weaker motifs can be found.
  • purge - for removing highly similar members of a set of sequences.

These are command line programs, so you need a basic familiarity with running things from your computer's command line in order to use them. (In Mac OS X, you want Applications -> Utilities -> Terminal.)

About: GLAM2 was developed by Martin C Frith, working at the Computational Biology Research Center in Tokyo, and Timothy L Bailey, working at the Institute for Molecular Bioscience in Brisbane. The source code and documentation are hereby released into the public domain. If you use GLAM2, please cite: MC Frith, NFW Saunders, B Kobe, TL Bailey (2008) Discovering sequence motifs with arbitrary insertions and deletions, PLoS Computational Biology (in press).

Contact: Questions and comments are welcome. Email: glam2(at-mark)imb.uq.edu.au. We would especially like to hear about any errors when installing or running the software (e.g. segmentation faults, assertion failures) so that we can fix them. Please send the exact text of the error message, and the exact inputs that produce the error.

Contents

glam2-1064/doc/install.html0000644007451300001540000000477411014153035015237 0ustar charlesgenome GLAM2 Installation

GLAM2 Installation

Requirements

The only requirement is a C compiler. If you have some kind of Unix or Linux system, you almost certainly have one already. If you have Mac OS X, you may need to install a developer toolkit, which should come for free with Mac OS X. If you have Windows, you can get a C compiler from various places, such as MinGW or Cygwin.

Usual procedure

This procedure should be suitable in most cases.

  1. You presumably obtained GLAM2 as a zipped package, called something like glam2-9999.zip. The first step is to unzip it, creating a new directory glam2-9999.
  2. Using the command line, move into the src subdirectory and type 'make'. This should compile the glam2 programs.
  3. To compile purge, move into the purge subdirectory and type 'make'.
  4. After successful compilation, the programs are ready to use. Run them just by typing their names (possibly with leading ./ depending on the settings for your command line environment). If you like, you can put the programs in standard 'bin' directories, or add their location to your system's PATH.

Alternatives

There is a Debian package.

The Makefile in the src subdirectory holds the commands for compiling the glam2 programs. (Likewise for the purge subdirectory.) The commands are customized for the widely-used gcc compiler. To use a different compiler, you may have to modify the Makefile. The Makefile is very simple and commented, so this should be doable even if you know nothing about makefiles. However, you will obviously need to know what commands are suitable for your compiler. Use compiler options that make the resulting programs as fast as possible.

The programs can also be compiled directly, without 'make'. For instance, to compile glam2mask, move into the src subdirectory and type:

cc -Wall -O3 -o glam2mask glam2mask.c alignment.c fasta.c util.c -lm

Modify as appropriate for your compiler. Look in the Makefile for commands to compile the other programs.

glam2-1064/doc/purge.html0000644007451300001540000000520210714470436014713 0ustar charlesgenome Purge Manual

Purge Manual

Purge removes redundant sequences from a FASTA file. This is recommended in order to prevent highly similar sequences distorting the search for motifs. Purge was written by Andy Neuwald and is described in more detail in Neuwald et al., "Gibbs motif sampling: detection of bacterial outer membrane protein repeats", Protein Science, 4:1618--1632, 1995.

Purge works with either DNA or protein sequences and creates an output file such that no two sequences have a (gapless) local alignment score greater than a threshold specified by the user. The alignment score is based on the BLOSUM62 matrix for proteins, and on a +5/-1 scoring scheme for DNA. Purge can also be used to mask tandem repeats. It uses the XNU program for this purpose.

Using Purge

  • For typical-length protein sequences, a reasonable purge threshold is around 150. To purge a file of sequences named "examples/lipocalin.s", do the following command. The purged sequences will be put in file "examples/lipocalin.s.b150". You should experiment with different purge thresholds depending on your particular needs. Depending on the application values between 60 and 250 may be appropriate.
      purge examples/lipocalin.s 150
    
  • For DNA sequences of about 100 bp, a reasonable purge threshold is about 175. As the sequences become longer, higher thresholds will be required to avoid removing too many sequences. To purge a file of sequences named "examples/crp0.s", do the following command. The purged sequences will be put in file "examples/crp0.s.b175".
      purge examples/crp0.s 175
    

Purge Usage Message

  • If you type "purge" at the command line, you will receive the following usage message.
usage: purge file score 
  options:
     [-n]    - sequences are DNA (default: protein)
     [-b]    - use blast heuristic method (default for protein)
     [-e]    - use an exhaustive method (default for DNA)
     [-q]    - keep first sequence in the set
     [-x]    - use xnu to mask protein tandem repeats

  Purge creates an output file from the input file such that
  no two sequences have local alignment score greater than .
  The output file is named ..
  Substitution matrices: BLOSUM62 (protein), +5/-1 (DNA).
glam2-1064/doc/GLAM2_method.pdf0000644007451300001540000043302610722500244015537 0ustar charlesgenome%PDF-1.4 %Çì¢ 5 0 obj <> stream xœµ[Û’Å}߯˜àÅ=ŽvÝ/~ÃØÆv€±ÍFaă4Óh0ìh…vè§ô‹Î¬Kwfu÷Þ¡ 訩KfVÖÉ“Yµ¯7¢—ÿÊÿ÷×øß¼|s!6ŸÂ//^_ÈÔaSþ·¿Þüé :…ô½’Ön®¾½ÈƒåFÓ;ë6ÎÙ^G½¹º¾øºût ³K%´é>ÛîàÛ„(l÷14‹èƒU²û\mwZ¨^Ý}>`絑Ý-~Æm쎤û«íN¹^é»i~“z{©Ô7WÿAb)ûh­D•êµuj³S¡!†ÍÕ„û/st‹Ÿ~ü,6VizmÀ°`ãÑE0›Q}”Jf¾HJƒ¦ÚƒZöÎH•d”Úň"¬^¡1ßâgÛd6”ÕÎÐÎ?¥æ`¢rE³‰}tÊ™´Ï²‡á›«Ï.®~ÿuw’&úî8€ž,ød2½v^§ÔN—œΣOb³‚ý¡Ð=®>†a7¼7„¹µö&vߦÖ0v 6Ƀ ø®œ\«ôL~{"ZR½†ö@µa¼wºž¤“…÷2Ÿ £Âs€mÁéîýé0i7vUI>v ÒuN/§ï,†T62rœ9k!¥`"YøøœŽ)jª;Qø†Ê3œÐÆBÄ8‰æèÚ§b¯ÁĹƒ—ÌC–IªÑ1ðÿa{¼ÓÑôÔ¸™Û ì`‹zésh„ˆ¤Óý˜§C²ÝyÿÃ4lX·k²Ðw7ÚÞEÅ5zÞ'\á<œöÌbývçàú »¿'-¬D¬¾l¬J6i?JpaDL«anóÆt{2ꔕôAÒ¹Nä›èûKÛã»wC®}Ÿj¸¬–l‹ÇMú½Å/P!tCµ2lÚóqŸ‹Á•qdͺùVÕ½?³•é–ïè/7 v4|7ìÉ®¿ðHÛ-k|SŽXÁeRªz$4âfI@R“ d K²a}KOá4ìø*‰dœ”!"©öpÁ páÀÜcOÕ$Šx=»ª…!lhñ ðtä©kÉágƒª6Î.cÙ·—Ó'“úÛK°SìÞ§¹u„P!æKc™Ïôè{96Ž0 uu…ŸHáÈ¥,„3ðáçäI^xµ|lØ¢iX0 &ßäV~Dw•¦´¶®k#nLÂè™fvÔá§VóìÙ4þQíJD`XM=/Ñ­  á‡rOCÇaf]`Li¨sxºŠ-³'/Û’;ê‡2J±Dò€à k^G<ê£éór‹þz¤HdD±ç:ìj]ì÷~çëÓvè€È#Ûˆïz/Ô æÐN"×ʱ¿:¯qæÐK0uEFb—ñÀÛ>ÝP Ç¾q•çKÆÞo+¶ó0tÜF%Ûûfßnè1êÀІlh5áQ®?†¿DAÀÀ€]¤µ‰áÐ2ŽûÅýnVLY÷¡ßÎC%­DÎf:Üó ´Ð,8ì ¥Á³¨X³µ1Î!9`6PR¡pZ ¼ ðc8„cÃë\]!GÉ3W´«AÆû ™ã%›§€Ò„±4±Ó­š(º#d Rþ;8Àºï'vsš¨ úXš¦'Ä5_¼([`»/ ¢ ßí(|kãŽú ù J ËÇþzýŒÞ-çyI“Ž$°¨aŠ`ByùòH ­Žþ3)Fƒ àünø7Ó%§‘÷×è?.ã÷3FdËž#aé/ñÏYÑX”pjJxR¼L¿ÃÑÙ¯Åöt¬"ÉZç×;_d¶n>R2ºß—ãÅ‚ŽZPb&nFöõv–ðÏ.™[ &Yûb)Æ¢Vf–Æ)#ž•Œ¾OT[Aò5üR{¤±ˆ¼’†ÍJ|óª2#µ&Ä*$ó±½Â©é™î0<¯yÖ¬¢–²%R©9Î"Q• r}×Ä~œk_Ì’2$G4^»j)åÝvIÂ=À.R{wŸ¯j_BÊUÙ-]¤`LmtÎøì{íè Qsƒ^)Xe -ð"–kÒ¡•Q˜Ñ‚…I:Ãbdw8ô»£àô–öÅ=¾Âi!Mý]ƒóht7ϧ=ñ Uš²"íÅx.3Ø8að†%';¥c²Áæ”!ñSNr‚—¾ gÀ$U¶7€)ž=®– ¿ÑtŸKRárò€YÓn)¾¬qQj÷?Æ` tåY·àODOjØW%k“ü^‹^¨i˜nCöÁnê8½ý®~pðl[Û/'(+i®Tæ|‡V¿ oÑ™¸ Ð_í(œ› ÆŠº)#:¤JŽˆébXÂ¥LjaiºB¦,dÝûýù†Ø,ívÌOCÇÎh-´Ú¦ˆ–{ÊVaZãÌon.suK¡Ív£Bvæüø@óÖûrþ\i9 áÓhK c–8œòòH[˜9Ú{JRÀûÐqgô¼øíU–™«á}„Ô0Ëñ%Ý‚¹m˜yJ0€ ê¡Pð²~.¨˜ª°Œ•žY» ç³¹Òq¨ Ê¥ýsv¶¨¥i½e‚|{æÍ³¤w¶Yw…«ÖA+>uXÒ>ݪgíã¢òe§©ò¡U~ýD/˜cÊG’9œHlXöœäqÀòy"Äz–eš¨*Yœ½niãì¹NèÌ#ëý`T»_ùü'Qq%â̸õ¬^³úòxT$©§Óߪ‘7~*Í‘ßø‘W{)gòy5þažê½åohkB¤åS ûYÙ>BÝùÈ=¯N@8â쾦¹o3ÞôŠ›¡ÎçgS>ÀÛ|þWF7÷¿=Ãq.=Õeï‡<¾—<´¯Tÿ ÊQ¤À¢áâS™"¦wݽ¡ŽaÈ›,““m…Æè› …´D\*2µî<¸äÇ…lb§©”±mÛßÖ›.5B¼Œ3 Ë+'ÊóÅb×n¿Ljn(Kš“7ÆÃ¦«§¦Ì†oÕðOŒÆÿ—¿Ú”ãzØç/Wÿ†ÿ7 endstream endobj 6 0 obj 3969 endobj 21 0 obj <> stream xœ½\ËŽÉuÝó+Þ(Û˜JÇûa@ °e,[ ‚Æ vU‘mkXC‰lj¨¿ñÌJðÚðùÜY72#‹ÕdS “ÌŠÇû8÷ÉßߨQß(ú3ýÿæÅßü{¼yýî…ºùþ{ýâ÷/4¸™þ·só÷w¤Ív£uÁÜܽzQfëmíC¼‰*ŽÆº›»7/~;üêËgŒößßîÔhLR6À{ñ?ü'U2Þ7œÎÃ_ßîlô£ ¹YäÖêÑú‡~éU´Ã‘mÐÎoh]¢OÓÛ˜œû»™¨Öcö^ÕÆŽI;<þüÅÝ_ÿvøWžç•ÃÞ"åˆ@°Æ²a¢Wåð;Ca¡J{T!ÈѤÑÚ9S·v7yÌÁÇ KXŒš¶þg^Ï)í=οsÎŽÞ¥á{¬á¬Ž˜…Na“8Ž(crHÃ{ ã•¡?žŽu™xòP_z3|ûíyñw´¸µÖÄp<í¨S6!xyz}žuœ¦áðu¿ÿ«BH†¨H\#ÅYæ-ˆuÎi­ôðŠ&ùQû<|;t~ùÑåÇñvc„ ÄáåyÕïÎ#ÄVg2 ôÝx,Vý„ÔeàöÅøáP^öPD¬°ŸµªƒO•]kg/ñë]áQÊkt®šD¿+7Šw¾eÖñÔò‚‘É*¨½«Ètß(]žiÄ®øÀ2îKôë¹Ø¸ ­ˆé& b<õ"–ã¡ È9Á–6- uøG>'B½Ôè©Ý‚þÇÛˆ7Ž5Ï#Òs‹(ŽˆLîKügå„$åA,"‡O§ÖÚË_òÒŽèùÈHQ(ކ®ÄÓ¢I<-´®÷m Šû{OÞ¹‘ô~-”òJ`¦™1ûu½@äb%h\Ö…#ûjuÄq*©BËÂ,‰*"« î u?,‘Œ]”uí6b¦w/;ELˆ\OEÌä@‹"&¬˜<ß2‚ã=ì"±ßo¤ÚÕUè †~¹¦òPN‰Ìêáe£ŒDÐÕ£T™9Ez˜´Rs^M\оEª¶6³öh«¢Ã J®-;¬JA[eº×÷ݾMSžÛ6¿(Ù¶r¶@ ¡|9+ÎlSÛ¡yUZJ¤xíÄ%sÖ&sSÉQ¹èÜÎùŽ×Ð!y¿Ùω3M ­7ÑŒI…/©[˜EÂßr”ÞRËäú>ˇ[𤋮Ÿ†—œyF*:-ìˆNàs(”Fcº"¿{ÛV³ˆØ¨74¡GÍSŠVM”ÃgÐÀæ†/œn˜9°ÂÐì=: ç|Jk.|C&¸©$J œ’Á-RѶÆ•Ii¬¼À ›—}™ßLeüº_SM“‹¾e.ålR[ÈýqŒ šhBÂ~o,ð©ø4Ìx+]¹àὬ|ö‹Ûh¯Ï]àVÀ³€»ƒbœÄ‹QÏ?9@*óìWá[u—Ky‘é‚ €‰qOU½RÇÕ€dÓ‰g;JX·½¤kµNœpúy²ði9ïþR:Z[b:6%Ž9Ój‚šoJßÅ›\ý}ñµ¿gúõ¢´‰ ø—Ÿ×ʲ𞢠ñ®P”¹²IQ"™v_/,ñm?¥RôÛ ¡¤†çÝW囆7xQÆËîhM [/AF ŽâŸ ½ÃŸoïþ C¾…1G h¦!ñrÈ qtÙ!ИÊ8íû¢>m´¾i¦yűÖÍ!ø‘´•“EÙ¤uÊÒÜÚû ¼…Jí5“ÞÉBWµ $±ª^1^òZm(È£91Ç2å=qYehPöƒ3<™ÔÈ(µ‚œ›®¬"ƒà¼¹éÂ19Â¥s&Õø2èQÜ[Ñ3ߦ£EI…R®‚åð?EZVi5Fïâ&«šõ)4æb=w¾pÎzzœCˆòÌg%Šmæ¼®I,wµˆM»+âí~-}u\§» ¢^öŸY“²[¾éOµT¢Ôˆµ6¿4ꞇF‡§åýº‚Æ«¿•iÑ”Òú>sNsQÙœ‡ª²›Iz»{Çç9[^é°/Ü Otn•¶ÒIz»òh/uëÞâÖË^Æ3ÛAðÔ’vuNäèrL%ȬL»¿k=O»T6’sŸ=Këq¦˜ÓÒ ²LŸ'’.AªÈÎvõ]ËHͨ…h6 nSŒQž¯ð?I¤¬mqgi}¬¶a²ùá'Xhl.ž±QuM"¿i{EËÚ-¦·Þã::nÞꉯ[ëŽâ¹ŽãpBÑZi Pz¾,ãÌ],mFeåMNšÚã½Q”ÌÌØÎÕ§ôejêžcÏI-õ´´:¹Í8_fت›ŒD6èþž>sõŠ|ž®ê@EÃca– ԇ纅÷ÑKªø[âž}uŸÓ€PJ-&V好bƒhŸ9y{WvÓ¾éQŠÅzâÓÔAŒSL9ü_/F t>åe|1wl̃W`Ç"¹6V ¯̤Ã÷|;°eví•Ö–¢5‡Y¿Î·<ÇÒÛ"YÊlä8 Û.ïp–÷tÇoWà[<À«æjâQÀ®ì/u‰sÒº/‚‹Ð¢Ã§ÊˆÝjɦ¨²]ôIîߟ1w¥:¥ R:É*æíº t™:<Åš.51ꎶéÉʆjsgÇú…^fùÜ»ÂDܯœÝö]2 ¨†©5O8Õ˜plâ"oÛyõ­[ц°>Ç%~Cc/ˆ»XOlW ð" j'³Æc=À&Í&Ån§}?ÎmàOz¡-¨Ùˆ]¹AçÅ­ŠÈüR¡UQL57ëÇôfmQ( V¥‘Ï ªÜ†×ÒFà:ww!Ýp˜ï:?Þ¿/¯½Ùt£L#°g£Òºl»Ñ¡É\×*R‘&¦.”k?_˜jî9±CÅâ/½Õ¬!‹ûÌÙØ¤²+s¨ìh²–ór NU3×,z©“(ô†ÆŸŽ?6×­­C^êšþÇ1æK•q’rhjê§òzÙ½šÞZÝJIV·tàx‚g6}ˆJ÷–øùGs‚Ãá(H-»î>S|‘æÞlûCa$™y‡6·Á,—à4Õ]>uÕp•üÂD£NŸ¬óØRæ±7D™.´››sÛÜf„PçÓº€µìõs⨳áN7Poá  að}"—ùÂz)ÛaN‹4¶‹½8xu9Ë1ªýüá⚈NCºQ‘ÝF;K®ÐŠØ?éjOóÑ‹·+ gú+5YV̓¶/»ÓÚ¬ì"ûý§Ûùà㩸[r¦­ÙßrîÙ ò#6hï‹¿ŸÞ—šp³Ö-z¢‹ytDˆM­”‹¶gM‰.±kÝÖœJ^z8V‰”æTnÙ_EGqOû²&9ßñÔ d¥Fì—m2}ýÅ-/0ÑmWŠ.ŠAé”û¾ÆË÷_|S‘w*+¬_Þþ‚ pEwžîY/ R#ôË.‚ecµÛEŠñ!5‘ô©LŒ‘{Áü-œ5ÃÛ®›é6¤Ûþ½Ä"sq§rþ¬°äYïëŽîzÍ× œÏ©ê2ßb°9¤nÅÊJ¥žâ_§—Ä1Š–uF.\§VÛ›&²Í0}c˜—À01~YíåÅ›–b3Bˆ¤Ç ÎCcZ[ÔRH*Aþm0›œÁO7Šë^½ÀrêWëS:Wë72z<¦ÜˆÒ©¬b_”ˆ–¢\g¢"Ý] >ݧe"9OýÛôWÄâ9jßø€ê‡ÛpÇÙ)¼r@1:Þt¸Ý¥x‡nôQh´k&]]=’†YxŸæu?~ÝÖg·*ŸL;Ú¶m•€Æº=#ëX°J»þ·àÎŒ¦BÖl}~lößFÅ1›¤ËÔ廨jž¿øŒ¥á’ßÊë$—Lwô)]<<¡kѸ¾R‚l“½TíB'×kT'~„æ»ÐµûnoÑ9Ü÷Ãôº¤OÃV-}5ý%þŸº'´]}!Ó„›L‰ÛܨSšï¾WÆÈün*ðê óüé«ââÒM^D«’¯÷\òÆD³¬øòMçônÉÐBú<@ÓÔœ3M¹|»œ‘¶ytɪâ,ÿ/bOªo€XÈ~ÔÌ@ã³ò¹ b£¿cæ*³qÆ(¶ î«À]–ñqYÓÆ†‹ì~Ó”>Üö>ÐæUèÛªç‰!oŸ‚§…UdKrS äKÿûU•>«-séF¢¸ÜôÔÊŠ #¶›´}߯¬à,ÑtoÐl…4Px¸š².•LjK­Å—ɋ܌þ‘ÔÔ*ÿÒÝ‘©JN·¼×í¾®Ý^Fè&»È ·o‰¬.ÔdûE÷i dù³/ÔP!ÄÈŽàÆ…šÊ6ýOî»!UMé\iÿŒà­Ü×K1¼î/‰?¾Ÿ4…®bíèó *> stream xœí\ËŽÉuÝ÷WÔÎY+ï‡-$k,HËê…í‘Ãî"Û4Ù¤ØìÑ ý‹ý‚7úA?¦s#"3oDFVW7I=c0˜šìȈ÷qî#nä¯wb”;Aÿ”ÿ^½¹ø‡ñ»—wb÷cüûòâ×2 Ø•ÿ\½Ùýðƒ¤ÚI9FkåîòÅE~[î¤Ö£w~ç…•6»Ë7_?ßĨ0Úo÷XÊaíð~J«ƒþ?EP^87¼Ø´·£ŒqøgzQ ¯¤Þcˆò³T£Ù|lÄ~j£…ÿqùS"Öìâr&F<èþÙÅåß=\b°QÒD?ܱxp£Ó÷{kG-¢¾¡¿kíM^ÓO#¥Ãýñ.Î&*ÊD…4F™²´ãK;ñ*‚W—×Ãï÷—¯0Dé£×ÁÒ3º DØäh"8A#¿N{VFZk{;Ò£–ÒC"ü•g‰Xm­êR2z#…*”ü!SRÏjǨm4yÍwÐ1ŒÁJÎ’Ûë}ozELÓFÿØ›^ŠÑEå¦éÙœïIîFÈî§e©Ùœ˜ot®Øã{þê]Ò;­•wË4V÷·ÿEÜ6?ܾݫ@BUÃwIt¤§ix½žßÈk)†wi~üN2)Úð¶"žFK[bò© ÖÏ¿a¿Ù$I»´«&þ©srøHó†Qáï×lßä!‰â •aÐ 2P•ÙûašœÅæ¡m®—gûºÅJFFhXGT0E?i(ô–à–ß0^ÇWyÉV9^—Y0áLÑÛüÌköìæÈgKkûÚ>¼û¦·UFÑ›ÅàótÇ-Í÷Åñ¡EÒ›#i´o´2p:çEæg|$:ãjEb¯=N7ø³´ ’¤¯•®ØL· OŸïÐ(!ðô˜Ô…”ÄÁR rZz{`ëgYÒ€2˜—¦•Á’¢B_Á©JÆ·{åÇ…^È>¾\éQ+ªF' ̆ۗyÕI?É<4Pà[ú¥¤ I’Æ)ì±Ò–L•Sþ„¦Ržr‰Äûc£AA‚ÅZ… EÚŸ£@Iޝ þ €‹qf”ºš+û2ëLœ…Ðd­'Ðrº¾M8‹` Zöv‘{Ïux@@õ䮓‡Qøžç £V,ƒÌE{ÚÓ šÖˆfø¾›ïͳåÅẹƒÄê!’«6£Š*!íðïÅ©[îÔÓK!îj4ÖÑÛD­¤0EZ°'á¶jx¯1;öAæA¢Ô2 NÔZ'"ˆà¸/¯£ òå1˜d !‡‰µŠ*ÀA×ã-ÉÁb¹CõÒ¯†‰«²£òepB.NÀÿ” "~âÊù1ȯöeñ²bµG@‚7BEîÚ#B„d=*áâa›²Úãð¿=b ¡,”¼£y…ÕQ*C8tsÒfEÒ ‘…+ ╈)6Õ^Ý ß”‚Øy“CµÉš l\}LÜ6ólè‡jpé‹ õg”»×®!0a„Y~VÂe‰‘l‘ –.¿Ø†ÚvcNÁŸ‰s0‘~¾Î/!#è`òœ _`¶ð5—â+€AX…™XOH÷ÀKeí±Nž´/ʼn»YW” ]] )S›s‚i…5E%¶øÐºî> jdîi(x0žÜªÏ0Š =ƒÎ õyaй„ƒRYžtÔáÈ Œ JhàûžÊƒ iSlä¿n†”ˆuò\ðK¸P‘›„¨l¶K%ò'øæj‹CØ÷(–…}i*@AØöÙÓØøYiäÿ£ß)ôƒv3úývoŒ%•®öøçe X²RÁFzy}Ìÿ^W JRbÕ"„»¼gëôÑP«ÑÛÂ:¥ˆV&+í(<¥éTã:oè¹XæÁÅþôø#!' 4†0E9ÿF4 È]÷°¬qªÑäŽák”ŒýªRÖd™^Î’ù>Qf½wZ5½©=¤HB”8UëŠ)€&Ènçu®Ò:2HYôEK ˆáY$$Q)LŒq€¶b}€Œºtu*¥ßØ íM*÷×Q<*¸ã™›¿­Œ¯&¹×eØ$ÖFkƒ{–:%åg[^RvªPÖÀë6F' '°…uWD;Î׺*z%}ŸGãÕÍ¢Û‰ÂZ‚޳ k*æÉu!yJ¾×&†*ÊSA{ 㓺S_ݨقßÁëS¾0Ž.ô%ÛÂbNðž[®éM˜›ÑUíO*MèºvUF†á‡{‚7ë]U®ùfzí ‚£‡“Ø’’­—«jwy(|¥¼è” ²ÎPµ}*ÈjœZØ™By8y^Ì(Ñ­“·Jþ,(;°RvžDipÎñÜXÏ¡‡áG‹Ÿá«o(ñU®î¹nX$qœè˜™¼r–ŸnÅÀÓÿ|o~±ŸØÑ¤¨ >.˜ð—Fã'$ê ÎC¬ζ»C?‚t]Ϲ*ô€‰¦Î’°!D5Å¥†:)òZ ]g+u,@Çx}"uåÿÛÜÉ‘šÿ™r§ÏS8r²æÙWéðÑï\ŸgJ{)?…gîaž}Ÿ ÍVy’tT:©º,§ m3¡‘ßð•-;ø \adMÖsfªêàô@Ò¶õ8Ý8¸uy ˜Æz~’‚ëmê)àÔyD–ŸÑx’2þM¬®YöÓ¤J ßå™%žÉø9'U~Ï6žšr˦ÙÕ›8b6Pª· r³ §k¦x©éx¶­ ÀV€gv!( ­×ëàq³ §3³x”ÖV¾,YêuÀøå³…ÁRdof¤Þ`|ÒÌ?Éá‹r¡+‹ º%wx–™¨œÑº`G5;Ù¢ÊP¯»P‘š&ó?“HMð%”R áá[VtX**·EüÒTÏßæÇbuºNOƒQUÄLÏbˆüd]é¬TFÄÆÇÌ#Âðãl# Õð³´ç$¸á$ÃHxy”SJªPìÀâäYuAûõq#À­ør]^•ZÙiîknèÚÑ}‚Êf¸KµóØWÒØÐK]¸á¸‰ˆnbÃqƒ¼ žï3¹¸¼ 5ú~Š´¥"eë» Iôû³#ÂHùò£ØC»ñ\#Osª€ØÃÊ27‚͵îÌ£JÛ¨"iS«ÜClOê•ÖñåÌŠ’†™û§.C'’Þ Ôél»™{+Åó“"ë‚Äé(ìœo§ÈþP½³í‹¨ñ2 `^¤È¬  Må˜Äÿ{»²Z$,ÆËJT·Ý,gieðq啿ÀâÐ1¬Zi—xí¾í¾¥ç6¶Á8Åöv»DO‡ü²5úi¶¤åpÆÅ¬åðˆYª7Uf²˜€P§*§T+Rc÷=[O>IÖ2 ãøé=;Óçî&¼ƒÕ›a?Æïò£}¯àèÇ} {Q&¬Ó”ŹÒÍŽm@³9}Ì[vÂLa‰)GSh$m·s Ç`û~ƒº×ÓÒ¦›³}^óP¯uçœ$ÃâÕD‘Œuú1¿kEåu{{1³ÕdeyµDŽ÷‡9è[š^YÝ3Q:”Š>]]9ïl‘»*ÚÑ×IÖ‹üT‰&€QÑQqmÒŒÌöÃ6¢ê¹ƒ›»¼ˆ…f³ˆ¼Î?h{!åY‹@ib¥\›JcTüô0crž‰ÑÒJ³5)‘B³›.ý¾ý™Ê:T;L/Wn¹Ù·VÝÇ•A‚o•_s©Q©!'Rõ\(óm>œ¨ÛðŸÔÐÏ’Ò©teë‹´]#¨{¢­ˆõ¦-Õ`Óq〉]_Ÿ÷óAjOÿ®Nq1(x ÿ1R…ÂÞxñŒ½´QSIUJCaŸù|ï7LóÞNÙ!Wƒå($ZR=iéRܤz/&­5dVV²/­ùÍÜ÷¦–ñ“ŽšãZ[$9 0R;~ˆUYjŠÓ~;âÍ`Ç Í|ΨœžcÎÿ;þfßëjãØÛârsÂÝìâ隮ə?æ³s$¶ý*?'3ëfPÇê{Óñ{­/ÔêÔ}09J¯¢ú<¸Ú’T®ŸÌk·7\8dI3FBXí‡%T;×OjK8ü”VŽs­ð§wŠ²Ý‚#‘T<ØîdT 7lw¢›,Ôm&ÖÝ!7< cˆs9CÍ’U`´Qã{· êÆˆ &-27>xû1 K ëK–d ¬Ì îúå¢fÇ" Í]í‹<± rMªÄcŒûÛ«é*¤Ní9W!7t¡‰X‘@Ë&=ê·ë¬ŠÛéç†IoÞã[Ú}´°íúÊ^å,I¿ÈÝÓ‘‘ÇBSÇßnˆåy–—¾–š’vË;~6:ºÒhº~Yc²Vå OW.µ­#cˆm0LO-Ðnëò䢳%›¼ÖÐé5 îÚ“OÖh«³ßÉ¥¹úø!9SCõÒrj} #>”Gµ“|·r+Ä¢’½VÄ(Æv ÅKÄÏòØdŸé—€•þ­ª%6|ï©ö-š8¬S†ôÞo¿3Syß&R´ ý%‰ÉWõûœ6k›RÄuþƒÕŽ5MÆED…ÌnØt,r½™SÓEŸ®¯Ê÷vÿ¦¤½7™ž*x¬³ÚìrŽò–~‡r¸C·ÎŒh‘’ä—êÆÂ/£Íó•Šušðô1žÓÍû‚Jâ¬ÿK÷EEÝ"*][Òç4*—açöI¯Úøê–êü€3¢^ã füc** Ø{¿ïéD4±ôýû©ãä_ {+eðÀ¶ôDJ]6KuŒ!ôúþ5;„¹â}ÿšŽ’ÍNÂÀ¨%(½þ]£5~”ù²}º‚ú;ô}uyñ j³²»ïÏÒˆº¨cÀû† ,Pó“׿ÜþhIMnùh‰&ík”Œé^úhɪž¼jF7é¨É¦ï[`øäù0¹†G]ï˜Åü¸ë³˜¿èõŽ˜¯w˜Ê0ú×;,%œù¶ßð»<°¾ÓaGIaèFGœ/§¼Ú\*ÖÚÕ厶S§ËÏüõ'5•5l… '<Ò£µZ¦¶‡°º5tgdºˆX÷…Ååçév̹O ž$§'˜ ÛðH¯LuºHÓO~€>6 L‹åo"ªæ”Ï7À§M3%ðD¢S}T¡)ñÓ·„«’oM”¤C™º}äØ?§%È¥×A¤qSÜékO\N·›`T³?yÄ(·;…Ûétiõ•Ÿ%¾9!0¿ cèï,‡º™ë ò×2K4!Ê$¸:êÞìA ¼h¾ÊÍaj¾iek›wžn½Á‰Hj‹-×ìÜ(ò¥Ž¤ˆ”©Ç—T¢„ÍŽ–YW§ü~DÑ-mÔ­Óçß–Ú8½Ú<§\cjþìˆÕ·§Æbx°âF0)¹&Wr>uü¹SÐàɇŠi;r•Áá¡vfuEfåbHõ—^–WK?â–Î!ɯÎi“ʉnÚ¢sø¥ºÂ¡¯Ú“ÞO´dP”ºyr#š§–çÙžnô̰~×ïO×é*b«z 5qårïö=¦¤£…m¶Pz•=%›Mzû ðèÛoV=Zx ^ ùñ^Å3„g‰C5ç#ÆßUlÑÆù„†¼KʶOÁh@ðúaÆêÐÐܽç<©Å›Ô^Þcì¹Va¤j{þ…kƒ˜-Ìeðø Ë»Ä6ðp¤šŒsXà ¿œQŽ ÇèÑ뺿xvuwy(ýì(}1Žn܃*"‹å2¿®òÅ”¢üââO”â¦endstream endobj 37 0 obj 4710 endobj 43 0 obj <> stream xœí\K“G¾ï¯˜cxšz?ˆðó C`{‰€´3c-¶4Zk5qà¿À€ÿ/«ú‘UÝ=;³Z9|  µzê‘•/3«²ú›•håJПîßí««}îW/î¯Äê—øûâê›+™¬º¶¯VŸ\£‘4«ØF§œY]y•{˕Ժõί¼ð­ÒøéÕÕ³æöùZ´Fkobs¿Þ(£[mtóœUk}lîðZ!¥l^mߦG§šýa~v|÷z0R Ù°á_ŽoÙã;šÉ¶&ºæ6}s|1 ŸiB7‡ñçWôˆßus“©16û7¹­‘žSúe^Š÷¾¹{Þ‹¦xÕQq_Ñ£’sìÇòÆ÷ô¬µVÞ5ad'Z4ù6õÓÑøæ6/^[«šm¦Ø,-‘¢-F¸et_Žw™f,Н/¿C[%lÀ„ߌGÆx> {W%÷²_a’im”=É`@G[jz¿þóõ¯¯4)±P¦ëÝ þú««Mÿr#e­¢Ÿž“¿^o´Õ­ƒ*•º¦­UnT›×ù‘ñ%-Jj©ÉÚby¥'%màâ=¾¡^–Fhnï_׊W¿}1>2þl' ›ú• «­o­´…íç;2Š8SæLe›"”ÆJñ E©œlÔã¾çŸS¥®Û¬3‘ä pÄØ*V *d'ª ½© (ÆD%ãjÚ5ÿ%Y×ÀbÚh\Yž5ízc…kiU¿XX¡#ŽskXÿñÀV8š[ë»uÐÄ Mö¦-æ‡ý,ñÒy¨=g!Ÿ¢àloC·L°ð¬o@fø¬³2f7Ç4‹Ž.BQ÷É26J˜V†lNÄÌ»r2O0W©A$Òè’ü™ú—u´-@14kòv|ܳÝØh|ÛÙ7ÚÓ>ÿl½*&Ž÷’,!‡ÿf’ÐòÐʺJ”Î'hÞ¸î!T¡9A'Œ%ubÖ;«@»<• @…ÒÞeüy^±d£ï GN®püÛÜ_YÙüo%DmlóÓ~¨Ð|Á¥cº3þNjÓCæ§W×?x†qì¤+œ¨ÿý£Ac±Ö-ÑÄÖIÿC2•Ö&IZÑÚeÀTý®’ :ªšc×SåÒ€&`ræßo÷LorǨìùWZT4ͳq 9Ž ×Ùê@žöÏc@@«õöôШRx¾ˆžU±@ýÉâ# q=½ÎÆ’^®L/òBŒChh-BÃ,Íô«9 QÏÌ 2ÄÂ¥#u'-át”’]ç4u„Xä€5!ȨI6Éf¡<‹XQ¡ óÂá-îó °Ò%`aÆ›<Ü–V{|2¥ùâéÄæ‚r§K! ¬ÈC¥o÷‡í¾žT‹“WSìó0X#ª›¯Çö»!Ú9/cR^#·(1q’1ñ”3iÓ¨ ì‘fCt& ´êqäpÌxÛ‘&4dÚ•Bkát¿ ÑmæXj&KÕ÷)¼X±åhŸC.l%]—”ñ$]—¹ºÜæID ˺ù%ÎÈ8°×ÿ)ÝbZ¬MY*hò®®wiOIÑ$“NJ©YgŦíª…)DKoA0¢œÿv•[Ék2%²În!óŽCË=™¹^¬³¶:µx¿}®÷=Ñ?îY2”iIû"UtÐ/©¯’wËñÕ4¬=Ú.…„¦Œ[Rª5š³ˆ™mÅzs‡G­\†i/m¯â­…J;7{.¢‡Ñê>hƒŸlHè|~°Û—m…ÌæÆcöß7Y 7¿æá&õ4V¨:ªÑʶ.pVóÆûÜ,<ÓókEñ6VöÐŽîâÞÏý Õ…Tu¬TDH%9TM £ô%ñ¯[´Âî׿ÝI‘Á“‘ЮڻL¡ÎîåÖý¢àã\¨Ätå>S¬Añ¶ØLëÖîê$«byâ0ô{™]„Ô-ídw.¢ UDìC´ïd¯f:·ãº=Om}½ðŠçÉã„éùmo“S…çóŽÆ«và‘^K+g998ÃÔŒ¦Í«PlŸÔ›•¥•øLýÒ3îðæƒ€"]N«°1^UvaؽÛfÉ®ã²Æbç× Iˆ*þù§¦k›ÏH”çgZÐv_ìθþ5wì¡ÈµÚáØãOëQÝH„6™m)Á¬dR‘^W‰Ñ²)']bðOƬiJ/nÿß°æSc®s¿Ò˜èQ‡ÇÁcê8:Bæ³êÃhÿ³‡R™…6=7w„í:ºÐI§d=HX1°þb/Cü3Ñ2Ý0Ín•g@?¦É’Ð$¯¤(Ws!SS+VµNô‰Îö¤ÿ,ÍD¤sëDcoœì´ð‡ã¥Çûñ~žøf|sã“ÑVV* V=@³Æ³ çÉnH¨/ ù4 k¥…}Oš_‘EÁ»Àéèå‡ç4µýùõÕgW°'»úöJ¡÷++­jíêÕ•vtn!û/¯¾¸°¼C¥#"µ‚…€•Ë;.ÒɤñRãõÜÒ"i#Í“ ˜”±þ÷LÉ¿ ¥|¼ I óCp'¶kÑŒHŽb|,ÆH1SŒ_qt‡^UÈ‘2~Ô{ž{‚kFxú8÷t:ÖróÝ{'‹\T øfMÉ®2óXÚAhO™hÁ¬ƒ{_—E5TÆÅÎeyõ—õ«¼5©\˜…íAô¾ù,sþuÂ'óxcÆmk§Eæ`*ú ˆ~€  rB½'Ñ#q°àƒ³zðZÊ XO\Ä­X}òW’‡7qXÐ/6æ„„ÃzjÙ>9Û6/{tùþ˜Ìw¢âï¡‘’*ŒJN0sÒ ²Çe'h ñÿ{ÁS^P´Î Jøµ1 Cšf»^ðƒ^†À çJ|sôØo„ªpN]GÚ~¬Ê/÷ŠHþ5´(z,¾1¡UÁÐvchít⧬P¦ëùj7à~4¼7ª!¨.žúCJ<¬ŽrèVÌEpꂷ膃 .S·¯ÒrÜÐu²¼Eø! gÓÖ{§s”† ü¼ñQ©­Õ+¬ ùo7×·'™ØPyOg$袽] ÏWV ÑÇë2¿‡bh“P ¹õóJ0ÑÍ“m‘pšìš%€«¢ËœôdÙ+Mh±p8AaÐÆoãA0ÆÔÅâ;Ás2\§.I³d°—ÉFH•¤¹”ÁC—‚Áõ,’е<4)Òyªì Çg-ð‘ ŠÛái¸Õ³ŸYg£©ì°IQгCô#%;ÇKa€6#Ci‡ˆˆ›äW®Â´),U¾^AíÄ­¦X†[êúÑü{nzGaL“Û@·ëÜÙ2)Þ úõiE'0‘[ÀS¿‡õÁAR%ᣭo™Ú˜‰…\ÀD®'ŒE ÝzEìþd¤ €àJGIæúˆ—Oì×sÜ€ó ¢:˜[BfZ×2Ãõχ£˜QÈ kË<•X¬BAè»ó›ßÑZRõÓÂX \\˜4ÇÄPl!¥ïOyŸ\… ŠN9 ¸|ˆ§5KAÓßÃÒzÍz—®è‚ßéÌÊTV­mLqr²S¶Ohð Óh-)¢Ü®5ÕhÓ|*hÚ\C‡AGFoR7éDŽa»·GztÖHºã5<¦1¬ñnª›FæëD Ÿªvcã}ŠÑ$]¢0ZðÉÏï:ÒñŒ“½D¯éøÍ"j¤R˜¦<×Ý–ÇÀÌÐ\¶Á»…“LÝòò V†Ô_óºˆm‹Ã.ãh“´<NóºxQ:étñ¡è”*©´é$%5ëªúnbŠŒºY¯ïŠÒ9œ¢šüÀÓ§ÌccÓ`Ç^q¼¨óõ˜§,œ³SÞ㡟ÌɹêȨ‹®å©²f–{îö]½°Û®:]8ÄXÂÂÛó{yT5W9Yø,£ú"§|upŸ‡2:\Ê“é¹~â‰v²-˨k™'Ò•«dNo}\¨V\'é*ž›ïÝçÛ\!Ñ %ýÛ|Ÿ ™– äb€ÍP0¸›¿íP^×CÀûu­ RBúÅ<®rrl¯L2RáJä9—@‰òñÉŠ1 KϵŸLÍf6Ý‚ÐCâu÷@–j©ºÔV‘Ìi'CÕ JÊ2|¡1×·/]иÕ*¤K"zì5ê[éWÖÿî–½ïväx ½þ¨È‘7J¤»sݾÔÕ~2ŸN©Ï¼²ÑU¨r}@„Ž.ÎŒ[c­Ô~6ÎI" uB|Z†ýñRÑåc2LEa »5Î8 ¬eqPÕ¸Þ ð.Ù¬E ’E-_ê¢âmáæð˜ºCôÓ3WÖ“aõÊâ†+’Tq7ôEÒ5-¹¬û¬"Ù\Š^@+’«ª¹Öæ92nkûßDÈßúª‚®Ú@T¶ù<PFDQ„úƒ¬T?Çö3‡Ú,3©¤â,7¸’º¿D@\œº®l:|Ô°¥{!££œ–Àç;ö‰Y°»¾·«UQ„T´(½vÚ{ >.¸€œCuBâ…Õ¹dv×3¦ºîšùBz¼™Göí k Š&eƒYä}Åœ)_÷³Äæ·kvU•xè¨ôõ“&k 7Ÿ6üXÑ€kþù²PÍüE]2’ä|[ô3¼âå€á×ä.ˆ t5Y-\ùiÚ®›‡N ƒèµ¹ênt˜®ü‘Uu«³ŸñÃ:b@AÕ·—”©*I¢¨ÎÞ}µn5L+«Ýh8«j·@¥ ÕÅÂÜTVƒçÕm¯²È™ŸŽ ©Ë±JYÒ…«:eQ|Ô9QA¶Îê ÓèÎRÐòLĤ ’Ÿ‰À•Iµp&Båxhvö™Èpîá3â±.ï :Îë¢ üÐ ®±k8ï:®‘YŒšY|d¶°ýaˆÊTD×ç-uÛî>åñCÛZwóÝ2ëZÒÇ™q[í¼‚ñI²4ùÞÂ$YÒ6]âgyÄ$[¢D]eKìª-7žÉ†’±H't›~ˆŒ/ØÓ¾{Ú¥%ÈÖi×È#“¸ ±ÀzRÜ‹d›æ”AÊÎä´Dƒ¤V9³€¿n…F1ÆbYˆp ƒYn ½yCïω¥}¹í^<´¿ªÇÇ¥fè¬îˬ˜«MvAôáßC¹í¿ò}©ˆÓðµÜß¡Ï yáNhïÐ:}·H¦Kmççê`VkËË?ç6í»OIuæ¥2*TR5,an L'°´pßfñŠ[}Ó­ô‰h1Q.ÂÒížâf7?r]\Ï%'ýœ}ôÅvávXÙÂËÖ×[Òµ¢‚ÆI’·!ûk;ñ©v: =/ÆÞVAÓÒM GeFjµ¡[õ2ÔÙâpLôÙÕÿ ú›endstream endobj 44 0 obj 4634 endobj 48 0 obj <> stream xœÕ\Ù’Å}Ÿ¯è7׺œû‚ƒÛ,ÃÆšpØ~º  i„E ës°ßá}nfVUfvÖô23Š!Z5¹Ü¼y÷{ª¾_°ž/ý/ýwusñ»¿ÙÅóWlñ1þÿüâû ,ÒV7‹?^a Î{¯5_\}ugó—²·Æ.,³½jqusñîê’õB8Ë}wŸÜhÅe·¹\J«1Úw]zÕKcE÷ý]9¦u÷oše¹aª»¹”¼wÖºn7ÍŸÌ ËŒéžâ·”Â÷¯«O‰8µð½7¨@œë%v_\}vqõÛHŽ\yÛ]ƒ%doœì^].i)¬éVD‡’Ò*:ð\1lcAsZßäë+œÕ8œÿjÓ>¡ñÜ{+x“Ö;ïÆÑÙF_-àÎþtzºMšâ)^) Ý×á'çŒwϳi7Ó)7ÛKázÆ­ì~#Œhêžy£ʾ$þZ©¹ñÍsÈ^h; þz¢'çã{—Kƒ#Y¦Ç'ž[9sŒo‰\îé6í×ß].…íµ‘¾K?5¤`M ›^báš­²WX¢¢AõÚÞ«Êa]¬¦¡ 6 æÂû|‰×ñD$õÛ´³S‰œ0ö:JÖ’+Ýk±XÕ‘·qO]È5ž%ÛG•R÷NÙrRd×Ý:14Œ~7Ž6Ï Z¡wLÓ"Ù­®7k®z¡D÷,žLxzéJ憑ÒÞÿKiz&MuÁ>CC.»gé_°& Ÿ´\z¯TAÈ6»üWqI [‘1f›62¢½ûÓé’3Þï‰W0/^tl-ø1âErDâc˜,^ƒ0×=Ë÷ât5ãíǽ@‹l w^äœßm¡Àåd´ÏI\?²­inVûÍõލÍ©`Ì+Ó2C¶Ûr>Ø¡v·8Ù;ã½8ÒÀù@W¾¤CÙÞ Ù½ŸÜ€ Ó{+3˜u .pH“Èÿ‚ÈÇUp•¦ø|%Žlç83ŽŒ_qÒßé ¼—­}° s‚IšÅ±••qÖ·´•–‚‹tz¡óiªW¸3œçý0ÚZ#EÇÉ}rͬhž Ez·€ÕÂÝ%£ô§àå˜f¢}0ò% ¼.ö%ÍbZz>N+¶ÂM{ܧ'B¤“}Cô9Íœk ®Us°R8aØñò:íõã(®-mÏ!S¦MŸ-ETÁÚ,²Ý/¯¾Ù8˜°@N:ÇO·Ê2ˆÜYÿâ"ï”7mª•Aôu€êš±‚ì I^]|ŽaL/~¼V‰bƒMr¶¸¹ÂÈžËñÉ‹‹'ó±dY¤Xk•њ8V ±äI\¹ âæâBÝâ‹ëaÅ„ˆ|A0:£G%y˜ZµÈætï¤û4¥ÁOHþÑWD¶©$åÐñp5Å”âŠöT$8ë0U"DÄ‘0r}ÆÂè7UYâ†Õª|ÐF1„¹JºJ•Ék ŵÖ-U½ã$¨Ç¨r)3  l*UùY 7XžÁ8¥Ú@<ë1›B¯ü0µñÁäŠXPºŸ[”PT+`Vj ^jK©Á!R,œ;+Ii)³TÊ÷ÈÚ2-‡î¦Å­bçkñ â)«äúÍ¿§:Æ:ìp¬éI`œ±§»NáRLqŠë¼}™‘dúŽÇ}T±Ây÷;Úq¡Æ@ø¡#pÞÁŽKÊgÆ'çEcpÚC·™=#{3†|¥È9§í¼© ¥Ræ±)ÕÛäó…§6ý£5µëñ·3|Âa±€+{;bqøÆ,¸Âý:õ­hDŽ٩Þ:±Pp3¸ª¢èªâ|ú©¦ŸÅKI½d^KÊm)°Ÿ C[ðpÓO ž2~¼œ-+晋–©„Ú”déھ bs²ª?õ#´‡%ñUµpÝvìÒìnè'ÈîÙå’ž20…Ic½Úk§h*TÅûMÕq ÝlÞ–è1¼7nn¹œÊ¦”(Ó›)4 ­-kV}5¸Bñ8âNaD˜òCâ½cBèî:H~‰vW˜÷Úãò—Å ¡5%¸vÝæM¢\:Êå®eGËKOZ¹œOïVæ’ ´#㣆“–86ã:§ÒþdQÓähÉz”I¶ìQ²5tŒ‚Î _Aͼ³Y‰ 3=.®l¸'+Í~ )L·ÞÑ_$#k ‹†]\G€ÆCâfMo½ñÇ‹5 ,¡jsޏ1êì TÒF Ðò­J¶Cûl¾Jµ²3« ”‡Õ”µ.@çÖ¦‚ ‚Ñ(;HÒNfY±'CšRîƒwï`§üØj!rPL½¬ª¿¤BÆt§«7\VwŸ÷T7yW:»Hˆy”rœ[ŠöfjÒ¾ ­ÖÀ“M}ioUˆoP³e)Œè]¨3äI5°³< {–Ø[+üAþ ß[,±p‚òÅA7¨U}«n„³Ö¥ð °DܬçÌ…Éçá+uO ]­àÎÞ¦*ÁŒÚÊáÓC£3Ê4–[]© =U²|lsžnrxD†š˜5ÄpÅöQ€‘Ñ#Ö¢_œ <bÂpªúÊ%5ÅöÍaà[¯¼HdóÒ¹°¸Õ͸Ž+X*Á-7%×Á6fáp†õ˜"ÄžÔ ¥¬õ« '³pø°C"žv"»çýåZH=ÛîI®ý«à´9îÎÞŽpK—ܪòT$êVmhÔj—ý#2Êd€ Q/@¨ *BD¦–וÀŸ­"#)0ªð¹½Œâ͹ëJZ°ìWAø6® ÿÔm²Ç37[m¤×Bœ–c5ÆŒžòè£h¨Îó‰lƒQÓá×o"¹\ò™s‡Qùõ…j‹$J²SI¨!Ø”ÁÁ2&äȶ–ÙÜ­7HŒ™îã°?8ÍÏ‚EEƬ±Ýý9€u BŠNÐDÑ{fòWÓÚO‡_/fÙO¨.Èaá)ÛÁQ>dÜ"¶ÜY,ü]ëü-¿SLªOõD%‘‰EþŠº¾gÊÔ•K*=S„)q¦¯ƒÂÌ»Ôñr: ±$µÕÃôH-ážmÄ¿ Ø[b7çZ:ž~•bõaÄ–%q7Ï ô‹h$™‹4o IM¥#ÎÓ¸*JNðTIò‚› …\Hî\X5P„ƒ&*8r' ÅHÐM° Ø„rŠˆf`;Q±ŽÆRÅA3®ØîE¶rþüؽáỿƒ“ážçhç8±…µùÄlÄÄ‚f8UÂ‘Ö @§¨ ~¶^Wéä¼çŽ,ÎŒ_Í,jn>Ë qqP>©àwqiI‘|0Œ Þ€î´\ÎqÃZ¦Ât†‡ÚßW 2,hªø/m±ùiaR¸Ü¿lvëÄêçšÉh§ywܦ©XÌìÆ£¿9¢µt +ìʆ’…|ÑP:iåÓª®×[ć‡#-Ç'&îÄ’£ÆF36¸(9–‡@@Äâ\eEùMá~RBï|WRxڶЩf\òBjgá^rí c¹gÊäEJa$Uøk”;íE2x:÷7e0†Õ¢ï_~ˆ‡L4qе‡us÷ùòBqp |!ÐU÷d÷rH½½Å²žÀBgYÈÀ(žKVw¤ê( vàâ¬F4Äú{ߦf¶*†ï%}‰]{Šz‹ÑqÂØí…¤xJ…ƒ‡b=ņ’¤T v©¯ÝÌ¿¯#éÚÆ ¨•*§ý$¢ :\Vië%D…Ö¬t‚¼Þ²é¾hÕµ@„Sª®œ~¼¥5Ú4-§ÔQT)zUÅ#®u¿U¼&Û}³jQòÁQ®¢ùaFðŠŸ“#™ŸЙм/¦´õ,#ßLŠvžÞ|Y"š`7º2Á¹zì‡u>0Ã[*ì@M!Ä;ÑhÊpžM¥¨[Jl‘U¥ <ÕN?œŒU$¤î‹K'Èn&<¬:+Õx³ù6þÁØ:ÚÂC‡%^_j àÅŒ)ÙE¶ˆPz½EE+MÅç Ýq4æöÈH#FàÜ>HüR¬|züâqoŽ‹_Œ7ÇÆ/ðÏHÅÇ‚v^é}ÚRűªôìËfw‹JBÇf«ÜTAIzé€)Øýeßg³ò—™žµë9óuáðç"ñy¯/Ë©¼JHvxøÜ”m˜8iW„\{¬¤Ú}«nì1L0¹X"–4\ÊÑ)A™‘ùûXJ‡TyÈu «™À%æ} FA‚¯j€d‘F2¦\ ^ìa× Œºã#—ôR ð» º²ð²¡³-èm gŽ]YIíû‡ziïUUÅâË–˜{:èê> †ûÕ£Áï>4¶æÑáwúÀwÅï+ÒP`²¸¹€.!Cþ}R !UBWŸLýÝÑ»u¿ ÂdÌÛAGÿÑôøkÕ§UúŽnV¥§Ÿ%¬*úÔb))V´é%°H…쎼¤%ðîŒYz±þ;÷’ŸÆ~ÂÕô’°„oˆ^òT7é÷Y(X\:JG;&·£ซ£üu‚L/ ÿ:ÐÉ c¾÷²á Æü”ߨì4†/¹»sn.¤óáÍãáÉ9Àæ¥-$}¨C>0°ùoI¯ÆŸê-¸lÀ·ã¹›‡@Ë#3mé£Aœ¼šSlÀÌxo3ç½GP´°T¹N«äßJª¢œ ~kAÉ–)jcé¡+z«UV"Ìb€—{IÙû¨ÐõfJ .·Wy\±[o*¡yt÷l÷C¤‚ Ým~Þ¬Z€×S‰®XÄIBäú.Û´Dµ„=FÒë®à¸U«~‹ú—U‰„X†ð(ÃÂì¶«Ã覸œð OŒ«ü`,·lLü Ù±jˆ+KåL]”Þ—ëº +F›m^üÙ£0TP·U]G‹Þš¢‘_hþ¢L2|ó šH=ªJ°MøÇAŒQSe‘>YvlU@ h´T‡†ÜÃâ²#kÔdàb4rÊi‡¡ŽµÍŽÞïsêìãœk©°>ñR¶I¨ÆÅ›‘©ÉEçM¢˜lÔnp‡hg¬˜Z@«º<é}VŒ†0Ùm²šiƬL[r3Lšr*|­üL;Í[—°£/1ÛuöÜBO½W4‘jªÔE »pÍçZû:ÖLãÒ™Ê×t- žÑ”C˜×ñ8Êñ¦å»ËA´(æfwù 'º½Œg§W4vÉF?& °A¾ÉBžV6LÝeÓZÈ+J›Mü¾ƒÀÆÏv=¹ ¸)‚Ìl‚1€¿ Óc$j6a‚„pº[Ñ7¥NÍVKßuKÐ\8.gçÞÆ«ßt ï <,jÁhz•¦j~F¦ÉQ[´/µ%¼rfJæí2Y¶¾x˜Ýà¦yõQï ‡ÖÖzð~Qª%¿÷ùÃ=Ç5ì2Y~W3¶@µÄge/3§f„žÃqâ"jé@eÈ_Ió&¾m…º=#A.æMÜʹꋙ«€QtZÇB‹Þ/˜ žQô=§d©£ýÛ¤ë){å…{§±5”•¦éÂÝOÿ%ŪpŸê"Ù o9¦²‰«KŸ_ü2 ïendstream endobj 49 0 obj 4808 endobj 57 0 obj <> stream xœÍ]_o$7rßO¡ÜS+Øékþ'܃ƒ\9\‚än$°ý°õ®|ÖÎÊ–&}©3ò SE²ÙUlr4ÚÕ:ax@±Éb±Xõ«býãÅ4Š‹ ÿÉÿÝxõë?º‹÷÷¯¦‹ßÁ¿ï_ýøJÄù?ûÿ: }Æ`¥ÕoÞ½J_‹ ¡Ô謻p“¥‚?}xõÍðp9ZY9ÜÌ—;å§QMax•Óa¸ÅŸZˆI ߯?߯𷜤Ã|¸”~œ„Së¸ßñ—Î ÷—;˜@)éìðí%ΧFìð—8„ ÚÑIVÒ°§¥tCšLÀh”Èÿ†Ÿr2¾|¯Œ‘ЈÔpüF°‘°ÿ¸Ìð¶êIø ‡y¼ÜÁPã$ÕðïÐA4Þá$ÂX˜ïã:5ý²|<âJë|»Òöx KWRØá5ô¨´lí…2KaÁÇuAW—;lBf @¹0zàN¢KHh~—Væ!U|ûmÛbÎQòžÂ™¿ÉƒTððŽ|¸Ÿ•)TŠ.ì]jµFmaÖ†j¤»0+³Ä5¸Å‚t®¸ž4\éx €6·ÒŒ&èáOßG¹RÒf´àDyJ'x³¿Kr·t`*…ÌÞ;ÝN¦ôá©ó]cE8üÔ ¢¨Žl6{ìÇ 2#$¶"”ê-Ñ s꬜_œXƒ&ì0Û¾ݽǴ„ ¤ñ°âÊ™þ®uPÚ“qÑW–Ž ?9`ÎgoBêÅ$8”…g2xȼðµ JÍ0oãHmŒ}:R¸m7Q†Ðt÷OjqmWCS¥Ý+¦›fr¾æ¶ìñ >ÇÎ%ÓùOûsd_îÓx(°À°–¤÷vùó9x81ÐdI@€Ä²Ý'æ b¨ÚÐÊSxè)¾«¤ø@±?^ÿ«<ˆÕ- ¯lOöœˆYŠݣƒ^~ÚZ‘—gLµ¾†»°Âbâ+ †ì£á°g2ÓqQË Dè•Ë-ü&{NŒ àTÏFåá¼ TÐÞ¦50\×L„áÍùˆ”ãdÍpu|Hjw–ŒH@xà…Õœ[”d✮ç=›²çQ.Ë5g3¬å¤1†ŽòX:xÚé¶=Üú ù¼ ù3€Øx€š--r^+°E0I4â†Ù8‰Eð€.?ljìßÒwK°ˆWŒ|x0Íž3Ã!ÆØ—w!`d–]1 ‚kJs“GÍÊÂVÀK qšÉö6¨’ nì,äÓ–ëv%cc£4lâ|‘«í¾ˆxrJ@4_'³mó‡ƒ4¬Ö‹ƒ†Ýå›?òÉm ùôĪeŠŽL Áì“C ™ýëŒAÃd«@RÞ¾.lDúýGai°7HX²_PÝ›èõMÎK“;³È°Cï%”Þ(õƒÖÌC8«~"€VË'JõäÁ(ÕR ëL8K˜ŒÇx€á°ßØÑ€êZlä/ t7TòS𨩳À©‹ôà” _]î ðTXÒŠq0œÆØoô‚ÿ’þŠ‚YD®HjÙ!€FwÙ·C‹÷y¢†ªðÚX0ù1µj}ÊXA«:P¥³ÝÔ%çAÐ8ÑgîòÖê°œ`Ê’Õƒ±¤¬a>¶Š º[ž"¨?×SDØ¿°Ý€N `Ãâ"‰Å‚#åÇ4£Òâ”ó„P1¨ÄPë¢ßôœ£³àSÛœ¢¯nr̺ÄHœ.i*/&ñl~àòÄùŽ×N«KTvვ€—Çwx¿ è%ÁÈÄ«Éú%Œ³a1<ô¥p6 Q;¹s0”C!¬ãH›4gÇÁˆ§\#ç Ã?1ÕR|åÿlca þ©Ý¬ )É8¡“¨zñÓMø]*YÐ] ¼&QÒ)}L£MJWÛ‡‘Oezøn{‹B`Rü9£3ÀN\ϼ/¿¯¿Lá“åK8…WE,ÚA‹hZ"?Leï®ÛЩÚúê¤=Æ›9g@Áƒœ+ë’‚ÿS<_`Rµm™eÐÄÞ ±˜åœhÃVA.}ÿºNNaCkäÛe‚.#_²‘¥¹°èÓxCGÖàIHŸM“¸Äˆ²Í“?Qü“`ƒ(Ãÿ— ΣiHHlœ6­e`ËŽMö¯‘MÁ‡öbŸ{Xè‹°I:F]ð ƒ pC°EnÊ€ÿ™BíVHÙ&&ðôXÂ,¿¹lòÃäPjùàË Ì„#ðÂ/0ðù/&0&üb³aS%0Óè¬Ï˜gÔw„b!;š±þtëO¶K;ipܬ‚$¸5qDêÖÎÜ]i±CÂoàê™Ô ÈK•Þ<º×¶Ýj_q[ûàšÃËш©°’Zhªº›AQt'ŒFHõ9‘Ô´–û4–Ó¶B Ú¤¼îù@£¢H­àU£‚Æà‚‘XôÉ8ê)$ðfiÝ‹ÿG¦'rdÒ~à [}%Ýb߉X²ÍYJÌâ~¤sáHií{1w. …v§¤‚„>³·Üä•Çvõi¼Š8–ãÏ9I¯.—/ÿï,¨Œ¡Ý“ `¢—õ™†UN†e¸,Âv8{ÂÕ.HZPÜ[!›vE/t6IGõUôCBù -²/žuÜ# +R4¶w3òä^l< huþóµP?X3Zm>SÞ$?>‘ãÞ©†ód1¢Ý ÎU®ÊNÆÛMZc7(ä—:‡fBïïL;SÉ:È“õð/—%/ðcƒ¢9­ˆêGàã:ݧø762ôLÿ&’a7·"LÐz·q/“ÿuŸ>tµÛŸd_E${÷ÚÏ:HEx¾å`Å\^”>bx¥J$‚Ö)ØÊˆ`«÷á%swƒô ¹Á`At)BCƒ¸­àBê€q ‘ŠÁ6÷Õ8TKœ-øßküöiTZ©ØvBø2[S“€š2Ÿæ-`CÆ ù ™Sãr…ÐÂÞî ôy„ì­;±É/”̱¯çbÚ8k”â¢Ùý™îMMØBQ×ZÿC.'˜z…mµc‚óÉÐÓ0å}„~Îaé3ÆY8æ×—-uÄ)1Vâ;¼Êv:-ܱj„eEԕ臽÷sóбÕF󀯔åY1î]ÒKÁêô~ hñiãÇC«†[ëðÇÉPŸ*þ;àÅíAWáÅHþl^í¼Èˆ7&Ê¢‰¦äé˰nšÉri,Oô‰q¬ÝR¬À¤*lEBüäÏ‹sô&Òý&.¼RÁ3ÍGŒ·ÁÐɆeAW²=NÁÄÕ9_ÈIÁˆÔÆmY¥f1¿Ë„§ z@Z€H˜úfNY”âV™Í“7sgªk1»ð³Ô Ñ nJu £ðÝ ÿe¹ü¨m9ZÖHüV=}‹¾¿v0£6ué/ìÉáBk½d¥§2m'ÖEði¾±9‰^NÕ@ILbÛ:)ÈcÆ*22ó˜ÜQê,½»ŠšEÐh5‚†>$C¾Ä¢ªZ¢§¯CøóV¥÷ëñÒŽ?0BuåæU(\‚dɤ©5JÜâwü ”6°#lhßJ—h!¿Ñû˜ãl%©µ‘q½©\ÜÄ«Öë˜ö«{ëÂó‰®ã‚ßì;½?)äû‚ˆŠ!©ˆs9>up;~fë"3lÜÜžMë›ML:=Ú´>Æ©£ bW÷iÊnå\ïŠã§¼*À~ĵĵÿnmÎÚaÁ×%úò•à/q>rCw Wã¾ûÌW<^gäê˜{wh½y†>Ð(Å¢2dØ᜔IŸ#¬Š@ey¨‘*N4;ˇÔïѾë¶sV=ïˆ1úZ,ì)á{³Ž:­?תAÞ!2ëÊ_*Uç’ÞKgq9•íëÄ"¸ÅM@xLß,ûùyÏÁàÈaz‹Ë« v}¦ ªÌXþÊöÆ`¤7°ˆàr®‚le°Ô ©oVSæ†ïûÑd‰í÷kj„[¥ª+¶±±¾1)ƒµÅã]ú,ÈڪŴ™*+ò€U}ý´I\Éo›©i§c/¬mOÔ&ñÊ­3×<®—3}ëqFtÌ+æ^¯á¢­›«¦KúÞ9X†2`.ª<µBÁ8å³Ãšé%ÊM6aŠÈô#% ɽÏé Ó >‡ÉwÏ”­‚ì¹®[zt>T "Z4<{¢W9P¿Nš[Cc®MçòìªJw_·¿Î³Å”©M©~ÛíÅívNæÓ,2çë4£çûöeûr/¯ÅåV™kéÔ ·ÕÃ7·™ïYÍìU¹ë}Ì<åy=³WºJçvnS? $šÆ>½u>Ž[£sŸEŒO—éÒ9FíÂèŒ=óbÖ…˜wnbi|TÜë3áRÞ·COeâs-ñÊ‹ŽÙ†Œ Oê§à_rÇ„»ß^æ(:?Ô¼¼1?ñiezâÕ¦Íëbá“xzÚå:æQd;ˆr›÷ <ñ˜eñ¯ð1á€áM*l_Œ÷ 6ºsð¼Ú…d©ayF!^Å„MŠ–.w?¸Q°fÕ)Bq ÙÒ™E¤òƒ-wÍ(Ó×KlW?‰ã«Â´!Í7¼‘£>eþÆÀ³k¼Ñ›“q©„µæmÀ:WC´­Â:/’D™Y0æÜ@²þ!’j=MV‰S§*1b×_ä«KùI{¢Ž¼”R}üÄ»føRª[ 7«b˜ÎA£xÿfFìòDfÊÂåhŸóóð]?üLPXúÎÆ§Îzo?74áNuýªÒÅOÎOsW mŒ©X¼ÿb4í–ÿ‰³zWEã »ænËbRuzV}=F̤ÆîƵìF§†+J\/W‹úµ­5JsXM­óZÌo#°C¨ëëcóü¹ÏdnhÁAUgV½¶’Ÿ;R'ÑŽF²äèEèI[óYJv-Þ;­dñÙ>»–q~1kU‹4ã¤êÛ d~ØÕ ¬\˜"5HAý²CCÏnĪÖé(ì¡—EþÜœôXK†:ýèû£›ˆ\ûU¹â*WõÂÑÉ«Õìeú(QéEœÄÂbÙämÖÄp…PSÕn¦ª¾É×hZÓ|¸®ü2ÀÆÈ‹Œ%Üù½[FÄ>¿}óêßàŸÿm;®?endstream endobj 58 0 obj 6119 endobj 64 0 obj <> stream xœÕ\ÛŽ$Çq}Ÿ¯èÇY]ÎûE‚$›°-(Ž ”v§›K“;3Kí©ýù,èÅ€ýg>‘Y—Ȭ¬îêÙYšA°YS•—'"³ê›èåNÐ?Ãoï®þñ·~÷êí•Øý þ}uõÍ•L7ì†ÿÜÞí~qƒ›¤ÚIÙGkåîæ‹«ü´ÜI­{ïüÎ ß+mv7wWŸwŸ]cxgÔÝà§Ê çºwtYZdw¼Þko{o#¿ù~j-ƒñÝ~*ãEŒÝ›ù†×i4邵ÅÈ÷ó-¯è§‰Â»¿ù%Ķbûè”3IìÐëూ_]Ýüèóî×4‹UF„îÛk-{ã½…l¢7R»?Ñßµ3>âï{ ¬b˜?µU!-dºù;’Þ-LžY>3M÷oô f“ÿ¡FuoÓxZ+ïÒªŒ‘RȤ.£ML"áæØcŠ›_¤;´71éË(¡¼ìÞ¼žÇ`ÃÝ¿šÇû1Æ“¦Vwó÷Ç,S´Š_þ"OîTDrªûr¼¦Êsh‹§îß<¾Ë°J¢¿!UÂ^1tÇûÛãÛ|ŸNúœx›ç¢eÜ^+¨G)Lö0N[Œx?‹À1Î/¬‡»¡í¿ãþðÀõ–&4J·ÀÄtˬ >ÊqÏnz=JÅ”üŠq<\“#PÐ8G—›Tø@6Pp©Z­x®Ì-úÀ—·œô R­Ô“ö×{£#V¯ºŸS Äèa毇YF\íIÃbl®âá7¬V8æK6Þ(0œŠ©øõlÑ…r² òꨞ IrH¯çÕ‘HÝ%kO„ðZ—aðø’ ún¾?™NÇhŒjD¸\’?Â-ë‰Z1ÛTn AB°§œn½-œüba÷tu¶¼î˜n’ aÁ¤îÍáêsþØÂ ¬3‘ÙÏìh+}Q)ÇÀ§OV´¶Zw·Vép,>œ8ÙûX‚Á-sƒÇÿË+šÏa[ù>.V6ÃìɆàRÏ]›Wù蟓Y,å•[滣L£Sd™Ö-n}/­:kq(R ¡Ìö( äa6ÞÝ0£2 O c¨®›¦s¸ÙOhcÕ6 C†(’¢l¯"¼Ã6b–eWh™Åٌ̑;BÝËàºMàLtób`…I¿$¹Ì·ôS ÔÆ•CŽ$0·ô$­F_`ȼ¼ Xé"¥…3öSQõŽ9KË´ðÈf=ŒCêîå:ÒdY0JebZ“õ¾À¡óx—fÔãÍÐLú¡{ãÓiˆ2Ú«ÓÇô“B¸ÖO@#eèXÒˆ·ø6x–$Pòz`Ãe—ƒ‘r¶75 â°øØï¬tʇ<7º/É3M=ý8ÆæÍ& “¼NòÇn6q¶› šà°&á,G…qËT’CKÂû¼žoýñ´ä%L0Õ%0 ½ƒÑf¯Êh[É 5$ƒ†€¯²Þ汉Bß?Ì*K·¢.¸,õd>væ ¦1¦í~qMõ.ú&cúrJûîlHtq…Ç"ÁD0þEƒúÔyb€lâmÁ:‹•vµ’A~£VJc“‰ ¢€ø‚‚®‰'ôˆÄUØ79'îV¡ä\GÎoy©rÈ#ï×3©BvÐñÂ4OéÅÈ^Kßýú~7@)Ï9JRÝX#´t½­Iêsu-"ÉEΕ"˜D£<¨0=•Kã¹$Ïát¸Â3^î[…ã%ºM4Þ%xQÒuï)9ª¼[ó%ÁÓ[n?Θ¿¬HaÔ!ŸkNL–×xV-ÂWÌEÚ.7åìðLžEƒE[‚ÎíäF…¤‰ÿH[‘Hß Hs8þ•êÊDR\ä‚Zˆ-±®% ß§KX™Ë‘Ð{TC92{ÚPxä¿îÇ3—,#Р4QzJ²RÊQdGÚe33ÔÔ^B1\ánªmB'§«CÇÅñŽ‹S½ua”ògó7©•#|P¶Õ©¡â,Ø8>ØO–o5”öÞŒÇÝ^²‹a¹Ÿ%¸ÑÀÒi²\‡§UX­­á%ÞNºŸ|5ÝܲldÝÌΗ4Œµ+¤ðÛ6¿¿å4¶À«õ°LW)ÿ@hØGcßçÂÄf¸êZ-®J,fÞ´#ì¯)Ÿ¤å”TôpæÈcxùe…ÄÄKâ”#{Ÿ/ Ê„úöz*2ØÕEýš†³õp’z„Ðiú¤^Oß ÃyçéZyb3fYóR’Ýz[•i ñ“m”3HRV¶ªÕ*P&FUPÒ ²†ãaàgR+z[Óª5ð:ßÄB0,AÄ6OL%žòúL±Ïÿ|UÎ&Z³½L¥I¢lé¬5qp¬Riºl!1ߘ/7àÛ,*å“—3káh5F–Æß·eÅ’‰ž¥{eãXÚ`•¬bI½bÌ2üq³£2´pÚãœžŽ Wim €·¶Gµ¦Væ}œFà½Ú‡AEÖ• »=Ø:i+R¾€Y—H>-‚’À2ÚÒSåƒBT­€t•d‚0gà]¢6‰|<gŠ(õ$^Ì9 áR@ÌÙSÝD,Ë#‡·}äkŠjCYF$ü¤JÃJÖÎÃÜ"±`ÀBAŸÞ¬Ò¾Hkïq̬}ÌS:jlw}ÝRJ7ƒnÛÙˆvCFSsÑfJÑ¡Dß[ã ãÛCi‰®=#K ÌŠFÿ¤Â¹ÿ&ZÍæD=ÊoJr_ôKft>4ZŽ<ð}‘Ê xŒ ¥÷°í ºÝH*”}át-h®š²lKÃÆ5¹4ïÔWÔ)Í!ÌZn{o †PØ.ª²³Z&ºÁUû|'ÏO¦I[$X¥Æ…ÉìÛL}…ñ:ß­ÃÎÁÞ:XºÛ€åK”ˆºwÒGŸŸ4¹wÖéuTÛÐýâ™Úä´‹.÷¨‹- ²¤– KÜ+6<°ÃK•ëŽTçN ~ŽV¨¢¶¾+#'_u¦n4ÓE·–Mž¶!Vvtj+Kk¦’åŽV$‚.Ø–™á—&{ÚÌ(áØ#Žàßû1Ê¿¦¬V˜¸å²* ¬zÚ¬o¹DRg0mÅmê‰[—6Ï+6ˆ¨¿šxÓ,çõÁ®+ÕÄÀZNµRòÇp¨ërŠË•÷û|/·‹-WÖè]Ùÿ¯Ks^N\·|a/Q€+SÖß_“q-ÔØŒaè,†0ô§}Í‚²Rx 7®é¼…ˆÂ·< ü(è.ñ4æ^¨pWÜ+$Ì!÷ò2rÿš˜d 3Õ&5®´Ò£;ù—ŽË=`–¨;tU ˜8›yn¥s™ä É1ÛÃUÞ1ct6è[{kù&n(˜6–³—Ðq˜Í^²–w*/¡v‡ö(ZšxdzïbT—x 1%@éw{‚&‹Ù‡%œ¦UÏ™ ÚwuSŸ ¥Ô¶½œì9®¦èƒ©yþ¨íd}öhÎ~Šºn®Œz^Ý \gy‡íØv M›QΔn±ª$ã‰Å ƒûCÛéPßú>ç)¥‡Éþ BªS2²Þ_b­Ô'ŒaÃì&Í¡-ØÝ^ß|ÕpG dÈEˆáÐRÈ%~ˆAE*n7%2WòAoù -ÇźØHmS_¹_mÞHÃcÔsjuKÝÖœH(ò”¡éO'´Þ_Oý‡7©ÀÑS·ÆEäÌ8ip„£PÍ6&U‰üαÁ6¬+ÿ>R¦‰¨„*]Xµû"Y"Ì#iªb¡¿»žzÀƒäÆŠåI|qÁ‰Pð!òC^¬¿}—ïV.ªõ±ñ™þî\÷—©ÓÒA„ëX1™íÏIL‰r³‰£àiÑ…©¹NU¬ò˜Éõgù'ØbwrB…(PF­N¨|é(6øº¿ä°­ÈjL+`1ìƒC5§u@;xð÷ïW$j…yZvw[v†.R”Ë®ÀØ›I> üiÞ‘é™?2d½5ÏAbÒ=ê=¥xË7HJ©ÆîÜtt‹¼ÌU²3—°*äÁü”;J ÑÄï¥÷¸5[£ ¹èû¬úŒÕs^?ï„anhmq²%“ I+Eg4%¤>šè«—B“Z^ M‘6›þn¡)u8xÐTÓG²Œ:3 ÷ÛÓ?ä{+ãDG§Î®gTˆžC!e£‘W¹<Ëý‘-eû 5ý§³Ã¡yN·Iÿ£ìQ¯œ ÿÃ[;™j¼>¢úE¶™ßÙ-ݧê(RÖy‚žff¦—QoŠÙÙ¹ºÿjyŠ#²¬|¥ž¯®÷–N¨Ú¥,™Íë”ÉX¨ë éD䄺6´á`ËPߎ›ùüÓðñRŸ?ŽAï§·d ž}ŒµS.b&Vž(ˆÏRуq’$ÿÛ’Dærƒ#¢MúôoÎÄñ…Hç<‘ÞO¥Ú°xˆ“gÆÄùÆ9QÃQ`þ¢Mù9ˆÓŒ!Ð)Mú.ðÈõQ ¢&¡Ú¹B@´F¬)zXÈìâƒól™tiÜ ’;0ò !O²Šwëƒô¤¦ø´ççƒiE… ±;{hJU#¢Ï kÚ½NIBZÕ ;¾ßüó\#z;ÉQI'@“¾N>7gЇˆ_Á¡@•ߪ˜ÃÙÐK…‚à@$€#´ñÊ) *ç8ø_Hc*äâˆ.ÕL.§…4Ããšñ” Áf‘ŸÁˆõŒ[Ry£bK™pÒTpÜò´[íZJD>²´-‹ ¤’rªÇ<ÛFFÉ7¸7—Ü=7²ÄθìfW>´0n ~–Z’j`[Äóù©O)t$þ±­ÕDúú‹H[&ùxkQ8´ùù«é¦'5 KÒ"‘h„¾¦ Ç8¿ÔÒkV˜¤å@¨c]æS^:ï@1ñ»Ù$M?öÀ =ž{(×MïŽPHú°Â¸œK\idµÿHoÐà¨=#”£¦$;ØTgöl3HxJ€ÚHL#?#Öµ’øØ"ª¶ë%Mq:¾†‚¾€½¨ {H•¾~¼pR-±]®Q+‚FöƒZ~s2L%y¹’U˜VµJ¦ÏV[T’¸^Ñ!=²’ójcz¶tÒãòôœ¶>ÿnÓ³ Û²³ÐâL Éä7°Ætå ÙõE*P ‚ã¼ìœ:1;jÿ³óhÛË’³£ÄxarF ôÿ•œD”›0EùGJÎä?Z>Ѷ'ça*=êY“³nAÃGHÏÆÒçe8J‹Äô ¡-»‘ëz¡ÆÚ¤çHÌÎFXµ¡ÄÝ_w[©²åù*ŒqÞT`ÔKh¶ÍáØz ‚ÜûT¾Ý8¡/´²Ó`§_ù‚GZvˆ4wAQÀ¸vK&¦^ÏSF65J+ç·$Ï·é½Úw°ΉA½–X?³Ûû`­hC«?ÒE_»±¡ñ¥•á5àù´õ!‹Koo¿)ÞM< _ °qýåŽÁªONh#Ò—D‹sbL”ò[^$ì.^1xŸÅ¢¯Ï±7ÁïòÚè[«l‹êpÈËš’)”¬^òM¾-/ ÃK#ⲕ¾\}*Áˆö=óÄš>±¼UKé%‹ÓïG{°J¶o²á<²—œG¾¬I'ÓÉíø{³§ß³sÀ%}Áœ6nX=߉jdÇô®Ë“ÅÞ~Dg£ÐO<°ÖÖz!*–ŸJZGÃ^{¼àuûÕ…•*úÒ’à¾x¦ü Ä(dâS†¾R ¦`@ìø×ä‹{Ršÿôêÿ¶E$Rendstream endobj 65 0 obj 5268 endobj 71 0 obj <> stream xœí\Ù²GZ¾×Sôe5£.r_¸`‚aÂÀ0>žÃ…tº-Ù–Z²ŽŽ±x›á.€àíøþÌZ2³2»ª%ù3‡Ûuªrù×ï_2¿Û±žïý3ü÷öå£?ý­Ý=»{Äv¿Â¿Ï}÷ˆ‡vÃn_î~qƒ—4ÛùÞaÔîæ«Gñk¾ãRöÖØe¶zùèËî¯ö¬J:É»wû¦Þ¹îLOóÊtOÂSË$WÝËð[9¡}÷5ý–Z8Ç»Ûý#ôBèî7ø’Å1ÈDZËt÷ ?•–R«îÙü3¾ ~ÆYŒgγxåTö;‘ȽSÞ$þóÍßbó\e›w½t–ïn>{tó'_v7{¬S+)±¤ƒT¼÷Ruwa`)…5Ýéíð܈îþ5ý½4¦{K³H<|~úüÃø‚ò–v{¶×4¸Ý ×3!ðÝ“q„åWxø5ýPœ³HMjz?ÿù }£w^tq i•ïnOOÓÿ “q¡ºoÿ´S¶{L£é^kÞý*LÌ¥±¢û,V* bþåLÌ¿£ÇÂÁ; Á„ìn“I^„…J­Ew{ŸüOòÊ´êÓ¡z ø~¯u/Y¾þäûûSB—“&夰X™7å›#7¬”9'UƳÞbÓãëÿÔ…Y!Þ¾6¸ìñ^Œo7$tĪîÏönto4RV'½æ~žp?MØý|PSx>Ð&<%)—‰û—ôŽ€Ô[šç ¼%ÑØ8ÄR‹8ü«™ˆ_‘öÃÒRêTï´ÍƾM¾dŠc#§ð>½SºÎµñðµñB"×ÏæÎó»Ó9Š­•óòÃjlïýù˜Œq~ש˜Í%.,CøŒ5FCÎ{Ç Fs&ã!ôÎôÞb°(J8.w²70L.~ò6žÇ 0wϣͰJU™à½ ¬ËFø–6,¸vÝéÝHආÈÀ  RÞ}=Sµf6’¯ÎqT+³ÎƒH¨¥ÒËXN•WóÉËÉtA4 ^W# çã>Ê,W=³*ʬa~$Ý sù‘7ßÌ&ªÆÕx2â ·Þf¼ñÖBÖx# E"°f Ô "¾Òl$´ÂtÇ{LI %mA_¥Xï¤Èõ0<„'ÍÜÌwÁB;x[X¾óí©ß,Ì ,/|qþÅΟkóÞF¸)"ø¦×V¥[¸‹Ó “ÉB2ê1,ˆiI÷³ªñÏ÷p‰ÞÁÕ'âôb~õ ŽˆšÌ‡7’½N><½‰+ˆéžFK‚7ÞM0ˆ£$Û`mnBS[x®:åÔëÞßÖ(ì‘ñ=“ÙZÏa·ž%&í”–š¿Ô¼U(f€ëƒ þ`ÊŒ™ìïÉø°²Šœ°)X,U8P#6»O²ª³û”K}Þâ?A¨†Ö¬¦Ò¸^‡}7Ãû'©Œà«ÆºâY à­‡Þ£ûŸýÍ7‹mØpH÷¸ÇÓàµñ ¶l¦ñþ£6 6vfæñ PÙUÌî2¨…HÚýWmx å<›†OÆLå5ÐÚöF» -=Cfç Ä-@`,†¸\ßÈ9™0ü}÷/á×:¨–Ôpµ²Ä.ø\ ¢àÓÓ*S5dŠÉ‘1q$–YÀ@öóÀ¦x"<&0Â9FùO$ÆûÅLb¦âlLcNéûÇÓãªÌÃÆ|#S>Û!Oƒ)(¤ÌC.ËäÞø[K`e˜äÔw7¿<¿[È&ž‚¾å°ì׫PA!¨‚sùÅžäF[3¶0úýùø$“¹‰•ï†yU'R±KM —KÖK;ÐÜ~©Wqu#ßr*»¨¢Ž”sãg£Sñ«NóÁ^ËÄ©À’@8…ƒžCàmOaˆšòÚë6×||(‡õtÿ=VSÄŸZŸ6Á¬ÍÍ0Ù´k¼,ئ· î[I+{ËÓH1~íçäzk¬8 à†ìQ8ªz¯œûpüz4QÈcáËœ‚³¿›Yùçmß«fCPšéOü~[¨­;„™äSCæÞRÐý[MP!ÏYæåÕ ß870£û} á§óãx—½4v•JôeIPž«†$h—Ïe/g.t4š0ÚÕ¼LC@ˆû+Æû‚–ƒçMK³2á9(æi|KÓeCÓadçö|H 2oiÜ‘E;ƒ“5¯ØÒ«´¸¡äŽƒ}Jê)>”y‚u}°2ØÓ°/œ€6¿&røð=üŽà4£\Ë4Â!‰ŒQŽÂ"­Åš´®+–à‚ó]öÉšÁr³gûC6XmÌR€ NŽ]¾×B¢$BsŒï~VwtÞ[¸?:ºÿr³†u3êú"tUÞ›¥i öÐÒÿ³¶t:I °x¦1zu%˜µÀ…rÍÃq^¢ã©²²Çj…-ã­E}†ÂÒ2ñ±75‘êò-Øôò¦ñJ°à¨µVî໽0¢ñሔ ð}dý—-¨ ¶þÍt ¨µ ~B»G2¢DH|è…©wŽq54ÂI’§,ݬ-¿ àðDŽYÅ|¦XOr"€˜gox`ß‘}eÙC‡rÅ”­Â×ÖÁÉs%×ÌV‰Y·Jùþk¤åm‘Ÿf»Oüþ0׫œ¡Š¼ò½Pãdl[^@k²ŸŒ×½»Â|ü}m…»X!üOr#—Í>CàƒõÝgW›ýËI‘Ÿ–Ù“}ßꇴ’G0ôçc†I¯Øn)àÁ²ÝCܵÁv³Ë¶[·Â<‰íÃòï(ßk€æã(7sÞõy‘U¶‡ÒÅC&qL[·ÌÇŽïmQZ”Ê‘ôµŠÚIQ,Y@½ºùf-Í˾ŠK•Ö–Ý:€VÖûnÒrQ+kz¤1Lïl«É!Iü.û+‹Ú},Š&[ô«•\¦Íç-ƒ”¸Ÿz‰B¥ÓêYô,"¤î¬J¶9ÖÒ(Ûë7c®/S1Â$;>˜°¼ÚñAu-á±;×=½§vcë „"Ty¸ëîc{ MRhHµjбœ «DTÎO ôóXèV¼¡`@l«§QßÐ]a‹n0Ý/'³Õªdn™®XfNj‰ùï:‰xƹ3צT ­ÌÈeŸÈ@žDºž—…X²&¡™Àul½[ö/Än·ûä[ýt‹M‡§Ø´€ÂH™×Ò4)ïäHÉšð ·Z5ï ȩɹþCðøÚ×ë03V¿øèA’.Ú… ËÁm…yÏ‹(Q_™ uTÜÌÛ\ú%B¹LŽÆ$«smiKâ m³$ÞŽ‘­žÅDáÞ «àiÇLVÀ¯Y€Å>!O Ÿy’Æ0Ó,/F”­öB—U¢]Y‹ Õ¹¡LêD藍†€P‡YœÛ_º¢£áh€œòÌ…J‚ç¾âupö ŽëN'ò†X´Š ²T²T¥ËJž½g‰êµ ²ÕðÔ§y=Ç,å|ÛpÆO‰7‰¦f¼Ó­£ (ý´Ö(yó5L-e?øù~ê«~K´æÔÈa»Û=~)a©\\4^Ç–è;<Æ Ë|»h¼V=Çë7{©¬öC[µQ®Ìc܆<>“’šŽÅ¶Z1. Ð};µ…oꯞ=µŠQ„ 7¡s)0yµsIK@Vmÿïu«Éå¨q_ÔHw}*Š˜ÊÔ’^ª˜ïí£¾/èàBã»Jµ ðù˜èÔËqhõQxç4Dƒ!.¬èL‹¦p+ïb¡ ¶r9¥ Õ€ÅrsÎjb­ÃJ€QzÊ„×0KR‡Üâpf!YQÚ4öæ|YŒkѸæ0ˆÛ+:ö§þM°˜øGWKiT°¥t ‘%éë˜ M¨D_Ê –²¬³•çÆOy‡)ËgkY>0žŽ€“·îƒª§ÏJ|ÄaÌT©X=)AÝïFe)¨DÙF„¾B††¢„jŽbŠ -ô ¯Ë¾+<Õ\xmqèâQ §Y¹ÕœK'%‰³ùè'%qD4VSÙ§¼Ü_·çDÑ£ˆÅã­r<êwç˃M8—ä6H›¥î©K:m+ü*k¸NaXý<Âó¸®Ö¡ªÔ>秊„'*äÒQGva/vùtnC=•Ý™”®(„æ¼Ìs…÷Yp:>#rꯓå½õ§lÐcœLz¾–h@ÞöiküÂ~ÛËY7—–#7|žúÉ…,z~Ôq§j4§éÐì–7|ŒȾLSRòÈíý΄×C,AR#|ž\©‰iæY29ù~>5”>Ïsz1Yç±m-‹òæm†úؘŒËÎR„çÜSè`l˜§«¬© £ŽB[Ž´`oW{X5ØæS‰˜U³ÞN*’˜Úwq•ÔÕ{<Ýfªyÿ$U‘XÆ3e·ZnÓ{V‡¼sÉÜ6}Ь+Y¥Ê‘U8/jVÁp’i•|²–o¦Tš[æÆî8ŒfùVƒ:ü1…ˆfË3ˆaÁe¦md'ª’àxÈ´,{ur. „N³{­ºó”ß½ÓªÈ;ħB7÷Äá0™À»öbd[¿GbþxqR&¸Ê¯ƒÄHéz>æ» 07ßP‹{|Ö>Šw^IÏDáŠTl Dƒyœ§¢©å'ÑIl¢©E Ú˜±ºA´ÒÎ4AtRŽß¢·”Êu¨5‚@´?~‡óB¯{³%†† R^hÑ´_”€)=ÂW³%º)3F7?rH³K`BK À»˜Lß|JFÂIŠð3éðƒë„' űÏï_G£räݨ°È]Ç.k@4ìT\Èd /‡Ñ”»“ØÅ…«.ÈQÌöÖ¨ôn…ÆÖOg²Ö€I¥_báL=.)¨²ÜFV© Éo½s½Í«&_ÅáDyìoJÕ ¯Œö¨§ByÐ+lC˜úÄX ŒÞñrW‡ sc;M£‚ÎË)Ks¹«ÃA1íJû{èTšª6Wt®Ê\Â(5;§¡ù¦8ü:»’cδN(ü8Ô9”i9Ίי`ëìܳC0ý p Gùu`!8COË#|ÓÌéµ `±ÀÖQXš%œ·nÌr154|­\˜)GÜš³xUˆfyf‡ ¶€¢ÀG±ëÞòzÑAD”c/*R‡‚˜d>Tõèhä÷s\GŒº„Åef“Iª\ 0<¼Ö"¶iÈÅj) ³Ð¢]çÀ™Oô8nªìЖùq¬j8]&$ã) éç÷Óˆ>š:™ßEV f5 ו„#¿%v®dF9ĉëâ@k=2,ÏᎰ~õ$îAÀ.PB¬qÿÑéuúpRhÞ›-v­&FÎ÷öÂ᪲ÒªépÕ—™Ì®Ø»za2OоuÑN’[009„c-˜%h+g+“£ðKç¼BexM÷רx Ñhn©"±loä…„ŠÌ‚†9u}^FHòÛv-/ĵÌËÐzÞEòQ=êvRžçC£¡•Ù4eÃ}¨S}˜ßjay²\-NU! Å.ºo"/Þ®w¸EÒ1½,´n‘©Š»Œn`›Õ´Pv=÷Âdõ>ÚƒsÅmCô”®ôú¸× UÏñiPoÔÛâd‰¡1=+qEØ“–°ÌiÖ2«úÑ•ÂVví…~€]{º FûÙ5ùÕ-Es²ªŒ‡*š¥Þ"t<ýûyÎv»òX¨´°e‡£E¬U‡ã]lqTÒ×[Íü3föáØ­ËíϸJUÂfCLh-d9ù<ùäûØ”-MÞ(÷f(“p“ŠÈœR ¢Š1G'¤RQÙè/KTi¨Óo%}¡,'»æbḠâ2[Ï_¨Yk¯9å²=ð´Ð-«E[3õ”f€6S•4B_çÌfüy›âN;{Nçø²¾ô™t–‚»ë3×.(“›[±¾ójŽÑs“W·Î½fr³oöBÎéêŸÑHPèO’‹˜%·ylE pæ±±bå ‡ Öd´P’ã‘B‚@›~ &&_®uñÚìËëõ¢©‘W[8W÷Ä®î‰/ùΜ8/”¸•4ôtY…w ×‹Ý —esÇíËâhÈÓÕ z‡1Œ‘eÙ—‚PØðÖ^•OûBn ÊYžš¢ú—Z»â˜öòú.¾!5oÕÆ1dîµN‰99Õsãq€ñ`áT 2c÷C_‚¨_žü⢔ˆp¶uãm¦ŸOÔ{ÁZÕ*¶H†·ã7ï“|Eæó›éöLÏ#£Æ+ÉþõÔHÌæº" urÛá^ãÒ~×JêxVÉ•£ÛéNOØ6Þ;NWŸÆƒÕ¶w2ëW¡üQÊу>ÄU(òª«P¦ÊßúU(tX3/þñ*”ÊäŸì*”6=è<¸Ÿ«Ñ$´Ö¹õ2BŽ">ÅÅâ$<5 6ŽþšùgqÃ̄žÎsŽ—?l°í„K¸ÍÒjnP|Ø!eGnþÔ¯žI/øÃÓÓk®ž)ï÷ÊÒ¬yÚ1jÍ]KñlSñàzI®ƒâIŸ¹àå‘“DñR ~!à»ÄUÍ{m7_'®~›Áey²dˆi×$…æÔÌ£Á» v€ªAtCÛŸà$×ÞLõé«-ï QâÁî YèZ¢Kôÿ²å“º(×k¿fÀ®ºy…ªki?§³‘¸¤üšî\¦µ¿¼yôøç pJäendstream endobj 72 0 obj 5428 endobj 76 0 obj <> stream xœí\É’$Çq½÷WÔMÙ"*ûB™”Œ¢D£D£Ô2 8U93 gj˜.£¿!?€ÔI? Óóˆ\<"#««gÃÐ$ƒÁPÈŽŒððåùùõNôr'èŸñ¿‡—7õ/~÷ìÍØý ÿ>»ùúF¦»ñ?‡—»¿½Ã iv±N9³»{z“ß–;©uïßyá{¥ñ§—7_vw·¢7Jšè»çÃí^kÓ+ã»{z¬ê¾¹Ýã—!ªî7é¡ö&v‡á ÿ¿[z!•é~—§Úu6àDu¯M÷ävOcEŒÝ0>T¡{ÍžòŸb %­Ã¯–Ùøˆ— ýÃqZÅw_Ñc£­UXû×w?'¦¸‚)Öa€cîŽ`Ã/1^+•ô}ðvúÝțִº.F5ýw*ñOsZ©±e+óàîG·w¿]Í—~†8Í÷ "SjçUk>×{ïâBèmæGšsoâµ·%¯™¸fé36²Noè5­EP®ëÓ)…Ì$YÁIÚËèû¨ýn¯l¢Î”ýým´=frX3IEˆÝÌ„y»hV•1$m ¹ÝOhóél÷"`U²{FC­ÖÖdóÏoHs´3>bËàûçôŠfT‡Ö6ÑÃÖn *ô:x¹»ûÅÍÝ_~Ùý,M˜Ä‰Ð$Ú á2F¯d÷OôX9ƒíî`VVw¯9Ã_‘Õ ~›ˆ²aV\EOÃzÓ²D’‡Ð}—~Iç1Aú³t¥|ï—ßÛò£cšwõ4™uÝ(^­¼KÚ Fé@¦JÈîü:ÿöQ.s‚ÐV]èŽoÓž‚Š¡;1Õböʈ;Ð{0HH"³HÇ.p¢Ÿµí¿=u½ wz–Ö×r -ZK¨v<ó¿ ¥rK •qRƒ:…êôõO|ÎÊ{#{å[âš+„õ^“„NØÂ«il[Æ´E-tCðç…a§¿Ki»ŸÎPÒ}½¨ßyV„Ñ\†–^ º>ÿÝ.?]¥Ôßd¦ ›p€~* ¿Q¬1¹…oé\Aà$¼Xæ:_ÅF…­ë ÑN– U$_“©aòbéñ‹i‰ÃùŲÀ¦FîhZŽ”n®·2Là¨Ëºìb`9 ~ÑäõbªMÏkz‹wÞÝ¥9An³åÒ šÉ¥ €\‰æ¢KÓN¹Bwæî çÙ¸¸,f1µµcp î.¨Þ[_1аUhÚ‚Z>…ø‚Š•ø‹ýíÞÂ;#n!MG ÁóÓ¬ ~9ÄÆ•°O{5*Â;- øªa:C泆]DÂU ¼É0öFö&†Ê*0§7ð®½ÚcÀëKþ³9žöñlå˜6}Þ@¼€X²Xuøzñ‡g¦ƒÅ&•¶åxøÛðÑcÖ½Ô¡G–ð€mÊØ+¥C‰µa=ŒˆÌÞ hpeœðÁÃÛ½‡+Иî'Y²Ñ{ž¯0%çðŸ=¢_þ”iVáV c’×îÈFpe£ûl b{ác6…•S¾½µ°dQÁD¢)ß²óß´$”ŒÓÄ……4zd7ðžSšëä÷؈§yŠ4áiãἕ^¾_r@Z‡ˆâË3ì`Ó1Õd;HH‹í"=kó‡ÃÄíËMĵÔ[!àPÞLûϤÞÎðZê{$AÁ¼‹É~•é‹éþÖ‹0ÞÝý6§&ÆÙ4_i”ÌœFÝ € L,üÁ9.…^qkøÌÙ‘[šþŸÈen‘æ©Ù¼S% å&ù.ÕÊŠ]´ÌÕ kÃìÄ0¥õõüšD¦{[º&n„ÇflçâKýmq}`õ0W½q”xîgjkÛ4ˆŒ•ÝŸ¾_|üÐæ€5H®_Û¢ *¥BM•ëL¸0}J‘¼Í”x'hMÖüÇá›üž¥‚ÔÔoó³ ýŒœZC7b­ãP¥4Þ8S¡bšEn-È ùÄ™y”óq€HáCp”QbC^I*Ç_†I'Õ•)5³£+‘s‘&E­Î·¢Ö^×Q«€ ®¨6¢Ö†Í«¼Ì3{¹NëóÚß/‘UÂ஋ªwèCžNAtWþL)K ËÈWx`¥y?7š+å8å½ÀŒ°¯šòü˜W?GJœœ2è$c.þû¼ÔRÝ”XbçšÌé»&¯OÏ Ô›°.Dx- (ÚÃPùFÙ4íh»¤H`ÂEt?6¤íèÐqŒ`r}%HEgº ¿^J …mÿÅ"Õ7yf‡l¡ úu+ÊÏÚxšKç­ØìŠ ±IúÕþਣ-©(41í6Âÿ- v~™…ït¡o[å,„ ÆPBd»»¥Â§Æv§lЛ©RS¯Ê’êœZ›˜ò¼½ ºÇK6Ù!•«ÂÉ^ÓSªÅJ’Iå†\Q¦šæa½g¹¼É*{Hh–*~´éK…ê+#Ð@å^u}*#2¹%øÜ#PlБ&QÑ’t„²Êß0 9pÆ0vq=«ÒzÏBhLg)‡²V”žê"¦Ý(ó±%sZ{„ŽUiYYS…båêÓÓ$hÌ8¬ÌšŽÖxÑþùt†j”S.WÜ5¢©ãÇ©¸Ïéyp??NžÁ¾©+9UEÝPeV”¨S¸?ÄÔD§®8¡÷ bŠPƒi6emáÊ茦‚ô•jŒç¢y¼ç%ÇçóCÓ¬÷Ô…ÆãyÚ<̉s³`—ÚuΧ5|’C¢‡/fZš)K œG˜èþ{<¶¬Ât«œôѲ¤S\7c ÀþûåЭ‰%–’€ÐÈÎÈa¤úŠ A ‰'ŰÌàs~‡ÇV˜Ra™SÙˆ^§3uèÔú`CJÉáÇøÀÉ…t¼–¦XhÊJÞ8K¤ã–p1Uh{¥‡Â‹_Ô-t¹Ûƒ¹ÐTõXu¸Ê±´”A?^öÊÜþ¦Ý €ÀÙ+]ª´²;‡ >wÚCtToëMÔÞæ©%ù=iE›CA½p»â•Çí^PXnDhMoS1\¯*8y¬òeñ¡EEÐý¡ÕkDÚ>È=ÔgÌ]’¼Ðrg(‹S!íóû–ÂÂ0¡-Pm6²€±ñ 3ýŒËÏbu„Ø, Ù@HÓ,ü„¤8­27òcꤠ¨é¢¼…d°±ë4ÕkawÅ+SH0Hߥ7 Rã"lËD•,Š’B€ÔüŽ|ßH¼¼DÄ¥aüªžÞD—wÖ5kzÔ[Aí5{öÎf#ŽÕK¬úóÜ·"½ö4ïOïn~…õÁÀïnT„£u~­=–{y†Í^ÜüëvçV)ò±s SR²3H,m–:·¨ÃEÒ‚m3Ã'ñL³&3Jë ŽŸ@bï v Z&¦0%USuPG³ÓéÖ^ÝËt¥4é@ˆð(i²w®"å“;ÁCs^Oõ$ѧU©Ç^`ʆ´; øsktÑËO±.«&8}’Ä.eîV_ ×£ø ŸÅ+´-âZ“¸€ “Þ+™„ñþj“ ÓWè¡tst Tf4Ñ.€n†&ãƒ÷@:ÁÖêÓ ÉcX7¡‰Í¦ñÿhòáÐD>«ø>‘—fù‡Û¹£qxT†Åñ¡Hr ƒ̾Ý|$ƒT=|Ä&cO+=šù1)ZÞ"¦ê ÉG§¶*Ýøtð²n'htM5Qžö·Ó¶ñX[WÝÑU;6FPÕÐ\åúÌqãø+ÿZäµáᾤ¦Ì {Úÿ4ctÀˆssµ²ÔƒqjTø¥ÿ¤ÌŠTî„Ï«ü¾eŠ’ÚˆU¸D”ÝD7‡†Óñ¹ÔJC]ÀƹÆ9ÇToÈJP<œÛž²pTй/y¯"p&^Vsû½Re¯'¯½=`¯YµP6çÐS5duÀî.¨+OÎL¬||?6É#Ò žæéAy.@O¡kºü¢9q.ɩƌ/uQpkûqQm”$"õ7”Éã§)àWtÕ}e&ˆ¹MC,lÈA[ì¼E;hSŠºJÔCPä'N^ÛsðáÊ,ïÚçò)e*£Öœ­‚UB.'(Q"dG8˜JÿSÈþÙŸHevïW8Ü .>Z¶õA£ßG¨ RADó£¶P±g7•?£Bè)ÔÚNKú!ÞÊÉ‘ü¾•U9”,1ÍÑBbÓô¦í•}z<òÐa}l¹êšŸ{‡Œ¤?Ôg·1]9XwÍ× 6ˆx0=újU~ñcôæÚÕ2å5•yƒüàòÊFÀò¬»?x£<àŠÓ(’ˆTS‡LÒ³)l¶­×m«Ä/==•í9<âÇÜF§Ì¡uÞ^6Vá8Xœ’¦§®'¹”'Û‘ ¡;9:†Ô '›ß•ºÏ3Ó]¶v— SÅÌ’©;õ~þ’fˆÿåvÂI”jëZ÷7 hÆû›”ÌM÷7BYv¥ ©]Ôª÷Ææ"M©Y MmVWË&~ºÛN¨¹Íü.µ!aàž”`¸îÊ´±la™½•X&nˆ­î¥ÏkXnØ*»þ6:BY› G9 [ uwï¬È7`#9[Þ)Ê—,Z¼08õ;m¶^e:B¡hÅ¡z¶Bð|Û5Rýkcº¯jvåL”]N³?¸g¬Ç6¡ˆ—oš¥øª×4Ñâe.Ní 4X‰ë:üÒj¢õÓ<ƒ¦H‹„L°x¹B±ŸF—=Êéä»#û(+ò÷šÀ¤®#P¯‡5U@Ê5úYÊWçh¨¼Fþ¯W·‹ŸV±›ßõÅ×y•ê†åÓL»õµ¿D»¹¬™…pM¯›R3i¡Ùè'OÞä%µqäAjµÄèbý—Ë㈵6ÀN~½<þb$%ø"4cדI™ xøT©âEçêÔ3–ðzS:â¢5h£¯ùX4 ¤^5ª<ªî|º fÉÆy¼ÌxC0(CØP_š^Õ)]Ù!˜†zê)jÕ—›ž„åZ_fjŸ]ïm*øò¦~ê±²ñI¯}w<†IØ©Û5ýŒ¡¼pÐn³gNüyn'KØ“gAÇaºL¨)š«Ë„­ÏR¬N’_A}zzc|g¯sßZSk!6=TÝð̬š¨ù½ˆ¨ìɬWíöÌÓaø"“dDùÕ™ÓÊ*jèüÏú*8ÍblYò]Vz6îFAáû´pÖ å¸‹'çûÜË ¹•­²Cyá›Æ˜P„¯F"¥Ûú$©ßÜ¥_Ì>Ñc¬(AºÊZ© nY[Y9êäfý6êÙPãÒ¦òbÕUmÞÛjx< —?a3}¸&G»TQÚ{¸Çómý)™@·¾Ó§k¤@P²õšCUóp¨+Í$4¶¥»¿£°~IEþQ›Ó휠äÖ(ŸÇeêã2"Ó!]œ>†“ˆæܹßÄä²^fÜØ£¾‹S·oG:è¿x·v¹-JƒCÙF»¤“-¬¦ëlÁÆ?£¢£‰Waª“ʦ[‹Œ.¥·«7VÇÑcàÌ•—×’¶É= LjÂÇdñøc/~$"”^UD ¹K(,–£n’ò¼n•¸×9ó‹‰õÄxZžJ&§ ¼X¾ê2;Ý¢#´yql„ßõűä:®ÐÓµÖ`Ó]U<åuÝ W×^wKƒx.¥¬Óþ‹Íø@·y~MaÍFÄ:hâ9Ud$5÷øôyÚg}ùŽ|xÐËOûˆñêDѺHeÁªBY–L†rG>2¶”3Ì—(ºqÎE¦‘¿-c.Þ¤¬ù×NŠüÒ™^8Þ¥R}+ÉÉÞoÖ‘Ÿ0ãä±GúÀ Eþ–—ØX™Ž‘›ò4ZÅš†´rEûÜ ýº˜?Pñ)Ï8Z‡ˆ/´úÒa¼—¤~ÜÕaFkqƒØž}'…¥.—?p€ òŸü­%˜¦l”T§»ÅYT[EÄåçF §\öt™¶©o.í©ýQZÍW½é¬ÿÝno°0Œíб`Zj®üÕÍÿ® Ý¿endstream endobj 77 0 obj 4510 endobj 81 0 obj <> stream xœí\Ë’ÇuÝÏWtxÕã@—óý Ã K–V@´$ŒCvZÝM2§1"f,Ãã/°µôÚ?æs3³ªnfe5z0 ƒŒP0è®ÎÊÇÍ›çžûÈùãF r#è¿òïþöêo~ë7¯Þ]‰Í/ðÿ««?^ÉÔ`SþÙßn~rƒFÒlârfsóõU~[n¤Öƒw~ã…”ÆO·W_l_^ïT„”r{üúZ J£Ìö->­½‰Ûo¯wø,dˆj{¼Þiô¢Ü›|C”ØÖä>}4ÑÛ훹ÁéÕÔâ÷7¿¤™;>ó€ùAó¿9`®¿¢™ˆ”ª4¯*oíÔüËmêÜ©^×z.F5¶¥9i%–þ·×;éìàƒÞþ”Úø »ã©ÁÊ8w]ÆÛ>#1ÙÁmAh©WÛçsgÛ¿GKƒ‰./J9¥äVÑkjˆÂÕB—zÑ"(·&ö±VÞu%iaóD·ÿ{}ó‡ÅZÜ „–êÓÉî_ðTxm¥‹]Ù¹!ÃD‡¥›ÁKË•æt¸î¯Ü`½/«ùso5fÂ÷´Õô¦­£Bµå½y¿ËÇÄ9³ÍgÊ:<ÍgJªXíÜ7£Ò¼½ÆAÄCµý=ÂAŒ~˶uûÙôRo;iÅ´Ü씌Sò¼×|8åë©9'dÙ¸íÿ•Ù×3Šƒ8ånðùQ,óg7W¿RâþéJ… ‡7.X58¹¹½Ò.*t<=ùæêÅ#¡}’úô@/3´ßÎjÄtó?H!q8Œ/ò×dô:ØÔa¬Ža3êyZÊs’†"¤Wô™¶èæùÕÍ_ŒÄÁ–K–÷‡CCУPþŽÔg×iµô"”Öw7ت 6DAò}¦×?§W°ÆÐ=›¶!² x¡¯•2Îðù_=]K±¥?yÖ¬ÈÇý}1iXü ÁÁ £Pº«b§Þ@y·"pGãëüTW¼¢©C÷œ˜^%ªh¶ÿ~mí ^\4ÕÖªíçÏ ïã]Õ3©ÏQÊ¿M³²àû]­óPޱé3‚ÄZdñÒØïò }h\­ýŠv8è h™•¸rªèç@§Ž/‘õö*ÏÃVìòŽIf?ŠO[ñ6Ï3ò눪jI‚Å'ðÛÀÙ-›Ë¡ÌÅ„Âoë—Ž|aÿSZ8ÍðìU}vÎRnö†¼Ywë¢Íþ]Ž%Ð'ÜñÀÈ‚ÔükŒ×¹ÛßQ·ND9âA¬­&ÀšÐ€nªØâ¥é øÀº‡¬äÙÒá5¯IH}NØ̶ÖöT Az{*] ¹ >nð¯Ð6ö¼•Ö ¡ ýñA%Š0>ÆŽ( ,È=Iêžzú®l…$´mSõ[ÑÚŠÐÍA­Y·f”Œ¤ð›Æ–G]lË?¦¸޶µ„HØÄÁ[S#{~+b¢b4\Û=AƒP ïÕ~vï=†?{´PÙydŽ9è½äßÒ€à¿Mšœâ:1ÐÈÞ:B5Ÿ‡Ûü\ËØ9š8èŠ)b“ŸƒcÛ;eÇSž›×˜zƒ!õØÅt4k]ƈjÜR–Ð$nÈÚ’B§mü5õ$ñŸí¢Ž ’ éŒõ#"Ô0‚©f‡ä{"„1|Ÿ0$¿à ÿ.Y+¡æCgÇC§´îGVÏÕA¯Ùöt<šíÙa"™”C´e?¸96P/ Úp›f"”ŽÑŸ©%Ó¨;ö;{LŒÂ@+)òø2+ÈÃûÂkix??ŽY¥ÛP_ZºReF”Ø`sgG‡uÇõžµxŸ×éeXæÚ÷ºaT,}= ]88çàdî@úÀ› “•„5]¥„•M®võZ‰Ø àðñƒ‹ l‚!½ÛÞ1Yî'aðÆ~?½Ê’2¡º´GRw ·‹¬É\œÃõöt0ÉìÊ脱œ0NS¼w‡°T³¢ùÅ$¨'”°†áûë¼¥á¼Ë¿cQE}˜ïö8·-6&(M\•Ú˜Öô\Kì ,Á‡õòŽéqÛ47¡sÏ*Ÿ‡Ù}´kÓìTÆ.LV?¹\dÙí@ÒÁÉþÄ&¡zLØõà¬}WÆã)‹JðþÊ¡ÚóÑߌCòws Ÿ¶ÛlSqd+æÝ³{ <Ñc›Ÿ²Ð˜‹/æwu'âÔÛßÏ?ƒ6G2Å|Ž\„cwÊ·§È{z›?KÌ„ œ¾° ]á´v@ ¡.tïJ5žÊLl\C9>ï¼iʆ§Ñ•j=mêMãÔ«ðc¶Ý@pžÔdBÃãÝØ}¹¢ÆØÛyȵ1c ɀͧ¨ÕEñ«4Øù·=eíræÏØúOz=Ëã±VåüŽ}¬€­ëƒ^ÀÚ²F£‘ôþmQ5Þ…úäƒÁ>¿bpºËŠBþÂ6ŠÉíe(ÕNÙZµp‘Ê¡Eéd£k z‘vEß¹7ÛÃ…‡Ã1A~¤~™ƒDtRŸ)š©^qxÇÅ+2å$á5lÍe FÍûFðÉ¢ÆlP±[ZöÑ™å*ÉŸ:°«§C7ê) zÄ÷)Y£ëðzEƒÒN“äOÍíÍÅ«»zF©e†—ƒÓnûå— ¶«@G_’¬Ÿ÷³±ù«28ì˪X¡ÎVˆòìUrµ§7lMº0otd8Ûµ¡GNLªY§>b° ²/#A}“à˜Öò˜e‡€:ÔÀs}iè3í~LàH‘E¤‚†u¦ÈMtå%!Ôɉh“Í|¾ÐŸ¾éc‡÷õ5Ü H…Åò©Á˜ßUîDmù“ãÆ^©2ÓGīĕ²PÎûê1g®Ù‚Ucßç§ âß7ÌZQ>³òG²5…ŸÚt´”uâ$Gn¨y\²l´—PÌ×Lƒ¸(…ÖJÆUV‹\§½ó˜E8·‹Ù|Ÿæ$õõñ”{0",¢SŠ.Rqž¼jxÛûýÃ9ßE¨Aº8ÆÓ æ÷yYE³ûtœHuÖ}œÂ‹Õ¤kŸ•zö±ÚÀ”;¥Å*Åå‘\c&(»Â<«ÑÚÜ-Ï]Z4'Ó9ÄáxróÍ)÷*tIïqaÒ–H’”æ¤W„Azù=QÃOFy98UYÝ™¶0G4Fø®ˆÈøzšt‘‡ óÒNÓ{`ë)D˜ªž-n¢, ^õÌ•2ùÂ81ž§Öÿ!MÆ… ·?¹&Éz‡þŸ×[™Jwd’ßà½@;·x¢ñÄNO_¼ƒÐAê R.Þá˜Ê3mŸÏ°[’ti+Z—2òÊãwù!Œ&ű*N/%k óWpúríÓ‘S‚N~ë SW¦ªˆ]Må•ÙÚíϯAg¼õU|»R8žÆø¶¬hêq³Ïüpý¶L©³²Ì´²ÀöÊD9Hßq™YÓ-oÀ@y‘õh#£IáMÒøØz~0H† wV¼½cnL‹­bÞdb(ÇEsè(LXŸÕ5F‚o[h¡RCØÆ‹ eÿ¾¼ó²ºyÔ ¨ŽsÔz¦•×’^‹Ò=²fˆ‚É*¦˜97ÞE’< Ü úx²Îf—ˆ8 mÒ™:ÖaÁyŠwjCX´@̨‰Ñ®¸š(>QHqÎYNÁ{¦ïhKÃJí˜a¯UæoHHÓ\É÷&äÙˆóMÑØw™q¤ŽTÍÉâÎŒ1taCEBpùçÊŠüOO>¢ÓRÍF¤ŸÁüg×…þõüñÇu~yäŸ>Ÿ1|( åj .R ¹ßáЋ»¼á›ññÙÂa5¦1==öý¶ÞýÈ­NÆCSr:2-cÊÍt”Vç§4¥a—!ŽÖ9zh‹"v2W_5q彤[R+u8¸ ½ «58Ÿ’]š`—†bö@îmU'µ¿³)=L¯Â‡`ø»¹¥Æ>‡ªÌ1¼¾Œ¤Üãù¡´þøÍˆÊ?V<Ícnêœ qœÌ…¢Ï zŒ° /,*v“wÙT'‰á7[!úÌL2bƒ‰†(üçqeÏd_Æwž¡U¹P—ÓZ’- WS’òÙ8oÛ ¯¥À@RcBÄú tÚØÆwè±´r黨U7^×3VÔ…wüva]Œ¦l[‰ ICž¦ºÜgUÝÙéðߤc.|P¶_l£WÆÖ0Îø4ºzF9˜ª¨áTŸ¿" žØ3IœÇUè|ÊÒ &]BË$\Ÿ—œ·ªÙ o7Hb÷:uŠêëŽ$×àYÓÄÔµÓ"CþŽ&é üÜ6ðëTʳO9™s-9gk :¨;7‚å2R›Ò7ÈhpXÉ7)i‘_„oñ¨zíèæ`u†^O<¼þSúL[v3©qä+Œh]‚ •³–•‰£7amñ¦)xx¼„ÛÝ”{¡ûà6´Þ„N•œ‹PSÉœ¾n×¼Äìº]‘Ò®rHt7ï÷ãбMDL°ŠÔÒè„ãPjì´Œ=©+-ÓzC®Q­ìe:ž²}ÊîðªMÚ+ó^Úº!+¥A¼ó :Z…¤k9ÿзôØ3¿PÆ‹ŒÃÚS 1l_¤ÖÈu×ZR™µ½›䎵W>C} É¥˜š¼JÓˆb,#¶¢©rÕî æÁ¯h@|RèöþMÚmKwÝpœ¡ ±9õ¯ì-šƒ‚›g\ogi´=ûoð u¸a»És gj?ÐIðÂí6àqJ5á4Ýþ÷)¥‡|€‰ð«‰ ]UzµB:ÛÊ!ôWmÂ#ëÈ+8™“‘Œ’“‰ϯ„Ú™´OEÜJž%VÈŠ @­N O;öå®Oúeó†tòœ‡¤zw8Õ`­I‚;³‹-'aAóý¢Ú?úcuì&ҲȫˆÞ—¦ØÐ»9œ±‚U¬þü¼økD©L Œi ÒÌ"NO›/ ¯uÍžQA©1{^‡»¨¥,«î×nL)ïœ`Ž"_o€L¢mr6æ{}_åÒé®(íR”,µÉEÙêå›ûÒéÞ¬àA€BrKÌ+7¸¨PÙ`Y¾Þ¨wù)°††Ës>M‡ÜD˺ö²<f=™Æóu©öÃK4÷ÕÖO[Õÿ--6Kç¶NJö#Eä Óæˆ 0*¯½V3èÃZŒ–k÷«²LÛ–©ã¡ O†Æ”/NŽ©p«-;¦) W6·¦cu£=L1›Dàb@rT‹-x¨C5huÞ]'re8Ózõ/g Ù»À ²*¨hâ¶–¨ÂjÞý˜{ðò\à«‘6r5?Œ¤Z”Xñʺe ºnºÊ¤1QãY’¼‹Ç ¢çcñV¥Ln“hO«5Áدd‚&a,êtSSN-½r¾Ýû*¬¾?KŠká}]X®=W)FŹº1^¥:™Çaî¹2ŒzÆ1e¬2n.°ÜO•ê³(òEÄV¹ìj'æw—f)+ì1³Ã~3 ŽN/ê{v¯+iv¨Ð”æ0œ£ì—‘­…Y}(ú~ ·EÇNMü]×c;køÖ9D ôèTV_{ð;CI¸ªD³±y«÷-8ã%ÝÇt¼ïÏÜ]X (uÍ"ökˆÔÚË‹«ô å?äÕ:Å`”PŠåp«jªB/¡»'P•fϲRL{VW ¦¢ÑúLÓ_ €‡¹ÂBÖ¹%ÝU‰ð|ר5“á¿F°b'(pBw¢ðæ?_OY®Ó‡òsñ©2LãI¬JPR´Y–+&T÷å>È®GÉpÞ‡\PãÖi³1]œb­§`Ë`’õ\õOã>UÁ¢SS}‰V©Ëp* ¢D[6Ö±9]µh ~.„3ÎÑíņ®È:JßzÊÔXš§ÒÔÔ»«/•Þç§^øtüè£ô]|á@w-…Hd…Ûî'vH©çÈz[S Œ"g}àHåvmmuæ¬$ÍG³²[?ZFzAÓR”$gí.£(tcÓÈÁB/ê´ÑC\("NâÜu†[Tœ,¶RRS]·<;…=¥;ŸMkÀ€FPtsýSÇNhâTÛZî,jEF ú# ­?kè:…\½ä•®`Ú¸ö‡Sªí?Œ½-üEz*V4EÀÓìjóòvžsGýÆbѲ7¯ÇÁcQêÊcn5!ù[îa¬ p+\õã¶lÈš€9þt>égý±ÌÇÙ<Ñ‘î»_` 4Ý„Ñ ûê©nyO”BŠ@y“u‡þ–"ÔîÀÿy_‡¶Çëhïó|µ‰-! éúuoS~£)jάlbàðÂìÎW%¶.Ã……k)aªê{·S´>6yũˇÊê§}…ÈyF‹K›:|/º,²¦â69ÙŸ•š¼=l@ ¿Õ¢ÒfÙþ–Á˜ª ~sõÿn ‚endstream endobj 82 0 obj 5252 endobj 86 0 obj <> stream xœÅ\[\¹q~ׯäét >9¼“ò`;±‘À±ag€ÒØ»ÓÒJ3YèOÙÑUEòtyÎLKêØX,ÔÃæ¥X,Öå«bÿx3êfÂÿÊ¿‡‡Wÿò‡póîÓ«éæ×ðÿ»W?¾RÔá¦üsx¸ùÅ-trÓM“×ÞÞܾ}•G«eÌ|¸ Sµ¯^ýqøÝnµÓvŠÃÿíŒmn˜¡ÑªÉú4|Äï·!Á÷{ E§‡?áGãtŒŠwþ >kÍdÿ÷ö?eq41¨›Ûß¼ºýç?¿ÄqZÙ†÷øÑ˜`Óð~´Úh?<=PI5œv{«Ô˜œ>ÑÚÆèà‡»ó@ÖùCžD©I¥ËÇÓ»< ÌqŸzš ˆ-4>ît„FØÞOôIy¤Œ†Ø¤Äºuøü7»½z›á?°تœËÄë¬:¼Ÿk£þú;Cߘ–íMQã2{;¥Ñǰµúkè´z Ÿ1ñ4g²'hþ÷¢•‹Ãü9O—T>ìöÐã*"ìx‘z‰CáÖäá|XÓ1O å²4¨R9 ‹¬!–ó|S0çþüÀ¥’äAYü…‡e\ ax‹WC9o“˜â=—ÉLthÎöBz³ÄÆ8øŽÌ^;öe^½0ù1M©=Z­½B‚8‚ÃûÅçDϪÑ(<8iS½ŸÊ¦—²4M.ÚPÙO©žs‘F¥çÞ³Òèu/‹™ðÝÞh;êÔÊ¢ÑzŒFˆÌñˆç‰_¸)'~ŸÛRL’iFÃÝVîÚçãGÜú-õ4ÉÂ-™¹˜ jó,êö`ÁÃ]à  YoÎ÷fS£ŸP®ë¡êi#sV: ™;v„åʦë½Í«é¡».Ú»~ÚEý"5té]áð "rÖ×–ãF¸¹å •’Ð*ò ðWÕ*Xl6–KÈ£‹^BCMé)©ñp¥üášJ •õ¾“>Þϱ»½Kœ …¾‘al3×–á:ŠÎŽÉÆx³_.ùüŒ?óæg UÉ’­ÎRƒ¢èÜh&П‚²=ü Æ9q޽ÅVpeÈþç!6v;Dàigç6ä†vÜÀb ‚ð°A²ÖO ‚˜èœš_ˆ±Biò£Š&h/P£‚‹ù—ùÀUˆó$( Õ¿°) J@Úȉc‚›Òd¸­Ÿ¹U;±ûOǧ7eëé˼‹=þ½¼ø(5œˆÅ„|7Ô®§¹Sä䋳+ÛêuhôÎ𳘙fXú e× SuØ Ëu…auÙ°¾*ç2;vÿîw•›—‘"­Ãw»B”q|þO…*æ/s€^ã@¤w\œÆà”œmãÌOsYÿ¼+’‘{&f¹DÌ!B9“è4žâºóÏÕ™µºFéÆô4¦„zN:VŠ&HxJ\9æ9œIâr '‹è7)OÊÕø†qø”gŒAšðÇÅÖ2Î̧²¼m•6‚ø¯=æc«\¢µV­ŸLÃuú&]Fìé–K`ã|«C`50ˆ_£CÈà(S}†—”G™Ëº)»a`ð¹Ñ¡:¤BrT'N‘á›/Xk¹Ö¹Hg@L=:i¢>æ•!vþÿSy Rž¶Æ´#~›íÄM*°0R!'½u%BÔZ×Ñë&>D½3Ù1ưvú ô­iT£wP‚ ˜óêo¦j~ ‹žW@û:LØ®/WI蔵ê6* [AjóÝúÁ,ŽÞêdM0€A¿}X|¾CZMS\Ù¸`àrNêë]VV·¯QcÔŽ/2ŸÄ¹­Ÿ F´®1 ,îл>-(ÆÓC6Þf~,ZD5¼ÂFX‚IÑ]†âõ`=Ám\."ר‚>0 …âp^:tÈN1ß•o5¨9L5¿Kï95Kë)ô <Éí‹‘G­‡lµÞw\BŽŠ2 jaý8™°³žYónY3М„?žÞW)鱃æ2;ç&‡qG`O !. gó«]ÅèâIªÄe$o^·¸Âåyr|,áNH{hÁ)šœZßiFƒ 'ÉNÒBÞ³UŸ˜Ö=æ=eZ‘(­/›Þ¼`TÒ­-3جtࣙVTD¨}ÒDÓ¶«×®&¶¾eÕ«ãÏa›¹„)g#MÍüx3ý”^xÄ{]e/ÛF?|Îa€özË9>ÎÌ™g}øHבÞo»Ë:ðUs WlkWÐa‡«6:œ|b"y*s©ìº uî(ùÄßeª•Yþ۬ȄZt¸ÝEƒá‰¯Ñ–’6â@0D…vÏŽ!+øWz ° %éORlu4¤¼¥B`x3§®‹ä–š³ƒ£]š¸OÆ¡RÌ—qqcöƒoâSö޼×#…ƒk)XÜtø vGáÚ¨VACÏÈÄ Tw›¯š÷õ¥8BY—¼ßü—ÆN—z¬FŒ8¡—óšqÇ£ô%ÛD©v÷,áã¿¡cfÓˆçã™>M1‰4èìó'è‹èà.ȃþb‡Y&" Ø©5"UÉÁþÁKp2ÖCªfÒ=OŠ®1Ô‰RbÀMP¼p{Qƒ5 b×5 ᬣ‹´Ó†¾ aXEKq1+BÎÓú†|Æ_»F°š M|‹[›TƒŠ¢Á¿Èé(8ï ׋Uü10 0U+ðaB SŸó:ÊÄ¡s7i‚Ÿ ¹ß×ñÒ_fHÍý,âèev÷1·¢!mluöÂíp±œW wààÛ¿ÀþÃUßÓ\ø+‘ÍS]A<>>,ÑÃ}é`õ3nÖc#Ň“¶ty”€Ï+ÿ©nÖ5ˆ\^>\QfÞ ìmnMZœ÷ Î(<Öçøg%h¾FÁ­CXã­ñÈ[êÐ( 鬿kÐÝ'ܨ QO"Ém:Õø}ЦUqXØá¯SF"ôŽ"ÒØÂ%2o3‹”ˆÒ"ŽÞG ËÂÊS´Â5b«ô`%iÁš³pfj‰ÒÎ4Ó­9ÞëÀNA%9^GU `ôÁÏ¿åÚ¦c¸ÇËRg¾=×:ýL"'W&hÛ¨lµ°¯BZëºSjT?Îjbº,¾*õ U­miu¶ÑÏy’Pʰzƒx–¼RÂ’âγNkÖ¢t Ö ‡ÁA¨°w‰³â6K„WdµÀÁ›‚©V«´ÀÝ5û:D*ž‰a¨û†9Ÿs¾Jù(O‚rõA»ç/=ÓGîoë¦ÓÄ-Ôf”S0×U,cF‡ üB;=fjî³ös£î) „¶Ù_vŸòTãjîØwßµÚvâôŸ„¡ÄÊ3vÄÔTæå¦š*“u8K—z̤cîû"yŽÝUÉ›;)Ë_ LùÚ'"/¸Ô$A?AÀp*Ð…!%Mí |É˲")Ž¥tȬŽ\dq‰Ž@›&E˜3ºß$.8‡íà²E./—êÙ3ÔÛ Œ^Kt:‚ 7Ü †5¶zœŸ“¬Œ)Ôt°j"ój¯,4LŽ Ôtã`#Ÿ£ï„ÛCÔÍXªFÁVð¢³&3‡ÓMFf‹ÚI9ÌǧFÍâ#mØü#]µ¨Sž¶d‹sDûSGŽ7ß‹Dú²¸(ò\#/À©Î W;w›§O½)Ã[½uQ+¬á–·ùÔ¿WÝ£Lg×.›9³ŸCPҬȚʦ\–#导Ðz䎑÷'žL[³…­è§^rp *"Ìûkš‚pÎC(ޱ4SæD´Éÿu6­ ‚‹6Ixõ´q:Gp}Ê»1²öŠ™É wÓb.’‚>gD¨F€H]T¢0³Ï ÷¹Èo×Z5>ŒNd¯®^x9‘X¯ á.jíÙçiÎ5±`÷´jÔ²Ü @+ó7¼æõSÞ²â"õ>·¡€7uÀi :^¿ØQ=Œ¨.«Áe¹+à˜·ÓJ ë$‘²/Æ ªO¥­®>U‹ ìë÷û¥*§uÝ»pÞ¹Î[‡o(´” jdÊ‚2±Ãí¶Âú:¥d-`Æ9Î?ž>{— 2\[3ƒ­`$®ž]w[=cÔhû`8em×fÅÃq0â&Ò_ʰY2]~K –úñ<äs&˨úH¶X\iÀssjʧ”ZédG´´Ž?±¤ Ç%™žýY=Ú®ˆ”5árÐއŽÀêi9¯ó@Œ¦ÙtŸózŒ®€AK‚ísäm›Ê¥ rP'"ÌÎj-ŽÊX3r3ÀlU·T ¬Î¹?:ö6-  QëQóxu›\úËJæž¾ó!$X]âC_UçÉóy\åBÄþ‡“ªý©-ù–¤!žßJO $L Åm¸”ùÂV·AÎÛ<È9QLÕx©Ûr–FÅfŒ>ÑiÂGÛ©.Z&^?©”ùÔ•C+®ph‹€Úê2àLgä,?¦G|SwÜ­ø×-®êÁï‰]Ý»¶˜ù!÷u¾Ím`ßË &h­¾ Ð#ÒâxvŒ Ð[®Ð®.»º‡ÖmÙtÐmf_àpm¨À—@„æíx¸fÉŒ×Ú2Ü«uÂ*Ýs3ÿ±“³k÷»Ë¹Í,ÂëÍÐÆ[C)çâ¡ã¹r-½’âÒîJAÖ›âøàl+¸¥S-­%ÛìE¶y2ÄÄê§ýëyŠ[Š&»×ÓÔzTÑ¥:p\N¬tÖ7Ä*§°3xyÀ'{ƒð@L*ùångïw˜5w "Q‘ò_K+*nЖèZ!wÁɈ‹{<¨»Ì\XÑÀefÓ» # ³l>vvÃÓùûlŒÁ¡½Ûã[g—+=p. ‘èàÖ”Y 7η¹˜ïqP£Q û\:Š]ëÄl¬0(‡Tö¦|\vám©KªÍl ÛýyŽµÒ…¦¦àïøª—ûínÁZ•kÁ/Nʵ [¡rW?tCWY„==ÅÜâ‚o ŠoXxÌ•jH§‘š\1fã¥Ó4#™ò_dž ^ÔÝþ4ˆÎeUÄy±®RÈbd»J 2rí'ÝlMþÏ)Jõ»öüBœcï;wÞ)áO„ìjzñ÷ù¼ËvÕy¬‹¿®y«EŽqÕÃ]Ã_½(°Ùà æ]¼Ú ¬ªœÀ‡¹²q~ÑÁÍH4kl¿¨Lb+`ª1kRZªqåÅÁcÁ7a_m0Úé‰2ü[YÆ%4èŒ-„c­ŽcIjп“iK7~c¡å‰ FÅ/¨°· ´ß²t4…Q²×ר ·$Ng£µø.‰²A>ñ¿„u& ÞTLBv%æx6R§Ø¤À÷Ã7¿˜ÔI;æ¶ÐÆ9P6±ûuGßþ†òt ›ïE8þJÏý^ø°é\úo1±ÜÅ“…ì꿆”9Ý"ªÂÌ9.¨$ýýFû–¦W,亅ï^Øâ£›¢d1Ygk혌.ÌBÕ¶¿XgZ> stream xœÝ\ÙrÉu}ÇW´ýT°ÙåÜ)æÁvØ 9ä°%"lK?`iÇ" ΘŸ#ÿÑçfÖr3+«Q …bbbzY¹Üà§ŒÁD÷ßÿ‚]JSì2¤}ì.~uvñ7¿ï^þðá|¯B/d°y­½‰Ý§4½ÖÊ»îp¾7Aa|L”z8Õ½½L¿Lôé﹤Ÿ²¶ûÃ9FU SwøBºAuÃd"Ƶɾ§f£­Uód¹MJ!ùW·yXP¨û‰&Ãú|wYŒJw:tiƒ=FÕÞS%±tŒFßiiºçåÞ¼:ß[ šÉȇ»½É`dHîó|>²?ÒÌ:FcT¦£ì­p|ÜbmÃJw·w)6-U‡N?Óài‡ø² 7áÂã ’NCç=¶”ÇéŸhýý‰ÀÞaµ0Ñ´5ÀÛÜSxÃiCXÕÅiØIÆd÷Ó”­gÄyàD­¶‘ uà3öçûàBoƒï~IÍ ZÛ½¡)M=Ç׸èνË0ßíÝ8Ç}þ»3†oäæføÌÉÄ"ô•^ðMá°à‘tÚGÏ(õXœRj½Mh–½÷ ì0ØHq"ŽPié;þso„ÿÉîj†H¨>*“!,4ŽJŽY/3ÏéØ}ɶÀtFwà®bŒ?!BŠ•ThqãÌB¨ dh¤¾ ¾W‘³=èd”ê!Ò8Pnóä÷_ñ €Œ6…XX¯’b€Eë›<­“ª»9ÜÏíl\6›øp“ èbè®.ç_¬-ƒãúð;kqFº»˜ ôö<§ Ýg¼D#Ñ[ÍGYJ™×ÚjÀÁŸVöই®Æ±&dA¨K½Ï»‚fïfšý4‰~Èé„?Ñç Fºšùñ@­Àˆ°%w'¡mì¥Ånùyp„~ÊŸ;wDCТqüx?åV EÆõÑ]±ô3 H´Ó7B¨pj“)%p¬Ãí°]©¬–¤YP öÛuæb¡ ·¥^§Ó޶W°VEÀz¬.¥„ŽZ^mSE©3ÔÅK¨"§² û·Ûq"ènà0ñI;q¾Ÿô‰5b\œýaøÈ»»š×Ëvñù>w&s„â÷ãÈŸòß‹ƒÚTtÅ7L茣Z¿UAa‘GurA#8ZUDô½€²ªx?ºÞ#ïçî0OºëËjd4‡…FùöÛ¦\¿âa+å8õ-¡ñæ¯óDØ¿:›¿äy´'™‘·ãÔ‚žÖ—9µQNÃâߣŒ˜<÷…¢«€0N6˜1u)˜‘P“L[N ¼¢ä4xQ87b/ua˹ÑX "q#6‹ÿ5 ã‰éq†×Œ_¯Ûú…I²/ç0Òµp!éO Ü“úEšGj$üŠ~Km<¶L^bvßàt’1 y ;E410N|wÍ9‹Šü\>å“b!à`t‚Ž·F>gÕ©.ÊéøjÚÐàL:îL* „E·ùâNòdãÙ[á[®g å#ÕØ›h!b_¥áC‚œ„C V´Â<±òš¨å¶à•¶µWÆ ŸÚí““:o§ µ TÎW&Y‡Qg—쌧¸¶ À4¢ ±r†Sk”­•bÿv\ËqÁÕÈw¹KP¦aAö÷Þ¹ÚyÎû,ûO‹5ÚÛ/E‘ pΕr‘&”ØþI”ëÉÞ};Ò¤€ÉH©ÂC梴ÎÄQ1Ò¾Ï_x[*–ÔfÚhi?•Q›ÏPk,u:“EGM©,F¹)5 iêõxG^Œ-õCn…9x] Zz³êÎõäkȇØýsj† ºðÍ6J^€4¡Ò÷V_Í€ÑN¾CšúsÛ"¡ 6ÚþÖ‚úù³÷Iš`Æÿ? ÅñÄYð$©3vÜu¯ì.tV`V ǵÑ#5­bïU¬ð5I»¤ï¬ÃfÙx—íñZFÁ½ˆ%+øƒè…*Y·Ù±7gÖ-î+.>ñŠš î“â#ÓlZƒÚb̯Ȣ‡\ü‚i+JTF{Ý–4v:¡°•©ñU‹¥”Ô m£°#Ôøù]3ú1sh(¹®~‡)[ÙKêäÔÚ²Gœ"ÀŽüfá"XÂe›AqÕË`'&ì+£§ÌìSÈOƒ•íCÔÿ¿“ÙæŒ lÆYjï…åû«ó)Z™V㢑7óˆÿ»ü;…5Š´À¹–½Ó:3„›ÃÃy–7¹5jÓý&YcJ ²j©GN¼O“›hÑдÐÏÉçÂ7¬CË ¹>¢°›2½Å$kfÍË ,9¶–œœcyx»†€§˜ƒš0ð ¥uk±ÚÎökÃú‰¤[r)Q•œŠ(, Nãù3ãæ›`8ÎÒ[„Xì ´…Pwj!ÒÓ '½Åò³Å¢eœ&¯…ä—aãuL–¶b¹ãÅt]öIþHéÑ­uŨ°Á1cˆóHï2Ä™äN€ØvÁWr窭»¹-š‚žþ„Ç>þ‘Ÿè6s…8Ìè*ʜ؎â©ÔR£e¯å@\-)í”B¡¢ánE­É€§<"QŸã-³™*"N‡Ãt )˜—P_äÜâITÕtúùTÐÞ¶8œ×)Gæý/|(¼†kWD|°“ïÉCàMõèÐ{0.í­ßf§Ý„¸æáB†ú…‡[%ßNÜ¡9;üjå⤘–V¨')VÙhä7K%k/E Pÿ;ãc——Cd¥á‡xúè‘…—j çAåÚh»™?e‚똵 =ÎFéªtE EPÎ9ÃÛ!ºìb%hi>0—‘»µ(ÎkO Oª•¸Ä-ó%^MÍ­}œ,“*J£À¸>z,õ†M#Iî%ü"à#ÐæâQGï%Ù>4}ëa[U/5zJž•c(JÇ"—ø1÷U sJ¦Îo U7¨ÏAdÚF³EJæ¶É¶Ò@ù¹íÉÆéT6x@X…3µÖ±„iJ[Y ";Yá'ÊZ¤³5…)0¶Z.Èç#× y³p:.so­äzUÃ^:Ñ[++åêÌ€†ì´®´ZZo"ÎR¨òºRýQî… !ï î’TNþqq ± .;xãßvÃ^›Ê†ÄUT«°U¾R6>†ÁÀîþj ®B¶§…>‰ßžSàÁÕ\J ÁͰ"@HyøCÃþKGðŸ.Î~}Æî~:StýÎXجÖïÞ£’~ÊØòîìõjMXÅ£CMÆì#ià^@8¦š0Ui—’N”!ëü©Ep‰Zÿ×£¡`Jýàö”òX½ãûÒøeÔsöE!óQû A…‡÷eȘÕëÁ…¿À—˜LŸî-|¥Ÿa²ŽŽûx0!5Nà G-wØàô«µ¿bñåJþq½5¾BÄ"¹²TÛF¸BmÓöã ¤M"’††¯¾ H® ¤H P%þ3Eðm­8BÞ[_ñ’|>ʰãÆÉ[è«0rsÇ0]ÊyªÛJLÍNæu:™ÃɃëÀ÷IÙ ?…ªyàpæoi3ï¬kbò0T»}ñÍc ;È\'•Ú&sç‘Ft²î5Ã4T|@0 @­K€œÓ „à,e‘öaB¤K5ÅC7# Ku®B„GcñÍ‹J ½R¤Ÿu÷·ƒ¢b%Y¨*yçáÐ4SèrMaÛ[%k#ÿw$s¼Ÿæ.-Ê8É„ø(6iÐW‹Uú†L›¾cxú ÿnN÷í( Ã¥–ñãØDk«%—ÅüžúùgÁn{Râ1B’©kÇ]<2` (Ï9 N#y+›Gac!zkgOyÂHÝt±§ºù-uÔ׉Py{Ôëb¶Ô(N\Q>îÁÉ-Ξ색Y•Ìf–ÆPw÷”å³m0‘×t±Ü5e())P¥ëëòÀDf%k&±Œµ²€ÅD¼"ÌX…ëx>pÊ)Ð5ÆÒô"Üþ1G6¥ë8ÔÛië\š*‚¯”ê)–H•æVËÊ 6ÝÒÖ‹Œæ0ÁÎÏäï(*) Û!EL¡ìƲ‘?eH[U¬m*"¡t‹,Ëp¾ ¤¦>üFØ©•ªpêdUqïʬ.÷ªL¡j_ßQB³t|aä ã=©iØë‹ª¥•˸†F*ÊTÓ¾=s,´.]ÄlTŒ?Géþ¼°¦0²ç=Yõâ[Úù‡ýpW…$\Dçâ£o*8*Ø—ˆá³QTóÁ n 9ˆ‰+g.Ïœáé~^Í€˜Tµ"àñ¤Úœ#l‘ÀhÊoòÌX6KIzëU¹Ù¼gQ­J]D·ˆña}‰.œ:Jc}²ÔcÏò.ª½ üá:îénÙÑ2Ô¢°MR¾†Ã85d/%QŠÔÁw*ƒ•9ö†3ø\\[ˆöõ¶®*Ì+fšvi<æK [în¦‹¶2¨UÆú^V†£V)Õóò&:Õ /L#A×§ôqß £D¾ø†îÊ×L’'.Éó:Y^QÈ“yjÓX¦Š½Gr}Ç;%ƒh ååà fç2̇w53d"õe ø2ízvÓkà‡ù·’[kà–«î5#5sIZúrüÁ):ý5Y0RxHåŸÑ}{e-ðü©J-• =é½~D¥ÅÒEOª´P˜¢ëk©É}¡RCÐ SËJR­ Æ.±É•”]¢ì E:UXþ|pW†îk¾+k| ÷»2t…CŸhWuú’×W¼˜ËòŒTr½7ŠcSUíC¶&sÓm€`T€c‡¥Uz…`Ûa­1( PBð)öïoé0¡0íü´¤ ¾\ÃQÔhºå£kK¶ø)Ë<<ˆùBixÊj„øøLÈôÍ‹Êq¨§ Ï00¸%¹ÑO‡+U' “ÁõÅ**^è$ú (¨€Ž¦çØjkA…ð¹ ÂyõØ‚ bó¿Ø‚ G†»âblµ "Ì?× *(92Ðwù¶‘׋·èîa¨_¡6Y\ º>_‚xË_ŽH™+Cz‰*•{ù„×›ò]É)(QÆWËkL¯ro¿¸8ª³ë´¸mPߊ*üˆò¾Aíä'Ç ›r*ŽO.ÉP^›¾Ÿ©5ßQc³Ýülš.Y›DEX{Òä#×s°Ë£GC¹æÕ¡³ã <€qeÉ[ dÁA7²¦–'X0N“„Hf'f´ £½Ý^†I>ûè V eM.Ÿ"½Aƒ|ÓtsñR6ZÄè–ý9¼Y×ãSÐŽ¬¡Ë†Ï9XŒIÿç샶©ðCíäsŽ•HTü\W¥x|XŠ:á‰eq1Ì—l&G>º,ÎÑWÜ:jƒ xV…ÞCg§´Ž‹1ü¾ŒªSè%¦:¢¢ ~ŠN¦êŠú­+zOÖ·—Éìµbõ~R+LÅ»~M #«xŸùs3 #)ïc¶ixN tìÜØ«ÎUØ „שŸo¯·å™µÎ/¼‹¸jÓ+`1YRåòÇÊ;rE`½~LrÜ_“ d€›¯Æ1½Ž{˜š›ö‹!—T¥/°Á„—>3WˆÛé žÕ)f½Æ³¥:ðì#.¿À£¶$ùå—*)ù·ªQËXº¦÷udå8ÔâºÕ6ô"ùYT‚]ß9_>qtäI‡ä@AÞYÃsAå{Zt²®¬M—õÑ,u¬˜ßCª/ßN¤Î©@bÔü¥îmÓÕR*¼Øí,ëÉÆb/CÕɺýõÙÿ)hgLendstream endobj 92 0 obj 5268 endobj 96 0 obj <> stream xœÕ\ÙŽ¹•}¯¯È·‰+c¸/úaðl°aØ*À´ý ÎŒVõX•UÝRu[þ›ù‚~š0üc>—Œå’ÁÈZ$c¦Q”Åäry×s/Éúv'z¹ô3þ¼½ú§ßúÝÛ÷Wb÷oø÷öêÛ+™:ìÆÿŽ·»¹F'iv±N9³»þú*–;©uïßyá{¥ñÕíÕ—Ýp>ÝîEo”P^vwôQkob÷~½ÖZy×}Øð©Ý÷*ôJÚÐ ©Íô„î~@³rs‚o¨Ùhkæ¢NmRŠbÔù}ž×ºÀG½Ï¸ºóð}¢BY× ßåvoM±Þðn:ç%‡S¿?cú(Uw¶­£ñÝÍpþùLÍ®ÿ“Xè8 6¯lØ–&ì®OàÝ·#_Ç1ÛM„ ¬OßT´æÇô.F5õýu•ø±¹³;×G¯ƒMò½X ì>ú.ûa¹!#ý»L: ®þ´t¾gœGi@yÜ%dfÞ- ð5Í'­3±iTD+íd6ïöh(<®ÁlX.*[þ$"XT!­§ ÝÙìFf¦æ¯rÊ^’ù0q3ë©€É[dM@tÑ®Òî¥Þ„êBKïrþîÁ—B8ÔWšîáÌÇ•lêReòŒ·Ln•ÖÂ<Ódé^3" ]Ê´#ó½Oê¦c4ª•K BJ(â~äÐ<£«%G¸Gôì‹ÿO1/yvâ“y—1¤8™GžéoÇ“1üv”:xxb"ÉìDÒÜVÍì;¢·‹TÊÒϬ ¯–k/‘t˜éÜw™&gJz–ÊQúã4L3ù€Ã>Ùƒ„w‘z´˜ç4Ç1ç·µ®¦æä4éõ«‹5&„#ëB©=Ølø0˜p½— (ecEAü†ã Ñégx¬®ð£ëë]«]ò(V&èæ°mEù¸ò}ˆ2Où™ý.Zh‘Ω³á|½pÙóKi5Âo&U€Ø‚ I"rY[tù3Ô°ÖÀ{çùœjìœÞ%9€Ûv$Û“MxÀ1ç <\ÿã—Ý?gG¢ÈÀ¬^éÊ!IþUU…Vê`yäu´û<[Jƹù}×€ÁtxL. äw7yÀ"Ÿø|æ½™-µ:Ó˜Çåá cÄÈ^zWÌ9­T‚ 6cËwd`Û‹¨»G‰cw¾]Ô軥¹=צò)D$røîXŸ+Y$§Â=Æ/'{uºàØØªŸ"'µÉÁTOj’=«–èp·Èžyöñ.¨M÷òÕJRø¾fžKp•Šá ZêÊb8Mã©NÐ|Ä:Ÿ Ja«vˆÙ«kr\% ú:·ØRubì ØûeŠÏsb@‹ŒfÎN @ƒ©¼ÿð!Sá‹wã.b­ÉÔ*¥~¢&§6‹Þe ~¿·ô¢ŒUL¶Óᔎ3Óo8{ŸÔ'v?faÐs¤-‡©±ŒL_åi‚E:( ßå+¤ ,H»‡‚A„12€Ï~˜¦2=¼kpãçØ ‚%‚¢`+H ±Ù×óøÚõàìÃ&j Ý3šERâ–n¨#²ÄÒÝœG>@±æBî?dkÓž³ï³8¤‘¸O*«é[R‘…eßð¦/¢ð¥:ú|*ŒJ>f#’ÆùH e×â|6\ˆö¢,„ ³Ð0dÌȆeW‡¢¶(ˆ,SNRäÅŠJácð D—'9U8DÇ’>òT¸¸´>±.gœ¶^4ŸNäÐaB—Î)O-šA¸§êD2â–N˜ÒpØÅÒkßNTDîa& o bhbÈXXéo¼áœ#Æ=3êšù²+ŽŒÉNTœ°>yúi±Ç-²™G‰Àó¨k¢W ”mƒÑ$X=Nyßk¬È°p? fÁ pPÆ©\>”T³éx#ÕHÓT¿º£•aBgQF„ R¤óÈZ!Û× ¥Tw|“hv‘ !#~¥\”}ä“°æ·Ë’-´LGÈü&ôðëD”Öƒûpm€ìÉ® É‚Á° Êû¤ß§‰cK¼Ìzÿ<<<­ÙÄ·~^:!t0D&ú“¿÷%í»­8Iœ‹¾W!y,àÊFvEÈ\1)^c §Z~1¨²_IÄŽOo&jX@a«~Å>SÒ”£©f€Œ¢ã¼÷D9ª ØâMr3‰Yº™´Ùý˜T$õ~¿q¥GXcUW ‹ ˆd¡ªjTšÏ@kJW2z²„‹Ôxø~ñðmVx®"ý=á5\óy`gN‘o0Ák‹Ø #ïò¨^͵ €‹ ToF:-4æ<Î*JqYI‡29¾N%°?˜!é"u (ñˆ.R·ªÊ0¼]Ç‘ iÊOyVQ”>Rd–7O:ÛwB‹YÞ7mss©„ŸQE¶´Q:I £¦Š£YÇÆ:¦<-ÓÈ%¤-l…V_ª”š.!Ó+“ê öö¤ƒæ%‡Råá´'–öR5ö¿€T^7M«b¡ßL“½Ï߇²pɯC}³ðsürz'a*(°Ë„×ÞáG.ýÕ]1 TCáÙ9ød;ÒÉ ¥Øu¢’j¹¦´—ãLô=LÅÂz`6)å05W¹qXã}©îÔÁTü|8Î(øf$_7ÿ¾åK–;U÷z(J§UÉ‘,>L}Bº\žcuÜnˆha%­ÏóýI@ºˆ4ûFªñ®¹WVäØÛ"ø[‚r.¥<Üò© ÚF ÔÅôN%‡¬€ÎDÐϲ¼„ e‘í±-°ÖFüHgCòº±¬‘Ÿ‡Ül»(3 t»$ÖYK3BH»”|“ŒÊ‡uÖW—ÊÏIqãœë¤Æa8e¤XŒil;clk÷eZpØ7‚NâW‰jeÓ ¨}IlI¸´ebýX㔆Þk9ÓÒ5—ON“‡õIcßãËT +%üЪDJS=j˽¬ìl#L³—C4ÉZÜ¡}ÊÒDe¸c~þ1OãàN‹ÀÁæõ–em­rr¦iƒðïj*)/% ã±ák‰W‰"†o_þÌ]ÊûÝäzF)Ù ;àA=´ët—?k‹D¡¹986îMÍEèhî [ò¡ˆZi´_SOæµ…VyQm¸)‘ÄbNšæbUð¡æwSÌ6nŒÃãTÖ§VùH¤‚%XéþSq‚0;ØIéÖTPñtíÂn„únA"Ö?¸¬!,•œ@>WÔ³–õ& ˜¹BêJ}%ü»Û8²ù.O,Åæ…Ò*¢d僽LL÷í"÷*¸N'eDT‰nZ7fŽs¤¿*4i•O'õm–)Õpœez³¾Á1*Äû<Ži‚OjJ5­j‡BËX»™Àç|]^¹˜À´ h]õÖÇeL.Ürþ¢»µ‡©fϧUNã*Ý—‹uêa M÷‡¥ùòùt,žu6Óaøq?c³CjVòãe>vˆþ6[œr±œMËÞ[EEÙ¹‘IÔ‰ÒHÖšéµâBðW{‘~£µäÝø&ñÖ*ªª“ƒæŠ0³¢7ÂUydR2A'RÍ!…qIû§)ZõJZ¼ºT§#]U/4¤·I©×‰$z/TglʱVŽ sN‘3|â5›DIuó-íÌ·î¸öºû5­~¬<ì=¯’1ºwºªâ%ßê$å ïr£ŸíÖOù|‰¢-ÇŽ|\,åÇùœÛ_• Œé€Ö‰b:¯+Ý çÎ=!xz﫺 ®,Ž—ÛÏ'v*Üe溺!Kü¼…«wŸÈˆÑÓNØ$?'¢u‰Õ7n@žÒ.éô¤ºQÇ–æ‰ÏWlpü´TµèØ™Ny·É“›îNÿoë¶;²çô¦æ@' Àü´Öµ¼ ÝäRRîŠ!“Ø“ÅsÀ»¨Æô; Ø“€×æžoiŽWÏè—´¦Ìa.r³Î…[Zq×Ü4‚®ÑMo?þÒº‰Nõ çKa¯r}Bº°ªa8:Kß.¾Gm8T]¸ˆ^þÿÐ;©lð4rê¯-½s@‰Zj~ù¾ûS›¥­W›­Ë~­×tæ2ßÒk?壗Ö—´VWÞ{Êmå|Õ¯¸¸¡`*tÿº Êï몃äs^nOÎå%Žy䫱žU–µ  £Ølš¿ì\ ÖŸLKЭ&¹}«sËr´Ž½ú"Ît£3ˆÇ"ì¥Ëüùôþ”×spÇO¼‹Ä­ªè!]Ë+o<¿àP.oÌ¿ì4ƒ²@#ÓE§úJÑgŸ¹Ãb3«7ê‡ßìg0âX¥ åîÁË\ja¾ãkðqޝi’[ÉÇü1×ðé8âÕt£¾}éŽÅSεÚn„éE½."«{q´4xxIµ/$®¬VQÏtžDÇ ;ÚLŸÐpCȆf¨2%z¾NFËË Ó³¸"¶þŽ\Z ZÞ¯)o.Yz t=t}¯}û2*›®RaT:^{“‡çž‹¥áž£|áÕ%H·^T7>œ,×뛜 CD÷ùUÁ+}åš“|Í[yŸo ã›oåaF'Ï:žK÷D-O½{GñÑz}è«,´µ•ƒBWzyYF¡?ÒüÈõ¦$åk;²z¶Q€ƒD‚ @¯"Õ³é!&pyóÝ ¡W«%¼¨ÄlOAý›!³zœcè¼*ÓKok¼ÆÆiߦm\˜iVï=•C2´'4n £¬V`I[G´ðBïŠ1OÌ~ÈcA†!ÚUTC°3¶~ÑB­Aš­|ah«<:õ>ÎoO©."áwBó'ý £ÃgàÁ6fɱ¡.òztcW•[ŠúÜ ,Â_"mkש±¯DïáœÃ³%¿<®_ÑÒÃÇwÝý¬ùÇ Õ@U!öÄk-Ð=‹” 4U)_l⬕ÿS±=­!$.æÞeÉã ‘© G‰†‡ä¼^½õÓE¦‘žòþæêoàI—ûendstream endobj 97 0 obj 4642 endobj 101 0 obj <> stream xœÕ\[$G•~ï_Qo›]IÜ/¬x€V Øôj‘ +Ít×ôx˜é{ÜcÏÏâ¤}\íÛïœÈKDddUÖܘ•e¹œqâĹ|çùÕNôr'èŸá¿×Ï.¾ÿ¹ßݾ¼»Ç¿·_]H~a7üçúÙîÇWxIš]ì£SÎì®]¤Ñr'µî½ó;/|¯4þôìâ‹îêRôFI}÷øðõåÿ'„s¾;\î´½u¶{@ïhíMìÊ7þpõ ZÍå«ß /4V¼ºÁü_c¬öR¹ô®Ò;×G¯ƒåw{…S»½ÄªyÈi «uðjX ØNì…1QíŠ1_‰FJ!»»—4^k­¼ëÒ–tŒÆ¨î›yé}m­êžÏOi(m:¸Ð=¼Ü«Ð cwøæ?+¾å_’v¸£—- ’ñXIºÃë4…V±{1O‘-’“—‘‘ˆs*ßJEÚ8¬Åvi\oÃÄö?b¤²ÊˆÐf¡Ó`üørv¾w7ÍCUÁàå¶ÙÁ §äôò'à‚'6ÙNÎ õÓΛëÙ^ª0LÑ]_^=iÈŽ–ÂÚ¥ì`¬ðçß]¶ˆÃµëÒ3J@D*œÞãQ¬ë®ŸÏÏïï.•ïcœŽžÒª{E”u²ÇŸÓ2Ùq>ºÜk«û: •NÙX1 ‚ÒÊu7÷‡4@ ß%iÔ ñ5ƒ°Áx–5"Å™½t$ Âާò; ^[éb“M ›µÓfrz7¢c%õô4*ÿn¥~m+Ò[³M-:ÌŠñ)ŠñQ$=§Çª÷ø9‘ô8Ó‹ñaÓâÁZYǞѴ"Û2z¡÷&ˆ†à’ÑSR51TJŸ‹m÷ÃA-bqp;˜Çï‹q¼ßõÿ4 ÂKúºWãÄ0æGÌç!]4ˆdK†ÝÕ//®¾GÒ³Åg`º²ù”äôÌôòæÀ\­Øhi…oòrÉ ;ÕÇàC<®þph+êÓ[’XI8“V(Æ÷—{+ Ž3tÿ:etf+ Š ÚÛ$§$w·IäÝÂRhk`c\!_æWžÍ7iê^A ½ÔÉX8-?& 8DÈÆc yã=&í!`•áÆcÓ+cºŸ¤£ Aæj•Û™ìñ5)±ÊtŸÎO±`ZEçôfþcÓT ³ÂÜKÈá‡Dê^äN¸­èù/ÓÒä?( ?…ËžŽ^|yžÌ"ìÒ«Ù.}š¨ðÒgz}HSim7«iØaÓ.h5§MqÊù1 KCªËUX>²©³I2ÊÞÍ|Ñ×,KZÆÞÃß ŠÇLƒß‚7y¿šÓ¦åXeÄë¢‚Ô Šÿ5m ¥³PA-a)È€8xm6 Ýÿ$­­qÔ6N–û÷ݳ ác ö&Vþ÷—ä=\°†ñYAâ “âµ\åa7¤ó:º Zv˜$m:Ëp{˜‚ˆG¹áþd`+1~†É‹ü„^GãiÖŸ^]|“¯ñí …Þ9A‚I~v#ÆVåôäéÅo×C× ®hš“|xL‘‹§ÂxÝÚ˜F‚m Úù[ZØc“!æ¦ù~ʧe|Íù4Œ©¤ F(]k™ªù'$gɽ’0$xÈËmê p:*Vêð¿-u Ú¢“:hÀbá ©ƒ‘#H±›2mCÁ½úAÔáçÉ¥ÁSêI&EÐAöÊ“"X¨µ Ó“·Px?jÂGćw®”c—tB'E ²QWKS$ÛpYÀÊÆºÁ²ý[ xz3Œ)‚=œG¤¬ÉžuPaŒ $cu9 +–‚7ôVhQ5À'¤ÁŠÐÿi¹ñ9 ü ‹£ öÄþ*¡.c›ˆ‘tð|Ô”Ö¢ë)¨ ”óþD®ämm™“Á"‚¨wÙð ºÔý¥E‹#S¤|EË.àØ.ia[ \è±Ù¹d(%©Kÿ{¾•ÔŠÄig#8—ÍFò½„½oj&ÄÁ9×)cl\’²• ž¨ž¸Ú£VˬY- ˜Éj)Ÿ&ùv5ÿZózòK @”Þ:ÎU–VÈ|‚°lÎ…f ¢´O­ äB¯),˜÷…”Ã9k¹ƒ¡ ô0^ñN`ƒ >fæé m'íðJCã•õ°ÔÙ îÏI…IRDº˜ìôŸptl.¥Uº-¬HßÌâTäB–ÔCš`OQ_›ID¥U"ó=•²3Ô!}•vgá¦ûÀP“ Îøä˜—ëNPî)ðœ”÷IJ|.cXéÒ4Ci i8b‚“‘:ÓyœޤÅHµ@ŘOf'Ò"‹’º™Þp^$Á|^1ój§ÎKxÊIƒçU{^,æeî0ãӨώ&ä"l´ðxB޲<_ÊÈQÖ@i­mÑ®pÒ,k§\2Й1ˆÿ1;ýç´åšg—GÒ⾆½œ©°ÊÏB!iJ•ÒÃPk­uk+)Nü£ÏÑ­Ö2! æ,4Ø‘=uöQpÊäù6é2%|(HÉtÙ]Ù·PemÀ(ßB•×™ÂXc¡(ÛÙÂKW™dâ,d°ÛZ„`‘Ó´ŸžåKlFs>‹ç„ë‹P9 —ªN†WèºL†¿34\Qâ¾A“ój£µÑû7p£d¡þÿºQ¶yQA2P4#áWˆ˜ô†Òã“7ð¢žêÑ4§ÆNôûs£ îl7êðè#t£ãyçE9°3½(pþ9e­wéD,5÷ãó¢4ü}xQÝRá÷àGE rmTR e¦ÊbÑ·Qæu¾H8¢·p¤‘’Ø'µ¦ªáˆ·¤¤—?µÚ•¨õûŸ[Q$’¦(V[ŠèÇZ%®RºHÕ9NF"„X#\T^%k…éCèniz«Álά*íŒJYéé=×!ž®»›RÉ[ÙýŠ=.8¹p/áçÍüî&‘Š¡OYá­ +e‚À3à?/ƒ"žqýq.6¢»Ã«Kk)óÒcV-½ot ¤ À+Ë,¡¹œ4+ÇyÐ]*ÇFßl(–ÇœV§¨(·æÌÆ?¢A®wF-Ízg^µ¼6#œïN¾NÛ 0€×ÙÂ9/–­c\uÌÛµnMF«²DËëi½Ü]]mï¯F)ë4däð4m£* ©¼ž1+”²-KòI>f*çR¦bLêù õù†3öÜs©žê´1 T ååD¥´Lå´§¤ß+Ì2§µ¸²K²«‹FµGDˆ´ÎÄEq}¬÷RE\)œ¤­*┇nÜ!ž¦ýѼ‹ý-jö‹ý)`“Ö »cèÁî bø2=Uz­' 2u) ¼Øå²ÝˆyysW‘v¤Éâ(¯óÞ…ñÜ©o+{ž˜+š.žÏÇÍ›•˜#7 Üh`ÙlÝ­A]©žw7‡Ñ>X˜‚¶ón‹ia µ2ÔÏ„õ{9$©ºšÏ8sjXóbåàrÙ~˜Íñt>¢ÖÌÙ N4)RÝF› â¼8Q}°Ô—RgŒkŒVšsb A庫ÇJFª¡Ý•¹ô¸Ý'§^ÔgÑâYDznS %‘ìc4|Öš9¼LG(H5³nnC%¿Xö¬OMÈ;?nöcÇS¨ÚŸ°ñ€r@‡Û0¤Ø.@‹Õè‚% §‡ðÍ•^Ò›øûý²wÐRê¶2@àpa©ÙÉz—Ü OèLÅ£™¨Œ/÷O‚H–ÍB¿ÝÏÈ{ëk3HóŠ`VU`ÞêZC1/â8\k·eo,aéD_¦÷B´¹+{4î×tŸ3J‚É„šfo<\R“ºÑžb ]¤Zt~àC?oåņeB©Â46ͨ™•»Ûºäz[øÐâT‰Kÿ¡ûb6YK°àI‚'£ø‡ùOÓ0ª¤.úÝh6Ý­z=nƲě²Ü_çMnëh‰W¾í™*<µ’)W`ŽS>÷ÙÐK§NK YkÖö\+ÕM?‘ÓÂìÔM'ˆûÛ&sŒ ÕòJæø;Cå´"L'pôoʲØàg¯æŸ% ÊÆ‹ÿS˜Fz/¨¿/KD n ¡S“Ì@~qaÔ *dú¢eïzy“dâuXóº[P½=pk%~"X(æ;|u95;Þ ó<ºìñ<ÜŽ2”7ÿÝMý•`4TÙ¥‰¯½k³îXq00˜ !?'Ó9ÕgE4ÞÃS‚£Ù¬‰Ù¬·Ã R¯ìÛÃWÁ™ö 3`>c1FÇ>²¿h€÷“¸1ýñˆ4µîâ=n‰$ãaüžCfŸïLJ…ÌLñmÔ/LÛP̵nˆWt*ÖÒè6Då>ðŒ,Õù‚h9s¶ b=bQ6]&¯Ò–q²tÉ…—¨£³‘àó$3Ñu†õ¸`z›¬mDŒäónÞ\rÓLÖ¡è¤MtZ†FGÏ–þÓÉkº ª¦s"Uwl뤲°™CÁ꬘*ñ¦³ÂÊ>,V6|³á…v4›Ûtˆ¼©Ø%}¼Ó漞¼Øè_á&z/b›ú†…ǵ{Œ 0.òèK‰™$K‡¥Eáö~b<ÜdqÏed׫(·ž„`ˆÝ(#pôæK+~ÚvóE-{YÝÃÒN7{÷4ól~yÉi"éD›‰ím¤Ä%En„!`BÿÖîš ‚ªö¦•ulã®Vʬ¹¨ñg³!(¿Ä-q†’{iê.ŠrEÂQSï(߸ñEÖìy i·dÒŬB7R›Ú%5¡¦Ú…ÓtàWG:ê•‹öCð=Ÿ¸ä 6ÚôA¸±Öôåq¾HÊåp#´’vóÏ•ž*É=UCŽ»Æˆ°lLjZñ¥Î,ôÌ ¯‡pÄú•@}ÅYW)Oº–ᤚnóÈÐL`±e,XÊÕN»Ò¿è×®íR!T¹IO_ÔÖ/ŸN=ñ À…U7‰bÀ¼÷cÃQgéÆû«oo7÷2RÙÑrž©™µûïö%!ôLÛ?·ß˜ª}¾‘AÕB„­•Z3ਆ±„,Çx]nâ[–RôU£‡pàO­Á+ÊÑD7—oÏ1ØÃ ú¨µé.ØQvÿ¹Mq$Áçð£è·Ÿò‘öÛ¯¯‡‡ûRç’?Âɼ0,¤w¶n¶mÜ›-´@4µÛׯ·8RÛ&][j?êOúQÅ÷‡eÓ* qâV?  ÄɬU?J/IJ€wîÇînœž¢—~:éïx6º©¸rÅÚ)&§¶Ñ¿LÛJnúbDÓ9YºÇ±Ù9ÁÓÎZ~úÓ $îY×ÊñÙ!Àl¸çO7HA6F•_¸*]t´Üã`©õx¥ï­Ž2H4ª¾Æ½¸&R ãŒpeùä½Ä hõI›ÃDÖ§¶d½ÍÚ3.¶_ªÈôzóFM°g8ŒyêÒQP„’µ£(?„ÐC[ŒÝ¨oÀ¿1³û”ðšš,›w"Z—•—^8P5)®`µÜ(wÓ-š“rçµ°»bȺ³ùÖ¸ ¡gÂeôÝ—³]»”9g*7tŠù^€aXô.»±·åî-—V·Ý½N8¶8#x×»‚i§g*VPd±Åᇇ¿dœ0TŽá‹~Q¦¾®sLöI[6©Î‡1Ù…êlÏÑ݃ѵo”süÕ}\wÌOÈyL ¢±ÚrJÌ ‘R7x>fEÊ㺔󚑱tÞ¼¨"åJÒ¤TEì`(…ÎuK‰ñŒ¬€lèS`\ªôÒ “ QRÃ;¨Œå®,í¤ª ‰d Y°$]yLeúág6×—ü2"›Z±¤¬¡t ‘ƒ£O=l\išeݪ0úëé´ºWÜvé²SÁ•BÓ¼TûjnÆürnÌ_&¬¡,œÛ4© +…‰¯dPˆ…F#p®Êšxæ}÷W®5Ðd.•8ñ3h·ü& kñwsª+çíw³\Ý>öP&kVà B_HÑç•ê…8¯¹¸Ã³-ryàðuÁÏ+¹Á ‹™þ¥@í´*¦¨óq´ªk|·Ž5ëh£nÄÌSx=¯a ©"+éû~[^¼KJã»E¡öAÊFÙ,ÀŸ¨¦ñ@¹HžjþfSó#A_ÍÂu_àÑ×i:¥Õñ~náDð¤‹2XUw×ôù1SWã5ßw,¤iœ¨ˆWšnÇŽÛh1{3Ùå/+Ù¡›ªètMmKSMõÍñéØ Sý©ò6´Õš0ˆ@Õ»t]M)5#=œkoY†¼üÄ[Ë Õe‡þ$ÿ²»ÒÔ°<7¯çc½{P‹Zf阙×ÃlÚ¯v›Õ×¢Ó¡žº½ÊTJšg½×QV‚Lv–Ÿ`8x۲ǛuC›¼T1ÉÝ ÝׇF£´2yµ¹lY’8Å'Ç›²æ0Sà!¾òÙÅÿç(endstream endobj 102 0 obj 4910 endobj 106 0 obj <> stream xœí\Ù’Çu}ÇWôcµÅ.ç¾Ðæ‹ÂÚ²¼h"èZÀL£ ƒ!ý¾@áËáý›ÎͬåfVV/ÃáP8ª³r»çî7óËèåFПáßë×Ïþþ?üæÕÝ3±ù þ¾zöå3™l†®_o~x…FVlbrfsõòYþZn¤Ö½w~ã…ï•ÆO¯Ÿ}ÑýÓVôÊè e÷~»ÃP*†Ðè­Ѹîyzë…–¦{žMP6v¿¦gmU²»ÞîÐC¯”íþ _Jg$:ùŠ:ÑÞ Û½Á£±Z[Ó½šs«ð˜GqQ„8ŽM0Å3‘&(c0ѱuõÏX¼4ÅâC¯ƒ—›«Ÿ?»ú;Z.õᨋ÷iØ ÕžSÚDo1"•P^b@<)EZ¡R±7Nvo¿¢>Œ!ª¼°üaš‡ÖÞÄŽ·x>¿Î]c5ž?æQ´µ˜Ç+ £EŒî®Ù‡¿››\ß³ÿ°&ïÒ£SÝþ.÷á°Ä¯·ÖöZ”³`ßßScì‡ÖÊ»a÷\±{ÞôNyÀçê`ùj-BPØŸæf‹Þ[+ÇæÿÕ “ju­ûàbTc[Ú­¤P¦û‡íN:Ûû »ß$òkãƒlާz+ã<ÞvÜ„OÈh°0;oÌí~ !(Ë–Ý]¿[p²¥Æ¾wzoÞ»—¹ µÒí-CL†Ø)¢ ïÝüî1ôŸ ëó0wJÛ±SBöàÞIÙG«ò.,H>]Ì,580´ï[z!½ÆwZÙÞûÃM9ü¢@_‚/¿ ¾Ø—&¢’ð±K²çÆÊn\½6cĨ€uéÞA0„üɻ‰›Û,³¤B ƒ©Í®èà·´N%mèöïi⺗˜ø[ËØ}FpN ƨÓ*ÙÞ°¯Ô­éU´wçÁ@Ö=´u6I×I&¼á{»êeîòSáp3  ôi2×91ö‚ÏJ:@xˆý¤°Ä²™ 2Hg“¡à¶å>§…ÞÜû#bÁõV|¶Íl0a¬7±…1LJØ™„¿ ÆC®÷ývgÀîŠíj&Câí  5íƒåñ*Bh–6HŽÝУº‚õzÃ&Ä×ÃæÐfôÛ-V4í41&ÞçÙh½ x6·l°ýWùKa}÷"‹´xŸ'i­…Z^óR VB÷þúÝܼ֋d`HY¢€…æ ØóÙ´÷\Ž=ŸÛóO|FYš †#*4õtR…bSa~à´_lû£Å'±'ö0¥?̓õgbÑ[廟Q û jj±ÎúJÿYHB, ’«Î"”mCÎB ^«î›D#¨kßPu©‡O¦×­ †‰.Ž‹ø9m„ÔÎ7-”ˆM‚©ÊwñÖ&‚©×†Oì’QÏ'77¦¶®Çòk‹=£ÚÝ6¤R€ >K%°Þt?Ü’á¥5¨Õ1;áþpà̑ÿ~W«Qr¥&Åpù?`,X¯ŸÚ.DàDûÍN7H<ʘö¦ILؾèrül„rÂxuÝgôjô§¼6½92#Ø»œGli;À«ûßíÕo6 ¶ç˜2-:ô†è/èð8¤L@-_9x×£‡q‰òv~óãÄòMº+èXm5)Œ ÕÓz#¿µÆðÀIÓ¢g2ÊKP¾)‘Uão³ûïE÷¦GçÁ}»%´æ,ÚBâb“,mÛý m¨9(WKõáa¸|gú£…Y’ùrÄX÷ÇÖ–¥Ç0MTesÀ‰cö8­Á­{f…֖„䉟ë¡+öó½†û߉=5>«¿Ïi~kÑ­qO Éå4kÜ,Ïçfì$ ”¸YÇo#Å?LVþsÞüÚ‡„ãI†õ& =ÁSK+Ú"ûäŒp›â“G|øØEƒŽÕÙL ÃÍt<) 0¾¶Ý?æG(ܬoÁ £/à-µÂ[É¿‰>d‹H®<Î`¹»P9®0?”.| ³,ÿçÓ£¦/Ltˆ£|”‘¡Ÿ8H÷'£´Ì2åÚþîï'7}@M,f‡O½›Â5"Ñ ûK; ‚ÏA0ÎÂJ¤–ÿ×Òb`4z?^ó?Ép÷ÚJ7_séΖB„,`‡$º DlK'%á oŠO²‘ÉT^"ÆýÍ[ëCe×KÌrt.œÈ E nÍ‹ðÓÿ›™88Ny“|…¥r »!ñN¹,…þ§5uH!ˆYH¡å jgÑ›0Æ+žÐû„yž÷¹Ó0€I–ÁÖÇ^Õ£ØàlQµ¡P’T$…à$ýs‹¤”!R‰ÕgôÅš1¡Ï5Ôµ Þ(ܤ|aÃGÕè>+ôx¦B÷FZšÿAêJÁž6ÿ÷JÁ~0ÂùcÉÂ6±m6U8ž²¼„pêc&ÜhÕ£d« ˜Œ¦î·4€*ˆ¥hø†iÄ‘ÿÆ4¢ýŽUû¿ß^ú¿•tU™÷.Tkñ¸Z3«j­,CJ%^êNÃô–qÐlWÛ畯¹È‹r ëô£W²ÛSÿ·é^l«¥±5zǨî·S9Ój]DÅæ«²\šü²È³\Ù‡W:îŽ~ÇçÚ—~ûõ©œï'”µÆ0<ý™ ¤‡¨¡\Gê>ùñ(Š´‘X]UÆÐŒu€«ì\Šô}ËÒ‡¬¬ª/"² `á~ ª×þf@Ÿcè{“ß9 îO©Ê#}I}ç÷`‡§.=’Qõaª±ƒ3ó(µG,m| þþ8Wí)J°ÎøT—ËRÇ;¼ës!^zŒÒ›•˜ŠI46 imÕ‚žUµù¼\áã£û‘‹ÊZ, ÇX¦Z¬¡JIšÀ%KQd”j"R>¸¥æ¿ßå¹­%ëï7Ç2Á\h=¨NÕG:ø[‡Š¹‚ýl0öŠ0º Tè¨ S³>ˆÐ¬)"Ýeã¡øh…Ý@°`ëÎõKÊ0]ú1nv!åçÛQºÚ~u1Ì•ŸÑd¬÷Nç„saÄ–‚.ùÑjÇú%ùç©C¨ ¢#’ÊçœáÒNBk jÅF`UKIËÑ®µ1`¬çB†eÄ|hâ–•„tпYŒUðú'#¯ÄJ3§‘m£p¢ø›ôD‚šjŽˆI­ g(ñ¡[ÊÙŽì¸V®§fGâ$þ2rƹ?!sQ^°-jÖhÕß驸…}Æû>Ó Øe$·à.u·S½mAÃC?}–ŒŽØÆÊŠþév2ŸOD_O¬Û1+-KaÈ{á–ƒ/!tÈ­ñS€üòRÙ{L†šÞj}&-S饘hùɸ¨º†t˜æc)Ò^vÙpäÍž)صr;n:$›&q’.«iÖ V·Àܲ’¯]±W—&ëVI¨4¦—©’…G)3Ó‘/ ùkƒ!_¬-Vù*GÁ,xkiF¤Ž÷o+™£UáÚ•8VYÖÂQà‹õJê:¯%´dC$Z#²ßÛ&]Éãä~’'Z”Õ¢ –·iK‡¸\œ×½unÖQäÖâ=]1‘JáhÂ&^šiÂÇÍÆ²Ôïý6¨6™ZpÓuÑÕ  fú æÀ‡RhD¥÷ÑŵX•î½ßw¢QLÕ²í Tè_Ù\þrIÈŽrWi}^(Ü«‚Cï2®½sÜç*ܼ•JcÖ&ÛAÑ÷RºRÛÍ€O:¬ÂD=Æòž"³m.ÊlOE4Ùfíe¶)»²î† kCoÍ*t¡­(–ó}'/…œ‚¥kñTHšPA÷ñ3Û‡˜äƒ&ÂjÀÉÔ Õõ‰[C<ö‰™¦ÂXüù”Š3Æ«sðnöL‰íçCs7ãja•ïW|Z¸tàJ„æÙ•¾©Î®4õ6ü$-j[~Ey˜ ¥ìÅḏ¨Kj@ÆX’8ZhV®HŠ8%kâ{“v`4†¥‰Å">”Ô†¡cªH½M6H¡4ƽ¶µ½EJꆡèmÚJù F“Æ!. Šëpgm…«ËŒ™/L-dé-õ~¾ ô³\¹•u¥L®ÖïèB/.uL¯mè~´ÏqÆ ½”L%8‰0ö¾˜ É‚,*M)xº†ìWs h<'T_¥ÜºûE쥴Ò2†½Ïƒ*˜üd¯Î3tk $_ÖR†IÃÀ¸>öj~ݽePj!Xª˜3ôw¹Ñ‡šné¦x7Ud€yäò‰»\€l|ÛvœÎ8zMÊALó¯%)”È~¬½¶~Ü¿r…œ¬U%‘Rn)B¨w(øýmaT-|À:…}?:þ.<²ARF ¤#ëN­Ñ%xbqœo¨m«x~tõìßñç¯øõª+endstream endobj 107 0 obj 4662 endobj 111 0 obj <> stream xœÕ\Ûr$Çq}߯ÀcÃÁiwÝ«èÐe]l‘ºp8Bvg†ÍÝH,(Aü'Gøu²ªº:«ºz¬; õöÔ5+óäÉÌj|w1âb¢ÿòÿïß½úçÏÝÅ×÷¯¦‹_ã_¿ú .òÿíß]üüÌtÆ`¥Õ×_½J½Å…PjtÖ]¸ÉRá§w¯¾~{9Ê;áÃpÄ£“¶axƒg9MAÛáör§Ä(¼”á¼ýòú7˜GèjGº¸þìÕõ?}1\_z5­TÁ„QL~¸¿Üa>¥¤³ÃkšO)§1_|ÔÁ™ázÔRI;7Öf’ÃW4µÀzxÄpÿ’&÷³r¸©»ÑtÞ„aÿ= ¡'lOæ‘•1réwÜhp»¬íôÍgF >üåRzÈÈ:+Nb0É;j‹µÇ·Ä;]J7†0©eÞUC!&†˜IŽR4(2ë_†ÚØÁ_ãY¯]>+ËÏJB MèÅõZð+3h¯{'ëF´(­ÿ<ä¹{#«ÑÛäÜ–V¤¤˜pnÿr¹£ójø¯8ŸÒ΋®&Éш Ê|—éħ‰Ÿx%‹ü»«Ä~`¢Ý§æB†YtññxŸº:o³Š‹o—\¼oØ€‡ÃñtI‹ßI˜úb'ÄŒLk¾ëŸpm²P!®ÞciÒ=-?NNˆæ´¼4áá´ôœ–„k£øÎïé-\¥ñì¹-;C&Å·KKÖàoÇ ¬GËLâ6Íe´_{½Í €K B|p»çP5^î´œÐ^ ¿ˆ¯­ƒe ¶wúšÆŸF+SØcštrªo¼l©ûãþ/BIàP¾-F=•°²Ñ T"€PooާãÔ\„Œn4¥¦šéÈ÷ÆuúáxÙ×? E0ó g}JõÔa§T'’=Ø),ªÅTÁá_FŸ=ßøø5âxÔäÈ›30¨oiã°`?iãXLëßÂÖéö[÷]ñˆ)Œ2صõÄ£pT~±–Êܽ‘Íhü4ùÿ?0MÇ£]e¡ì´¹ÐïéˆüCê¦X¤­Og>Á[¼\¿_ÚF•§!„iL/§ ~*Ó·‘BpWrÓ·/LQŽßÒ¬“›šdW¦ÐåŠL™×:úãC„Ê…¹Ãïè ÔÞlØ&RÖ®*ñ‹ G÷L~‘jr~ ¢êÇ=‘$ëFk\ýzß7ûýûGo)Çq1êÚÅP¯çDnÒê Ÿ PûBÏnÊž@»Vt€oӨ呤}8Èsÿ.ÒZ ­üÇxi˳MÆÍLÞ<í=b¦ÌhE~–… Ùt£ÒÂtv° 0üþôv–øcíä´O*L¸k‹¾Š2m!‡î`’h[isˆ~Ÿz «ùë%ÜèIžEc¨—Ø´ÕM§Ù·mÚj_ÙtdÝÑÅè'WŸŽµ1J'GŠŠ0”£Wÿ²ØãGI(F¸2ƒ8|ĈŠsÕ@‘šaÉ«ÓzTã°p7¼YÜ÷1ù— ëùœÛŸ‡“ýOò‡âሼ¨qñ‹¥7sF¶‚8×Ã%|¹4(Q'›Å¬¯øïiKqËã#ÌJJ?s» È3%¦jÒa%Ziÿ7Çs°úÆGSà<§KUpü´0˜@-àk¢œpø¡Ð36׃†8j³dêtHmÿ0¥¾ØºÕÆ9Dšé·×=kQJ„ôÁ‹Ãã\c åõ„Og¯(¡‚•¤ý*QmLœ<á™Ð7¼ÔòøÇ8ë‡kîÚr›É`Ži, k/vöÙš+Q¾ÁѼCù|˘Ï7kû·IÚVØÊõ,äãî>M¢´­Ò §ræV¨ùÐ3l #Œ"Ëöµoâ–Ög;¹£®â¤ûôÖZ³vXŒ Ó$,>YÒe=¶"Ac¤ÔùEi…–_]–Ìáû¸>Íì»øZ ÁÝÒâ›8‘ÞSò«¼ÎŠƒþ•|ŸÆÌd1h@p¡ê÷>å-…¤&ÎMfnb”"õ"RcÁêº “˜¸´nÞÁç‰tM $¥œ§ÁàvÆŒ GZ3“±4g„·`P p‹ØfçªÖw,ªa¶Ð·à2áKM ÁºáúÃwÊÖó.­Ï•=Ókçj³9~Ó“Ky8žö±™ˆIÙ®uñß§ÍÚÔD:ƒ>~3wd¼æû,„Iò^‘:šFWdywiXŒ˜hÒ„=ßèa;UÕ#•@eìöLd¤É'[¹Í2.×iàÜæšOD=à§Ô•hEç"³Ðäµ´qQª¤ÇWi1ºÖáS^¢ìdib·, ßÏ)ñŽ˜ñŠ N>#p£–äçtKÏà%Þ¾T­£ô‰¸NðP$¶EÀ0déXñ¢¢©?“øâð ¶ž UZëTÙ ?Ëg¨Véã/ RåBÃæè­[ìýái[²¢NåñÚ Î<Þ¡~]V²oõ<ûŽCtb\¶Q.&–*2¡‰¾ïê¬,ÈV¬µì‡*ézL£û°€«+DÇ ªº¦èŒÚäývÚÀŠ®˜žE·ß7‰ÕSYj“qÄÚh”±1g~È2pØSÌRpAKRpïtD6óá$M½LšBʨÿ4TæÃql5—;jµÝÎŽs.RäGs§V­Û´Bë\«©Ø.eáOÇ}Ecø˜ìD7x€Å1½’UŒø¡ŠÓÁæ[j­÷r¼ÿ¼Äƒ×BöÓ_܃ô£ŠÓî—D˜„²Z&göØ M¤´û\‹£XÀSbM WÇÚC®ƒYT:VÄ,¶³gÑ¥½:éÛ¼Ô`³ú ÂûâÓßÔ«ò¾Ë7L€&¥ó=ôNŒ½ã!BÕ9ÈAøq³r^¬µôÊ™u(XA´%TÑðÀ¸ç& Xig*ß)áb,"L:îE[7i‡LbC§à­m£.DiH´¤žHõ|°ªÏ²§Ñ²Dõ¾@ÐMÁ°JÒ§¼<-p´óy?¦—V7ncnùPE¤\o¡¶žTâßéµÄ{ÃA¯_ÙÑêù„ôçÆ7½²R>uáb›T—lÉŒÌ[QU>‚)HeЬÉá1lš”Y)Rk(b“àêç9ÀjGçCë³Á™Gm›l¢PáS’‚ZLÚýTœQàÈÈØ^s b>ªì½NBÕÚ¾/úÔ0…¸ND½‘VÒ2áôØ*:¢-ñEAÎ87/YÝ4”™dü¦³¥ß¥qm€Bo•ç8R'`ŽñHhû ÒF¤k åŒã9ô[®)\v4‰ÂQrEäSи̶vB7<ÛtGŠ5Ÿ[?°Zwn9ylcI-ÈØ´Ö!À㥥· þ²Jiæ+9óM^„ºAH |*$Úº×ÁHYÀŽ;… j[gÝ‚(ÅÚ"b[®× ĉç<¦­9'úàð>ýnÌ3›FÕÝŽû´0‰áö<•Sû4‡¢œ[­.ÌZnË‚[§Ÿ]MAs"ÝQnÍ_ûËÝüë®DÀÔ¨†Ê@b¸Õö´s"ƘúNJ`×öBµ9sLèTk‘1çé;FËÓU5¤œçÓî§äšôtÜo›ø£Ù@1%òi)@-Ì`y÷ù÷L8ä…Д€–±  CÒÞWyK‰àÙ«x—A@T- ê$âj3gïc®ÔIÂ&ö–(ްš¼Õž½¾ÇîÀžzÌGÁ› /v”“æ\ùìK@ñ4£LM¿B ñ+zá@ƒtÃ#8Y…fì‚h¥1÷A›¢ `3̤¨JèÕ-âlBø,=ÂSéVZ)g£´)²“»ý$µ~~šœ®rÝÀ0fòß•ƒšG@ãßäù¼þ Ò×ÄÑyÍ ˆÊk6OuŒ¦[:Ä‘QžÿäjkÅFØ[raëõ§Ñ:.ƒ8Ì×lòè@-Ú°ÁôÞ“¬£Q‚œM·¾ŽtÙžó×ñœS$ËÖ]d!`o±tŒ9©ÉÏ/©oœÆ}¶Ü[â7†®®Óº„jA€Þ,å—eÊ+%ìÒè±ÂfôÕÓŽH_,àb‰ç¥.-ÀTÁùñ4ƒ lm«T½JæÚSœHÛ0JšFi•IX•ÍoÒX³…CRgFñFëŒüMY`Ã¥fs‚²Ý䢗jùcé·AÙÙÈÌÝCSê`ÑÓrÉöw© 䀜þÖ÷tâxÒñ)ž'¤Nаmfd)ÄÞSF Îx…ˆÀG`MQÝRýë>u£#ùœº…ÉdHOÝÒ¦bU¬{-Èc"«–+†ÉáLj‹ŒÌòX. r vì÷Ëù÷]Qó;µ4ôËcX\´N/Óò(+ #J!`¢ìQè>ºå±¾> 7DUS|‚T¤]ßç`r`ézQ›xŸÃ 5‚©`&ŒÎxƒ­…>ÄÒ}T ÷(:5¦Ñ^ÇBgF69Ëæ1·ömdnR…;‚A¯}å¤9ž•æ‰mÍäúBo)µMö+ßçÕC\,8%Χ„æ”–‹èÀ‘Æp1nªã’¾¡tÇV»LÃ’*«Ô/é-s[.9©^r’­¥Rîð™Réj³ÅÕEº2g\UäÏç!ËSÞE•ŒÓ}O¸BÈIÀ3™Fð­{ômŒ03>%³å¤:QÕqrÊKÉ¡šXë¯J×ݾÓq!úŽ›X’…?á†qñî×ÕÒï1J|Up¨+Ë“‰¬&·”—§T¼Ã+&A¸h éêdþþTgyuóy:ÐU«Œ2Èûx±* »ú1œc0ǵäzž†<³ yfPòŒ_A[3ƒ<~×aò;U‘Í*+[¤û]@•üEqå*±Ã¿–!BmÄëWœM; U+k©ŽÂ¸ ‡TV Âý< «HØéPû}Z¥™Âð鯵†:7ó˜~U«Œk´ª"¥kò‘êEÜ~³”`<|uÕÌ]e_ÖyüDüÚ/†2ÃÐ,ÞJ"mXYDF¶‹¸¢E˜tÉ#"ˆJ"ˆëæP;õÛÓï6]ĪF€±’XfÓEAôˆÓ¥Éïà´ŠÁ4eI’†2Ëi¶5½îvÂ.Ê„%Œyñ× îÖHXRün¤Ì“ÐÔù ßÄÅÑ7>¯«·=vÇW´1uK£MK!ãÆó‡€¥@¤DÅkŒ-’Êh‰jýäÖ©ô‹cÝØ+i–Ô/\!“Îö´Øë<ñ|«:µdѩݙgoÏómG©“4·•:_ŠÖËç¢GZ{åÔ¹¶¶TD Ïk&Ûæ;côõlþÕr?ò*])ÊùNàòŠdŦM¾“°Ö…ü=`^Yår"ÔZèO°3ÒBöi\ARÑ”Ab7ÚÍ~²HÝÏ?¯Ržg·ßÃxF[ê-ù¢O(MØ_»¾*Øx߈×;¸•qɉÇòÌÜc)á¾®6¥) +4ÞàóWaþ“0ñÊÌÝKš®íNµ$ÏWÈ€wãK~¾ÖCg9ppŸ¦ñŒ—ñ»Ê<^/=׫vÌ “Šª4‚ÿ~õ™i´Ú$hø•[LpÜ‚:„GÉÛ"ˆ0|ZjާãMÁãõßÖé$ŠziNî׺u» ÈÅ?È d˜cX’9ý݆­ÄóK™vú6TÕxM_øSý¥‰äÜç—ÉM¼Í¾À×wqªooâ½!+O°õíVüVUU‡ª¾Îí  vÁçÜÀ•¢˜˜³×¢¤)â°¬ó9Æ¿ ÂÜo~ÇFlèën^GííŸÎ6ñQ7ïFÜ0öm4Ãt†¿ 3 ï9ƒ\†nnùcû.>²AãüžþþÏÓÔ™u«Ñ;–%À[ÑFƒH[½¥Qó_^¿ú#þû;f?òendstream endobj 112 0 obj 5054 endobj 116 0 obj <> stream xœ­ZÛr·}çWì#6åã~ñ›-+N$DZE¦ò øÁ\ŽD%â’¹V\ú¨ü¢O3ƒÆììRª¸X*‚˜žF£Ñ8}ºGïV²S+I?ÃïíÍÙ—/Âêõý™\}‡¯ÏÞ©,°~moVß\@HÙUê’×Þ®.^•·ÕJ™ØgVA†N<º9{)^®eg­RR‰@Cc‚MâçõÆIÙ%ãųõÆ„ØyÄó7Uø††Zê ÄH² ʈó"ìÄxl”ñA‹÷ë D¥ŠI‹_êE²)ðÙ[â?juŠe Ý9ëá«a9¥ÄßÊ0xU-öâI^Ä$ÄõZÇNª`Ä~÷ºêè°Ó Â’ ,èµVbÿ¶šñ…½Å4ãœwoë¸Çr»•QÜ“cŒ^ôïªùû~·í[¶ tJ‚­Ãvþº 옟ú]Ùƒ0 ‹ªÎ'±ç‹2»ªäç‹ggÊu6ÅÕF©.9½º¸ÂÙyó†V±¶qóúäžÜo\×ñCÙõì/æ§CÛ†§ÉÌ/_¸Äc7™.:å¿Ùb:O f’¸ÍÇ%eBP“´rúîØôžÄ‡±){Ì….ac_“ˆ²AÛˆóñ[÷]ÒV|³&éd£-{(‡1,o ÆÅ‘»LbKÒÑ„4ìX%i}ÙZ{-cì´µnÜ…¸±]N¨êY‡ÿ£ã-›\“_U÷²çj|œêÜÇ:Ôuèë0›;£57%Õ dC[‡íInT K!‡MãZ•m2¼‰‹xó‹Ë™(ž–¡sâû|bÆKI@á©•êi # ¦è²Ñò¡@”DœûŸË€¾mòbéª7·×ã@5Â&†4B–Û³¸ÎKùΗAHA1¬dËRüÈè‚ÏQ3í™ÝæØs˜õf¶ 6g<+ª°•­2¸È†¨ø{ûü¢…ˆ¡¸'iïMv,E?TWôû `>d/+Ž ÕUõ0Ȉ ½Áynæ“é ŽAÑ?×QÃF¥é^Áßν™³¦“)hrÃã<Üu]%$¾Í¾ô}«í ÇG Úèd®AÃýå$Ý"½ yiCzdE7ùa³"vô»e°ä/~µÞXí:©#\Uk¸÷»,QR,ÛÑåå}±Rš6-§Þ»åTýb%“W“z>ÿ‡:ìYû­hÃâUEêÛ*ÀÔåAdx™Vߟ]üéåèVÈËyŽo§²“ohÇ©„[d!á"ȧÕN竘2YË1}ž9W€Ñ’p;yR€…ÓìŽË:$ö@.œž/å£qd†u“ %Û@°óC¶qñ Û0-,Û|Mh£àµ@HCdî\j‚DãGHT,ßY‚D–O~:ÐåL@ziöFëh‘7ÌœÞæ7%!hÖg’£¬H³xÍõÍÓb&½üš2LZ-XÍIü„1ų×^ÑK¦sRÿ_ 3aòˆýUÏAeÅìևƔX`;€µÐíQ\2«òžó ¶RsðÐrä0Íû‡:&%$âµâ»ï œ8ŠË¼ŒI ¥ Híúò&ø¡¸ã2K§ÐsïéÙÑßQ€u`¶°j‰Êó3k/Öà4ŠÇ4bÎ9þ¤&–üž`KÃÝ 1Èc(† œÍ˜q6Ù™N…Sx9q‡9Z£9Z°FJ¨ËãȦ—x³ªÏ}ªEëÐÔ¡®Ã/š<±ÁuW2-ëyï\¥83v­ñW´Çán¹†Èȧà²LA#w5›g¢/Ji$SÖ—<Ɔ`±t̮ٙh±A€Xž6W´¤OŠÖ¡YÄ–Ô FÝŽ§²´`ŽN¾ ¡öh朽yœº ÷‰ßþ8´Ôý¡*rn%´m',+TµË`È7JÌÑÃ^ÍIuëÙ<Í7wÇæ‡ýù”q®oF‹° ÓK#í¢Xj**~äÅ`mP]íûÌ6©¦r§ŽédBuüuÏrÞ{ª¨kDÓ0ç5¹c™¡•2 <ç²¢Úm£a¾û¢M£øakïÊlT¹äŸ€ñŽa7“¾êG-ͧq‹Ÿ‡ÑŸ¶8uOÁ­¤;ƒ‘;¶0¥S@õö»S¿À±‘¼ž:Úœ©!B* ²Í@>ƒm^»ªã ÌȮ̎Á÷ÆàÖ \Ä?J&".ÏËÐæJ<›j]4‹²ذ\ÝѾÇdÃJm—™é"ðÇqnY'{±Ù…5 uMzÒ™ÀŒÂzTé QÇ&jQ Ãôç¥R´ °çÿ^S¡|l.ÇAK¯”ÏW=¿5”E…h(‘%@0Ÿ··t’æl®idäg[#dX0m7¤½6 üu7š’3©ðÊŠ¿¬§ŽÅžãBÿÛ:Ä ŠumEF[P0õ9·{¹s]Wüëhtæðűjì[ïÕ!3,x]U´(>ÇÚñæ|K·Eˆ÷ÃÖråÁܽçøË]ÌË]ØÝPáàFIÜ ì¶¥Ú&\óÆGnžjX¤®ÿ®§Èzû†‚ò–±{œTˆä¡¼÷˜LÑkÒúA‘J’E™¤ÔaaJd¦±|O7•lÞµyxŒâWA],=mZƒ²ÛgVåEãùì«bBœuÔzµÛGÑAÝ"" ¨ð¬=Ö¢çý 6ý¿-OPcšÌêt–ýÙŽýãí.X+Á»¯'þÆ|>ͽûm~÷†ëkõ#iQ¡È6Iý1¨Ÿ& þ”H¹AæÉYxø(à¦O.g¢Ÿ‰e;xœî#¯BX‘Á«;úyHqC=ù|¹L uXKš’ä©ß U U,é±ÖQθÏÉ=žÿ|M;§JšÓéåv–þh–)’îW‘jƒó> /Contents 5 0 R >> endobj 20 0 obj <> /Contents 21 0 R >> endobj 35 0 obj <> /Contents 36 0 R >> endobj 42 0 obj <> /Contents 43 0 R >> endobj 47 0 obj <> /Contents 48 0 R >> endobj 56 0 obj <> /Contents 57 0 R >> endobj 63 0 obj <> /Contents 64 0 R >> endobj 70 0 obj <> /Contents 71 0 R >> endobj 75 0 obj <> /Contents 76 0 R >> endobj 80 0 obj <> /Contents 81 0 R >> endobj 85 0 obj <> /Contents 86 0 R >> endobj 90 0 obj <> /Contents 91 0 R >> endobj 95 0 obj <> /Contents 96 0 R >> endobj 100 0 obj <> /Contents 101 0 R >> endobj 105 0 obj <> /Contents 106 0 R >> endobj 110 0 obj <> /Contents 111 0 R >> endobj 115 0 obj <> /Contents 116 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 20 0 R 35 0 R 42 0 R 47 0 R 56 0 R 63 0 R 70 0 R 75 0 R 80 0 R 85 0 R 90 0 R 95 0 R 100 0 R 105 0 R 110 0 R 115 0 R ] /Count 17 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 18 0 obj <> endobj 19 0 obj <> endobj 33 0 obj <> endobj 34 0 obj <> endobj 40 0 obj <> endobj 41 0 obj <> endobj 45 0 obj <> endobj 46 0 obj <> endobj 54 0 obj <> endobj 55 0 obj <> endobj 61 0 obj <> endobj 62 0 obj <> endobj 68 0 obj <> endobj 69 0 obj <> endobj 73 0 obj <> endobj 74 0 obj <> endobj 78 0 obj <> endobj 79 0 obj <> endobj 83 0 obj <> endobj 84 0 obj <> endobj 88 0 obj <> endobj 89 0 obj <> endobj 93 0 obj <> endobj 94 0 obj <> endobj 98 0 obj <> endobj 99 0 obj <> endobj 103 0 obj <> endobj 104 0 obj <> endobj 108 0 obj <> endobj 109 0 obj <> endobj 113 0 obj <> endobj 114 0 obj <> endobj 118 0 obj <> endobj 119 0 obj <> endobj 135 0 obj <>stream xœ]1à EwNÁ DÝ"–tÉЪj{bLăzû’tèð-ÙþßzýpÈg.)À 3wžlÂ%¬ 8ybRqë!]­0›ÈD3ñý‰È7º½¿›ÅS¶—:’{‚Å%ÀdhBÖ5îœÓ Éþ­ÔÝál7g‘jZ¥Yg¤®RJª?åRa:8¬)!å ^Á 'üýC,)¾‰}”yVˆ endstream endobj 38 0 obj <> endobj 136 0 obj <> endobj 31 0 obj <> endobj 137 0 obj <>stream xœ]=à …wNÁ È_ÕTŠXÒ%C«ªí˜ˆ!€zû‚“tèð,}ØÏ<³~¸ÖDÊÁÉDªU· t„ÉXRVTwÂ*gá ëo¿?h½ñ]ÌÀže}Ƨr3I§`ñBBvÒï´æ¬úk5›aÔûd]q”nxš£t«/ŽJXd> endobj 138 0 obj <> endobj 27 0 obj <> endobj 139 0 obj <> endobj 25 0 obj <> endobj 140 0 obj <> endobj 23 0 obj <> endobj 141 0 obj <> endobj 142 0 obj <>stream xœ]‘=nÃ0 …wB7°ü''€¡%Y2´(Ú^@¦éÀCdCq†Þ¾tÒ¡Ã#ô‰äƒðTœ.çKš7[|ä…¾x³ÓœÆÌ÷呉íÀ×9™²²ãLÛ“´Ò-®¦8½Åõûge‹žv~7.>Ëf¿*÷%ZF¾¯‘8ÇteÓ;úi †Óø¯UvûÆ0=Gë!¨œ«()¨œ«Ç Bv}S•s¨ÀèkÁ#0*aÓ:E±j+`#ˆ{­ãdz+¯]/VV]­(V†»ƒ`'уÊÕƒ<El[ W< Ò.É.ÁU> endobj 143 0 obj <> endobj 14 0 obj <> endobj 144 0 obj <> endobj 12 0 obj <> endobj 145 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 146 0 obj <>stream xœ]O»ƒ0 Üóþƒð¨:!º0Um 8Ê€…0ôïKtèp–Îw'Ÿe×ßz¶ä#8|QcYZÜ`¤É²(+ÐãÁòÄYy!»»òï'Ø dv>¨™ä³¼\óªÜCè4-^!ʼn¦(ÚÆ˜Vë?éŒæpÖ›3¡*ê*ûO%ES‰ó&àqÌMs“TÀ2ýžñΧl_+ÀS& endstream endobj 66 0 obj <> endobj 147 0 obj <> endobj 59 0 obj <> endobj 52 0 obj <> endobj 50 0 obj <> endobj 148 0 obj <> endobj 39 0 obj <> endobj 120 0 obj <>stream xœcd`ab`dddsö Ž4±T~H3þaú!ËÜÝýsÉìÝ<ÌÝ<,s¿_ún'øÝœÿ»‘ #£›wT¼s~AeQfzF‰‚†³¦‚¡¥¥¹‚cnjQfrbž‚obIFjnb “£œŸœ™ZR©§à˜“£ÒQ¬”ZœZT–š¶Ù9?· ´$µHÁ7?%µ(¯ (37•yá"†e EŒ] ;™´{øþ3×Üfø^¶‡ñ;ÃO æŸõßËDg,î^¼¤¤»VþÏ;¶Ú’î¢âÅÝ3äùþ3{2|ýÎÎøå;;ó÷òï}¢ëòåe”äçe,/Y±nÑòr@Už± [ü(œÏ¸û{?ó÷í?rEû§öOêžÉ±ª`qvrcV]»ÜoÉ?®]íõÝ’õ«'Oî›0µ_ޝdÑOû%l¿…§²ïázÁ½g:Ïaƒ endstream endobj 32 0 obj <> endobj 121 0 obj <>stream xœ-’}LuÇïh׳c›ÚeózQ·¨QÌ| ÁIJiØŠ/LÔi v¬ƒÖ–¶GzÐèëÝsG -/G»–aEp„ÿÙ0ûÃD¢ÿ QcÌ¢™üƒñŸ'Ï“çùæù<ù>8¦ÎÃp×”WVV¼²“ŽáÒñ<éqÈÆÍÁs{@«­úú&ÿ*9„^>€ž?ˆ©püó•ÛnÚ\ß࢞.†:U\\D•ÙL´¹ÎØHU] &›Ñ¥VꂽÎlr¹ ©2«•ªÚQ4QU¦&ý™éòîær»ÍÑì2ÑT¥ý²‰nÄ0lϳ¥âS ;ÃÎcÏbL£b{±nü9|>¯ZõÚ6^Yåo««W1X~]À7_x BܪÎgã|§ ÛÀÎ$ ©—NjùP¢Q±\ð\ªß*Ô´´+íëËA`X^`ÃÄ}V›aô¢æøÞ=eÖœ¹gÁÐ$?ZZTZ$«N!¿ªñ:>‚ÐKäoçéz±Žœt$‡òÿÆQÙ½‘U•Dm¨u£î”ÓnqXì™öáÜç““ä×[.È@ˆáB­’y¯¶ê"."3í¥ô±t,#ñ¿‰3±tÏ $‰[5s†'.È9< ˆ&ùèP”Ìüxká&©þG®Zõ~w-å1û`ÛÍAOÀ ñÁRýÝwÐá1R¡3¼„ÉÆ\ä©ypv±?©¤^p„I;¬V›­)Õ:6=q}‚”ÿ=¥k-1\| èèö £bo‰¤wÔb¶[-Ÿ,:WVÐá/ÐÁ)r m }Ýq.¿?wVÞ_&kÙ¡"}Qò«?WF¦˜êb}z„þæ·Z ª$§ô».>Í÷Þb\„‰X îm¦ÃЬwÍ9A‰¼\àìvhQ‚áH Ø´~œå9è‚ °l—|d+UÐeæüÅ@8<`ïˆú2cÝÑgaŒÏ‚¹,Œ@6<DO &’íÐÒÖ £· qˆ 1¡gÇÆõ㊨vêËû‰úð.þ|w]%©7žÒED ж“t0ËC¡`Ø Bù4‘¿ì™bù0ø lÐ-“[K¡v`• ×µ«éñY1B."C–C‡üpæ(ø!ö†=P&Î|Wÿí_sèÉÝÿPäA²³¡ñt5W‚³ÄHRIð}ƒ_伡ŠèDb~:!./Þ¾¹¬\×è p ³PÓ— L0M¹ô|âö’iòã7ß­yçu²Án¡ëÚˆüæÌFIFïïï×ÈFqï̾µ‡É}ê·µÍÄ´Ú5í~ û­(éÎ endstream endobj 30 0 obj <> endobj 122 0 obj <>stream xœeS}PTU¿—]Þ{*âÇø&¨çîJ”ZÚh†ŠÙT2Ñ–b„’JÊ´À« ,Ëò%¨»{XEBsÄÏÄüX¿Å1&†0µQ'-tjFeÆÒÆû–»HwÑÑ?Þ›ó;çwÎïžß}#¥ÂóaŸ,>ÍN”_òä#W€ô¸Mò]Õì ~ ðS~/qícåcä©£di4ËQ8Z€¾FÉ(• ¨@'Qú ýºÁ<qpXš)ÇlHJ¶h&…MÖL ¥ù8Eo6ÄëR5:K²>EgaÀ¨Y”oÐ[rÞÑ|l4j¢¼š(}†Þœ¥O8^XZŠ)Ó¢7k"ÒôæÔ8³.~•ÞbÔ'Z,¦ç@œeôË•úÑPÍKœgHz¾Æ IgÖ§öÏ0$ €.†¼LýÓR†Q—‘Üd¦xÏŸ–jѯ¶˜Ìi ™ño8”O0d˜ŒºœÁÒ 20z’Yg„¡Qï¾7#$ÙðãÑÓ-‘_.]ƒ°.Ã\ޏoÄ•x®Â›ñ\·¢Ñ^÷yôŠ@&´ ¹P^†/ùäù¸o*²O”Ë•ÿôáˆhäßçSÛ„$·f»ÄíïÄäF§‚Ü`P씸s¤®“vqO)Xê@ýe‚Hº:i£…s/NÙÉ(;¦ð<í 'u/M¤$Š´.œt1šw ¾6ÛKqIÜ&Y.ÉêÊvQ-Ë­‹f¿D‹a´É)Rír’íÌ^N´^Á?%ľÑíÒ°™L0á–Â)=¾,‚Óæ°•'Òvh ¢!dËó6K†9?yéiÝOdJ+YCŽþªºF:ÛÉårõ1"Ë÷±ú{†&h\íܰҖ› faecÞŽµZ¢/þpÅô›Å*k•ØÍúô¥Ó©©ôý•T3oœB’y¨ý³ë9‰æÔó®á®ªáÊœ4¿aÍ•~~ì‰ÐÿNµ- endstream endobj 28 0 obj <> endobj 123 0 obj <>stream xœMRÍoGŸ‰ƒ³P‹†J–pÛ¬·•*QC„^ ²ÔSsL%js0x©Ž ë N¨S¯×ëÍóÚ±w½W‰Œ¥Òª•…Šrþ€V\ZE…Cs©Z$„f5¢k§‘ª¹¼y3ó~_ƒÑàÂy&Ožÿ¨W~`¼ƒwŒ˜#›žÎðpØÀ1x³óâ-Âï!ì›Ä?Œ†0þìs_0Ïx¢—温¯B<ó¡g”?rä0slšå¦Î"Ìd€±ÓÞÚ„™“ÑsS,?7Æ ‡™½1æc¹+lp Þ¾4ó3 ²\$ÀqÑx˜=Ï÷‹>F˜ÅØË3p¿<îwBC«ÍÞûy¡[¨…8¼€°‚(K@ûÑ z„߯—ñÓ‹»_Ûv>Fäj¯ÄÖ%W×—¡Ñ˜…yw÷Ž}~âñe¸îÞº§­“ Löq›qˆÄGüº®( ºtQÒ’$Š´é·ÖâtYIƒ+•…tIÒD7ñY>Ó—Jå³u U±ª*Š®ÓÄß[¦¿š*çË઩š®ÊŠ [¨Øi±;ý?}i#^ ±kF"±X$ÒŒµZÍf‹Þ½™øe…Œ´ ÝÀ›ï[ôëKý9H¸_UíOÞ^•ÒÒÅLRÎJ2]ôìó Ùüd ³(W¤õàO§n/‰JNª¢5õÂúчîÿíüm=ê½0iJTó•šR.)týûï~ýg­VV P¡*Ùâ}êæñÏnHš¼(•IçÅôí‰'ÞÄœeãÔÿ³Ñ´æŽ­?4¶LŸ06œÕ’Z‚kTÏż Yî>0멜(Á7.HVsšdÜ7ë{õ¬% tMÓk™b²ìî®’ÂCíÆ·cK¸»mû||;¶Í×—1¶¥ä ò›ó[PàZj-´Æ7Ä+âÞJ¦dø¨nמØÎÛxfÿäãY/䩤Z KUúÞ_ÏÉ»µâ¢8¨9E(šïŽ?ÿòOa¹ sJ )/{?àî>Ûþ@–ò™ÕΧ«vsxq¨½ë7è]ƒ‡ŽíºÃпD›Ñ endstream endobj 26 0 obj <> endobj 124 0 obj <>stream xœ}’{LSwÇ·î½`Atk2çvïåEйfœCšàÆ`ÙplBâbÁ»¶J©k ¨)…B%µ‡Ç”‡²ebؤ.ó ‘ ˆD戦ñ±§!J²djέ? k£ÿìŸýwNrßóù†ÄiÃ0ñ†‚¬X𚺒Q_Ѩ¯²@›##‘úxв ~òh9.ÃK1#…Ä1Ln^ñçÛî½v‹Éì”Ó érÆúõYrŽU±[ÊŒrÑiV¬Fg4)—·ØÊ,ŠsïrNy¹\ëpÈ…ŠC±W);b› 6ëîJ§b— l;{Åf£Õj$„$šékô3ÓúyŸ‘D¢%ËÈr"’Hã'K¢â OÈeFb*˜[šÕ›æ›Áú™º$yQSõ@HMÄÒuaÜfÕ¼¨û}û9³äS¥RôãS0>(,âw‚{•¨˜¸ž&\Úr †—ûú¢.)ü*èüNz†…QÜ4ÊÌDœl¤ÿÔu÷Ã@ÐnééjîùÑÝR$îÖ=Çã’ž¦q.'ØA蔞KúçÏ…˜Ë±ažU›1Ogá|•žÜž†ýÙPeÏ=šœ™¸v î ˜”:K_¤)YëÞÜz¶ñpðıPwø3qèçé¾þÛøÎº‚Ü]&‰î§õžz8¶ªžûïOðÓ,bô)h!}¹˜š®šz†Ú°„ÊB[tô5{ItjK00°ÿ|éölkkK |%tÔBCÌÂñâÔ‡!ߺÏF˜ÈÝÂ%S»Ùì1K ]¼å@]¶è0qM€ñ­ßÃiÀ%¾î(G3¿6ÆQýšjj1‰Ã×a`Ë1* '¹äê@dS€tcÅaŽð¡Äð11.+ MlÓjÃGµI„ü ’Ÿø endstream endobj 24 0 obj <> endobj 125 0 obj <>stream xœWyxSuº>!%=,"¢¹¶#ž^į×u—‹‚ 3P¥,EYºÐB÷4ÍÖ¤Mš=ç|'û¾5I›&-ʾAY.à\}@|ÜFeuô:—ûK=™ûKË<Î]æþ“'ë/ßï{ßï}ßO@Œ#hÁ²e‹çäŸ=»G›>.w¯xÇôï°a\Î {u&. ­ÌÍOP%š,Þ¶¦¾e…UÏj”d§ÏêêpB†Úû­ý@º" i9+mä¶Ú!AÌåsy^Ê&Ñ^Qÿ¬UoÖ¬€b]È­}¨ï’úè8t³qˆ³I&dÈã Et YÉx{lô¹?Ù’ŒGÅ*0 $¯y^Œjе£üµñSþ"ø³ÐgQúúö¬àüGÈü•0·$w§x«¹½ä¤$©§vE‡.ÎíZÃ?ÈÓ<ÅÓOž}Ýæ~ð‡°Û0šÆh¤æ>ÂO€6 Ô;ßF‚ïÒ{ŽÈ¾abÒÍ$îDßµQˆ¹×sÓÄ7n »Ð´½{¿p‡¸ @‚ v:lMÛ¬ÐHµ@‰³H£Î¦bAai›f@íí½Þhâïä§ÖTÏFeEŒÃæ'xº¢;í¤'Ì%óh+¤6PÐ ± PC+´qjNa×iÑ`´C=ãÒ+ý4šÁ÷•–ªÚ6ljSóSøÛ*+³v° 76Ð·Ó ýT ÒcãlЉap¢ ë83­çHB4J¥.\¸øÎÅwÐm¼¾È¥ç`ÁܦÙf3äV,§&ÓøËTº¹$Ä ÃÃ@EGÏK…µ(K fÀd·j†"GgQåà܇ÂÜÅá‡ÄœÝŽtY}:åÓFFJÙŸÜ†à˜Œ&ÆÌ¨U¼J1PÛû*ówñÿÀÏäg=øö¢OßÚ¾wݵüŒ¾!ŠoOí 'Ò‚­ƒµJL”îUÕŠ [L©L—ÝçÑócbS³\)WŒUõå@Ölí½ôz×½>ríx$ äoº^è´2&Ö–/9a»…êð³¹³â®D"žŠìÏ¸@Ö$é1{ŒÒF+´PõPálÄ0à¡Ó†XÝÇ@'˜Á`6š fƒÅd6ó>\Ä¡#¦0Ø+Ž;ÂC !Mãü<5¤˜Ò1j`(Ãgœ9†òþ†f±¾B5¯X[ÆÚæ²£#«÷X|]ÝHÐ]ÐÇÅ!g$‰QKÛ’@ºó­×\c{­²ÛìàwpÈ“ñîH~fw:#`÷ûó´}¢’PÓƒ‚Kß ‡?^$vÙ¼zÃè Ô‹Ï‚¥WøÛqÓ­¼¯çüt? ýꯟ}Op!õV‰,ZÆÒi£*ù{ùsøÛ€œÉO<ïó ÇQ!šF¿{å?ŽÜ‘çðÍ6˜im0?]. 1±œ€}¹? >Þ,î.{½n„È€TÔÈVQ °¬YUÊÿºÈªÃ´‘§!²»ýjͼº‰ñé¿\ùÖdÒëASÜéƒ8•S‰z±¢¹».£Ö"g(ßt2ßl-c•›¨ü½e/ñ/bQ+á"2Óþ õžB´òªØˆõq.mºQÓhX„¤¨•£&4{6*äçÐ#„H™ÿ8©¨3/²‰‰,ù¥SìÝÎ9àÚî¡‚ß—òÓez~þ¼ˆÞ²éÉÜY’ŸþS=]´'¯§'QzŸ`xiÄîVŽt[½¸Ç`µR òº–%ü¬²õü|Àó?:àJŽG¢‚ÚºN›Úª¦mÜ-†d8]4̹bNê$jvGÉç7: ZÖ¢0SŠ¹Ú§€¼OtÆê-FsDèîÉã-ÖF°ÐF‡!á|1;G/:úMØgŠGŽþÏ77Ùô¬…¿{$Q¤ßš~ܾÜù¼½€7Ži7nZ#¡O¢c×ÃYAî—_ ‘msîî/ì.»·ïµ=o&qs6Í&´õ]3´‘òX{w÷@׫“eë6)Öo¦Úνìo…Ê4Ͳ-+ÁBjÃàsŽŒ‡Šœë:ºÈ^\¢2Ô˜$´I¢¯´Èëù»Š¬Z³sH×G# _ÂKÙÝCît¾®{Åuè:úÇkƒYzøMôÖ©¹Éâ³FM–0„ü{ÜÇß^z™´™/l¨I¶†uT¯2n}W—´¾¥ƒõ î¬®n‘¿:¨‚U>ÙÀ€3•†,™n *ššd›—¿Uó5ZºûÃõÙñe°Kf{§- )èŽgRáLl—=†‡ù„-U›ŸÒ QB™5¢ÃYthpZîÂÍ}ßß}g{î±Ü°Ø“µ;Rò-ÑïP!̪T-ݰ•®¬_¦Y„¹!!F#F“²7/Ãçä§÷_äï§ø³"•öÿÌ·xÿwE&ï=ÈÆDFÈpàvFÞDî¢;£é¢Ow—oÐj-2Z·ÑÚjò_þ­á½ëû¾‰ç£…–1émTÇæšÊ¼B«o¤Ý'œÚ™ÁÇø!;šûUIIHîÅø¾åâß PÁ¥í—…èÊðxqT—j–4µ4©CŠL_&›¡øò—تµèðŸmØW}òÛCˆŠŒù¹ÓJÉžÛ\¹H¥%”êötùR´?Èz}=ƒ_:ƒ?ž ?y´jÏêŸoä§«ÇÈä 8¨ÞO î2ê3Jdævé2<ª‚+‡ ¾<ëþmÎ8Z|…Ôï s%¸¨˜6)i’4K4Ay6Ó×ÛGñÛþô”X½híÊ ½ÓÙôö@„ìQ…” -’úê½Ò³gÑ„A4e;õúÁ°û R|rÃÞå¼°„§;ò…9GÄC¥Ïœ8È´O]ßÉt°–¼Gu¿ž®ï rêÜ¿‹=}˜v· ƒuz!m<Üao‚­ ­iÓY„1õG쾨ʠÒñØ%Ú¨^$Å0)–ò/±V«O’Õ®„ì®.7uýrÀò€¨Ÿc lž(4_4Òm¨±éïƒâ­Ûì‘l¿²tú¹,da'dÙ ÛÏd€ôâÔÖCƒJÉq*ºÖÁ81º°;ÃydXö×àôXî;±o§Ý÷>¾`’>“Û0–väÐÊÊaW$©C~+ØbåáÀİòxؼÕ2&Æ8Fà:›~=ÈYÐFûßÇQ‡~—MaÚ¦ ØõF%£»’–Ù±¾úÆh›€ÍËóqñ¦|JAŸ\=ûµ½óÿ*üÌ‘7-m¸—Lq{PÊ„)7ewD áK¦Ó2X°0z< è$ž©úº=Ä1Ô¢²PºrÉÂWpñÆt&vw/Í9œ1Àçüäp…£/¾{ 9>ôÚÑS¸‡!ìÕå&C-´ªc¦?u` u÷ÚUë*7”QUu •êüT“°zœ@D®uPð s¿Ï}/öíâܧ€ †!0:M­Ë­ÐŠce-‡{Ì5Ùq 1µãÅÀýÝXßÓtŸÍaÂfÆÚÁŽl*RÍ+Yº:`©CvŒ<:϶Fä’*yé’s›>þ ßü6w´g›ÇW€f½—ÛôGa®]{2¸g.2¡ ªUm:µ™²õ&iÇ*`ÚKµ«#ÛäTU­ZR] ä–²ðÕãÙ÷ÇéØ!§bäPåî5³7ýdFÓÜ»Ș·³Uf[´ô*~6(¡ä'þgû]ÇàÂaª{ÓIù9ø]Iì?øqÝGÈ÷˦–fI‹Úoô˜©e¨êImüÏÂåXÆ ŸÆ!eœõ7ø"ÞB%yÓúÝÀ¶e¿)Ö×Ö­)4‚"¼?ä7™RGdÍM­5ëOÉŽÙßw Mõ¬=Ù†kC…çÐÙ[X무bÑòu¥@V)2{z{¾Ì"!¸r8=€…t;$;þÆ÷N•ĪÖWÕUË©¶ýûñÏø!ó q΋N_}óà1 2m¯*uë µùîߺÕýáºËö÷„¹EŠ-JL˨ûÅ£!Ÿ‹rù¼;\IWWàˆ;íN¹S®îÀA°'¶ï8öÚé«@žrll]^Î 5tg3–5¹öPÝñÿ¦«å•U@*¬ád·+?L·ï¿ § júÔ¡¦ðx V¯¨¯0~²0ZOCiYc•éÝ©J(YƒVFÊk0ú?1ðí:ö÷ ü½Â~$ög÷=Õä W¦’Ú´¥¸%o#”É០~HæÎ‹ã½ÉLOú˜³çy¯iù> endobj 126 0 obj <>stream xœ¥X tež¯¦!”ˆà1-iÁ*ÐÁ…q•áDD@@N¹Bî;Ýé$Ý9ú>ªû_Õ÷™«Ó¹ïÂ.95, ž+3#àìŒ:îøU¨¸îW 0:ºóæ½}<Þƒ¼îÊW¿ÿïúbø0B"‘Œ\´rå²™3ÄNáÇKø Ãø‡¥™‚óf{¿qŒ–Âèá-(óýè‹ûm,Úp/1J"yiÅÖ‰iÙyªâE¹yezjšjâÔEÓ&Μ={ÖÄ…ÙÉÊôÄ„œ‰+TiÉÙ *üŸ¬‰ërÓ“Uš''.ÌÊš¸VüFþĵÉùÉÊÂ䤡#,ÊÍÎ+P%+'®ÌMJVæ$då¥%äå§'%g©Ä©òÒÒÓsU …ɉª\%AO­X˜“¸ zó+‹ò¶¬zQ±z±ò¥üµéë2Ö/+Ì|¹(kƒ:{ãÜçæì<µ{߉ýZ‚˜NIÏ%)î_ !/}Âh/¦L˜ %16å‡9³bŠV MwNãk·»„{…Ç„)ÓO.û zÔu©ö%tf†N¨­­h«ì ŸŽTšÃVÆPÅ/kVï2iˆÖq^W%½<"³jÀ^Z¼cý®’\ 7—Üs´ ­=H·¾ÙÛÝä[‘Ù‹Ýâ°b†½xÇDoðçe‘HKK{ÇÛnyPdI鳺LŠò¨ Hsf²D­8ÜÞf{a±Ja³ÒB)†e:j‰ˆ>)¯;H#Å‘»˜Ü;âÐއ˨Äâ+|Ì2N=0r`…g¬íz3×AªMC&7Hkº ~Ç4 Òzptv5pÅt!gá ^§»¦ò¼³¼¼Ï]Í:}~‘«Þn?ÿ+ ôTµ~ä$Ý!¶Z?#MÌ„tü&wÄê£O;‚…PŒ½ÔÁÃÖÄ ¾ÚTå`UxŇ²Ã}Œ´C´•[ôµÙmû9mFVO¯áL1ˆÞ¢m<_ï²€Ým@ÜÀ'ñÞb§ÝA§˜? ;ÛK´öOo•¼þ…´Ÿí_.sÚ½FÆáÐë©Åó‘íï R|’|¡@P`°gc_‘ éŸ¾×sð8}ýãÊ/ÀI `ÇÞf²SÆÕ‹/­yiÝŠâ@Μt Í8]ƒžý ÝEŸ¹tãèç@~óæ|Ld°ÑìaàªÜšHZуbàŸý´W#3¥ÛÍ;€Ôa9™ð«66‹3i‡1¹j€²Íx¡}h–·žç4¥½$"Ñ}h zìÆÚó 6oMMÊ  'vÖ¤ z½Q£I×®æç^_1%«½­˜>§—y›ªÊ;[›½•@öÔ¥­^!ŒÔ$Óé‹·f¤¹L{ÕÃç ‰ n­# ƒÿ<ò¤þÇd¬‹sƒ‡ô[¡ˆ˜—Ø|Õë…¥ñv«Ã vÑyC~Îëä¨ÝhÔ±óh>טּS߬'LG£ª(~‰ØXOõ%¤ˆg]N/¸H·Íƒ€­ÐLí&l]$ÌRX‡póM¢ ¡ÿ·õ’£×y×çÒ~5¿T†ž™„aš%ä EB™0 Ÿ‚~ÒP>ÊE&j`áÀ‹²©‹ÿň )ïãñ¼óíŸ}äÇ\'L[”'̘*Œ¥·¾2{õ,ÑN¤s¿¼MëŸJÑÓÈnW–!‡­¦ÑïãPÎùTüøIÏ¢áÂã´ðù?1`òc‡ÌßÉ9÷ù]ÜŸ¯nâ· ¿}VFç¤Ì[ ŒÅï6âëÍ’×ÓÄÑÛ6ñ‹d.ÆcÖ'&æS'’*°Q£„±ÂTaò´7W^Þ¿§®«‹6¦eã£)×d[ç µ¸Ìˆ)øs×7@ÉVÌ)/çáü´@£ ²U¶÷+7#Iå>ºõʱ}{E ›c¶¬r]š»nù: Rÿƒ¸wín@g1HS¯KÑ)ôŽ ÍC ú[4üýeW„q´ðþ?ˤWÁÛrId| Äø/Äì5Ø‹~#ÎÍzhôß{Ì?Å]=ž÷RRÑ3I©ôæ×V™°z„I"I>‰'ˆúZQ{‡¤*“qnÌ*NÌaÑŽý˜zY˜š²TX€¿0å5Äÿ%îP¨4ƒÎœMc:3XFV—ÅïsºË]Ôi¤á±ºÍøa:†*\ Q=%VÔ>dñw²® G“âИ–œÙù`·åÑ`Ár°’V§ÙÄ<ç¨(Zèl´‚ä\\ÑP®în ìV Žù†§«H:¾"®«Ä[!ÒâÔTB_ƒÎ|ÆÝòO×±Yr®4ÁUåk¯ºèit…›ÕÅ|Þæ†ýÐå:²­ù  K‚j¬þÚ®ÎÌ–M/ïØ’«¦L½©mÛþû¸]‡™Æˆ`jE;$˜Èþ+î]_IÎäð+‘&Í'v¿“(Û)–|§œ³û \òmTás*ͳ@Έ;‡¼·ñ‹Ã)š1_6&¶kñˆ˜_ÆOû/à‡ÉÕ|Å ÍØN¯ŠÔ÷ãææÃ¹ÆÒ k$ü,.Çɸ{4x\å"È—ãZqü34õò! ³ü4švZÊçGÉrEP@–ùKc±ºÊ=½;÷.âS&ïxîJi³…:f8¦‡õ¤B5K]6Ž«¨ÝÖúh"kKB…ŠìÂ×ÖžNü=»ÝÓÛ¥®×…¨¼¦÷ª/Ñ ½dsÝ™Ïêš“ÊqN Cˈ‚÷x k½Ÿoþ¨ãú¸Jù»ù›2O3Píô³m8øÈKH SÓK^JJ¢Š ™31­‡Ç¡d­ìëºû"|M~2óœ0Žvß Ø¾œiŒ?í—Ä^à ý£Ï£ªô¢»ã¾¨Z—Vjʲ¨hs®1ŠH@£!ü‡Î¯#x=tíf³R.ÜY¬2ÃÛÓêyÝÕFs|м¿´5/ â½Éx«Æ=ø¹ä£¾ý}RÔÝ?B-«Påå)òÔ‘âºÚ–ÚjÁÀhY¨3²ÑuGp»îÍìÞ<=Y˜lâ)Wá¦oô´tà#WBf¡¹Ðf MŠ×²d§A¡Í€Br[GÚa¼DMöÿ}‰Ò¬ÈxeÓ­%Ê©=#2;y¦Øf4áÝò"*½(í—ßê xÉ(ÓQ[×*m¬×…„ÑÂHáž9Ç·¿^J—ÛmÎÇyÉoJHr.ЇÆÝòi<);¡¨Ð(óZ·%¨§jŠÂ H%^4Â]›TÇN5^n½Jy+ÿ/U4½¿¶yHJCžYCïHív؉åúYÉA4ï4úý1ÑvȈ¸ü÷ý14¸Q¡ýÞÀßsk©R½`²+ðR¥w€æÇK•0yà²m0J媨Õ.÷‡<”Ûß‹Vzê;˜K`˜±™ì:»x±º'ñXKcEwŒª?<ù“-«èÕ&åjm°«ÒU몠]•à‚¼µ¢ùÙ`kU[[mÝáã÷çÙqn[888ûVƘºÁTkhŽíiQµ¿–»Ý4w•žœ”˜\*.›°§žBÃøâVÉe4LÊïæ¿“ùÚ9?æoEªý§Iù J:戻‹QÜ]|ÐP{=]Çx(‹Ýl7 #vÄç?¾dÃF¼ƒo”s:pËÀllèhiË k¶è–¬<¾íÃkßžÿK½(‰s_Þë[þ¾oΡÕx°»Ð5™;èÆEº GŠNc*2SŒy›°Î¬0gÛ5 Á¥ÉÎZU²³’€œ W*ÛÜ{¡±t°ÅÁZíÍèÞòDÊOýïúžÖNœsŽL¥>×\Œ'=J·’ÉÒÞ­<{¨†åïXZà]8p¶¡¯ãƒ6ô&Oæ•+•˜_‹ßDõõ Ø é9Ó›ÒÒ¶¹-¯åt“·Õ×ùÇwâ·é—í“<+EÁŸÓCM╯ü0k4‰ô¸€aôv3”È×H;Ô^íª¤ªv‡Þø‡[½:Èlh‹Ô±nwµÚ’W‰‚šþI¸i’xi>òÁ>g7bÙJ`²1§ßÙ˜ý/Ýh¯6@!”–€Cè(_Â7Œ¨¬ Œ!ê7q–Ä ì¢4 fE€Õ\ñàÅ¥Xµ*N±F¥“þpà{g‘‹ ƒ¼\n_XäÎ\+~ãðç(A,^Í×Ð…kRô):)ó4Ô^»n¨ƒm®µH ùƒŒµUõ[I_“¶A¥£”ç_ äùèZA¦'åsr~ŽîøÛùzœTÕÆ5YÅKS„‰tÉÊ´„ØUP®wÇjpsh,ð•f+™Û8ßuÑã¤B)]I}@þõ4’Õ‹ðí6³Î˜¸$£TÒÖóÄ‚è17‡ ®ìÿãRiÎ5eÓºMÖ"ýk†‡Å˜a+2¦ßzJ«§¾ÍGENu£)þ=Îðq4I€ÜLO]› Äm ù6=®¿pqYº!óÅõ?¹¸<¶7™Óä[‰ûž~ÓŽ )”#ÌtäÖ)k2ÝJ˜ [–«¬§Z^»ÝOÓ´«©ŸV”ÿ½ŸJ»·øÃÃ'Ò›Óøs²úu]gÝ~œ2Ø']6¯)?ëJ‡”Á»Š!yè:G§ ²Ao5™Ê„ÚÌøÞìˆÚ.³òÊDzÖ–˜À@"­‚ÕNÕK—ȯEÍÑžù‚g`e2ï‚Ô¾ÇÊÁÁ{»ø•]t¤:Ó´j‡(w”5ærtïb5¬)rœ9:Ä{ã»8®³†@OÀ-^¼Hd}„ðj zþo´,&E;XÙy垤Œ"en^TÑ »üÊɱ¸n,ë([˜¶*#ƒÖëK´Ùms?Â[05†ggÍÍuQÉ)~œ”_Þ¿M†wBÖUÐèכ͌…¡„¯þg%>¤ r½ß ;½•Ò»úˆ¤¾#*¹Ê#iÿ,Þ* y¼n~•±ƒYK ¼.D0vVÐÉAç³­<þA|ØŒ»?A¿?4»uz †Xñ²| KY5hEŒ**A%è[™»&°Üd¥.PÌä:ÒŒ”ðë÷ !Øå¥A]eM¨ÊÉQ.øØnôd[^¯- aOo]“ÿµîÜÿÂ^,tÈ×Iû»]8ÛË»]åîZü+‡|تp¤›(ífõó¥+u›õ øëÖ­3æ¹9¿ýD³·ÉÛ$š“®çïWš‡.HyÒËÐÌ',âÅñ'û|söwµgÞ£ÂÚ³z<Þz²ÂkqZÌ cfhÍ–Tü>d|PWƒI¢o Q5ˆÄ3à>=–‰f°š.ضš\ú¼ìéùóõØWe÷ž»u+zèò‰jlôaÜs)°†l^ˆû_ Z8X¦K1šÃÏ»ûÐë8k ûgˆ—6 «XC »ÆF s¾Ÿ¶ÀŸÜ çåx™h8&ºBÞJ1Xp…øÇ`ù²§ùV±V”Ú4z«p?¿bxâƒ]²˜ðË”m`ôEs0ÑÄJʹÁÅa*zê‘ð‘ÐÑðÑnø n|·÷`Í`‹¿>ö) OåE~ž:Ë7ÎNK}ú7Ë!U¼“‘QºXÿÌ6ɾÿøªñ«w¤¨’_&îË~\x„{È;·èºë*š‰¨/¦÷R©½«q´‘±h]gKT[VCEuQm9õåu±gªÞ,ƒ ŸKݹêÕæu­¯Ð¡Yýö–Wa¹,Y˜ûäú]ûÞ;ÛV£ñ]b§¾¢;Ñå6t9&Ùwuœ—ò[yFv^ƒèÉ-<)t šéÍ‚ô 4 =zŠú„‡e•ç¢õ\j<Ò} þˆgùÚ-¦MùSic¦L¿½ðÙäEiK’·ìÄKQaóõ}ž7þ,ŽoÝ•Áñ½埪Çwä-žzKÊ/ëÿ 8¼<³$ ~ÁÁÛ¨5B‰ð´UxLƒ0AO\œ‡Æ˜MYæLS–n›!Y4G¯ÃíæX§“â8¼4ÞzÆ&£ñ€cÿà ×:@âºX¶Ê¹¨¾4ú4M “ ¾g;½žaÔ3˜ÍëÄY$|%r«ô^ÑÞGÊî•5í·øuÊtΖ:_m ‘îE÷ìEóÀ7¨b½Æ¬6Qfµq‹Em·*Ÿf´ŒÁ¨´L¹ùÛ “Üմ늻ˆîi­‰×¼ÑófTÂwð×deÚŒ\\7 CÀïözÜT¨¼¶é@Ìë ¸±½Ìn³» \_eª³ûmá2|‹ÖdõeVÒÂãŠ5PTT•ô˜‚Xÿ‚˜Ð †ã„„àÈÖQ¿»›5|Vtô]õžÑ£ âÔ¾?L endstream endobj 15 0 obj <> endobj 127 0 obj <>stream xœ­zXT×ÖöFæ•ñPsÆ–ØÄžh5vEE¬Ò‘^¥Ã SÖÌÐ{†î€€ ±&ÆD1j,ÑØnb4šx÷!›ïæß‡AÍýonrŸû}Îóð0Ã>çì½Ö»Þ÷]kQ½,(‘H$Y¸jÝá··ø¡"~˜ÿ†ØëUt&[B_1ôíÕ8lL?+~ô ¤€¦ ¤z‰D‹Wlq]¶ÃÇ7bøØ…ã†ÛÍž=s¸} WØ· á«Ü"|½Ý"È›€áŽÁ;¼"b&·¾N¸"|ø:¯p¯°^žÝÏ^á6|U°§WXзÀ@7Š¢VÚÇy¬Zì¹zaˆ×‡E¡Þk>óYî»nIÄÇ¥‘~ë—íôwZà¶":Ð}ã´qÓGn1¡iæÄæm³&ÅÍžüî{Sì\æ¾3ÆyêXcã^ŠšD¤¶PÔ"j25ŠÚJ­¡> Þ¦FSk©ÅÔ{ÔêMjµ„²£Þ¢©¥Ôj=µŒšJ¥œ¨åÔ4jµZAM§ÆS©•Ô jµ‰ZE- &R›©ÕÔBjÅR}¨×©(jeMõ¥)ªD½OÙRý©`j5€J £QVT"ÅQRŠ¡vPƒ©Þ"¨è5j IES.ÔQ´…¥…—Åoâdñõ^ó{}féhyJâ i¡ûÑôçÌjæ@ï·zö¡ûüøškß}óúmè÷¼ÿûý ¬ðxàêmƒÆ ŠôÔ*SÚGê?xô`÷Á¿²õ¯ZOµ>desÉÖÎöÖíCv í7të0ËaþÃÞXö†ß¿p}¹\ ÷¥¬¯ÌWvwø¤áÃsFˆG¬ñùH¿‘§G usôÕßD«œ¨þ–`Bž3‰Ð°»èÛ*1 å±aù› x^Ìl‰³:«AÆï¦÷@á÷\ƒI⣚îà sÁWÏTÒWtrYW%í£–¿Ï…ð¥’þÉä¶›Mü2ƒ¨¾Ó^Ìì\ɦ¨³â TŠ´ìÑõ½MÌ&x' @Wh÷éšÀGÕõÆDo«ªÖksµ:ÙAdm‰@r OÒ*u PÚ:B@7é/À^Ø5íjÆC;@B–¼ÁF>—E–øª%Ž”ôÿÍbÀ) »Koñ‘&QÙ-1?Ýe«ÏÑyJ„:H1ଋԒ=˜4ű»4ê´¤·°Æ‹‘Q™«N‡tÛêf(ãLt¨f™:BÀC¨#|ePè‹Æw‰lÒü‰‘냯€4ˆ€èRSz¶Š™êè∨ÈÄ@—vŸÃgÚNœ¨äÈ®&è)0ñ–í‘F+dqfåyäuÞZÚ€,Ð#—Ó.rXJNب=¢«j’=BH–Êဠ­¤¾øñÙ3yNë8œðoVn$‡Ðìf# ·ÁДPâgX Ày{ð*Fzé[вS·Èúÿ&:JÉ«PÃæ*Ñž›hã1Âü묻J‰LhiTmµ¡d÷óZÞÇƒÞÆˆ?‹4¤õÍÍݪdµR¡æ‚&/OòfÃÔ}h:šy£ýXÎO#¹¿8ÇDÛ)"è^ËW^#Eç86Ù¨"QbðÜ€J‰<*:œGwŸæ®àºQ8Íh訑ñMZ)þÇ"#1#9ló@Ÿž‡4ýl´]%=¨“4ë¿€òúšUŒ)œ~_×$ã+é&]Þ®Ò„çJB4©18¸ë” Ià '²3tΈZLVHv|´à‰µ”Ga¼‹4tƒ.«ƒC%glX±e&Ëî'³ÊΟ…¯˜;oßÀ¯s]/·_IKyþad{ïîßî̾ŒÅù²Uø‹™KU£5ôãöÉKmœ=º'øPÅ6ŠjùÞb~ÿ&›“:Hg R †Ã—$r<ݲJ’ù´¬Yƒ$\ßÕ/YjH³MÈ"¨D7%%ÈÁ2L’ŒûìtÅ jI^%¯â§ÛÞD»oŠyäÇ¢Ácžã~xÐx,"eÍþ<õFý~úI9ŠÙíàZr0l?œ†&Ãã•ûkv”·Â~ØY½½z;¬/ð§H×H× ÍÀ˜q,7F¶ó¶FäÝnEÐSvÎZÏüˆ]F£1y–&úƒ”¬C2þg~ 9@K5m¯vŠûŒ‡Y,ýq,’œ=°§¾J†Ê{a7šÔ¤Z¸Õ%r;¸€OuøÞÐ6Õ hƒfÝ©º妽 Ç¡ÚãM.y±$1L7ÛtclX-?»VŒâ;ßa“ó5ÚhŽ÷ê$E`Ði*TZ D3]eе:#M«IWð»Ùä$i5YÀBV™Œ?D×@Ç3B¾š-j?ðƒ-:_9žsˆ¬kMBrqiêœd}üŒÙ-îœÔ9—-,¹R I)Üf{ï¦M‡'€-vÀÓñT¼{ Ø­F3D2ÄäBV¢»4²˜iïáeh ‘%”ƒ Ìú^qíN_`½öóˆEÒñq¯¹n®‘Q2é£s=Y»˜¥p•uù¾`›=Ú£ºj¨#昙yiý’IËÑ‚nà%Ÿ#ˆFq¬QåÐ1o&?‡ü2Ѩÿ$.ËMÑ¥%«)j™ïh;Ø›ÁcwDsà‡pšm9›‰ÆÝªÚ̳\<ÔS8ªÇ0 öðÿ áåµb~ç06+œ$‹)V@×µžÔK$©—,d¹û:šEÎe'é²í©rÐ@Šml”s¼))˜,‹ž„W„Ì"R!î}ŠŠ¬îœU%dÎõ™¸Ó =`Ñv<$h9^‚'áiØ»¡Éx ZŒ–£ h*ráð·ø;vò*Dùè­/nÞA£á\Šß˜ù¶°aüÝ öãnóÒ'âÆÎy즅ÍA‹Ö ux(²Ãódxðÿ gÍ»×ÌEO$ŸÂùÈ#‹ö­É™N¤‹£|¶D…¬[ûVw5 Zg†Áøª(ƒPŽÅDV®óO³xÉŸe?I{M±”>ªMt?óÞPÌŒ_ǃ½…˜ mûêŒ2= `ñüc‚#ÃüCœY°ú.Éâkn~õMû´ —Ù™UÍ„¦ÝÊ6ŠP¯sîˆÑb~4‹$&Ü1’ï>üp¿¾R‹¸$eL"„1ÅQ5uE†Êfï† ÌØ0‚Ãôœ€køÊ‹Í¶h;tµÐ ÐJ}'m/:9ið$´·éŽ+:üLŒ¢ÐyÍ• ¾ˆºþäDZßá7døùïèù…H4ê¿"Æa/\†ÆW"¡B%,ª0Gù®M…[œˆÝÔWO;eB {ºÒ–*qçðn‡†'G,Àó ‚l{øÝp~”ç?CV…JÃ$Óåã9;”*1+ +A“ f}1–1U’`iÙuêåþÊ_"á+‚E‘ÒôÒ oÔçêêÀÌ=ÔK‰ß\þ.+{’È>ª¼z®2?`É-<†ÃŸÿ 4é/v;ŋݹí!”IK#ZR íиc¯ÀRXm^m>)vsµäFm&ä…NNÕÈ‹|cÂ` ¤Ix˜øMÌÙ- ëËÈþÅ l@a&þM“Q“wýë_tï [Ùê‘LdÉк%=ã3b'¼5ëÕà3À‡´Sõô=½Ü[¶‚–và^Xš¼oiì¶›Nýý¾cà~ïÐ.ú÷ÿÞéøXâ0VãøìF$kžŠÖ]ú¦ú“=M§~'¨ô 6¡YÑÏçÑ*1²xz” B+Ã$šÙÃÇ)™ÈoqàW³x¸€‹Ïr„{Œ/²]¯=®«$¦­ÑœíeÊŒ™ô§t~/[Vb 5ÕV•×÷4HÄEM©µú¸:ô,úâì’ûKè)oÃâÁ¦UEžÇá¤í…㧯¢÷Œx–K&§U€"¯óh[w8R5š¤TÎw]`{Û;$â™SGÌ:¶àjˆ,Oy$éB,#}X“º;µÖ»<4—X9fÑæ…3ƒæeÚÀ­=®:«iÒ䦀êEE:wWd–V——ÅV¯o8fÚqÖç.©ÈÞßüˆ,ž,»1Ó 3·¼ŸšÐs'}ô®˜ï䟲=í‡ÄWeO,´Ìÿ}ÓŒñQ”Hÿéš¿R/T„Žâ¢?_ó;·nÙne®nki4?ôkG£Ñ/½:QDã1¯Ôc1=më’3•G9ômÏ_®‚êOÏ…)hâÇûk?­ãÌúOzíâïøðnHx<8úËrŠ_‘·Š‰Â…Wr²N»$O_‘¡\Qº¡j˜êCppLTèÆƒO\þôì}NÚÕ9¹W]xePPxxPPex]]e¥ðÁ`ÔÍ.GöÍ¢¦*”}e=žÜ9›íB’èn÷Wˆ¦5  PJØ%W]®9D0$ˆ; a$ç iÓ?…ƒäõ ÚH€<è‘P¸Gè —–¦çV*ry‘_!žnfòÃ^¸¸awÅ(RHª>ïW-$lI—'ÌéNX5}Mß“0•|*$ãIE \ëNF(=GeN1kòr~ˆITÆ'ˆùiè6›SQ²ïœöåX"¶éb…æ¢Y“Ñ@Úl¥üMœmƒ{¡zE¡xmu ”úÔ8ª#^%Î@º¢ ÆÈ&3A—Vž“žÛcIðè:Ú.z~NŒZQ1«Ñ¥e‚Ò/žÊÍ>s¤]W.ì!H•Á¤Ý[¥KöP¦É•C"D%$¥¤â¸¿ Aÿ!ý7‹Q»¡UÓª~AÿÏè³]Ñî1¶Ñ±Êh²ªVû‰®ê NS'¬ò†Hð:&4q¤è­ÍÅÓiÆPq,9þ½‰Î¸OZÇñƒþ¢NúÑxb0¹¢ï=D’No€heÐ%º›f«zøÂVÏËÎFôÑœ“¨¿Ó$jC½Ð¸Ûbô˾½Ùqƒb œôáŽæï®n 6GîHpµ¿èp÷é¥ —ódÚl’ˆ= ¿†n+„3äþ®j/3¸ÁTð"k¢„D_™¶æ|— ðßÐ]¶ô°© Qˆu$Éw$‹.ZØR“ÆCÞ)@–8çØŒEõÊ| ±R¶5-` ÒlR‡C ™ÓÝ ÅêÜÄ E^`Vôtœf3Òò…‹õfx(aƒÖGXòUùþÈ ÿÝ&#AŸ"ÀC—™Qøj²yŠ›ÓåÂG¶ 7CÆÌò"âÄ0t.gÿMâ骠ŠtÒÍ/u_˜BcMÈ¿¼æÞ‡F«ö+[ ™ç/UYKãäèö×lºG[0å§ ¯Ë>s¤×†)ä~Êr¦‰·ø4{¶l.Þ ÌìÅÎË ±Õµ¥†êü´†mZYM㡼z`ð|GæMd[¾IõjeàüaÁ•y÷QØ™s[;ʸT4‹CO\¸Ãe‹{ãáÚo¢Ù™œ¹Ù{UÐüh~&‹–"ûììcG®kmMt¨ÊŸÔ“¬ƒ$‹t«&3’!n×.ÿsø¨ ºø¿dì…4bZ†Ë3“s!É6Гô¯Äu5ao÷X“v‚éû_U®¥I”O_R·Iìî½{UV›šÚŠ:…ª5¡t‰ŠÊÕÙ‰G¶œ˜¦X5×fîOɹ™¶PT”cè^¯Y¦Žƒà¬ Pq´š‡Ç˜µqvµóº­kרwùCµÎ¤­&µÚ®®©O-€"0Ö5œþ²Î3[Þ²9[^GКœ"Lrwk?ÖIƒÙ¢Ùm>AŒ.¢N°EöNÿ2ôìÖ Æÿ«¹çÿvB*XÛX¯„;öy./§¥—ÿ¿i©YDå~t÷Èëù9TvÓZzÍçû±èÂ?qâÃ*Z«Í.¬é`¤ñE훿úbÈ2î1–ÌÝî'Óãb¹ÓDo´yÅ-”]  )´Ò«Ú]¿ÜÁ[íä²3ÀËÏI˜ƒU†7'”ª.%áì%>EE–wŽ „òk¸ø×ü ¶ôľÜa®¨Ðz€ºP Ÿk ~D@ªµïr·ÁÓøDMº:“PÊî“P-°¢jI7ˆ·ëÜ…+N@9äû?°Á².{<—kôš,Ðÿ›Õ—!=-ß9wuÚè“õ»  tYéh6ŸaƒÞíÊ4hkþ”!¤@\Òïf°BW]´–þT‹f³¨lš0ȵçv }”Ô;ëèžFõÎZúÐ4†ßJ 3.Y%¸]|ªk‡%ªz«$HÅ÷¶4Û[¬/ÿÕÑ Bq'ŨéY¸*GýÖ#K4`úg¤ËR(• ¨Ëbd?Ž=§ö<Ï/±Ub¨AÅ(Ò•™¹÷¾@ÒO¸#È"‰á–°óÈZdñ#ZiDÖ7­?ÞjBÑwIŸÌ;¡m,zmöLmÝçëá´AÑJ ¸p¿ S•‘ª!wM“E%o‰ZJŒþ¶,çò½š<ŠÙ)q2|ˆŽ”Â,>3Ë+n>~ŽBÕ¶ì˜bo'lf¤¿Érw ÷ôÝFÀ¹îXì'z’âyJª*+c«ü|S·M??žhóô$È——•£ùÏEÈÚˆæÅh›=~`»oLHhhIH“¡07“XgV«F JÿÔ…+WÉ’ÌHÍPfäÝüõáІ×ÿ›ËÌÚõ­¿Nl¡>­b”õlëø_'>jÅoü#žîŽ'?²âæýÖ*«ö{ÈóÁò{ÖÒ.dƒ®³•4ÊD›ŽT¶+v¹xp ¨Œ7ïÎi9åúá,<Å,•IÅÄ,zˆÄßÿ\'}ç,^â½ik‡^×ٕxJQÓßš¹Zÿä^ñAXeâJ½aiÜ¶ÂæXŸ@‡mĈ2fI˜UŽ´¢ƒoÙ*æ'¡XÕK ËÀ`ˆ†®G ’B(‹Š‚è7à:!¢¢Ê P†È;ID PVø»¯xL)DßmÆ8håÁF7I«u0+Ñ]†+þL=y1­’ã4äت ~€‘ÞÄ}¥äñíÖOw7íŠ0pîjE0Ä1~Õ‰eÅ»?Yßn?¿¶ ‹8,ù§QÚ=]éÎA9ÿÙ•|R.‹ˆùþ9›#¸‡r+%¸?¨ ”eL˜Ä»c­/Î9SŸ•y•xyHäqs°(ÒÏõÃ2x“`ÙåàA8Ë¡á#ýGÙÇÓ+ oïÿ´ÇF`'3—,.)fµZMŠàÕ®Î2…‚QÙ ük×}6¼ÍãÚŠó3³sP¤4È»ÃéC‚ùˆ—’`þù)ùÐ> Kéu%h´J¡;i˜‘Xä8JöŸÅù˜XìGÂþðëƒ_åÔ@r-—¬ŒÛ¡“_¢`þ诠OíLfñþ1q¼zCÒ ôÎä‡#ö£êý‡­¥WÐL~»m·r”0§?k¿xéìÆ…ë<·:ørÆxöËæCGáóàSƼk?9FçÒîÌå%5‡U‘¾õîÚ éŽc‡ŒxºôdùýÍ¿7ÉxµsÑåq¹+Z™1nlmlGà‡µÑ°š±Ÿ¿qöô…ŸÞÜsdOâ<Ѭ¶U¼#[[ã•°K¡à4jÆ5¦×g}yæSY¾@²z&+-=M>kîãP鲯±´¦ZPÛÿæ²îb½H²3ºõùéSR°¨×Œ§è½óžYK1…ö¡_Ø5'/,ݘúñ„·æ9Ìó3F×™ ƺÃÎÏ™+h¦í£H»$õÚPWYàÖª0MŠ&\ )šT ìb¤]ry”pû%7š—ŒÃùnŸ_ò‰¯¬1Íd„½LSˆ!(Ü?ÁuÊÃeH„úß¿ÿôÆÊ«£Ê¹re‰)»…SYâcu±%x²òGkM´`/Z€ A=gTê»ì–`én¶HÂbbÐçæá~aËSxÀíå¹Àd¦ë³dÝÿEøJPܬóG„‰~é:ÑçkÌ_û<“ QP¾¦íùX,qêÑ› £ˆ¨÷¹‡wÄüzaJJ›ˆ3’»vøÃo³š|÷8®qõR¦qAÍŽ!ÀLÄÌFLýgjƒ¼ÿâë/âBž³È’~t£ý³CµÑÀÅ©¢„YBV“¬J$mjƒiúUÃÕmA4ôhf 9"çþmˆ§j‹2¶*m¥·(š‘¡íB¦®óˆá"Ý ›™„{KòÀç/yY?¹ÓòIecZp ç©N‡(ˆÌ+McúºgÄ5%((O‚ÝóiSŸó¯q}zÍ4ôímÌéÛ÷¼¡o?Šú§l — endstream endobj 13 0 obj <> endobj 128 0 obj <>stream xœW TTWš~EA½‡§õ=PQ㊑i$ÝÆŠ+EŠb ”²(K!.ì[Õ_…²+û&–AJ Œ¦£qk—IÚq\Æî„ÄDÿG.=™û &NÒçÌœ9·êœªóþwï¿|ß÷ÿWÁXZ0 …‚õðr÷›÷¦üsª4^!M°&*lù¡°ßÛ l”`cyzÂkž£°ò5|o:d” …çj¨] њаX‡éo8ÌsssuX­ÙéàKÿ„;øDmÓ„Ä&ÌqXî°N~#Æa]HLH´6$xèl¨ˆ]q±!Ñ^QÁ!Ñ‘ ÃLYœ¹ÍË}oT°Ç®w—l÷ŽõŒ [«ñ‰[¿B»3><0"¨™a&1›˜w™%Ìf2ãÏx3K™)ÌZÆ“qfœ˜eÌ<ƇYÎLcÖ3+˜ùÌf%ã¼Çü+3ƒñeV3~Œãάa<˜Ɖf‚±d’JÅÅ5‹`‹+JGe¢ò™e´å#«5Vª1ª8Õ5vûwn ÷Üz³õÀ0÷a9Ã]†ë‡aco³×–·=cÛc·c„jDÔˆo¤áv?*×ê0£³YZY©úÝøôrÝ¡ˆ]fz1 ¼—¾tQÙÑÙY\‚ZuÔø)4@=Ü‚gfã ¢Šr Àh<Ø…cÆa•êq¶š­V7ö@ ‡ï¡ŽÎbÉCiiµ"Tv?Z¬íbÈf“ô¹YQ ¥”&àsÌ¿ tW. ‚`è`‘S³†vHÌÎÎÐg‹Äš"ÿ‚VÝfUŒnDA$xÃnjt™E¯§Ì¤‘™IöÚ€žK! ’ 9×hh,†ÎS£Õl>øéýoŸ©ìú­À, 3)P‰ 8†ù¯‚>$^aïh=Z¨ÈÂ4+5ûY‹ä†§š­1Þ„ct Å»]—OVÅ,Hýo X;);£YÛ¬hA\†Ã”RZóÅɲO¯OÊÒ÷ìZ>8â8ëìEŽÅ±yu™z½^§³³÷C4xbo]UËáöû„ÍÝ@<—ްdÂWsqÎkB.O°ûÑr¦#-¥ÔcVà´v©W>§Gó$]z?µ*´`O4꾫*ˆÓëwg%èâõ ÀŪU5Æ?úûïƒþƲrÖcr"ê PÍIÝë^JÎM)û2È-æ]eQ•¡à þÜ ¥ãeèe˜èθ¡s¹|øLNËOH `ã*¶6xRXLš:Ÿ8Éßþí»Û+L§D_=s­Ì¬W:œ%‰%Š'|à¿ÄPj=pôzzu‹Øtþbn ´Â™ÓV¹³’™$3úVâÊ* 2+>CGÉЦìOéwák 'NxÇçcyíbŠ“42‡8‘í$ß o =‘E;V–aØŸ’Éz1•Ì"¼ï¿èMÆ'¿Ujuu{¸H+¨XC+ˆ> øöPSŸ*%?ÜÍ×äB]cú-íb`›Ïáµ4qοs"£ˆÃsgœ‰3Ïö••쇌}úìÄ q÷ÊZjá¤ÇñçÅKc«áTUsÅñ÷«Íð ˆa£œÞÕO™¤–þ‘̓‰]‰ŽÊþü+aDÀ©$šÄ‰d %¡è@q]舡 Wù•°º)äÿ[™£Aý1çËÖkgnܬ»÷àSuCÀɵÅ^0 ¦'/Øè­Y¯^òyK^Ò} Ž–&PZµüB+7×ãtJ·¨%³pñ‰÷?ÆòRÎ` ÍI߆ ŠM@x Öû}Ã6‡mY¾cž¼¯Â·KfìfŒ¡ÂhÕû9%FHN<ªÌdøsUï•RS‘Q¯Ëö§¤î-·íxÂÑêæ’3­¡mKœ‰2„p‚ÓbõmòÃ`¥îÐ:5Ð8j©:¸°Ôm&]Þ¾¤»†<Çvš*lÀ <¾­ÂßÿõÁsdf= nâÀ¬¡XT ÆÐL× h%†Å×¥ç‚Û²àJæŠDÄ.ÊVÅåÌœ÷ö>—Æ8Þ”‡óÑZ8œ¾¸ ÓÞº:SYk§ï1ÿ?h<PWªÈ‚_ ü¯–…€l9Žo>½sO(šîcL_î}%ŽÁ•|ÇîóPB+tq£3²9©Pl(­=XfÌΤ-3‘ÓÙsô葊ªÚ„ãê m‚Vª .ð£xÖ¿½4¼0¨M#îÝ“¡ ®Ù^µ/&Ã+ÖqÞŸ/ÇÕøÖ—ßy´¶!ºXð¯]ói[Þ ™u^R T@¾¡¤è0‡Ãsy¸þÁpýáCðܲ<]ÄóÄŸ¿u#Ñ7,l-eĸÐó-—/A‰Lˆó³äô7ÐO‡œþq8ŸJÀ°þ…üÀcšî§ƒéFœ„.x Òø‰=6t³_çouÛ°1Påž¶u¦°žl² çCûb˵Ééïèb¨¤94*Z®á¾kJÉVZÄW@Þþ ¤î²²“Ó3³£J·çR•Š 3€Œ™„#ãš2ÅúLSÆA8z:¹·Aë·º´'JȨÔö§…ìX‘°ìH/É3Bi¥p´âlØÇPöÝøZ1Úwì6Å—‹A'4¹ W½[Üç¡ •¹K£‚!1_ÖŸ*È©_¶{YsÿIÇŸºiI„ ˆoT¯êÍ…ÿWÇÿQ¹L`’LZ3ž4a³yÔ Ð[ÐqìèýÒQYÆ7›nÂÇܳI_/aÀêg¤÷"ýïCHÇ“ìè³8\uŽ'UïnÔÐl9]Ašsa÷õÕÀ}_üäHYZNâ}z¢^ÌÜ®‚U~5íiFWúm˜èPQÉkl¦» kŽ›÷z½ ù=Å¢m°µ±f\T©øžæÂ¶M‰¡2˧˜Éô Té§ûOŸžÍí¸GšXÇû±7oŸ9[è ôeWDD†¿ WkèÈ¡X,£Iêü§ÈZ¡Ä˜~%ߺ£)8(\Ò¤i=ejjȲ‚6¶‹¯0ì: ÁåA†yI3YZ›$s?{ZñÙ¼õD‰yÒj~zuöM8Âuš.öô<ÜLÆV 9ZÐWüTMôfet¥gëSRõ¦èª§fÐÖ5yÑ<¢XÞ¼ùÈñœï±ŒÞØgqźjíáĆ(ðãÔÚ?ËùDlÄ©i‚¾râ_"Ì{aCA¡PTTp¸®î–û‰rCr¾Ò×÷7¯'DQ'umîø`Ÿ´æçžíÇ. X³ð¬ºn¿f‰ç/²’ÂN»ù¢ö6Ü3 †·T¸ø—þm)£Å.T–®Gçøg§ì¦sø?¦©âI Z P‘ÿ§woà™©VÝ5>§óÖáßà®Lϙң»,}œïZ@,†˜XC^v†Ét7<Ö?–GK³*T7 éš¡t\FËb©f›Ï ®gÐ,o'»#Oæ™UoVС܎Ï+9˜IÊCuºW‡òúêÌt=è3S䡼ðxBÊcuK©I$¬Ê/±¸d`TÁcf Ø—B¾± ’:`¨ÇøwRµVâ4ñ8êû⢂ë`ofwëâa;숕O*®ÍNËÊÈÒéD²’Lµ’Ôìo)*#ª®ÿDÑ×ÙÒâ’ÃÕåhKœÇå¥Q—õ\J<Ôl­ñ 5ì„#Ð&ß_öA<$ädå$ùiJн?X²åóÊrò.ȱGê©BAâ`òØ‚!‘Æž•"N"‡ ‹-VŸÈ÷oº=l#µ¹Èæ¤J<˜š“Q™ ËN×g/"kÇ+dëXz{Ù;Á"­qöÀky Ó«Á¾ˆjV~e–ë#¥qò_ûjÈÉÍ+ç^’Nêéb\DÿJþ·ÙøÓ`6þô³YLz@ÕƒêÑŤ8Aá$kŸÏñOÝ?#Ž>dX¦kàñ„úƆª–Šôò½E‚© –öîZkˆ›¸%o’ù[‰Ò¹øë_|Øv¦RÜêï„NUU>TÓÛÅqµJ¡†#Šóülׄ›‚Lü'2Mߢ:¡lLf^¹imú*ûPí}|ŽXNݼlç>a߃e%«`&øziý¹ÿãÕKqïÜ¥“Õq ÿ©ÿ¯ì«sxo/Éið¯2ú]QVQZÙù^wòi¹Ó÷}I¯2g?!½7ïÙ$òçßï8WÞFŸ2zE¬‹Ù.†ûoNÙ Ë`{Çjn°ùàçn¡M•<¡`0­Ý3i=ŸE¦> endobj 129 0 obj <>stream xœµ•yPwÇ»i˜îĨiƒ††Šk” `­««c<Ð xD®…™áă…a˜y ÷}Ì0ŒÃ ˜…äˆGÔ°(‰×*–ËZÝ-ÍcùëÉ-·1šd·Ö¶v«»«º«~¿×ï}ßçû{$áè@$)’…øøŽ¿Íâß%y7þWà0û¨=Ô œ)pvìp›à=%OF«&¡yoI®^.Q(w§&Äŧ»Ï–Ìq÷Y²ÄÏ}E²,5!Z*w’¦ÇË’¥éÂG’û&Et‚,}÷<÷IIî!ã;ÒÜCdi²Ô YÌ‹_KÉJUº,Õ=H#K•ñ¶Ä›zP?êAû®<½ç‹=œ> k€©ƒb#'HÜ=W) HòBå¼AŠŸŠö±&=‡ÝDZhÁLüvýÎQèÍ~D4—”äçi ´\ŠßÚt)0ÒYV´‚3ÐE¶ùÜi²Â3(ÃE ‚¸ä¾3/ùþþܳú Êbvÿíz…t%â<ÍÞ|P2ò–œ£±¶µMiݹXî™/Ö!J„güÜ­ú/¡ ZáòK‚Vj«;9ûT°¡cÂÝ.ôðj¢ø ‚rc­?Ák¡_1hÖß"tÀ° ’é…ÚšNéïÐ÷«ý8jP‰üÔ‰sÅ P•è}yŸM¡™`Û\‡=“è–E ݯuí"ˆÈJbtè;æ~ªc¬ùgÛqes̰!#ùd¹™(´”ŸÅ"ö@*‘nnÜó ™]·q;©«é'Î}2xEü'U(-‘KcÖÀh£Xˆ2il¼¦M}H"ò…Vòc¬%£E‘¢ÊP&›3ÍíM“‹q0+§ÏWæ Í8ðs3މUÃ)øãxjšÒ.ŽwçØñ4¡næßµ‘M|:Å{¡»l¥©±÷|‘°J®Í‚$È€}°}þmi2ä@®Tö¯qµ+vDu:€Òé–Ï IpKªv (!´<¾aª45Iè=üƒki–¾ Ê¡L_Þȼ<.ŒháÀÈ#ÙwE $LCFVP¯{GWüÁȺÀ, ²ZÌæCq°ké9ÒÔ Ìç§e>\4·.÷ƒeÌÒ{©g¿êï>b—D´ÇõÓ|ªî&7 ÚD‡¤åeÉàD½8à(;geâÎð¨Î#È-«éÔ ’RÞÏþåHçÃ.ý7>üAºaoLÖõ0Sàÿí„ÿ/ g[mä½_°ýý9Ô4,XÖÀþ’á&º¤Âz¬¤¼%¶WvD?~ˆX4uî#L…F¤J8} M ¯n0wöÙŽÓö4‡®UKÓâ¸]IÑIÛ â;ö´þ¡JàUã2Zù™Æ{#‡Ì䡤¡Ð$ô˜EehR÷ÉÎΜdƒ8[QªúLËÆzÛqÙ …Óß³X‰­È9è6"G ihú¼»ïû&.S¨94 _`!y ·9×¢> —˜ßþõK[lB½¸!¶ÁNØ ‘™²ÔãöDë$šùK—k„Æ­ºEñ ;ɶà|Om­ÆÀ¨DI8ÂÉ$*nª¬­®(»uBññ"쥌™…ýoœžчz «V|Œ4ÇŒ˜Ã_3?š ‡5£ß “)´EÃftÅÈ3U)Jƒª­¾º¼´L\\\EÀè!«`}ʆÛ9M¡N ¦ ´ ´rø*¢Å/s4ÚgÉCèBˆ¡èÏ,Ü*ø&n8ê–ÄÁ*y¬¿"P˜Ïò•«º–_L;cÇm§:¯éÁ)FWÙßC@S&"sÎÀ0\‚¸Úpºñë/Ú{…©y*ݰ¨6–ÂX Ës‚3±C`fü+‘à2úá>ÆåÑû(QÐ)-eU¢Â=y¡ê½ûsC Y˜šA¢Ö–³ç-fä…܎÷$ó¯ S›Y3{ÑÖ>(n¶Ô´f¹ZЊ N~>Ìí㫼‡¯YÏáHœá”Æ“´KF³}y3¶Ô#E•K«iÛ„¡7ÅýŒÎo+‡œ'Ä?ñnèà endstream endobj 9 0 obj <> endobj 130 0 obj <>stream xœ}T{PTU¿—]öÞñ¹Š“Ý»™&f€˜…à(Š‘1*‚š òÚöÁ‚l(˺,Ëî·vå% "ÂUDÁ´ QÑ|Œ#:cf£fÚ”Sj:“ž»Šî‚ýÛœ¾3s¾Çïñ’z$IÊ"¢c‚CÜÑláuR˜á!¼!B×q×Oð‘€ôØ Ï“ÐÚ‰(l< ˜@HH2rÕ¦•Z¯ÍLÏÐ)ü#æ*‚CCC˲•ÚÌÔäEt².C™¬/YŠuªÔL¥N¨X–•¥ˆqgä*b”¹Jm¾2m´s„*[§SjѪ4¥6‡ ïO—¹ãÜŒ•º@Ì$‰5Ä "’ˆ%¢"Ž˜Løˆ³ñq—Ì%o{D{tIb%CÒÏ¥ž3FÈ€‡„ïˆGøKx—7O¢iW%B7rÊõ2“ž‚Ô¥Z¬ðÕÉUßbšyYŠ5R ÖAGk¨¡Hd‡»¨Äbˆd4B:%VìY#VDÛxaQ‰F\+å¥{¬åF0‚µ¬´g ?ö+ˆK-Î1½‘;û N@‹•æ©®äÔBçàœh®ª—}‹—: `Ëtu0ª; íÀÃ7c)ëAEÇi\/ôÉ‘/~ì‰Ëd¾#’ïÿPMol%Hé ’›ëmö| ñllîJ ‹Å¢¸qŠVèáT++œ¶SÈð÷Ä #g®„é•À9+ª‘Ñ5ÕÏ>ü£l 0u;mâ9 ݉‘ÅÐÇ ]T_ 1<žLåƒÍfÞ³†ïùùŽ— S£°°éÑW¸\C]¨2dz¸ˆ²8R®„=Û>öÃÓ=¹ß{u·ƒýˆBã*=yjÍ.ç׬ðµ~ø†²õjÝöÌìÌÒ sÞªGëÐFD×ò'kÒ°{ò¡ ôîž5[Dd(¯-W2 &"ƒ¼¢8¨¦ŸÇýŒeo†¼Çã©¿Í{¤½/öï6ƒµÄf5X˜¼•±™ ’ZÔ½YýpNÑözùn4ëû#'àœ\eÇRwôMn\‹êÈÖNTÜ)A—„0y£Ín¶Øl; L™e—±Ì²­#Ñþ…(±$uíÚàçùmförQ³e¿~¡9Òéäܸ …YW꙲:°›€6ÙlÛY<‹ÒÛmN‡Ý^é`œUõ-Îê&õ1Í9 Ÿœ¹Ý¯>XTËf·gìN®Œ­]Qi¾îì³—Î9Û8Æ^ê°•]å{Ù1ê£Ô?@i" ï¡Ay¿ñö MÚj`lɰw±ç+5†Û)¥¥t•褮Wt5/*;êëU–ŠnÅR¿žº~³2*žÁ¦ÿ{)®ÝwD!vðÂ\ž†·® èàYd¤^m(a¶„lº´ºs)LÇá8ÏÃ)8½‹Ðò;?´ ¶³{S©@‹d6ºIQ¸-Ïð(´‰|2€˜F š'øË‘‚Ç ­—Yge`¥ રÑ:Îßdõë¨HõæäœÔ¦_˜±Íó}MàÉ/ï ü!‰ð> ¿*ãr“Áb.5EÀNQöXYg÷õ÷ï^<ã<¥‘WÀµ™Øããw‚ÓÚJk«;µkªvšÍ6«…Ùwÿ|ÏE  FÎ_¸ñØOXó¯5Tûø ìñGÿ:?ÕØ endstream endobj 67 0 obj <> endobj 131 0 obj <>stream xœcd`ab`dddsö Ž4±ÔH3þaú!ËÜÝýƒíÇaÖÆnæn–¹ßk…¾[ ~·àÿn*ÀÀÂÈèæïœ_PY”™žQ¢ á¬©`hii®à˜›Z”™œ˜§à›X’‘š›Xää(ç'g¦–Tê)8æä(t+¥§•¥¦€-wÎÏ-(-I-RðÍOI-Ê+(ÊÌMe```4``ìb`bdd²åûϸã'ÃÆ?Jæ3¾ø¾’ùûß颦öOîžÍ±&wIvr}fc»Üo½?nmµÝÝ]’ukê¦LíéŸ6QޝxñOû…l¿Å§³æúÀ}x4pZö endstream endobj 60 0 obj <> endobj 132 0 obj <>stream xœ­X TSgÚ¾!.j­B£ä·s¯µþÖ¥Újí2¶ZÆâZP ¸tUa Èìy“aK€ ‹€àÖbÝZtÛj[l;]ìÚ™¿Ë|¡—sœ/ Óýœ:3çžœ“í~ßû½ïó>Ïó^1Ç`±X~Á»"¶­yÜûv©g!Ëó ç7ì,&öÛâ‰_˜Í†Ù3Ürãu ¿=>—`³X/ì<œ!,Èâ'%g/Z¼|Ñš§žÚ°hsZb?>6}Ñ®ØìäÄ´Ølü!uQxFŸDàFûÝž­ ¬s÷±QòåÆ<£LVK4šBÐ*m™µ¹UNÊ íª6 UPo•‚TK˵I:pƒÅPi©mìoîoê'Q>ÇÊ<í›w¸$FRù%• ï>ª‡êt©:4VB]•DQ*³SMÇLp4^<(er ™Ê°¹Ì _&‘3ç6ë#ÁÄÚFn 9è`!Ÿ«(ö&Ûâ¹»Oqx1‘UÔèjrôœŒéÞÁÌe¸Ìbfé²sÛ>D¼÷7›Aj•*5šR)µyÕZe!‘Yƒ£#®¯'è®Ë§Ž ‚Õ¶8rÎm¶ÄA6Ár³^ÿöwìoçy<\s»Ù|H»e …4ó'T )`>¼îU;Ôpx #’`™¡Þí‚B¨•büçÉJqxbI´š'•h ÊŒ*S[§Üt;Q¹§1V)Ó–Ð{tj'Ø@ÆòÄó´i9ç'¿Ô‚̼*0˜ŒVÿ Í<4yQÊ—KC0½ûY1l{1léèSuiòÂVy»ÁlÑ‚©ÜFãj¿ïíר×à¹ù×Ô~êáz&¹–.t‰frÆ+BR×?û¿ ‡f‚8HPÆEs\yÞ"ÿv‰aQÌ¥Ÿ;ÞÂÉ£¾çKq8 §~¶@ Þã ÅÈù}õÞÖ¡` Í,b®s™¹œTЛŒú ­‘¾Š:}Ñ&ΧÆßf®xæaƇȺýà@z«[y•í1"7÷³°+ëî–sÉÅ]ˆ‹×~„bŒL7áûO§œˆÝ~†î>¢­È“-Ãbr–Béôˆ½ÑûüÞÂèP? clÏ™‰5\­^gi‘륪RFE-“–h$ÈçI* ú„NVªRƒ†Ú͹…®X\_63“y”Yº~h˵®cö“GiëþîÜ#Ð öf›»®§r¯çí‰&GN‰ÃówòÌWµ lÆ&:¬‰+M}ñ™ _–žk;åFþuýtóù¡S}`†FM]F…¨"òA¥Qªåä]¾óBñ„›=‘íy‡[s鬾UKê+µµf¥¡,5EZ|}*ŠbÈ—X4zXm΃\(SËÔRÆgrGê©•×h´¹ø óþUDÓj@­*Ååžt‰#ÿáž0ÊõT!Áä-C‘V] <+”k õÞ°/i‰÷Ä*7 ­ø€=qzb#W[®5B9©Ó˜KÕ ”Q;7Ç\Ù]³Çǘ¦„yòK…¢ ¥œ¨(…\R½—ÙÈÌÛñ$ž8‹_hFkn zì“O†Þò›®•ë2PÑ^"±êµµåÔtµ™—ÜèÑin }ƒýóN¼T• !Ë0ÍË “ kD >^çÔñ°FT–‚x/+Œ&gy Ý…–š ›ã†‡ã™…–¡åÿ=º?&‰ŸN—ŒFWfý “ƒH–AŸËæš;/\ÈÁŠ=‚X!3+}]’³e/»Košõ^ÒÓÌ&t g0ø9W¢‡¤HÄmƒ7ô'꯷Ãe0‘C‡zw,f^ÊlYsbýg?OkÛ%ìí©4¹h£ƒ;€žüR_äÑF!ÿ!æ)Hñîó]j¦:¡ÌóÛu‚T§’$%gˆ¨’ÖÌ#€ü>Þûº®:o£ò~'‰Ñ(whÈbŒ#/TÚ衃îÀ’ÙþÃ\štÜéjT~o°g­uc%uÔßðä»Ñª·íVÖ8º0ÎFmž%Üw9µwhx#§ú/ú:ÛUs·u¤ /eWW‰ÒâÃGæÔ•Ö477ˆkŒ[žÅÌç˨\ÆÇw›ûy¸½môÎó“þ%»Jãä¹<)¿8* J!_/±µª› tTˆ²²ò’£r»¿êC‡ºL^ÅtMù'ºèfMÌÿÞ@W¸è1 @ ÿù‡`𤙑_ ÉQvOŸz飘²{HÙå +¯¦± Þåæ÷9WOgîÈ+ZžxNNØ—ŠkàõÎ6BbGW®Û0Зã YQ®æ â¾hq²D%YlÉwÖ¹«{‡·[S^HÚ—#¢$# õ)ÿ¦·™ZÍ:¯ã*U¾uËá™ãP;FÆ…c ¿Fps7”ì“çfðyñ/ÇCC*­ æJ;Ô’Ueõ™©â„øî‚ñ¯ß|ýÍz ±<ÛËm ƒrž½ÐPZ’-MWRŸµŠ…-1 ™Œ³Œyhýñk§ú*+é˨šÍl— ^ܼHõ›ÖmÈß~œn>sl§ò5Ë©WMª>À¤ÿê ´zìÆúê³(àU¶g¾Ç+PJ…PJJŒ…MµÎÊ¡¸ÞmŒÜʨg/‹[äÔ±ÒÁRˆ$Âg–äì6œQ§ л£¾¸*7;£0úÅѤ?¢=hÎÐëâ,T†1É d“}솫»4ÁJýXonN™«³÷ 8̲É4jM¨yKQ½½ªÖª§Êmíh¾©eÚ Yº´ººö†ö‹WÿmkrrZªào ‰†øˆ c›P€X-ÌÆi›äšÚÌ:¾Ú¡ÈKŸÃ*¹rud$–¾/;È¥*ÆÂÜ5öü™¼þÜfÅÔþÊNðznº÷—:á2ªñE'p°X,V•‰ÃiÉËJ1ä“›Ï .Ž·}c6©ÅÅE‰Š* O`)LS¹Úú&½“Ö7ŽÎ&÷ï­órËÎ)ÓËs£àÌ쯱Q&•›œZ+¦­2ÑÏpºÑ²òjŒFóJsqö˜'|×s ïÚ›œ`æ¨F©˜·¯#~øï§ïäº4Rªà@ü¦=@ ¡¹Æ5¦zšÓ¦!Á{'=pöø+±ï.ô qô0÷{EJ®ÄE’е.gUGU7íxÕŽ¯ŠVŒ›zò•ÄæC«øÌrÅw>ßÒáütÊç+²KÒeù´$U’.Í.N)Á—8Q‰ÙŽLhоÕV”S_+<ÙÜæ<³8W˜—‘Õ ­nh©o½3 `Å~¼……Œ¡ƒc쉙?m…FƒE;:<áßkó°hßϰðË/ÊñÒ¨6ªr›ò¤8h¸È¬ª-°Š­9D>¾ñ‘µ›6u}Õhpé­è´: }kÈKÔÞ£F1‰j™F…EnPMZ]…™²V:Û+ªº#/ c?€ØèP@«¬/³Îr—èmÉ7¤Z:¾­°úÈwßúëÍ[-!›352e¥û~ßø¹ïzÉÇðÆöTxruF-«ÈïUƒŠP—óò3ÒÓùŸÎV#mmMT]䀼þW¹Â;à(ÕÝñy¯zÂØž„G£å 9*¦ÔT«‚8:bôq@b”› ¡³÷”ºX£¢™'û¤)eÒ­ÀË-ƒ‰Im:Ú¯‡>ºTGqOyEY y»ÀdÕbïf»c8ÆÞ©šæ¨ã—ÎÝü8ªÍÔbÑQ§ÑÁnÅ¥\ØÍ(UbìHd˜iƒgustÔ[)GOõy\ï²Q¼7?ç]¨nlh4µh ´ÁZ¨‚±-®–Æj»Ýå>×;t sŽI¢ÕÄÊÉ ’3GK]³ 3ú¥˜Øx>µg›H”\xÇ3c(/Àæ3úÚÏzæ4ì™S±gNùEϼ–ñ îC¯2*¢óc‡¡Ýà ÿæY:=ò¼ƒ U¦“%Æ© އ8}òâ3ÝÊÉùRä@)™=r b@ÏG>.¬œŽÇåÏ=b7ëÖ—lO§—\[LæA m˜†¼©OIRŸŽ†—õ89^Ï:E;•œZ<§Ö©*³˪һ CN Êß´gK‚“›¥}:L@ö8:›yU¹ª0x6äLü¥[Ÿ\ûرFÜÖáÆ˜àö³n½vŸ7‰š"Šx/u:ÑÓàj®¢jT_ºSP…*J–U¸%?6xß=?˜ì¼ž3Ï3‹;M±¤—b2¾BCåj?ôœ÷:cy»)ÌΕ v=ýsf“<Ö«Ö(Ôr{Íè&~òôã$è*í­§FqÁÞ"¡,]]Fogª~òDâ(Z7}ï'7ýûŠ<¾»áå-ûL£¤W¢ê£!ö§ðÿð_z|rוø½Š„oÜ–MÒUi$ò6ô‡üÍ@þhzÄ;%òs|J59‡›•b¿vÌr¤qhSèl ­G{:{~nø™ÖDøe|€|+±ÞDY¹‘=C’–’YWèìtw´QWÞAosE üTAjvM^K§»ÝMÍÉqL<ç`\VtXÇab­~î™c³¨™364ÌöwXfÏ&ˆAp˜— endstream endobj 53 0 obj <> endobj 133 0 obj <>stream xœcd`ab`dddsöuŠ0±TH3þaú!ËÜ]/ÃÊùÓ‰µ›‡¹›‡eó÷›Bß¿ð×``fdtóŽrÎ/¨,ÊLÏ(QÐpÖT0´´4WpÌM-ÊLNÌSðM,ÉHÍM,rr‚ó“3SK*õsr‚@:Š‚R‹S‹ÊRSÀ6;çç”–¤)øæ§¤å1000†30X0012²/üϸIï?«6Cý‚ŸŒ‡eXVýø!:iî¬î½Ý‹³¥u¤w¥uguÿfêoïæžË>éJwsGGkW‡üoï?þ¿C~$³>?ÌÖîØÚÜ­ÜßTõˆ}µÝo“?b¿ƒ²Ï³Uwý–èÈF’þ>éÏÏ©%Z×vK®èžÒ3}ù÷€QßýÿDMϛս¸[rM÷Ä SsðÕOÿé4ý÷¤)ßãç²ýŽÄ~˜ë»0·‹ù|ÎSyx¾ /æáíáác`«‘‡ endstream endobj 51 0 obj <> endobj 134 0 obj <>stream xœW XSgÖ¾1{±ˆ–ô ¨MPQܨZul;uA‹âŠ€µ€È¾¨ˆ"˜ä$A6Ù‚"Y„+.ØVkmmµ«ÓN;.j[§Ô©s.ýÒñÿÚÖ™Îÿ?Ïÿ܇„$çÞïûÎûž÷¼GÂX a$ ëáã0s†å_Wq´D3D|Q $pŒ•®•5ØJÁÖªmŒýŸíÑø<úÇ™#©Dâµ|£G|BFRtdTŠó$ÉÎ3_}u®ó¢Øˆ¤è°8gŸ”¨ˆØúa‹óÚø°èˆ”Œ—œmÙâ¼ÆrG²óšˆäˆ¤´ˆðÁÅ=âcRS"’œ}âÃ#’â†qY”æã¾Â#!båâ7W%Ez%G­I‰^›ê›³uKHl¨¿‰aÆ1˜•Ìbæ%f<³Šñd¦3.ÌjÆ‹™ÁL`–03™µÌRÆ•ñeÞ`f1ëof6ãÇÌaü™åLãø3+æ&–™@SÁ°Ló/ÉɇC¢†üMºPÚk`õgë7­¯ÉÜe•¬Ë^áêm¬lLCÇýð9þ¹Í¶£m³m¯ ›;ì»d»£Ãÿ0üúß?<ŸýX²sc÷X‘À€€Ñ»ZÒÞX*ÆõÏæ³ëwB&ÄÃÞœ=Dgþ»cîvuÎàÒT²VÝ)}#œ€·à¸šXÍl8 3”ètÊÓ8̲‹d¢õ4fø:¡ î@ ›Â’ûb 2ÒhMÒev‡õ1Deß$5ÈJEƒhË– /}f²&V›I¤OÓq*Vß;µ{wiµJÂ-‘c­u¯ Û¬™©ÕÒ-éCiÐeWšÇ¦lLݳd18í.ÇPœ_[-ܱäCÑñqéáBèÅï\zû°‚®ŸuÇrì¾ó‘&{”Ñ+eò®.W±Gtõ­ô„4G´œà…,Jnõ¼×lL[  µ^ÿPÊþ¸î„ëT¿5‰ ù dX²0ÇZÅ^*„p%¹ÄÚ=–<Ã䶉ÃÛ$­øºãóR4‹SùŒmš4ØÍmjI?ÜØdì¸E¸‚ÕdÉ"zJŽ8ÝŸ†/áŽ"WX¶veh5YyŠÄåÓ€#J@×î·G"ßR¡VPÚ=¶òh¤ï œtNü™.!v¢#OöˆõÙuÙ N$I…Œù¢ RµÚxu²ZC“Ç%Yz›ž¥ÎB;E*‰Í€L]†>ΠÕA ' :ëÌŠ·–æí§j(:˜_ŒM"qÔ™ïF%3îA;½îƒ‰ÞMñ.2IdS!²“8J°—m-™î2a…`®è€½8ްèê ±Q|ŽÇ ôfû*_œ¿ÑgŠe™<2Uï_„Ü׳?#sf/˾ïÊä?ÒõÄp¾öåßιBž+VÎ!—y²»ÐOV 4 µÍíòqQ؉Ó´ËM’&šöB|A*žÀ8GMï#sÉ+3&'2âŽ+þ_¿Ý‡Ã¤ˆ,特Ýg*š•UÇ;Œ=45Ûj¢ŒÑà ¹Ù@" \S¬ JM¸ú¼½Ø}”ß 2òLñÀûìJñG–xþJVÞsb½ÁæÑdâ¸Yd,qüzNz÷Ô¡ºFå—X“eøˆ'6+#Ô—±võôÖŸP6t%ð6´ÅÔÄqv?9>Ûõœ¸÷œ{ûçðÙ¥Z]½)ãÿƒt5+晿(Ù©Ó–ƒÓa(®UŠ×Y¨ÑéŽôp¸:A¡^áþjàTul%Th+5 jR9ódÊué|“-ˆ? ’Ëè&ª{¤ý…ý3ù*(ÎØ­ÑìÉQ¼±ÊçôÒÊ%”zâF&“‚ôõ¸­q8²Õ{t™Y»!S«ÜCF‘a+&Â<˜{Èÿ]ÕÛ;¯ÃWð–™÷>xÿƒÛûÏR à›5DnH×ij«×é땃È?ÇšDÉù°6ûGÈPXdžä×1ÿÂC•NWVÖÖ~¶ ¸+o­ öd¬§¿÷ô)³€ª¸(·hq¯`;£Nîj§üð*ÑiÆ}â²ÐoKFŠRþMϯèF(ͺ׺—á/ÐÊÇåÇðµAæ|#C) kJàpcî'ëO+ß4ùUzQÐfÏv!Ï“QßOÁ9ør磊ÊtÈËÔämËU¦m\ãM#ÆjÑéŒò˜•þ„®Ãx¬¾­­´ÐôÄAe©´M·˜ìŽ~YÛ@æ¡›´¿ ¿æq ™@+.‰d%™DÞ$aèLÆãVÌDNÀ…ÙŠ¼Ë¯÷#¡Ÿn¾”s nÁeÃ_O~Øþ p>Šo{£uYþ|Xž{_ñ r÷L]–õûžJŽ+ŽÐUŠ®ýr~@D×ã èfL S'”fw• Õæ»<‰‰ìðEzgK@Ñx ˆd§_LÐÆ%³¶­°>B;Ú)zGÒ½{°WëÐî{…V›± â¸Ð¦­ Mƶsëü=ÃÖ/OQȻК%¯ý¦¥Pž=“ªs$ЄӾ½f”vû¦ûž(ÅÅ(…;ž·äÿÌÆ"\ÃÏ‚+]]påÎXKg)‰Ý.¾;ùŒ¦ŽrÛåüÍ«BÒ±íåÊ£åFý~&O³r¹¤ŠŒúúŠªCµ™-ÛUê¨MŠŒÒã"ÊEßyž¡Õ¡M)Êø¨ÜÍÛó7´Åpò~&Kíž¶|TÀù…¨BÏ›®Íyoi³bí‘•0!òt› ³[¡Jòq—È:mdh >‘áëÈHb»¡»ûâ{Pf)åZòV+`Í9 ËÆát_¤ýŽý¯óæ,X|1ˆEœ„@ œ´€1kO³ß/R ج’-Ê ž¢X5è,Ã9P;ÿ ±áêB$ï”S G7Ù·v„\ÃôÅK$ ü›…ÞûAà.݃ªë­q¾ûºíº<#p‡`_­ò3Ö¢g{5®H<U\,¡$v«N¨ÎT¶EµæÞØÁÉïšr¯g­µp:¤ŽMü¤s§"¯,v— ¹)J"aÓawe¡T€ôÝ1g¡¸F| pbçÖ–¨#Êð†˜‚y¸§†åI³¡b6(i®åG‘ŒüÕ…¬ŽHUhñžì7}Gþùôïø–ÿÝØÐòÊf²MI6š°q°@p7NqF·¿voCþÌc#eqŽ~ÞŠµð yU‰SÓx䎞y>àúÈ/É*…yÄ/5c¢5CÛ)­™A·€¬ü4E¿Œ¢×ÝéàoÀ†«Ñ'S/í¥¢ûÏ_•×Pÿ“¦Ý•¥Uæ©âRca%쾖סٟó‘vߎ«¾ÁåÅ8;×"´\P-yHS3Tb¬8–§Ö–Lĵ*™ÖuäIj.ò/ä0ë|;õÚ§]o¢8§ `—Ä$ǯ†Ëµ´©K$Ú»8Ãþ&Î C-íü¦ˆ~0A³¶Yà ™l0¨ó³ÊÉ<ŒtÄ‘}eû‹ ¯€“À&¨“¨@&€·>ŲÇZ0¨‹rÈj2ÙQ ü­‹4Ÿ¦\£Mð¸NЛà8œ  ×ï5˜º~£´?•f`ßü¢ – ¤Ð¡*™>]¥Oµ<½¸G›­VçjÕÊq¤˜Èð˜õ[‚,F믉¥î.D¿Æ\`ëAZØk‰{ø:ŽÃý–°PM¨6¶À&}ô@º™‡fæïª§:È/)¬x„¥ŽHé3ßqO«K¼{^‚2RLé÷æŸ9­ª&:^Zºj·¦ùÉ¡†L·0Ú¸ò(º™ì›Ðf>>³-Ê—&½ÁoÀ(NɪKáPmd)Wè(`µưw¿O&¯!v{g=±ŽÒÑ+Ž4éJ»Þ²@ÍÊ…ÅjR¸›L5Gd|ô™ÐÞQ£ÈÄ™ü4vêô¬¤€°–“ÈàËe§ ´–¥gÖ=;7† þ9È{þëìx»çRsÍÖù¿?;þŸ¥ìÀv—þë[ïM7DÀlX³œ“þ;“æ“©Ä(¾8Ð(ž±¾™¸YœÀc÷3\úN`Ë«**Ë«8ygNQϺ»£qòßëvŸLp_·5YY@¨Êg·œj8O½‚až*ðM WÆ…fÇ€'„÷î:H¶ª»Åäûe‚äЫéO½"á *túFCµÞå&h£4A>I¶NAC6Yh^ëH<Å ëo-#†Ó!ãuˆ¢·Øö±d ùñ¿ýŠ{~–lû…gåè.ú9¢»Ùï™oé ´rÿ„ò*“%5¸ Æ[ ø§ã#ÿwÔQ.e@”’|øŸ¬§²dq.Õ -hœˆ«Ln~À~ùaë× Æ¼¬ZEfnB&„qá ‰¦ã uíg7]&CÈâNl®Ôx’‡”ÖÙûûÝ÷“‚b 2ÊH`!+ EÙsŠ¡Vs«mmÚ mmQvÄv˜ÎÖŽaþáÒR endstream endobj 149 0 obj <>stream UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 150 0000000000 65535 f 0000085805 00000 n 0000141634 00000 n 0000085629 00000 n 0000082861 00000 n 0000000015 00000 n 0000004054 00000 n 0000085871 00000 n 0000094588 00000 n 0000128638 00000 n 0000094247 00000 n 0000126165 00000 n 0000093722 00000 n 0000122167 00000 n 0000092954 00000 n 0000114023 00000 n 0000092258 00000 n 0000107284 00000 n 0000085912 00000 n 0000085942 00000 n 0000083021 00000 n 0000004074 00000 n 0000008809 00000 n 0000091385 00000 n 0000102918 00000 n 0000090890 00000 n 0000101504 00000 n 0000090231 00000 n 0000100339 00000 n 0000089427 00000 n 0000098360 00000 n 0000088932 00000 n 0000097044 00000 n 0000086016 00000 n 0000086046 00000 n 0000083183 00000 n 0000008830 00000 n 0000013612 00000 n 0000088422 00000 n 0000096403 00000 n 0000086155 00000 n 0000086185 00000 n 0000083345 00000 n 0000013633 00000 n 0000018339 00000 n 0000086305 00000 n 0000086335 00000 n 0000083507 00000 n 0000018360 00000 n 0000023240 00000 n 0000095877 00000 n 0000135963 00000 n 0000095722 00000 n 0000135301 00000 n 0000086444 00000 n 0000086474 00000 n 0000083669 00000 n 0000023261 00000 n 0000029452 00000 n 0000095376 00000 n 0000130922 00000 n 0000086616 00000 n 0000086646 00000 n 0000083831 00000 n 0000029473 00000 n 0000034813 00000 n 0000095124 00000 n 0000130388 00000 n 0000086733 00000 n 0000086763 00000 n 0000083993 00000 n 0000034834 00000 n 0000040334 00000 n 0000086905 00000 n 0000086935 00000 n 0000084155 00000 n 0000040355 00000 n 0000044937 00000 n 0000087033 00000 n 0000087063 00000 n 0000084317 00000 n 0000044958 00000 n 0000050282 00000 n 0000087161 00000 n 0000087191 00000 n 0000084479 00000 n 0000050303 00000 n 0000055200 00000 n 0000087300 00000 n 0000087330 00000 n 0000084641 00000 n 0000055221 00000 n 0000060561 00000 n 0000087395 00000 n 0000087425 00000 n 0000084803 00000 n 0000060582 00000 n 0000065296 00000 n 0000087534 00000 n 0000087564 00000 n 0000084965 00000 n 0000065317 00000 n 0000070301 00000 n 0000087695 00000 n 0000087726 00000 n 0000085131 00000 n 0000070323 00000 n 0000075059 00000 n 0000087858 00000 n 0000087889 00000 n 0000085297 00000 n 0000075081 00000 n 0000080209 00000 n 0000087999 00000 n 0000088030 00000 n 0000085463 00000 n 0000080231 00000 n 0000082839 00000 n 0000088107 00000 n 0000088138 00000 n 0000096616 00000 n 0000097265 00000 n 0000098787 00000 n 0000100607 00000 n 0000101768 00000 n 0000103193 00000 n 0000107628 00000 n 0000114550 00000 n 0000122452 00000 n 0000126430 00000 n 0000128869 00000 n 0000130579 00000 n 0000131206 00000 n 0000135512 00000 n 0000136248 00000 n 0000088182 00000 n 0000088819 00000 n 0000089174 00000 n 0000089911 00000 n 0000090718 00000 n 0000091296 00000 n 0000091814 00000 n 0000091921 00000 n 0000092788 00000 n 0000093544 00000 n 0000094161 00000 n 0000094893 00000 n 0000095288 00000 n 0000096317 00000 n 0000140263 00000 n trailer << /Size 150 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 141761 %%EOF glam2-1064/doc/alphabet.html0000644007451300001540000000622610663266537015370 0ustar charlesgenome GLAM2 Alphabets

GLAM2 Alphabets

Alphabet files

Alphabet files allow glam2 and glam2scan to operate on sequences over arbitrary, user-defined alphabets. They also allow residue abundances to be specified. Their format is inspired by that of vmatch. For examples, see robinson.alph and dna.alph in the GLAM2 examples directory.

Note: as soon as you specify an alphabet file, the glam2 programs lose all knowledge about residues' tendencies to align with each other. So, if you use an alphabet file to specify amino-acid or nucleotide abundances, you probably want to specify a Dirichlet mixture file too: recode3.20comp or glam_tfbs.1comp.

In alphabet files, the # character introduces a comment: everything from it to the end of the line is ignored. Otherwise, each non-blank line defines a symbol of the alphabet. The first non-whitespace character on the line is the main character representing the symbol: this is how the symbol is printed. Any characters that follow it without any whitespace are aliases (when reading input). This is optionally followed by whitespace and then a number, indicating the abundance of the symbol. The abundances can be counts, fractions, or percentages: they will be normalized so that they sum to 1. Unspecified abundances default to 1. The final symbol is the wildcard: it is forbidden from appearing in aligned columns, and all characters not defined in the alphabet file are aliases of it. No abundance is defined for the wildcard (any number will be ignored).

The order of the symbols matters when reading Dirichlet mixture files or looking at reverse strands.

Built-in alphabets

The p (protein) alphabet is equivalent to using robinson.alph (and recode3.20comp) in the GLAM2 examples directory. The n (nucleotide) alphabet is equivalent to using dna.alph (and glam_tfbs.1comp) in the GLAM2 examples directory.

FASTA format

When reading sequences in FASTA format, the > character begins the title of the next sequence, which continues till the end of the line. In the sequence itself, whitespace is always ignored, and non-whitespace characters are always part of the sequence: if not defined in the alphabet file, they are interpreted as wildcards.

Reverse strands

glam2 and glam2scan provide options to look at both strands of the input sequences. This may only be meaningful for nucleotide sequences, but is actually defined for all alphabets. The reverse strand is obtained by first reversing the sequence, and then swapping each symbol with its opposite in the alphabet's order (apart from wildcards). Thus, for nucleotides, these symbols are swapped: a:t and c:g. For proteins, these symbols are swapped: A:Y, C:W, D:V, E:T, F:S, G:R, H:Q, I:P, K:N, and L:M.

glam2-1064/doc/dirichlet.html0000644007451300001540000000314710663247164015551 0ustar charlesgenome GLAM2 Dirichlet Mixtures

GLAM2 Dirichlet Mixtures

Dirichlet mixture files

A Dirichlet mixture file specifies residues' tendencies to align with one another, and is the basis for scoring columns of aligned residues. The format is identical to that of UCSC Dirichlet mixtures. For examples, see recode3.20comp (copied from UCSC) and glam_tfbs.1comp in the GLAM2 examples directory.

The GLAM2 programs only read lines beginning with Mixture= or Alpha=. Mixture= is followed by a number giving the weight of that mixture component: these weights should sum to 1. Alpha= is followed by a list of numbers giving the pseudocounts for that mixture component, as many as there are symbols in the alphabet. The first number after Alpha= is the sum of the pseudocounts, and is in fact ignored by the GLAM2 programs.

The pseudocounts should be in the same order as the alphabet symbols. For the n (nucleotide) alphabet, this is: acgt. For the p (protein) alphabet, this is: ACDEFGHIKLMNPQRSTVWY.

Built-in Dirichlet mixtures

If no Dirichlet mixture file is specified, the default is to use recode3.20comp for the p (protein) alphabet, glam_tfbs.1comp for the n (nucleotide) alphabet, and a uniform prior for user-specified alphabets.

glam2-1064/doc/glam2mask.html0000644007451300001540000000221410663247237015453 0ustar charlesgenome glam2mask Manual

glam2mask Manual

This program masks a glam2 motif out of sequences, so that weaker motifs can be found. Masking replaces residues aligned to key positions with the symbol 'x'. By alternately applying glam2 and glam2mask several times, it is possible to find the strongest, second-strongest, third-strongest, etc. motifs in a set of sequences.

  • Mask the top motif in my_motif.glam2 out of my_seqs.fa, and store the result in mask1.fa:
    glam2mask -o mask1.fa my_motif.glam2 my_seqs.fa
    
  • Mask the top motif in my_motif.glam2 out of my_seqs.fa, using 'n' as the mask symbol:
    glam2mask -x n my_motif.glam2 my_seqs.fa
    

If the sequences do not have unique names, glam2mask may mask the wrong ones. It also assumes that the order of the sequences does not change, so don't do that.

glam2-1064/doc/glam2scan.html0000644007451300001540000000746410663247413015454 0ustar charlesgenome glam2scan Manual

glam2scan Manual

glam2scan finds matches, in a sequence database, to a motif discovered by glam2. Each match receives a score, indicating how well it fits the motif.

Basic usage

Running glam2scan without any arguments gives a usage message:

Usage: glam2scan [options] alphabet my_motif.glam2 my_seqs.fa
Main alphabets: p = proteins, n = nucleotides
Main options (default settings):
-h: show all options and their default settings
-o: output file (stdout)
-n: number of alignments to report (25)
-2: examine both strands - forward and reverse complement

glam2scan needs three pieces of information - the alphabet, a file containing a motif found by glam2, and a file of sequences in FASTA format:

glam2scan p prot_motif.glam2 lotsa_prots.fa
glam2scan n nuc_motif.glam2 lotsa_nucs.fa

An alphabet other than p or n is interpreted as the name of an alphabet file. Motif files from glam2 often contain multiple motifs: glam2scan only considers the top one.

Output format

The output begins with some general information:

GLAM2scan
Version 9999

glam2scan p prot_motif.glam2 lotsa_prots.fa

This is followed by motif matches, sorted in order of score. A motif match looks like this:

                 **.****
SOS1_HUMAN   780 HPIE.IA 785 + 8.70

The name of the sequence with the match appears on the left; the start and end coordinates of the match appear on either side of the matching sequence; the match score appears on the right. The plus sign indicates the strand of the match (only meaningful when considering both strands of nucleotide sequences with the -2 option). The stars indicate the key positions of the motif: the alignment of the match to the key positions is shown.

Basic options

  • Use -o to write the output to a file rather than to the screen:
    glam2scan -o my_matches p prot_motif.glam2 lotsa_prots.fa
    
  • Use -n to specify how many matches to report:
    glam2scan -n 100 n nuc_motif.glam2 lotsa_nucs.fa
    
    Matches are sorted in order of score. If scores are tied, they are sorted in alphabetical order of sequence name. If sequence names are also identical, the order is arbitrary.
  • Use -2 to search both strands of nucleotide sequences:
    glam2scan -2 nuc_motif.glam2 lotsa_nucs.fa
    

Advanced options

The remaining options are somewhat specialized. For typical usage, it is reasonable to set them to exactly the same values as were used with glam2 to discover the motif.

  • Use -D to specify the deletion pseudocount.
  • Use -E to specify the 'no-deletion' pseudocount.
  • Use -I to specify the insertion pseudocount.
  • Use -J to specify the 'no-insertion' pseudocount.
  • Use -d to specify a Dirichlet mixture file.

Motif format

Some users may wish to make 'fake' glam2 motifs for input to glam2scan, for instance based on motifs found by other tools. Most of the glam2 output is ignored by glam2scan, and a minimal motif file looks like this:

                **..****
seq1         10 HP..D.IG
seq2          5 HPGADLIG
seq3          7 HP..ELIG
seq4          5 HP..ELLA

The sequence names and coordinates are ignored, but some placeholder characters should be present. The stars indicating key positions are necessary, and the first and last columns must be starred.

glam2-1064/doc/glam2format.html0000644007451300001540000000412610663247246016014 0ustar charlesgenome glam2format Manual

glam2format Manual

This program reads in a motif found by glam2, and writes it in a standard alignment format (FASTA-with-gaps or MSF). This enables the alignment to be passed to third-party software, including graphical visualization tools such as Kalignvu, Boxshade, and WebLogo. On the other hand, not all the motif information is preserved: in particular, the key positions are lost. Only the top motif in glam2 output is converted.

  • Basic usage:
    glam2format fasta my_motif.glam2
    
    glam2format msf my_motif.glam2
    
  • Use -o to write the output to a file rather than to the screen:
    glam2format -o my_motif.fa fasta my_motif.glam2
    
    glam2format -o my_motif.msf msf my_motif.glam2
    
  • Use -c to make a compact alignment:
    glam2format -c fasta my_motif.glam2
    
    glam2format -c msf my_motif.glam2
    
    By default, residues that are inserted between key positions are written as unaligned with each other. This best reflects glam2's intention, but it can make the alignment large and full of gaps. With -c, inserted residues are written as arbitrarily aligned with each other, just as they appear in the glam2 output.
  • Use -f to make a 'global' alignment by adding flanking sequences from the original FASTA-format sequence file:
    glam2format -f my_seqs.fa fasta my_motif.glam2
    
    glam2format -f my_seqs.fa msf my_motif.glam2
    
    The flanking sequences will be written as either unaligned with each other or arbitrarily aligned, depending on the -c option. The sequences should have unique names and their order should be unchanged.
glam2-1064/doc/glam2.css0000644007451300001540000000013510656026607014421 0ustar charlesgenomepre { margin-left: 2em; font-family: monospace; color: #00008b; } li { margin-bottom: 1em; } glam2-1064/doc/GLAM2_method.tex0000644007451300001540000011716710722500112015565 0ustar charlesgenome\documentclass{article} \usepackage{amsmath} \author{Martin C Frith} \title{GLAM2 Methods} \newcommand{\ud}{\mathrm d} \DeclareMathOperator*{\argmax}{arg\,max} \begin{document} \maketitle \section*{Overview} The GLAM2 software aims to find the strongest motif that is present in a set of protein or nucleotide sequences. In fact, it can analyze sequences over any user-specified alphabet. The method is described here in three stages: firstly, what exactly is meant by a ``motif'', secondly, what is meant by ``strongest'', and finally, the algorithm used to search the space of motifs for the strongest one. Most aspects of the method have close analogs in the well known Gibbs Sampling technique for motif discovery \cite{Science.:262:208, ProteinSci.:4:1618, NucleicAcidsRes.:32:189}: GLAM2 is essentially a generalization of Gibbs Sampling to allow insertions and deletions in a fully general fashion. Having found a motif, we often wish to scan it against a database of sequences, to find other instances of the motif. GLAM2 includes such a scanning method, which is also described here. \section*{Motif Definition} A motif in GLAM2 has a certain number, $W$, of ``key positions''. The idea is that the key positions hold residues that are important for the motif's function. An instance of the motif is a string of residues (amino acids or nucleotides), where each residue either occupies one of the key positions, or is inserted between key positions. More than one residue may be inserted between key positions, and a key position may lack a corresponding residue, meaning that it is deleted in this motif instance. What GLAM2 searches for is an alignment of substrings of the input sequences to a series of key positions. The number of key positions is optimized by the algorithm. Currently, each input sequence may contribute at most one substring to the alignment, although this restriction could be relaxed in principle. GLAM2 requires the alignment to contain at least some minimum number of substrings, by default 2. This lower limit is a useful generalization of the OOPS (one occurrence per sequence) and ZOOPS (zero or one occurrence per sequence) modes of previous motif discovery algorithms \cite{Bailey7584439}. For nucleotide sequences, there is an option to consider both strands of the input sequences (direct and reverse-complement). \section*{Scoring Scheme} \subsection*{Overview} In order to define the ``strongest'' motif (i.e. alignment of substrings to key positions), GLAM2 uses a formula to assign a numeric score to any given alignment. The task, then, is to find the alignment with maximum score. While the precise formula is given below, some desirable characteristics for any sensible formula are noted here. Firstly, the formula should favour alignments where key positions are occupied by identical or chemically similar residues. Secondly, deletions and insertions should be penalized in general. Thirdly, deletions and insertions should be penalized less strongly when they are concentrated in a few positions in the alignment, suggesting that those positions in the motif are more prone to deletion or insertion, than when they are scattered across many positions. The formula used by GLAM2 and described below has each of these characteristics. \subsection*{Motif Model} The formula is motivated by a simple statistical model of a motif, with position-specific residue probabilities, position-specific deletion probabilities, and position-specific insertion probabilities. Thus, each key position has characteristic probabilities, $\theta_i$, of containing the $i$\textsuperscript{th} residue type. ($1 \leq i \leq A$, where $A$ is the size of the alphabet, 20 for proteins and 4 for nucleotides.) Also, each key position has probability $\phi$ of being deleted. Finally, the probability that $x$ residues are inserted between two key positions is $\psi^x(1-\psi)$. The use of a geometric distribution for insertion length is arbitrary, but it is the simplest choice, and since $\psi$ may vary with position, we doubt that more complex schemes would lead to much benefit. This model can be regarded as a hidden Markov model, where $\theta_i$ are emission probabilities and $\phi$ and $\psi$ are transition probabilities. Hence, in a set of $s$ independent motif instances, the probability that a key position is deleted in a particular subset of $d$ instances and present in the other $m = s-d$ instances is: \begin{equation} \phi^d (1-\phi)^m \end{equation} The probability that $r$ residues in total (in all instances) are inserted between two key positions is: \begin{equation} \psi^r (1-\psi)^s \end{equation} The probability of observing particular residues in one key position, where $c_i$ is the count of the $i$\textsuperscript{th} residue type (so $m = \sum_{i=1}^A c_i$), is: \begin{equation} \prod_{i=1}^A \theta_i^{c_i} \end{equation} \subsection*{Motif Priors} The values of $\theta_i$, $\phi$, and $\psi$ are, of course, unknown, but prior probability distributions are assigned to these parameters. Then, total probabilities can be obtained by integrating over the parameter values. The total probability of observing $d$ deletions is: \begin{equation} \int_0^1 \phi^d (1-\phi)^m \cdot prior(\phi) \ud \phi \end{equation} The total probability of observing $r$ insertions is: \begin{equation} \int_0^1 \psi^r (1-\psi)^s \cdot prior(\psi) \ud \psi \end{equation} The total probability of observing $\vec c$ residue counts is: \begin{equation} \int \prod_{i=1}^A \theta_i^{c_i} \cdot prior(\vec \theta) \ud \vec \theta \end{equation} The prior distributions of $\phi$ and $\psi$ are assumed to be Beta distributions (the simplest kind of Dirichlet distribution): \begin{align} prior(\phi) & = \phi^{D-1} (1-\phi)^{E-1} / Z \\ prior(\psi) & = \psi^{I-1} (1-\psi)^{J-1} / Z' \end{align} The values of $D$, $E$, $I$, and $J$ are chosen so as to give GLAM2 the desired level of aversion to deletions and insertions. For reasons that will become clearer in the description of the search algorithm, these parameters are referred to as pseudocounts: $D$ is the deletion pseudocount, $E$ is the no-deletion (or match) pseudocount, $I$ is the insertion pseudocount, and $J$ is the no-insertion pseudocount. $Z$ and $Z'$ are normalization constants. The use of Beta distributions here is ultimately arbitrary, but they are a natural choice since they are conjugate priors of the binomial distributions for deletion and insertion probabilities, and they allow the integrals to be solved analytically. Also, the shapes of these distributions allow considerable flexibility by varying the pseudocount values. The prior distribution of $\vec \theta$ should incorporate prior knowledge of the functional similarities between residues, at least in the case of proteins. To accomplish this, a Dirichlet mixture distribution is used (a weighted sum of Dirichlet distributions): \begin{align} prior(\vec \theta) & = \sum_{j=1}^C \frac{w_j}{Z_j} \prod_{i=1}^A \theta_i^{\alpha_{ji}-1} \end{align} $C$ is the number of components in the mixture, $w_j$ is the weight of the $j$\textsuperscript{th} component, $Z_j$ is the normalization constant of the $j$\textsuperscript{th} component, and $\alpha_{ji}$ is the $j$\textsuperscript{th} component's pseudocount for the $i$\textsuperscript{th} residue type. So, this distribution has a potentially huge number of parameters, which should be exquisitely chosen so as to favour biologically realistic values of $\vec \theta$. Fortunately, Dirichlet mixture priors for proteins have been extensively investigated by a team at UC Santa Cruz, and we simply use their parameters \cite{ComputApplBiosci.:12:327}. For the case of nucleotides, we use a one-component mixture with all pseudocounts = 0.4 \cite{NucleicAcidsRes.:32:189}. These are the defaults: alternative Dirichlet mixture parameters may be supplied as input to GLAM2. As far as we can tell, previous implementations of Gibbs Sampling have only used simple Dirichlet priors rather than Dirichlet mixtures, hence have lacked prior information about functional similarities between amino acids. This ought to give GLAM2 a significant advantage in finding protein motifs, even leaving aside the treatment of insertions and deletions. Using these prior distributions, the total probability integrals can be solved analytically. The solutions contain Gamma functions, denoted by $\Gamma(\cdot)$. The total probability of observing $d$ deletions becomes: \begin{equation} \label{eq:totdel} \frac{\Gamma(D+E) \Gamma(d+D) \Gamma(m+E)}{\Gamma(s+D+E) \Gamma(D) \Gamma(E)} \end{equation} The total probability of observing $r$ insertions becomes: \begin{equation} \label{eq:totins} \frac{\Gamma(I+J) \Gamma(r+I) \Gamma(s+J)}{\Gamma(r+s+I+J) \Gamma(I) \Gamma(J)} \end{equation} The total probability of observing $\vec c$ residue counts becomes: \begin{equation} \label{eq:totmat} \sum_{j=1}^C \frac{w_j \cdot \Gamma(A_j)}{\Gamma(m+A_j)} \prod_{i=1}^A \frac{\Gamma(c_i + \alpha_{ji})}{\Gamma(\alpha_{ji})} \end{equation} where $A_j = \sum_{i=1}^A \alpha_{ji}$. \subsection*{Background Model} To score alignments, the motif model is compared to a background model of independent sequences. The background model is that the residues occur randomly and independently, with probabilities $p_i$. For the nucleotide alphabet, the default is $p_i = 1/4$. For the protein alphabet, the amino acid abundances of Robinson and Robinson, which are frequently cited in publications on NCBI BLAST, are used \cite{ProcNatlAcadSciUSA.:88:8880, NucleicAcidsRes.:25:3389}. These probabilities can be adjusted by the user. Thus, the probability of observing $\vec c$ residue counts in one key position given the background model is: \begin{equation} \prod_{i=1}^A p_i^{c_i} \end{equation} In the motif model, residues inserted between key positions are assumed to occur with these same background frequencies. \subsection*{The Formula} The score $S$ of an alignment $X$ is: the likelihood of the alignment given the motif model, divided by the likelihood of the substrings in the alignment given the background model. \begin{equation}\begin{split} S(X) = & \prod_{k=1}^W \sum_{j=1}^C \frac{w_j \cdot \Gamma(A_j)}{\Gamma(m_k+A_j)} \prod_{i=1}^A \frac{\Gamma(c_{ki} + \alpha_{ji})}{\Gamma(\alpha_{ji}) \cdot p_i^{c_{ki}}} \times \\ & \prod_{k=1}^W \frac{\Gamma(D+E) \Gamma(d_k+D) \Gamma(m_k+E)}{\Gamma(s+D+E) \Gamma(D) \Gamma(E)} \times \\ & \prod_{k=1}^{W-1} \frac{\Gamma(I+J) \Gamma(r_k+I) \Gamma(s+J)}{\Gamma(r_k+s+I+J) \Gamma(I) \Gamma(J)} \end{split}\end{equation} where $d_k$ is the number of deletions of the $k$\textsuperscript{th} key position, $m_k$ is the number of residues in the $k$\textsuperscript{th} key position, $c_{ki}$ is the count of the $i$\textsuperscript{th} residue type in the $k$\textsuperscript{th} key position, and $r_k$ is the number of insertions between key positions $k$ and $k+1$. Since scores calculated by this formula can easily be of unwieldy orders of magnitude, GLAM2 actually reports $\log_2 S(X)$. \subsection*{Fitting the Insertion and Deletion Priors} It is desirable to choose the insertion and deletion pseudocounts, $D$, $E$, $I$, and $J$, so as to maximise the model's fit to actual alignments. Suppose we are given a training set of alignments, with a total of $\mathbf{W}_D$ key positions, and $\mathbf{W}_I$ potential insertion sites between key positions. We seek the values of $D$, $E$, $I$, and $J$ that maximise the total probabilities: \begin{align} \argmax_{D,E} \quad & \prod_{k=1}^{\mathbf{W}_D} \frac{\Gamma(D+E) \Gamma(d_k+D) \Gamma(m_k+E)} {\Gamma(s_k+D+E) \Gamma(D) \Gamma(E)} \\ \argmax_{I,J} \quad & \prod_{k=1}^{\mathbf{W}_I} \frac{\Gamma(I+J) \Gamma(r_k+I) \Gamma(s_k+J)} {\Gamma(r_k+s_k+I+J) \Gamma(I) \Gamma(J)} \end{align} This can be accomplished, crudely but effectively, by plotting the function over a two-dimensional grid of values for $D$ and $E$ (or $I$ and $J$). In every case that we examined, the plot indicates a simple hill-shaped function with a unique maximum. \section*{Search Algorithm} \subsection*{Overview} The preceding sections have defined what is meant by a motif: an alignment of substrings of the input sequences to a series of key positions, and have suggested a formula to assign a score to any such alignment. The aim is to find the alignment(s) with maximum score. Unfortunately, the number of possible alignments will be astronomically huge in most cases, and we do not know a practical algorithm to guarantee finding the highest-scoring one. Therefore it is necessary to use a heuristic algorithm. GLAM2 uses simulated annealing, a very general technique for finding the highest-scoring solution in a large ``search space'' of possible solutions. Simulated annealing begins at some (presumably non-optimal) location in the search space, and repeatedly performs stochastic moves to ``nearby'' locations. Moves that increase the score are favoured, but moves that decrease the score are also permitted, which allows the algorithm to escape from local maxima. A temperature parameter, $T$, controls the preference for higher scores: at low temperatures they are strongly preferred, but at high temperatures they are only weakly preferred. More precisely, the stochastic moves in simulated annealing should satisfy the so-called detailed balance condition: \begin{equation} S(X)^{1/T} P(X \rightarrow Y) = S(Y)^{1/T} P(Y \rightarrow X) \end{equation} where $X$ and $Y$ indicate locations in the search space, $S(X)$ is the score of location $X$, and $P(X \rightarrow Y)$ is the probability, when in location $X$, of moving to location $Y$. Note that detailed balance implies reversibility: if it is possible to move from $X$ to $Y$, then it must be possible to move from $Y$ to $X$. The temperature starts out high and is gradually reduced, giving the process a chance to evade local maxima and settle into the global maximum. The stochastic moves can be generated in many different ways that satisfy detailed balance: generating them in a way that explores the search space effectively is key to a successful algorithm. For example, some previous multiple alignment algorithms have employed simulated annealing with simple moves that adjust the position of a gap in one of the aligned sequences \cite{ComputApplBiosci.:9:267, ComputApplBiosci.:10:419}. Thus, each move explores just one location in the vast search space, and many such moves may separate a local optimum from the global optimum. In contrast, GLAM2 uses an extremely clever technique, the \emph{stochastic traceback} \cite{Eddy7584426, Durbin00}, which allows a single move to explore efficiently an astronomically large number of alignments (albeit an astronomically small fraction of the total search space). Moves using the stochastic traceback alone are prone to getting stuck in a certain type of local optimum; so GLAM2 intersperses these with a second type of move. The stochastic traceback moves are referred to as site sampling, and the second type as column sampling, because they are analogous to procedures with the same names in the original Gibbs sampler \cite{ProteinSci.:4:1618}. At each iteration, one type of move is chosen randomly with 50:50 probabilities. A modification of column sampling allows the number of key positions in the motif to be varied. Together, these moves can explore the space of all possible motifs. To assess the robustness of the result, GLAM2 performs several (by default 10) annealing runs from different random starting points. Each run continues until some number of iterations $n$ has passed without finding a higher-scoring alignment. During each run, $T$ is reduced by a fixed percentage at each iteration, by default starting at 1.2 and decreasing 1.44-fold per $n$ iterations. The highest-scoring alignment encountered in each run is reported at the end. \subsection*{Site Sampling} \subsubsection*{Overview} In site sampling, one of the input sequences is chosen at random and re-aligned to the motif. All possible alignments of substrings of this sequence to the motif are considered, including the option of excluding this sequence from the alignment altogether. However, if excluding the sequence would bring the number of substrings in the alignment below the minimum permitted number (see above), then exclusion is not considered. Both strands of the sequence are considered, if the user selected this option. One alignment is chosen at random, with probability proportional to the resulting alignment score, as defined above, raised to the power of $1/T$. \subsubsection*{Scoring} The calculations can be simplified somewhat by dividing by a constant factor: the score of the alignment of all the other sequences, excluding the sequence that is being re-aligned. (This also scales the values to moderate orders of magnitude that are likely to be representable by the computer.) In the following, primed letters refer to this alignment of all the other sequences: $s'$ is the number of substrings in the alignment, $m'_k$ is the number of residues aligned to key position $k$, $d'_k$ is the number of deletions of key position $k$, $r'_k$ is the number of insertions between $k$ and $k+1$, and $c'_{ki}$ is the count of residue type $i$ in position $k$. Using the fact that $\Gamma(x) = (x-1) \Gamma(x-1)$, the score for deleting key position $k$ (cf. Equation \ref{eq:totdel}) becomes: \begin{equation} \delta(k) = \frac{d'_k+D}{s'+D+E} \end{equation} The score for inserting $x$ residues between $k$ and $k+1$ (cf. Equation \ref{eq:totins}) becomes: \begin{equation} \iota(k,x) = \frac{s'+J}{r'_k+s'+I+J} \cdot \prod_{i=0}^{x-1} \frac{r'_k+I+i}{r'_k+s'+I+J+i+1} \end{equation} The score for aligning a residue of type $X$ with key position $k$ (cf. Equation \ref{eq:totmat}) becomes: \begin{equation} \mu(k,X) = \frac{m'_k+E}{s'+D+E} \cdot \sum_{j=1}^C v_{kj} \frac{c'_{kX}+\alpha_{jX}}{m'_k+A_j} \bigg/ p_X \end{equation} where: \begin{equation} v_{kj} = \frac{ \frac{w_j \cdot \Gamma(A_j)}{\Gamma(m'_k+A_j)} \prod_{i=1}^A \frac{\Gamma(c'_{ki}+\alpha_{ji})}{\Gamma(\alpha_{ji})} }{ \sum_{j=1}^C \frac{w_j \cdot \Gamma(A_j)}{\Gamma(m'_k+A_j)} \prod_{i=1}^A \frac{\Gamma(c'_{ki}+\alpha_{ji})}{\Gamma(\alpha_{ji})} } \end{equation} (Hence $D$, $E$, $I$, and $J$ are called pseudocounts, because they get added to the observed counts: $d'_k$, $m'_k$, $r'_k$, and $s'$.) \subsubsection*{Dynamic Programming} To set up the stochastic traceback, GLAM2 calculates values $M(i,j)$: the sum of the scores of all alignments ending at the $i$\textsuperscript{th} key position in the motif and the $j$\textsuperscript{th} residue in the sequence. The calculation is made slightly simpler by constructing intermediate values $N(i,j)$. The quantities $\mu$, $\delta$, and $\iota$ are raised to the power of $1/T$ prior to using them in this procedure. In the following, $L$ is the length of the sequence. Boundary cases: \begin{align} N(0,j) & = 1 && (0 \leq j \leq L) \\ M(i,0) & = \delta(i) \cdot N(i-1,0) && (1 \leq i \leq W) \end{align} Main cases: \begin{align} M(i,j) & = \mu(i,X_j) \cdot N(i-1,j-1) + \delta(i) \cdot N(i-1,j) && \left( \begin{array}{l} 1 \leq j \leq L \\ 1 \leq i \leq W \end{array} \right) \\ \label{eq:Nij} N(i,j) & = \sum_{x=0}^j \iota(i,x) \cdot M(i,j-x) && \left( \begin{array}{l} 0 \leq j \leq L \\ 1 \leq i < W \end{array} \right) \end{align} This procedure is similar to the standard algorithms for pair-wise sequence alignment, but much slower: the summation in Equation (\ref{eq:Nij}) causes the whole calculation to require $O(WL^2)$ operations rather than $O(WL)$ operations. Ways to speed up the calculation are described below. \subsubsection*{Stochastic Traceback} The values $M(i,j)$ are used to pick a random alignment, with probabilities proportional to their scores to the power of $1/T$. Note that $\sum_{j=0}^L M(W,j)$ is the sum of the scores of all alignments of the sequence to the motif. If both strands are being considered, a second matrix $M_R(i,j)$ is constructed using the reverse complement of the sequence. GLAM2 randomly decides to align the sequence on the forward strand, the reverse stand, or not at all, with probabilities in the ratio $\sum_{j=0}^L M(W,j)$ : $\sum_{j=0}^L M_R(W,j)$ : 1. Supposing the forward strand is chosen, the endpoint of the alignment in the sequence, $0 \leq j \leq L$, is then picked randomly, with probabilities proportional to $M(W,j)$. Having chosen the endpoint $j$, the alignment is determined by iterating the following steps, with $i$ initially equal to $W$. Firstly, GLAM2 randomly chooses to either align residue $j$ to key position $i$, or delete key position $i$, with probabilities defined in Equations (\ref{eq:tbm}) and (\ref{eq:tbd}). Then $i$ is decremented, and unless deletion was chosen, $j$ is decremented. Secondly, GLAM2 randomly picks a number of residues, $0 \leq x \leq j$, to insert between key positions $i$ and $i+1$, with probabilities given in Equation (\ref{eq:tbi}). $x$ is then subtracted from $j$. These steps are repeated until $i$ or $j$ reaches zero. \begin{align} \label{eq:tbm} \textrm{prob}(\textrm{match}) & = \mu(i,X_j) \cdot N(i-1,j-1) \; / \; M(i,j) \\ \label{eq:tbd} \textrm{prob}(\textrm{delete}) & = \delta(i) \cdot N(i-1,j) \; / \; M(i,j) \\ \label{eq:tbi} \textrm{prob}(\textrm{insert }x\textrm{ residues}) & = \iota(i,x) \cdot M(i,j-x) \; / \; N(i,j) \end{align} The traceback can be performed in $O(W+L)$ operations. \subsubsection*{Faster Algorithms} GLAM2 provides two options to speed up the dynamic programming procedure. The first option, noting that Equation (\ref{eq:Nij}) is a convolution, is to calculate it in $O(L \log L)$ operations using fast Fourier transforms. Thus, the whole dynamic programming procedure requires $O(W L \log L)$ operations. A potential disadvantage is loss of accuracy for smaller values of $N(i,j)$. The values of $M(i,j)$ and $N(i,j)$ (for fixed $i$) may differ by many orders of magnitude; since the Fourier transform mixes these values, the smaller ones become corrupted owing to limited precision of the computer's representation of real numbers. Unfortunately, in some cases these smaller values of $N(i,j)$ have large effects at later stages of the dynamic programming. The second option is to replace the residue insertion score, $\iota(k,x)$, with a more convenient approximation: \begin{equation} \iota(k,x) = \iota_1(k) \cdot \iota_2(k)^x \end{equation} where: \begin{align} \iota_1(k) & = \frac{s'+J}{r'_k+s'+I+J} \\ \iota_2(k) & = \frac{r'_k+I}{r'_k+s'+I+J} \end{align} Here, $\iota_2$ and $\iota_1$ are the posterior mean estimators for $\psi$ and $1-\psi$. With this change, $N(i,j)$ can be built up as follows: \begin{align} N(i,0) & = \iota_1(i) \cdot M(i,0) \\ N(i,j) & = \iota_1(i) \cdot M(i,j) + \iota_2(i) \cdot N(i,j-1) \end{align} Thus, the whole dynamic programming procedure requires $O(WL)$ operations. This is the default algorithm for GLAM2. It is remarkable that this algorithm samples from all gapped alignments using the same number of operations, $O(WL)$, as the site sampling step of the original Gibbs sampler \cite{Science.:262:208}, which only considers ungapped alignments. The change to $\iota(k,x)$ introduces a slight deviation from detailed balance, penalizing long insertions, but seems to produce sensible alignments in practice. \subsubsection*{Numerical Considerations} The values of $M(i,j)$ and $N(i,j)$ can become too large or too small to be represented by the computer using floating point. A rescaling procedure is employed to mitigate this problem. After calculating $N(i-1,j)$ for all $j$, and before calculating $M(i,j)$, GLAM2 rescales $\mu(i,X)$ and $\delta(i)$ as follows: \begin{align} \mu(i,X) & \leftarrow \frac{\mu(i,X)}{\max_{j=0}^L N(i-1,j)} \\ \delta(i) & \leftarrow \frac{\delta(i)}{\max_{j=0}^L N(i-1,j)} \end{align} The product of the rescale values, $R$, is recorded (in $\log$ space to avoid overflow): \begin{equation} R = \prod_{i=1}^W \max_{j=0}^L N(i-1,j) \end{equation} In the stochastic traceback, the sum of alignment scores $\sum_{j=0}^L M(W,j)$ needs to multiplied by $R$, and similarly for $M_R$, before picking the strand. Note that this method is simpler than rescaling procedures that have been described elsewhere \cite{Durbin00}: there is no need to record an array of rescaling parameters, and the traceback, after picking the strand, works properly without change. This rescaling keeps the maximum values of $M(i,j)$ and $N(i,j)$ to manageable orders of magnitude, but the minimum values may still underflow. These small values ``usually'' correspond to extremely improbable alignments, but in slightly pathological cases they can be the seeds of highly probable alignments. GLAM2 attempts to warn when this occurs, by checking whether the traceback passes through values of $N(i,j)$ below the limit of accurately represented numbers (DBL\_MIN). As noted above, the fast Fourier transform algorithm entails a more severe loss of accuracy for small values: in this case, the warning is triggered at values below DBL\_EPSILON. In addition, illegitimate negative values of $N(i,j)$ emerging from the fast Fourier transform are immediately reset to zero. Finally, problems can occur with low values of $T$. For instance, an entire row of $N(i,j)$ values (all $j$ for some $i$) can underflow to zero. To avoid this, a lower bound is imposed on $T$, by default 0.1. \subsection*{Column Sampling} \subsubsection*{Motivation} Site sampling alone finds high-scoring alignments, but often with non-optimal distribution of the key positions. For example, there might be a key position that is deleted in all substrings, while further along the alignment there is a column of inserted residues that are all identical. In this case, the score would increase if all the letters between these two columns were shifted across by one position, so that the identical residues become aligned to a key position, and the deletions disappear. Unfortunately, site sampling moves can only shift the letters of one substring at a time, which is likely to decrease the score. So low-scoring intermediate alignments must be traversed in order to reach the improved alignment. Column sampling moves solve this difficulty by providing a more direct route to the improved alignment. \subsubsection*{Overview} Column sampling has two steps. In the first step, one key position is chosen at random, and removed from the alignment. In the second step, a new key position is added to the alignment. These steps can be viewed as moving a key position from one location to another in the alignment. Removal of a key position has the following effect. If an internal key position (neither the leftmost nor the rightmost) is removed, the residues that were aligned to it become insertions between the preceding and following key positions. If the leftmost or rightmost key position is chosen, the residues that were aligned to it cease to be part of the alignment. In general, the number of ways of adding a key position to an alignment is vast, and the addition step needs to be restricted to a manageable subset of these. Furthermore, this subset should be chosen in a way that ensures reversibility and detailed balance of column sampling moves. To achieve this, some properties of the key position that was removed need to be preserved. \subsubsection*{Details} Before removing a key position, the following information is recorded about it: whether it is deleted or matched in each substring, and the number of insertions in each substring between this key position and the one to either the left or the right. The direction, left or right, is chosen randomly with 50:50 probability before choosing the key position. When the direction is ``left'', the leftmost key position is never chosen, and when the direction is ``right'', the rightmost key position is never chosen. This procedure requires that there are at least two key positions. After removing the key position, GLAM2 considers all ways of adding a key position with these properties to the alignment. The numbers of insertions between it and the neighbouring key position are preserved relatively rather than absolutely: in other words, they may be shifted by a constant offset. The alignment score for each way of adding such a key position is calculated, and one of them is chosen randomly with probabilities proportional to their scores raised to the power of $1/T$. \subsection*{Changing the number of key positions} \subsubsection*{Overview} None of the moves described so far changes the number of key positions in the motif, yet we wish to optimise this also. This is accomplished by two modifications to the column sampling procedure. Firstly, in the removal step, a key position is chosen and its properties are recorded as usual, but it is not always removed. This allows the number of key positions to grow. The decision to remove or not is made stochastically, with probability $q$ of removal. The correct value for $q$ is discussed below. Secondly, in the addition step, a key position is not always added. This allows the number of key positions to decrease. \subsubsection*{Modified Addition Step} Suppose that a key position was removed, and that there are no other key positions with the same properties. If we do not add a key position, there will be no way to reverse the move, in violation of detailed balance. Thus, a key position must always be added, unless there is another key position in the alignment with the same properties. One way to think about this is that the key position to be added can be ``absorbed'' by a key position with the same properties. Specifically, GLAM2 counts the number, $V$, of key positions with the same properties as the one being added, and adds absorption by each one of them to the list of alignments that it considers. Finally, as usual, one alignment is chosen stochastically with probability proportional to the alignment score to the power of $1/T$. \subsubsection*{Probability of Removal} The probability $q$ of removal should be chosen carefully to maintain detailed balance. Consider the probabilities of moving between two alignments $X$ and $Y$, where $Y$ has one extra key position compared to $X$. In the following, $V_X$ is the number of key positions in $X$ with the same properties as the extra key position in $Y$. \begin{equation} P(X \rightarrow Y) = \frac{1}{2} \cdot \frac{1}{2} \cdot (1-q(X)) \cdot \frac{V_X}{W_X-1} \cdot \frac{S'(Y)}{V_X \cdot S'(X) + \sum_Z S'(Z)} \end{equation} where $W_X$ is the number of key positions in $X$ (one of which, either the leftmost or rightmost, is never selected), $S'(X)$ is the score of $X$ to the power of $1/T$, and $Z$ sums over all the ways of adding a new key position. The first $1/2$ is the probability of column sampling rather than site sampling; the second $1/2$ is the probability of choosing the direction (left or right); $1-q(X)$ is the probability of not removing the key position; $V_X / (W_X-1)$ is the probability of choosing a key position with the right properties to get to $Y$; the final fraction is the probability of adding a key position in the right location to get to $Y$. Similarly: \begin{equation} P(Y \rightarrow X) = \frac{1}{2} \cdot \frac{1}{2} \cdot q(Y) \cdot \frac{1}{W_Y-1} \cdot \frac{V_X \cdot S'(X)}{V_X \cdot S'(X) + \sum_Z S'(Z)} \end{equation} Thus, to achieve detailed balance, the following must hold: \begin{equation} \frac{1-q(X)}{W_X-1} = \frac{q(Y)}{W_Y-1} \end{equation} where $W_X = W_Y-1$. This can be satisfied if $q$ is a function of the number of key positions, $W$. To simplify things a bit, we express $q$ as a function of the number of \emph{selectable} key positions, $W' = W-1$, recalling that one of the two endmost key positions is never selected. Then: \begin{align} & \frac{q(W'+1)}{W'+1} = \frac{1}{W'} - \frac{q(W')}{W'} \\ \label{eq:qW} \Rightarrow & \frac{q(W')}{W'} = (-1)^{W'-1} \left[ q(1) - \sum_{i=1}^{W'-1} \frac{(-1)^{i-1}}{i} \right] \end{align} The summation in Equation (\ref{eq:qW}) generates the Taylor expansion of $ln(2)$ about 1, so the unique solution that prevents $q(W')$ from diverging is, rather surprisingly, $q(1) = ln(2)$. \subsection*{Initialization} At the start of each annealing run, an initial alignment is constructed in the following manner. The number of key positions is set to an initial value chosen by the user (default: 20). Starting with an empty alignment, the input sequences are taken one-by-one, in a random order, and added to the alignment using a site sampling move with $T = 1$. \section*{Motif Scanning} \subsection*{Overview} In motif scanning, a sequence database is searched to find new instances of a previously determined motif. An instance is a sequence segment that has a high-scoring alignment to the key positions of the motif. In this section, we first describe the scoring scheme for such alignments. Secondly, we describe an algorithm to scan a motif against one sequence, and find a guaranteed maximal-scoring alignment. To scan a database, this algorithm can simply be repeated for each sequence. However, some sequences may contain multiple motif instances: we do not want to be limited to one hit per sequence. Thus, we also describe a method for finding suboptimal matches. The techniques used in this section are all standard \cite{Durbin00}. \subsection*{Scoring Scheme} \subsubsection*{Motif Model} The scoring scheme derives from the statistical motif model described earlier. To recap, the model has position-specific residue probabilities: $\theta_i$, deletion probabilities: $\phi$, and insertion probabilities: $\psi^x(1-\psi)$. For scanning, these probabilities are estimated from the predetermined motif, and from prior expectations. Specifically, the posterior mean estimators \cite{Durbin00} are used. We are given a motif with $W$ key positions and $s$ aligned sequences. The $k$\textsuperscript{th} key position has $m_k$ residues and is deleted $d_k$ times, so that $m_k + d_k = s$. There are $r_k$ insertions between key positions $k$ and $k+1$. $c_{kX}$ is the count of residue type $X$ in key position $k$, so that $m_k = \sum_{X=1}^A c_{kX}$. Using the same Beta and Dirichlet mixture priors as above, the posterior mean estimators are: \begin{align} \hat\phi(k) & = \frac{d_k+D}{s+D+E} \\ \hat\psi(k) & = \frac{r_k+I}{r_k+s+I+J} \\ \hat\theta(k,X) & = \sum_{j=1}^C v_{kj} \frac{c_{kX}+\alpha_{jX}}{m_k+A_j} \end{align} where: \begin{equation} v_{kj} = \frac{ \frac{w_j \cdot \Gamma(A_j)}{\Gamma(m_k+A_j)} \prod_{i=1}^A \frac{\Gamma(c_{ki}+\alpha_{ji})}{\Gamma(\alpha_{ji})} }{ \sum_{j=1}^C \frac{w_j \cdot \Gamma(A_j)}{\Gamma(m_k+A_j)} \prod_{i=1}^A \frac{\Gamma(c_{ki}+\alpha_{ji})}{\Gamma(\alpha_{ji})} } \end{equation} \subsubsection*{Background Model} We evaluate a potential motif instance by comparing the motif model to a background model. As before, the background model is that the residues occur randomly and independently, with probabilities $p_i$. The $p_i$ values can be adjusted by the user. By default, For proteins, the abundances of Robinson and Robinson are used \cite{ProcNatlAcadSciUSA.:88:8880}, and for nucleotides, uniform abundances are used. \subsubsection*{Score Parameters} The score of a sequence segment aligned to a motif is a log likelihood ratio: the likelihood of the aligned segment given the motif model, versus the likelihood of the segment given the background model. Thus, the score for deleting key position $k$ is: \begin{equation} \delta(k) = \log_2 \left[ \hat\phi(k) \right] \end{equation} The score for aligning a residue of type $X$ with key position $k$ is: \begin{equation} \mu(k,X) = \log_2 \left[ (1 - \hat\phi(k)) \cdot \hat\theta(k,X) \; / \; p_X \right] \end{equation} The score for inserting $x$ residues between $k$ and $k+1$ is $\iota_1(k) + \iota_2(k) \cdot x$, where: \begin{align} \iota_1(k) & = \log_2 \left[ 1 - \hat\psi(k) \right] \\ \iota_2(k) & = \log_2 \left[ \hat\psi(k) \right] \end{align} \subsection*{Search Algorithm} \subsubsection*{Overview} We wish to find a maximal-scoring alignment of the motif's key positions with a segment of the query sequence. This is a standard alignment problem, which can be solved by dynamic programming followed by a traceback. \subsubsection*{Dynamic Programming} Dynamic programming calculates values $M(i,j)$: the score of the highest-scoring alignment ending at the $i$\textsuperscript{th} key position in the motif and the $j$\textsuperscript{th} residue in the sequence. The calculation is made slightly simpler by constructing intermediate values $N(i,j)$. In the following, $L$ is the length of the sequence. Boundary cases: \begin{align} N(0,j) & = 0 && (0 \leq j \leq L) \\ M(i,0) & = \delta(i) + N(i-1,0) && (1 \leq i \leq W) \\ N(i,0) & = \iota_1(i) + M(i,0) && (1 \leq i < W) \end{align} Main cases: \begin{align} M(i,j) & = \max \left\{ \begin{array}{l} \mu(i,X_j) + N(i-1,j-1) \\ \delta(i) + N(i-1,j) \end{array} \right. && \left( \begin{array}{l} 1 \leq j \leq L \\ 1 \leq i \leq W \end{array} \right) \\ N(i,j) & = \max \left\{ \begin{array}{l} \iota_1(i) + M(i,j) \\ \iota_2(i) + N(i,j-1) \end{array} \right. && \left( \begin{array}{l} 1 \leq j \leq L \\ 1 \leq i < W \end{array} \right) \end{align} \subsubsection*{Traceback} In this section, the values $M(i,j)$ and $N(i,j)$ are used to find a highest-scoring alignment. First, a highest-scoring alignment endpoint is found: \begin{equation} j = \argmax_{j=0}^L M(W,j) \end{equation} In case of ties, the lower value of $j$ is arbitrarily chosen. Having chosen the endpoint $j$, the alignment is determined by iterating the following steps, with $i$ initially equal to $W$. Firstly, if $\delta(i) + N(i-1,j)$ is greater than $\mu(i,X_j) + N(i-1,j-1)$, key position $i$ is deleted, else residue $j$ is aligned to key position $i$. Then $i$ is decremented, and unless deletion was chosen, $j$ is decremented. Secondly, if $\iota_2(i) + N(i,j-1)$ is greater than $\iota_1(i) + M(i,j)$, a residue is inserted between key positions $i$ and $i+1$, and $j$ is decremented. This is repeated until $\iota_2(i) + N(i,j-1)$ ceases to be greater than $\iota_1(i) + M(i,j)$. These steps are repeated until $i$ or $j$ reaches zero. \subsection*{Suboptimal Matches} \subsubsection*{Overview} The previous algorithm finds one highest-scoring alignment of a motif to a sequence, but we wish to be able to find more than one alignment. The usual definitional problem arises: there are a vast number of possible alignments, and the second-highest scoring one is likely to be a minor variant of the highest-scoring one, but we are not interested in such variants. Thus, we adopt the criterion of Waterman and Eggert \cite{Waterman2448477}: subsequent alignments must not pair residues and key positions that have been paired in any previous alignment. \subsubsection*{Method} To satisfy this criterion, we maintain a matrix $F(i,j)$ that indicates forbidden pairs. $F(i,j)$ is initialized to all zeros. During the traceback, whenever residue $j$ is aligned to key position $i$, $F(i,j)$ is set to 1. After the traceback, the $M$ and $N$ matrices are recalculated, with matches forbidden whenever $F(i,j) = 1$. Only small regions of $M$ and $N$ near the newly forbidden cells need to be recalculated \cite{Waterman2448477}. Finally, a new traceback is performed, avoiding old forbidden matches, and marking new forbidden matches. These recalculation and traceback steps can be repeated as often as desired. \subsubsection*{Stopping Criteria} Retrieval of suboptimal matches from one sequence stops when either of two conditions are met. Firstly, if an alignment with no matches (only deletions and insertions) is found, it is discarded and the procedure is terminated. Such an alignment does not add any forbidden pairings, so it necessarily terminates the Waterman-Eggert procedure. Secondly, the total number of database hits is limited to some value $n$ chosen by the user. If $n$ hits have already been found, and the new alignment has a score no greater than any of these, it is discarded and the procedure is terminated. The database hits are stored in a heap, which is a kind of partially-sorted array that allows efficient removal of the lowest-scoring hit and insertion of new hits. \bibliographystyle{plain} \bibliography{GLAM2_method} \end{document} glam2-1064/doc/GLAM2_method.bib0000644007451300001540000000662510633164632015533 0ustar charlesgenome@ARTICLE{ProteinSci.:4:1618, author = { A F Neuwald and J S Liu and C E Lawrence}, title = {Gibbs motif sampling: detection of bacterial outer membrane protein repeats.}, journal = {Protein Sci}, year = {1995}, volume = {4}, number = {8}, pages = {1618-32} } @ARTICLE{Science.:262:208, author = { C E Lawrence and S F Altschul and M S Boguski and J S Liu and A F Neuwald and J C Wootton}, title = {Detecting subtle sequence signals: a {G}ibbs sampling strategy for multiple alignment.}, journal = {Science}, year = {1993}, volume = {262}, number = {5131}, pages = {208-14} } @article{Bailey7584439, author = {T. L. Bailey and C. Elkan}, title = {The value of prior knowledge in discovering motifs with MEME.}, journal = {Proc Int Conf Intell Syst Mol Biol}, volume = {3}, year = {1995}, pages = {21-29} } @ARTICLE{NucleicAcidsRes.:32:189, author = { Martin C Frith and Ulla Hansen and John L Spouge and Zhiping Weng}, title = {Finding functional sequence elements by multiple local alignment.}, journal = {Nucleic Acids Res}, year = {2004}, volume = {32}, number = {1}, pages = {189-200} } @ARTICLE{ComputApplBiosci.:12:327, author = { K Sjolander and K Karplus and M Brown and R Hughey and A Krogh and I S Mian and D Haussler}, title = {Dirichlet mixtures: a method for improved detection of weak but significant protein sequence homology.}, journal = {Comput Appl Biosci}, year = {1996}, volume = {12}, number = {4}, pages = {327-45} } @ARTICLE{ComputApplBiosci.:9:267, author = { M Ishikawa and T Toya and M Hoshida and K Nitta and A Ogiwara and M Kanehisa}, title = {Multiple sequence alignment by parallel simulated annealing.}, journal = {Comput Appl Biosci}, year = {1993}, volume = {9}, number = {3}, pages = {267-73} } @ARTICLE{ComputApplBiosci.:10:419, author = { J Kim and S Pramanik and M J Chung}, title = {Multiple sequence alignment using simulated annealing.}, journal = {Comput Appl Biosci}, year = {1994}, volume = {10}, number = {4}, pages = {419-26} } @article{Eddy7584426, author = {S. R. Eddy}, title = {Multiple alignment using hidden Markov models.}, journal = {Proc Int Conf Intell Syst Mol Biol}, volume = {3}, year = {1995}, pages = {114-20} } @ARTICLE{ProcNatlAcadSciUSA.:88:8880, author = { A B Robinson and L R Robinson}, title = {Distribution of glutamine and asparagine residues and their near neighbors in peptides and proteins.}, journal = {Proc Natl Acad Sci U S A}, year = {1991}, volume = {88}, number = {20}, pages = {8880-4} } @ARTICLE{NucleicAcidsRes.:25:3389, author = { S F Altschul and T L Madden and A A Schaffer and J Zhang and Z Zhang and W Miller and D J Lipman}, title = {Gapped {B}{L}{A}{S}{T} and {P}{S}{I}-{B}{L}{A}{S}{T}: a new generation of protein database search programs.}, journal = {Nucleic Acids Res}, year = {1997}, volume = {25}, number = {17}, pages = {3389-402} } @book{Durbin00, AUTHOR = {Durbin, Richard and Eddy, Sean R. and Krogh, Anders and Mitchison, Graeme}, TITLE = {Biological sequence analysis: probabilistic models of proteins and nucleic acids}, YEAR = {2000}, PUBLISHER = {Cambridge Univ. Press}, } @article{Waterman2448477, author = {M. S. Waterman and M. Eggert}, title = {A new algorithm for best subsequence alignments with application to tRNA-rRNA comparisons.}, journal = {J Mol Biol}, volume = {197}, number = {4}, year = {1987}, month = {Oct}, pages = {723-728} } glam2-1064/doc/glam2_tut.html0000644007451300001540000003225311011073107015456 0ustar charlesgenome glam2 Tutorial

glam2 Tutorial

What it does

You give glam2 a set of sequences, and it finds the strongest motif shared by these sequences. More exactly, glam2 gives you an alignment of segments of the sequences. Each sequence contributes at most one segment to the alignment. glam2 assigns scores to alignments: the score favours alignment of similar residues, and disfavours insertions and deletions, but less so if they repeatedly occur at the same, presumably fragile, positions. glam2 attempts to find a maximal-scoring alignment for your sequences.

Before starting: beware of confounding similarities

Biological sequences often have strong similarities that are not interesting. These strong similarities need to be removed before weaker motifs can be found. Here are some common cases:

  • Highly similar sequences: If your set includes highly similar sequences (e.g. equivalent sequences from human and chimpanzee), you can get a subset of non-highly-similar sequences using purge.
  • Repeats: Biological sequences harbour a complex menagerie of repetitive and simple sequence elements. These are often prominent motifs. If you wish to avoid them, mask them before using glam2. These tools mask various kinds of repeats: Repeatmasker, Censor, seg / pseg / nseg, DUST, XNU, DSR, GBA, SIMPLE, CARD, CAST, SAPS, TRF. Another approach is to run glam2 once, then use glam2mask to mask the motif found by glam2, and then run glam2 again to find weaker motifs.

How it works

To use glam2 effectively, you need to understand roughly how it works. glam2 starts from a random alignment, and makes many small, random changes to it, which are designed to find high-scoring alignments in the long run. The longer you let it run, the more likely it is to find a maximal-scoring alignment.

To check that a reproducible, high-scoring motif has been found, the whole procedure is run several (e.g. 10) times from different starting alignments. If all runs produce identical alignments, we have maximum confidence that this is the optimal motif. (To gain even more confidence, consider varying the initial motif width: see below.) If a few of the runs produce different, lower-scoring motifs, we still have high confidence. If all the runs produce completely different alignments, we have low confidence, and the run-length needs to be increased.

An alternative is to check that similar, but not necessarily identical, alignments are found repeatedly. This suggests that the optimal motif has been found, if not the exactly optimal alignment. With large numbers of sequences, there are so many possible alignments that it is not feasible to find the precisely optimal one, and this is the best that can be hoped for. Furthermore, the precisely optimal alignment is not very meaningful: it is rather like writing a moderately accurate value to twelve decimal places.

Basic usage

Running glam2 without any arguments gives a usage message:

Usage: glam2 [options] alphabet my_seqs.fa
Main alphabets: p = proteins, n = nucleotides
Main options (default settings):
-h: show all options and their default settings
-o: output file (stdout)
-r: number of alignment runs (10)
-n: end each run after this many iterations without improvement (10000)
-2: examine both strands - forward and reverse complement
-z: minimum number of sequences in the alignment (2)
-a: minimum number of aligned columns (2)
-b: maximum number of aligned columns (50)
-w: initial number of aligned columns (20)

The main input to glam2 is a file of sequences in FASTA format:

>MyFirstSequence
GHYWVVCTGGGACH
>My2ndSequence
LLIGGPWVWWADDDF
(etc.)

You need to tell glam2 which alphabet to use:

glam2 p my_prots.fa
glam2 n my_nucs.fa

Use -o to write the output to a file rather than to the screen:

glam2 -o my_prots.glam2 p my_prots.fa

Output format

The output begins with some general information:

GLAM2: Gapped Local Alignment of Motifs
Version 9999

glam2 p my_prots.fa
Sequences: 4
Greatest sequence length: 14
Residue counts: A=3 C=2 D=3 E=3 F=2 G=4 H=4 I=4 K=0 L=5 M=1 N=3 P=4 Q=0 R=2 S=3
T=1 V=2 W=0 Y=2 x=0

This is followed by several alignments, sorted in order of score. The topmost alignment is the interesting one: the purpose of the others is to indicate the reproducibility of the topmost one. An alignment begins with a summary line:

Score: 18.0451  Columns: 6  Sequences: 4

Followed by the alignment itself:

                **..****
seq1         10 HP..D.IG 14 + 8.72
seq2          5 HPGADLIG 12 + 7.39
seq3          7 HP..ELIG 12 + 15.7
seq4          5 HP..ELLA 10 + 9.71

The stars indicate the key positions of the motif, i.e. the conserved and presumably functional positions. Positions without stars hold residues that are inserted between key positions. No attempt is made to align inserted residues with each other: their column placement is arbitrary. Gaps in key positions indicate deletions. The plus signs indicate the strand (only meaningful when considering both strands of nucleotide sequences with the -2 option). The rightmost numbers are the marginal scores of each aligned segment, i.e. the amount by which the total alignment score would decrease if the segment were removed. The marginal scores do not in general sum to the total alignment score.

The alignment is followed by a multilevel consensus sequence, indicating the dominant residue types in each key position:

                HP  DLIG
                    E LA

The residue types are ordered by frequency from top to bottom, and only those with a frequency of at least 20% are written. This representation is borrowed from MEME. This is followed by a matrix of the residue and deletion counts for each key position, and insertion counts between them, along with their scores:

 A  C  D  E  F  G  H  I  K  L  M  N  P  Q  R  S  T  V  W  Y Del Ins Score
 0  0  0  0  0  0  4  0  0  0  0  0  0  0  0  0  0  0  0  0   0      7.33
                                                                  0 -0.263
 0  0  0  0  0  0  0  0  0  0  0  0  4  0  0  0  0  0  0  0   0      7.98
                                                                  2 -8.61
 0  0  2  2  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0   0      4.55
                                                                  0 -0.263
 0  0  0  0  0  0  0  0  0  3  0  0  0  0  0  0  0  0  0  0   1     -0.642
                                                                  0 -0.263
 0  0  0  0  0  0  0  3  0  1  0  0  0  0  0  0  0  0  0  0   0      4.21
                                                                  0 -0.263
 1  0  0  0  0  3  0  0  0  0  0  0  0  0  0  0  0  0  0  0   0      4.28

These scores sum to the total alignment score.

Controlling speed versus accuracy

Use -n to control how long glam2 runs for, and -r to control how many runs it does. Quick and dirty:

glam2 -r 1 -n 1000 p my_prots.fa

Slow and thorough:

glam2 -n 1000000 p my_prots.fa

If the top alignment is completely different from all the other alignments, there is little confidence that the best possible motif has been found, and glam2 should be re-run with higher -n. (In our experience, increasing -n works better than increasing -r.)

Looking at reverse strands

Use -2 to search both strands of nucleotide sequences:

glam2 -2 n my_nucs.fa

Minimum number of sequences in the alignment

Use -z to set the minimum number of sequences that must participate in the alignment (if you set it to more than the number of input sequences, then all the sequences must participate):

glam2 -z 10 p my_prots.fa

Bounding the motif width

Use -a and -b to set lower and upper bounds on the number of key positions in the motif:

glam2 -a 10 -b 20 n my_nucs.fa

We do not recommend setting -a equal to -b, as this dramatically constrains glam2's flexibility.

Setting a good starting point for the motif width

glam2 automatically adjusts the number of key positions so as to maximize the alignment score, but it sometimes has trouble with this, for two reasons:

  1. It can only add or remove one key position at a time (unlike GLAM and A-GLAM). If it needs to add or remove multiple key positions in order to increase the score, passing through lower-scoring alignments on the way, it will be averse to doing this.
  2. It needs to add or remove key positions in a reversible fashion, which becomes difficult or impossible when the number of sequences is large, especially if the number of sequences is much greater than the length of each sequence. In extreme cases, the motif width may never change from its initial value.

You can help glam2 by using -w to set the initial number of key positions to a ballpark value:

glam2 -w 100 -a 50 -b 200 n my_nucs.fa

In this example, we guess that the optimal number is around 100, and allow it to vary between 50 and 200.

Tuning deletion and insertion preferences

Use -D and -E to tune deletion preferences, and use -I and -J to tune insertion preferences. The relative values of -D and -E control glam2's aversion to deletions: increasing -E relative to -D makes it more averse. Likewise, increasing -J relative to -I makes glam2 more averse to insertions. The absolute values of -D and -E control how much glam2 prefers deletions to occur at the same (fragile) positions: if -D and -E are both low, it strongly prefers deletions to occur at the same positions, otherwise not. Likewise, if -I and -J are both low, it strongly prefers insertions to occur at the same positions. To turn off deletions and insertions completely, set -E and -J to huge values:

glam2 -E 1e99 -J 1e99 n my_nucs.fa

Unusual residue abundances

If the input sequences have unusual residue abundances, glam2 may interpret these as being a motif. If this interpretation is not appropriate, you can fix it by changing glam2's idea of usual residue abundances. The best way to do this is with an alphabet file. For example, you could specify the average abundances for the taxonomic group that the sequences come from. Alternatively, you can use -q 1 to make glam2 estimate residue abundances from the input sequences:

glam2 -q 1 p my_prots.fa

This works well if the input sequences are much larger than the motif.

Significance of glam2 motifs

glam2 will always find the best motif that it can, even if you give it random sequences. Thus, it would be nice to know whether or not a motif found by glam2 is stronger than what would be found in random sequences. Here are two ways to answer this question:

  1. Brute force: This method is slow but good. Randomly shuffle the letters in each of your sequences (for example, using shuffleseq from EMBOSS). Run glam2 on the shuffled sequences, with exactly the same options as for the original sequences. Record the top alignment score. Reshuffle and re-run glam2 many times (e.g. 100 times, or maybe 20 times). If, say, 99 out of 100 shuffles produce lower scores than the original sequences, then the motif is probably significant. You can speed this up by lowering -n and/or -r, as long as the same values are used for the original and shuffled sequences. Once significance has been established, you can then align the motif more accurately by increasing -n and/or -r.
  2. Decoy approach: This method is faster, but may fail to spot significant motifs, especially when the number of sequences is small. Randomly shuffle the letters in each of your sequences, and concatenate each shuffled sequence to its parent sequence, separated by, say, ten wildcard letters (e.g. 'x'). Run glam2 once on this dataset. Does the top alignment more often include parent segments than shuffled segments, and/or do parent segments get higher marginal scores than shuffled segments? If so, the motif is probably significant. This can be quantified with a Wilcoxon signed rank test: see a statistics textbook or the Web.

These methods use shuffled versions of the original sequences: control sequences obtained in some other way may be used instead, but should be chosen with care.