# HG changeset patch # User Peter Meerwald # Date 1186917274 -7200 # Node ID be303a3f5ea8c310e34fddef8f216a8e480264b2 import diff -r 000000000000 -r be303a3f5ea8 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,9 @@ +syntax: glob +*.orig +*.rej +*~ +*.o +.dummy + +syntax: regexp +.*\#.*\#$ diff -r 000000000000 -r be303a3f5ea8 ANNOUNCEMENT --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ANNOUNCEMENT Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,132 @@ +Watermarking source + +version 0.4 + + +This package provides source code for some watermarking algorithms in +portable C code. Currently it includes the following + + watermarking algorithms + + Bruyndonckx [bruyn] + refer to + O. Bruyndonckx, Jean-Jacques Quisquater, and Benoit M. Macq. + Spatial method for copyright labeling of digital images. + In IEEE Workshop on Nonlinear Signal and Image Processing '95, + Thessaloniki, Greece, pages 456 - 459, 1995. + + Corvi + refer to + Marco Corvi and Gianluca Nicchiotti. + Wavelet-based image watermarking for copyright protection. + In Scandinavian Conference on Image Analysis SCIA '97, Lappeenranta, + Finland, June 1997. + + Cox + refer to + Ingemar J. Cox, Joe Kilian, Tom Leighton, and Talal G. Shamoon. + Secure spread spectrum watermarking for multimedia. + In Proceedings of the IEEE ICIP '97, + volume 6, pages 1673 - 1687, Santa Barbara, California, USA, 1997. + + Dugad + refer to + Rakesh Dugad, Krishna Ratakonda, and Narendra Ahuja. + A new wavelet-based scheme for watermarking images. In Proceedings of + the IEEE International Conference on Image Processing, ICIP '98, + Chicago, IL, USA, October 1998. + + Fridrich (2. scheme) + refer to + Jiri Fridrich. + Combining low-frequency and spread spectrum watermarking. In Proceedings of + the SPIE Symposium on Optical Science, Engineering and Instrumentation, + San Diego, USA, July 1998. + + Koch + refer to + Eckhard Koch and Jian Zhao. + Towards robust and hidden image copyright labeling. + In Proceedings of the IEEE International Workshop on Nonlinear + Signal and Image Processing, pages 452 - 455, Halkidiki, Marmaras, + Greece, June 1995. + + Kim + refer to + Jong Ryul Kim and Young Shik Moon. + A robust wavelet-based digital watermark using level-adaptive + thresholding. In Proceedings of the 6th IEEE International + Conference on Image Processing ICIP '99, page 202, + Kobe, Japan, October 1999. + + Wang + refer to + Houng-Jyh Wang, Po-Chyi Su, and C.-C. Jay Kuo. + Wavelet-based digital image watermarking. Optics Express, 3 + pp. 497, December 1998. + + Xia + refer to + Xiang-Gen Xia, Charles G. Boncelet, and Gonzalo R. Arce. + Wavelet transform based watermark for digital images. Optics Express, 3 + pp. 497, December 1998. + + Xie + refer to + Liehua Xie and Gonzalo R. Arce. + Joint wavelet compression and authentication watermarking. In + Proceedings of the IEEE International Conference on Image Processing, + ICIP '98, Chicago, IL, USA, 1998. + + Zhu + refer to + Wenwu Zhu, Zixiang Xiong, and Ya-Qin Zhang. + Multiresolution watermarking for images and video: a unified approach. + In Proceedings of the IEEE International Conference on Image Processing, + ICIP '98, Chicago, IL, USA, October 1998. + + Piva/Fotopoulos [cast|test-pv,hart,sub] + contribution by Vassilis Fotopoulos + refer to + + M.Barni, F. Bartolini, V. Cappellini, A. Piva. A DCT-Domain + System for Robust Image Watermarking, + Signal Processing, vol. 66, pp 357 - 372, 1998. + + V. Fotopoulos, A. N. Skodras, A Subband DCT approach to + image watermarking, X European Signal Processing Conference, + September 4 - 8, 2000, Tampere, Finland + + many more algorithms to come! + see what is in stock: http://www.cosy.sbg.ac.at/~pmeerw/Watermarking + + and utility programs + + cmp_pgm - compute difference image, PSNR, ... + cmp_dct - compute full-frame DCT domain difference image + cmp_dct8x8 - compute 8x8 block-based DCT difference image + cmp_dwt - compute DWT domain difference image + + + +Contact: Comments are welcome! + +More algorithms will be added over time, I have implemented about 13 +watermarking algorithms in the spatial-, DCT-, and wavelet domain so far. + +Please report what problems you have, suggestions, ... + +Peter Meerwald + +Dept. of Scientific Computing +University of Salzburg +Jakob-Haringer-Str. 2 +A-5020 Salzburg +AUSTRIA + +pmeerw@cosy.sbg.ac.at +http://www.cosy.sbg.ac.at/~pmeerw/Watermarking + ++43-662-8044-6327 + + diff -r 000000000000 -r be303a3f5ea8 Fotopoulos/CHANGES --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/CHANGES Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,2 @@ +removed #include - it is not needed and MS VC++ does not have +it (Sarat Atluri) diff -r 000000000000 -r be303a3f5ea8 Fotopoulos/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/Makefile Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,44 @@ +# Makefile + +include ../make/make.config + +all: cast-pv$(EXE) cast-hart$(EXE) cast-sub$(EXE) test-pv$(EXE) test-hart$(EXE) test-sub$(EXE) + +.SUFFIXES: .c .o + +.c$(O): + $(CC) $(CFLAGS) $(INCLUDES) -o $@ -c $< + +cast-pv$(EXE): cast-pv$(O) common$(O) + $(CC) $(LDFLAGS) -o $@ cast-pv$(O) common$(O) $(PGMLIBS) + +cast-hart$(EXE): cast-hart$(O) common$(O) + $(CC) $(LDFLAGS) -o $@ cast-hart$(O) common$(O) $(PGMLIBS) + +cast-sub$(EXE): cast-sub$(O) common$(O) + $(CC) $(LDFLAGS) -o $@ cast-sub$(O) common$(O) $(PGMLIBS) + +test-pv$(EXE): test-pv$(O) common$(O) + $(CC) $(LDFLAGS) -o $@ test-pv$(O) common$(O) $(PGMLIBS) + +test-hart$(EXE): test-hart$(O) common$(O) + $(CC) $(LDFLAGS) -o $@ test-hart$(O) common$(O) $(PGMLIBS) + +test-sub$(EXE): test-sub$(O) common$(O) + $(CC) $(LDFLAGS) -o $@ test-sub$(O) common$(O) $(PGMLIBS) + +test: cast-pv$(EXE) cast-hart$(EXE) cast-sub$(EXE) test-pv$(EXE) test-hart$(EXE) test-sub$(EXE) + cast-pv < ../images/lena.pgm > ../watermarked/foto-pv_lena.pgm + cast-hart < ../images/lena.pgm > ../watermarked/foto-hart_lena.pgm + cast-sub < ../images/lena.pgm > ../watermarked/foto-sub_lena.pgm + + test-pv < ../watermarked/foto-pv_lena.pgm > ../wms/foto-pv.wm + test-hart < ../watermarked/foto-hart_lena.pgm > ../wms/foto-hart.wm + test-sub < ../watermarked/foto-sub_lena.pgm > ../wms/foto-sub.wm + +install: cast-pv$(EXE) cast-hart$(EXE) cast-sub$(EXE) test-pv$(EXE) test-hart$(EXE) test-sub$(EXE) + $(CP) cast-pv$(EXE) cast-hart$(EXE) cast-sub$(EXE) test-pv$(EXE) test-hart$(EXE) test-sub$(EXE) $(INSTALLDIR) + +clean: + $(RM) *$(O) cast-pv$(EXE) cast-hart$(EXE) cast-sub$(EXE) test-pv$(EXE) test-hart$(EXE) test-sub$(EXE) + $(RM) ../watermarked/* ../wms/* diff -r 000000000000 -r be303a3f5ea8 Fotopoulos/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/README Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,21 @@ +M.Barni, F. Bartolini, V. Cappellini, A. Piva. "A DCT-Domain +System for Robust Image Watermarking", +Signal Processing, vol.66, pp 357-372, 1998. + +V. Fotopoulos, A.N. Skodras, "A Subband DCT approach to +image watermarking", X European Signal Processing Conference, +September 4-8, 2000, Tampere, Finland + +parameters: +for starting coefficient reasonable values for the dct and hartley schemes +and this kind of dimensions is around 5000-20000, for the watermark length 10000-50000, +and seed/key should be in the range 1-1000 so that the output file of the testing module +gives a right similarity diagram + +for the subband dct version, things change corresponding to coefficients +because the bands' sizes are 1/4 of the original image's size. +starting coef should be between 3000-5000 and length 10000-20000 +for the alpha parameter i use 0.2 for all bands except LL for which i use +0.1 + + diff -r 000000000000 -r be303a3f5ea8 Fotopoulos/README_VASSILIS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/README_VASSILIS Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,67 @@ +These codes use the DCT,Hartley and Subband DCT +Transforms for watermarking purposes.All schemes +are blind,no original image is used for detection. +Each casting module is accompanied by a testing +module.Supposing that the watermark key that you +select during casting is in the range 1-1000,the +testing module will test all the keys in this range +to produce the well known similarity diagrams used +by Cox, Piva and many more with the peak being the +proof of the watermark existence. + +I do not include a detection module because this implies +the use of certain thresholds. Although the casting +methods are almost standardized (multiplicative formula) +there are still questions about this thresholding but +the testing modules can be easily changed to fit this +purpose. + +The DCT scheme does not use the visual masking improvement +that Barni and his team suggest in one of their later works. +In all casting programs we assume that the coefficients are +diagonaly scanned,and ordered as shown in the following example. + +---------------------- +| 1| 3| 6|10|15|... +---------------------- +| 2| 5| 9|14|... +---------------------- +| 4| 8|13|... +---------------------- +| 7|12|... +---------------------- +|11|... +---------------------- + +which is quite simple comparing to the zig zag scanning +pattern that we know from the JPEG standard but does not +affect at all the idea that we have of the middle +frequencies.Also the user should take care that + +starting_coefficient+number_of_coeffs_to_change<(N*N)/2 + +which means that we shouldn't exceed the matrix diagonal. +To do so the scanning scheme should be changed accordingly +but this doesn't seem important because in all of the +schemes we don't get out of the middle frequencies coefs. +With correctly selected parameters,the schemes perform in +the same way as if the coeffs were zig zag scanned. + +In the Subband DCT version,the first set of questions +about starting coefficient,number of coefficients to +alter and alpha parameter, refer to the LH,HL and HH +band while the second set of questions sets the parameters +about the LL band only. + +All schemes should not be used with the same set of parameters +because each of the transforms, possess certain specific +properties. This should be kept in mind for testing purposes. +To use the right set of parameters please refer to corresponding +bibliography. +All code has been tested in Visual C++ v6.0 + +Have some nice tests... +Vassilis Fotopoulos + +for more info,ideas or points of discussion +email vfotop1@physics.upatras.gr diff -r 000000000000 -r be303a3f5ea8 Fotopoulos/cast-hart.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/cast-hart.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,112 @@ +/* Watermarking program - Hartley Transform based */ +/* Module : Casting */ +/* Author : Vassilis Fotopoulos */ +/* Date : 26/7/1999 */ +/* Revision : 2.01a */ +/* Developed at : ELLAB */ +/* Electronics Laboratory */ +/* Department of Physics */ +/* University of Patras - GREECE */ +/* Copyleft (c) 1999 */ +/*------------------------------------------------------*/ +/* pseudorandom noise generator's code is */ +/* taken from "Numerical Recipes in C" */ +/*------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include "common.h" + +int height, width; + +void add_watermark(double **in, int N, int coeff_start, int wm_length, int wm_key, double wm_alpha) +{ + int row, col, count; + long int elem, L, M, temp, seed; + double a; + count = 0; + elem = 0; + M = coeff_start; + L = wm_length; + seed = wm_key; + a = wm_alpha; + for (row = 0; row < N; row++) + for (col = 0; col < N; col++) { + elem++; + if (elem > M && count < L) { + in[row][col] += a * fabs(in[row][col]) * gasdev(&seed); + count++; + } + } + +} + +//-------------------------------------------------------- +int main(int argc, char* argv[]) +{ + FILE *in, *out; + int **image; + double **image_i; + double **image_d; + int c; + int N; + int coeff_start = 5000, wm_length = 10000, wm_key = 123; + double wm_alpha = 0.2; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:s:l:k:")) != EOF) { + switch (c) { + case 'a': + wm_alpha = atof(optarg); + break; + case 's': + coeff_start = atoi(optarg); + break; + case 'l': + wm_length = atoi(optarg); + break; + case 'k': + wm_key = atoi(optarg); + break; + } + } + argc -= optind; + argv += optind; + + in = stdin; + out = stdout; + + open_image(in, &width, &height); + image = imatrix(height, width); + load_image(image, in, width, height); + + if (height == width) + N = height; + else { + fprintf(stderr, "Cannot Proccess non-square images!\n"); + exit( -11); + } + + image_i = dmatrix(height, width); + image_d = dmatrix(height, width); + if (image_d == NULL) { + fprintf(stderr, "Unable to allocate the double array\n"); + exit(1); + } + matrix_i2d(image, image_i, N); + hartley(image_i, image_d, N); + add_watermark(image_d, N, coeff_start, wm_length, wm_key, wm_alpha); + hartley(image_d, image_i, N); + matrix_d2i(image_i, image, N); + save_image(image, out, width, height); + + freematrix_d(image_i, height); + freematrix_d(image_d, height); + fclose(in); + fclose(out); + +} diff -r 000000000000 -r be303a3f5ea8 Fotopoulos/cast-pv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/cast-pv.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,132 @@ +/* Watermarking program - Fast Cosine Transform based */ +/* Module : Casting */ +/* Author : Vassilis Fotopoulos */ +/* Date : 21/7/1999 */ +/* Revision : 2.01a */ +/* Developed at : ELLAB */ +/* Electronics Laboratory */ +/* Department of Physics */ +/* University of Patras - GREECE */ +/* Copyleft (c) 1999 */ +/* (without Visual Masking) */ +/*------------------------------------------------------*/ +/* pseudorandom noise generator's code is */ +/* taken from "Numerical Recipes in C" */ +/* FCT implementation from the University of Bath */ +/*------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include "common.h" + +double cu[1024]; +double cv[1024]; +int height, width; + +//-------------------------------------------------------- +void add_watermark(double *in, int N, int coeff_start, int wm_length, int wm_key, double wm_alpha) +{ + int row, col, count; + long int elem, L, M, temp, seed; + double a; + count = 0; + elem = 0; + row = 2; + col = -1; + M = coeff_start; + L = wm_length; + seed = wm_key; + a = wm_alpha; + do { + do { + row--; + col++; + elem++; + if (col < N) { + if (elem > M) { + temp = row * N + col; + in[temp] += a * fabs(in[temp]) * gasdev(&seed); + count++; + } + } + } while (row > 0); + row = 2 + col; + col = -1; + } while (count < L); +} +//-------------------------------------------------------- +void initialize_constants(void) +{ + int i; + cu[0] = cv[0] = 0.7071068; + for (i = 1; i < 1024; i++) + cu[i] = cv[i] = 1.0; +} + +//-------------------------------------------------------- +int main(int argc, char* argv[]) +{ + FILE *in, *out; + int **image_i; + double *image_f = NULL; + int N; + int c; + int coeff_start = 5000, wm_length = 10000, wm_key = 123; + double wm_alpha = 0.2; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:s:l:k:")) != EOF) { + switch (c) { + case 'a': + wm_alpha = atof(optarg); + break; + case 's': + coeff_start = atoi(optarg); + break; + case 'l': + wm_length = atoi(optarg); + break; + case 'k': + wm_key = atoi(optarg); + break; + } + } + argc -= optind; + argv += optind; + + in = stdin; + out = stdout; + + open_image(in, &width, &height); + image_i = imatrix(height, width); + load_image(image_i, in, width, height); + + if (height == width) + N = height; + else { + fprintf(stderr, "Cannot Proccess non-square images!\n"); + exit( -11); + } + + initialize_constants(); + image_f = (double *)calloc(N * N, sizeof(double)); + if (image_f == NULL) { + printf("Unable to allocate the float array\n"); + exit(1); + } + + put_image_from_int_2_double(image_i, image_f, N); + fct2d(image_f, N, N); + add_watermark(image_f, N, coeff_start, wm_length, wm_key, wm_alpha); + ifct2d(image_f, N, N); + put_image_from_double_2_int(image_f, image_i, N); + save_image(image_i, out, width, height); + freematrix(image_i, height); + free(image_f); + fclose(in); + fclose(out); +} diff -r 000000000000 -r be303a3f5ea8 Fotopoulos/cast-sub.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/cast-sub.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,247 @@ +/* Watermarking program - Subband DCT Transform based */ +/* Module : Casting */ +/* Author : Vassilis Fotopoulos */ +/* Date : 25/4/2000 */ +/* Revision : 7.0 */ +/* Developed at : ELLAB */ +/* Electronics Laboratory */ +/* Department of Physics */ +/* University of Patras - GREECE */ +/* Copyleft (c) 1999 */ +/*------------------------------------------------------*/ +/* pseudorandom noise generator's code is */ +/* taken from "Numerical Recipes in C" */ +/* FCT implementation from University of Bath */ +/*------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include "common.h" + +void add_hor_add_ver(double **in, int N, double **out); +void add_hor_sub_ver(double **in, int N, double **out); +void sub_hor_add_ver(double **in, int N, double **out); +void sub_hor_sub_ver(double **in, int N, double **out); +void band_synthesis(double **ll, double **lh, double **hl, double **hh, int N, double **s); +void watermark(double **i, int N, long key, long int L, long int M, double a); + +double cu[1024]; +double cv[1024]; +int height, width; + +//-------------------------------------------------------- +void add_hor_add_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] + in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] + temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void add_hor_sub_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] + in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] - temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void sub_hor_add_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] - in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] + temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void sub_hor_sub_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] - in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] - temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void band_synthesis(double **ll, double **lh, double **hl, double **hh, int N, double **s) +{ + int r, c; + double b1, b2, b3, b4; + for (r = 0; r < N; r++) + for (c = 0; c < N; c++) { + b1 = ll[r][c] + lh[r][c] + hl[r][c] + hh[r][c]; //Reconstruct each + b2 = ll[r][c] + lh[r][c] - hl[r][c] - hh[r][c]; //of the pixels + b3 = ll[r][c] - lh[r][c] + hl[r][c] - hh[r][c]; + b4 = ll[r][c] - lh[r][c] - hl[r][c] + hh[r][c]; + b1 = (b1 > 255.0) ? 255.0 : b1; //Check for positive... + b1 = (b1 < 0.0) ? 0.0 : b1; //or negative core! + b2 = (b2 > 255.0) ? 255.0 : b2; + b2 = (b2 < 0.0) ? 0.0 : b2; + b3 = (b3 > 255.0) ? 255.0 : b3; + b3 = (b3 < 0.0) ? 0.0 : b3; + b4 = (b4 > 255.0) ? 255.0 : b4; + b4 = (b4 < 0.0) ? 0.0 : b4; + s[2*r][2*c] = b1; //Put them back in + s[2*r][2*c + 1] = b2; //the right position + s[2*r + 1][2*c] = b3; + s[2*r + 1][2*c + 1] = b4; + } +} + +void watermark(double **i, int N, long key, long int L, long int M, double a) +{ + int row, col, count; + long int elem, temp, seed; + double *v; + v = dvector(N * N); + put_matrix_2_vector(i, v, N); + fct2d(v, N, N); + seed = key; + count = 0; + elem = 0; + row = 2; + col = -1; + do { + do { + row--; + col++; + elem++; + if (col < N) { + if (elem > M) { + temp = row * N + col; + v[temp] += a * fabs(v[temp]) * gasdev(&seed); + count++; + } + } + } while (row > 0); + row = 2 + col; + col = -1; + } while (count < L); + ifct2d(v, N, N); + put_vector_2_matrix(v, i, N); + free(v); +} + +int main(int argc, char* argv[]) +{ + double **i; + double **o; + FILE *in; + FILE *out; + int N; + int c; + long int M1, L1, M2, L2; + int **image_i; + double **ll, **lh, **hl, **hh; + double a_ll = 0.1, a_other = 0.2; + int wm_length_1 = 10000, wm_length_ll = 10000, coeff_start_1 = 3000, + coeff_start_ll = 3000, wm_key = 123; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:b:t:m:s:l:k:")) != EOF) { + switch (c) { + case 'a': + a_ll = atof(optarg); + break; + case 'b': + a_other = atof(optarg); + break; + case 't': + coeff_start_1 = atoi(optarg); + break; + case 'm': + wm_length_1 = atoi(optarg); + break; + case 's': + coeff_start_ll = atoi(optarg); + break; + case 'l': + wm_length_ll = atoi(optarg); + break; + case 'k': + wm_key = atoi(optarg); + break; + } + } + argc -= optind; + argv += optind; + + in = stdin; + out = stdout; + open_image(in, &width, &height); + image_i = imatrix(height, width); + load_image(image_i, in, width, height); + if (height == width) + N = height; + else { + fprintf(stderr, "Cannot Proccess non-square images!\n"); + exit( -11); + } + // starting coeff. for 1st level decomp. + M1 = coeff_start_1; + // number of coeffs to alter + L1 = wm_length_1; + + // now the LL band + M2 = coeff_start_ll; + L2 = wm_length_ll; + + i = dmatrix(N, N); + o = dmatrix(N, N); + ll = dmatrix(N / 2, N / 2); + lh = dmatrix(N / 2, N / 2); + hl = dmatrix(N / 2, N / 2); + hh = dmatrix(N / 2, N / 2); + + matrix_i2d(image_i, i, N); + + //---------------------1o decomposition------------------- + add_hor_add_ver(i, N, ll); + add_hor_sub_ver(i, N, lh); + sub_hor_add_ver(i, N, hl); + sub_hor_sub_ver(i, N, hh); + //---------------------Watermark medium frequency bands--- + watermark(lh, N / 2, wm_key, L1, M1, a_other); + watermark(hl, N / 2, wm_key, L1, M1, a_other); + watermark(hh, N / 2, wm_key, L1, M1, a_other); + watermark(ll, N / 2, wm_key, L2, M2, a_ll); + //---------------------Synthesis stage-------------------- + band_synthesis(ll, lh, hl, hh, N / 2, o); + //-------------------------------------------------------- + matrix_d2i(o, image_i, N); + save_image(image_i, out, width, height); + + fclose(in); + fclose(out); +} + + + + diff -r 000000000000 -r be303a3f5ea8 Fotopoulos/common.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/common.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,571 @@ +#include +#include +#include +#include +#include +#include "pgm.h" +#include "common.h" + +#define IA 16807 +#define IM 2147483647 +#define AM (1.0/IM) +#define IQ 127773 +#define IR 2836 +#define MASK 123459876 + +static int NN = 0; +static int m = 0; +static double two_over_N = 0; +static double root2_over_rootN = 0; +static double *C = NULL; + +static gray maxval; +static int format; + +void open_image(FILE *in, int *width, int *height) +{ + + pgm_readpgminit(in, width, height, &maxval, &format); +} + +void load_image(int **im, FILE *in, int width, int height) +{ + int col, row; + gray *rowbuf; + + rowbuf = malloc(sizeof(gray) * width); + + for (row = 0; row < height; row++) { + pgm_readpgmrow(in, rowbuf, width, maxval, format); + for (col = 0; col < width; col++) + im[row][col] = rowbuf[col]; + } + + free(rowbuf); +} + +void save_image(int **im, FILE *out, int width, int height) +{ + int col, row; + gray *rowbuf; + + pgm_writepgminit(out, width, height, 255, 0); + + rowbuf = malloc(sizeof(gray) * width); + + for (row = 0; row < height; row++) { + for (col = 0; col < width; col++) + rowbuf[col] = im[row][col]; + pgm_writepgmrow(out, rowbuf, width, 255, 0); + } + + free(rowbuf); +} + +int ** imatrix(int nrows, int ncols) +{ + int **m; + int i, j; + m = (int **) malloc (nrows * sizeof(int *)); + for (i = 0; i < nrows; i++) { + m[i] = (int *) malloc (ncols * sizeof(int)); + if (!m[i]) fprintf(stderr, "\nIt's not working"); + } + for (i = 0; i < nrows; i++) + for (j = 0; j < ncols; j++) + m[i][j] = 0; + return m; +} + +void freematrix(int **I, int rows) +{ + int k; + for (k = 0; k < rows; k++) + free (I[k]); +} + +float ran0(long int *idum) +{ + long int k; + float ans; + *idum ^= MASK; + k = (*idum) / IQ; + *idum = IA * (*idum - k * IQ) - IR * k; + if (*idum < 0) *idum += IM; + ans = AM * (*idum); + *idum ^= MASK; + return ans; +} + +float gasdev(long int *idum) +{ + + float v1; + v1 = (float) sqrt( -2.0 * log(ran0(idum))) * cos(2 * PI * ran0(idum)); + return v1; +} + + +void put_image_from_int_2_double(int **i, double *f, int N) +{ + int l, j, k; + k = 0; + for (l = 0; l < N; l++) + for (j = 0; j < N; j++) + f[k++] = (double) i[l][j]; +} + +void put_image_from_double_2_int(double *f, int **i, int N) +{ + int l, j, k; + k = 0; + for (l = 0; l < N; l++) + for (j = 0; j < N; j++) + i[l][j] = (int) f[k++]; +} + + +void bitrev(double *f, int len) +{ + int i, j, m, halflen; + double temp; + + if (len <= 2) return ; /* No action necessary if n=1 or n=2 */ + halflen = len >> 1; + j = 1; + for (i = 1; i <= len; i++) { + if (i < j) { + temp = f[j - 1]; + f[j - 1] = f[i - 1]; + f[i - 1] = temp; + } + m = halflen; + while (j > m) { + j = j - m; + m = (m + 1) >> 1; + } + j = j + m; + } +} + +void inv_sums(double *f) +{ + int ii, stepsize, stage, curptr, nthreads, thread, step, nsteps; + + for (stage = 1; stage <= m - 1; stage++) { + nthreads = 1 << (stage - 1); + stepsize = nthreads << 1; + nsteps = (1 << (m - stage)) - 1; + for (thread = 1; thread <= nthreads; thread++) { + curptr = NN - thread; + for (step = 1; step <= nsteps; step++) { + f[curptr] += f[curptr - stepsize]; + curptr -= stepsize; + } + } + } +} + +//-------------------------------------------------------- +//Foreign code - FCT from Bath Univerity +//-------------------------------------------------------- +void rarrwrt(double f[], int n) +{ + int i; + + for (i = 0; i <= n - 1; i++) { + fprintf(stderr, "%4d : %f\n", i, f[i]); + } +} + +/* fast DCT based on IEEE signal proc, 1992 #8, yugoslavian authors. */ + +void fwd_sums(double *f) +{ + int ii, stepsize, stage, curptr, nthreads, thread, step, nsteps; + + for (stage = m - 1; stage >= 1; stage--) { + nthreads = 1 << (stage - 1); + stepsize = nthreads << 1; + nsteps = (1 << (m - stage)) - 1; + for (thread = 1; thread <= nthreads; thread++) { + curptr = nthreads + thread - 1; + for (step = 1; step <= nsteps; step++) { + f[curptr] += f[curptr + stepsize]; + curptr += stepsize; + } + } + } +} + +void scramble(double *f, int len) +{ + double temp; + int i, ii1, ii2, halflen, qtrlen; + + halflen = len >> 1; + qtrlen = halflen >> 1; + bitrev(f, len); + bitrev(&f[0], halflen); + bitrev(&f[halflen], halflen); + ii1 = len - 1; + ii2 = halflen; + for (i = 0; i <= qtrlen - 1; i++) { + temp = f[ii1]; + f[ii1] = f[ii2]; + f[ii2] = temp; + ii1--; + ii2++; + } +} + +void unscramble(double *f, int len) +{ + double temp; + int i, ii1, ii2, halflen, qtrlen; + + halflen = len >> 1; + qtrlen = halflen >> 1; + ii1 = len - 1; + ii2 = halflen; + for (i = 0; i <= qtrlen - 1; i++) { + temp = f[ii1]; + f[ii1] = f[ii2]; + f[ii2] = temp; + ii1--; + ii2++; + } + bitrev(&f[0], halflen); + bitrev(&f[halflen], halflen); + bitrev(f, len); +} + +void initcosarray(int length) +{ + int i, group, base, item, nitems, halfN; + double factor; + + m = -1; + do { + m++; + NN = 1 << m; + if (NN > length) { + fprintf(stderr, "ERROR in FCT-- length %d not a power of 2\n", length); + exit(1); + } + } while (NN < length); + if (C != NULL) free(C); + C = (double *)calloc(NN, sizeof(double)); + if (C == NULL) { + fprintf(stderr, "Unable to allocate C array\n"); + exit(1); + } + halfN = NN / 2; + two_over_N = 2.0 / (double)NN; + root2_over_rootN = sqrt(2.0 / (double)NN); + for (i = 0; i <= halfN - 1; i++) C[halfN + i] = 4 * i + 1; + for (group = 1; group <= m - 1; group++) { + base = 1 << (group - 1); + nitems = base; + factor = 1.0 * (1 << (m - group)); + for (item = 1; item <= nitems; item++) C[base + item - 1] = factor * C[halfN + item - 1]; + } + + //printf("before taking cos, C array =\n"); rarrwrt(C,N); + for (i = 1; i <= NN - 1; i++) C[i] = 1.0 / (2.0 * cos(C[i] * PI / (2.0 * NN))); + //printf("After taking cos, Carray = \n"); rarrwrt(C,N); +} + + +void inv_butterflies(double *f) +{ + int stage, ii1, ii2, butterfly, ngroups, group, wingspan, increment, baseptr; + double Cfac, T; + + for (stage = 1; stage <= m; stage++) { + ngroups = 1 << (m - stage); + wingspan = 1 << (stage - 1); + increment = wingspan << 1; + for (butterfly = 1; butterfly <= wingspan; butterfly++) { + Cfac = C[wingspan + butterfly - 1]; + baseptr = 0; + for (group = 1; group <= ngroups; group++) { + ii1 = baseptr + butterfly - 1; + ii2 = ii1 + wingspan; + T = Cfac * f[ii2]; + f[ii2] = f[ii1]-T; + f[ii1] = f[ii1] + T; + baseptr += increment; + } + } + } +} + +void fwd_butterflies(double *f) +{ + int stage, ii1, ii2, butterfly, ngroups, group, wingspan, increment, baseptr; + double Cfac, T; + + for (stage = m; stage >= 1; stage--) { + ngroups = 1 << (m - stage); + wingspan = 1 << (stage - 1); + increment = wingspan << 1; + for (butterfly = 1; butterfly <= wingspan; butterfly++) { + Cfac = C[wingspan + butterfly - 1]; + baseptr = 0; + for (group = 1; group <= ngroups; group++) { + ii1 = baseptr + butterfly - 1; + ii2 = ii1 + wingspan; + T = f[ii2]; + f[ii2] = Cfac * (f[ii1]-T); + f[ii1] = f[ii1] + T; + baseptr += increment; + } + } + } +} + +void ifct_noscale(double *f, int length) +{ + if (length != NN) initcosarray(length); + f[0] *= INVROOT2; + inv_sums(f); + bitrev(f, NN); + inv_butterflies(f); + unscramble(f, NN); +} + +void fct_noscale(double *f, int length) +{ + if (length != NN) initcosarray(length); + scramble(f, NN); + fwd_butterflies(f); + bitrev(f, NN); + fwd_sums(f); + f[0] *= INVROOT2; +} + +void ifct_defn_scaling(double *f, int length) +{ + ifct_noscale(f, length); +} + +void fct_defn_scaling(double *f, int length) +{ + int i; + + fct_noscale(f, length); + for (i = 0; i <= NN - 1; i++) f[i] *= two_over_N; +} + +void ifct(double *f, int length) +{ + /* CALL THIS FOR INVERSE 1D DCT DON-MONRO PREFERRED SCALING */ + int i; + + if (length != NN) initcosarray(length); /* BGS patch June 1997 */ + for (i = 0; i <= NN - 1; i++) f[i] *= root2_over_rootN; + ifct_noscale(f, length); +} + +void fct(double *f, int length) +{ + /* CALL THIS FOR FORWARD 1D DCT DON-MONRO PREFERRED SCALING */ + int i; + + fct_noscale(f, length); + for (i = 0; i <= NN - 1; i++) f[i] *= root2_over_rootN; +} + +/**************************************************************** + 2D FAST DCT SECTION +****************************************************************/ + +static double *g = NULL; +static double two_over_sqrtncolsnrows = 0.0; +static int ncolsvalue = 0; +static int nrowsvalue = 0; + +void initfct2d(int nrows, int ncols) +{ + if ((nrows <= 0) || (ncols < 0)) { + fprintf(stderr, "FCT2D -- ncols=%d or nrows=%d is <=0\n", nrows, ncols); + exit(1); + } + if (g != NULL) free(g); + g = (double *)calloc(nrows, sizeof(double)); + if (g == NULL) { + fprintf(stderr, "FCT2D -- Unable to allocate g array\n"); + exit(1); + } + ncolsvalue = ncols; + nrowsvalue = nrows; + two_over_sqrtncolsnrows = 2.0 / sqrt(ncols * 1.0 * nrows); +} + +void fct2d(double f[], int nrows, int ncols) +/* CALL THIS FOR FORWARD 2d DCT DON-MONRO PREFERRED SCALING */ +{ + int u, v; + + if ((ncols != ncolsvalue) || (nrows != nrowsvalue)){ + initfct2d(nrows, ncols); + } + for (u = 0; u <= nrows - 1; u++){ + fct_noscale(&f[u*ncols], ncols); + } + for (v = 0; v <= ncols - 1; v++){ + for (u = 0; u <= nrows - 1; u++) { + g[u] = f[u * ncols + v]; + } + fct_noscale(g, nrows); + for (u = 0; u <= nrows - 1; u++) { + f[u*ncols + v] = g[u] * two_over_sqrtncolsnrows; + } + } +} + +void ifct2d(double f[], int nrows, int ncols) +/* CALL THIS FOR INVERSE 2d DCT DON-MONRO PREFERRED SCALING */ +{ + int u, v; + + if ((ncols != ncolsvalue) || (nrows != nrowsvalue)){ + initfct2d(nrows, ncols); + } + for (u = 0; u <= nrows - 1; u++){ + ifct_noscale(&f[u*ncols], ncols); + } + for (v = 0; v <= ncols - 1; v++){ + for (u = 0; u <= nrows - 1; u++) { + g[u] = f[u * ncols + v]; + } + ifct_noscale(g, nrows); + for (u = 0; u <= nrows - 1; u++) { + f[u*ncols + v] = g[u] * two_over_sqrtncolsnrows; + } + } +} + +void matmul(double **a, double **b, double **r, int N) +{ + int i, j, k; + + for (i = 0; i < N; i++) + for (j = 0; j < N; j++) { + r[i][j] = 0.0; + for (k = 0; k < N; k++) + r[i][j] += a[i][k] * b[k][j]; + } +} + +void hartley(double **in, double **out, int N) +{ + int k, n; + double **h; + + h = dmatrix(N, N); + //Building up the transformation matrix + for (k = 0; k < N; k++) + for (n = 0; n < N; n++) + h[k][n] = (cos(2 * PI * k * n / N) + sin(2 * PI * k * n / N)) / sqrt(N); + + // Now we have to multiply the input with the transformation matrix + matmul(h, in, out, N); + freematrix_d(h, N); + return ; +} + +double ** dmatrix(int nrows, int ncols) +{ + double **m; + int i, j; + m = (double **) malloc (nrows * sizeof(double *)); + for (i = 0; i < nrows; i++) { + m[i] = (double *) malloc (ncols * sizeof(double)); + if (!m[i]) printf("\nIt's not working"); + } + for (i = 0; i < nrows; i++) + for (j = 0; j < ncols; j++) + m[i][j] = 0.0; + return m; +} + +void freematrix_d(double **I, int rows) +{ + int k; + for (k = 0; k < rows; k++) + free (I[k]); +} + +void matrix_i2d(int **i, double **d, int N) +{ + int x, y; + for (x = 0; x < N; x++) + for (y = 0; y < N; y++) + d[y][x] = i[y][x]; +} + +void matrix_d2i(double **d, int **i, int N) +{ + int x, y; + for (x = 0; x < N; x++) + for (y = 0; y < N; y++) + i[y][x] = d[y][x]; +} + +double * dvector(long int N) +{ + double *m; + m = (double *) malloc (N * sizeof(double)); + if (!m) printf("\nIt's not working"); + return m; +} + +void put_matrix_2_vector(double **i, double *f, int N) +{ + int l, j, k; + k = 0; + for (l = 0; l < N; l++) + for (j = 0; j < N; j++) + f[k++] = i[l][j]; +} + +void put_vector_2_matrix(double *f, double **i, int N) +{ + int l, j, k; + k = 0; + for (l = 0; l < N; l++) + for (j = 0; j < N; j++) + i[l][j] = f[k++]; +} + +void set_in_binary() { +#if defined(EMX) + _fsetmode(in, "b"); +#elif defined(MINGW) + setmode(STDIN_FILENO, O_BINARY); +#endif +} + +void set_out_binary() { +#if defined(EMX) + _fsetmode(out, "b"); +#elif defined(MINGW) + setmode(STDOUT_FILENO, O_BINARY); +#endif +} + +void wm_init2() { + set_out_binary(); +} + +void wm_init1() { + set_in_binary(); +} + +void wm_init() { + set_in_binary(); + set_out_binary(); +} + diff -r 000000000000 -r be303a3f5ea8 Fotopoulos/common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/common.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,28 @@ +#define PI 3.1415926535897932 +#define INVROOT2 0.7071067814 + +void open_image(FILE *in, int *width, int *height); +void load_image(int **im, FILE *in, int width, int height); +void save_image(int **im, FILE *out, int width, int height); +int ** imatrix(int nrows, int ncols); +void freematrix(int **I, int rows); +float ran0(long int *idum); +float gasdev(long int *idum); +void put_image_from_int_2_double(int **i, double *f, int N); +void put_image_from_double_2_int(double *f, int **i, int N); +void fct2d(double f[], int nrows, int ncols); +void ifct2d(double f[], int nrows, int ncols); +void matmul(double **a, double **b, double **r, int N); +void hartley(double **in, double **out, int N); +double ** dmatrix(int nrows, int ncols); +void freematrix_d(double **I, int rows); +void hartley(double **in, double **out, int N); +void matrix_i2d(int **i, double **d, int N); +void matrix_d2i(double **d, int **i, int N); +void put_matrix_2_vector(double **i, double *f, int N); +void put_vector_2_matrix(double *f, double **i, int N); +double * dvector(long int N); + +void wm_init(); +void wm_init1(); +void wm_init2(); diff -r 000000000000 -r be303a3f5ea8 Fotopoulos/test-hart.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/test-hart.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,109 @@ +/* Watermarking program - Hartley Transform based */ +/* Module : Testing */ +/* Author : Vassilis Fotopoulos */ +/* Date : 26/7/1999 */ +/* Developed at : ELLAB */ +/* Electronics Laboratory */ +/* Department of Physics */ +/* University of Patras - GREECE */ +/* Copyleft (c) 1999 */ +/*------------------------------------------------------*/ +/* pseudorandom noise generator's code is */ +/* taken from "Numerical Recipes in C" */ +/*------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include "common.h" + +int height, width; + +void read_watermark(double **in, int N, int coeff_start, int wm_length, double wm_alpha) +{ + int row, col, count; + long int elem, L, M, seed, i; + double a; + double z; + M = coeff_start; + L = wm_length; + a = wm_alpha; + for (i = 1; i <= 1000; i++) { + seed = i; + z = 0.0; + count = 0; + elem = 0; + + for (row = 0; row < N; row++) + for (col = 0; col < N; col++) { + elem++; + if (elem > M && count < L) { + z += in[row][col] * gasdev(&seed); + count++; + } + } + + printf("%ld\t%f\n", i, z / L); + } + return ; +} + +int main(int argc, char* argv[]) +{ + FILE *in; + int **image; + double **image_i; + double **image_d; + int c; + int N; + int coeff_start = 5000, wm_length = 10000; + double wm_alpha = 0.2; + int width, height; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:s:l:")) != EOF) { + switch (c) { + case 'a': + wm_alpha = atof(optarg); + break; + case 's': + coeff_start = atoi(optarg); + break; + case 'l': + wm_length = atoi(optarg); + break; + } + } + argc -= optind; + argv += optind; + + in = stdin; + + open_image(in, &width, &height); + image = imatrix(height, width); + load_image(image, in, width, height); + + if (height == width) + N = height; + else { + fprintf(stderr, "Cannot Proccess non-square images!\n"); + exit( -11); + } + + image_i = dmatrix(height, width); + image_d = dmatrix(height, width); + if (image_d == NULL) { + fprintf(stderr, "Unable to allocate the double array\n"); + exit(1); + } + matrix_i2d(image, image_i, N); + hartley(image_i, image_d, N); + read_watermark(image_d, N, coeff_start, wm_length, wm_alpha); + + freematrix_d(image_i, height); + freematrix_d(image_d, height); + fclose(in); +} diff -r 000000000000 -r be303a3f5ea8 Fotopoulos/test-pv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/test-pv.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,127 @@ +/* Watermarking program - Fast Cosine Transform based */ +/* Module : Testing */ +/* Author : Vassilis Fotopoulos */ +/* Date : 21/7/1999 */ +/* Developed at : ELLAB */ +/* Electronics Laboratory */ +/* Department of Physics */ +/* University of Patras - GREECE */ +/* Copyleft (c) 1999 */ +/* Testing Program */ +/*------------------------------------------------------*/ +/* pseudorandom noise generator's code is */ +/* taken from "Numerical Recipes in C" */ +/* FCT implementation from the University of Bath */ +/*------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include "common.h" + +double cu[1024]; +double cv[1024]; +int height, width; + +void read_watermark(double *in, int N, int start_coeff, int wm_length, double wm_alpha) +{ + int row, col, count; + long int elem, L, M, temp, seed, i; + double a; + double z; + FILE *f; + M = start_coeff; + L = wm_length; + a = wm_alpha; + for (i = 1; i <= 1000; i++) { + seed = i; + z = 0.0; + count = 0; + elem = 0; + row = 2; + col = -1; + do { + do { + row--; + col++; + elem++; + if (col < N) { + if (elem > M) { + temp = row * N + col; + z += in[temp] * gasdev(&seed); + count++; + } + } + } while (row > 0); + row = 2 + col; + col = -1; + } while (count < L); + printf("%ld\t%f\n", i, z / L); + } + return ; +} +//-------------------------------------------------------- +void initialize_constants(void) +{ + int i; + cu[0] = cv[0] = 0.7071068; + for (i = 1; i < 1024; i++) + cu[i] = cv[i] = 1.0; +} + +int main(int argc, char* argv[]) +{ + FILE *in; + int **image_i; + double *image_f = NULL; + int N; + int c; + int coeff_start = 5000, wm_length = 10000; + double wm_alpha = 0.2; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:s:l:")) != EOF) { + switch (c) { + case 'a': + wm_alpha = atof(optarg); + break; + case 's': + coeff_start = atoi(optarg); + break; + case 'l': + wm_length = atoi(optarg); + break; + } + } + argc -= optind; + argv += optind; + in = stdin; + + open_image(in, &width, &height); + image_i = imatrix(height, width); + load_image(image_i, in, width, height); + + if (height == width) + N = height; + else { + fprintf(stderr, "Cannot Proccess non-square images!\n"); + exit( -11); + } + + initialize_constants(); + image_f = (double *)calloc(N * N, sizeof(double)); + if (image_f == NULL) { + printf("Unable to allocate the float array\n"); + exit(1); + } + + put_image_from_int_2_double(image_i, image_f, N); + fct2d(image_f, N, N); + read_watermark(image_f, N, coeff_start, wm_length, wm_alpha); + fclose(in); + freematrix(image_i, height); + free(image_f); +} diff -r 000000000000 -r be303a3f5ea8 Fotopoulos/test-sub.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Fotopoulos/test-sub.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,237 @@ +/* Watermarking program - Subband DCT Transform based */ +/* Module : Testing */ +/* Author : Vassilis Fotopoulos */ +/* Date : 25/4/2000 */ +/* Revision : 6.0 */ +/* Developed at : ELLAB */ +/* Electronics Laboratory */ +/* Department of Physics */ +/* University of Patras - GREECE */ +/* Copyleft (c) 1999 */ +/*------------------------------------------------------*/ +/* pseudorandom noise generator's code is */ +/* taken from "Numerical Recipes in C" */ +/* FCT implementation from University of Bath */ +/*------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include "common.h" + +//-------------------------------------------------------- +void add_hor_add_ver(double **in, int N, double **out); +void add_hor_sub_ver(double **in, int N, double **out); +void sub_hor_add_ver(double **in, int N, double **out); +void sub_hor_sub_ver(double **in, int N, double **out); +double detect_mark(double *i, int N, long key, long int L, long int M, double a); + +//-------------------------------------------------------- +double cu[1024]; +double cv[1024]; +int height, width; +//-------------------------------------------------------- +void add_hor_add_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] + in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] + temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void add_hor_sub_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] + in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] - temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void sub_hor_add_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] - in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] + temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} +//-------------------------------------------------------- +void sub_hor_sub_ver(double **in, int N, double **out) +{ + double **temp; + int r, c; + temp = dmatrix(N, N); + for (r = 0; r < N; r++) + for (c = 0; c < N / 2; c++) + temp[r][c] = (in[r][2 * c] - in[r][2 * c + 1]) / 2; + for (c = 0; c < N / 2; c++) + for (r = 0; r < N / 2; r++) + out[r][c] = (temp[2 * r][c] - temp[2 * r + 1][c]) / 2; + freematrix_d(temp, N); +} + +//--------------------------------------------------------- +double detect_mark(double *i, int N, long key, long int L, long int M, double a) +{ + int row, col, count; + long int elem, temp, seed; + double z; + + + seed = key; + z = 0.0; + count = 0; + elem = 0; + row = 2; + col = -1; + do { + do { + row--; + col++; + elem++; + if (col < N) { + if (elem > M) { + temp = row * N + col; + z += i[temp] * gasdev(&seed); + count++; + } + } + } while (row > 0); + row = 2 + col; + col = -1; + } while (count < L); + + return (z / L); +} + +int main(int argc, char* argv[]) +{ + double **i; + FILE *in; + int N; + long int key, M1, L1, M2, L2; + double **ll, **lh, **hl, **hh; + double *v1, *v2, *v3, *v99; + double m1, m2, m3, detect_value, m99; + int ** image_i; + int c; + int wm_length_1 = 10000, wm_length_ll = 10000, coeff_start_1 = 3000, coeff_start_ll = 3000; + double a_ll = 0.1, a_other = 0.2; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:b:t:m:s:l:")) != EOF) { + switch (c) { + case 'a': + a_ll = atof(optarg); + break; + case 'b': + a_other = atof(optarg); + break; + case 't': + coeff_start_1 = atoi(optarg); + break; + case 'm': + wm_length_1 = atoi(optarg); + break; + case 's': + coeff_start_ll = atoi(optarg); + break; + case 'l': + wm_length_ll = atoi(optarg); + break; + } + } + argc -= optind; + argv += optind; + + in = stdin; + open_image(in, &width, &height); + image_i = imatrix(height, width); + load_image(image_i, in, width, height); + + if (height == width) + N = height; + else { + fprintf(stderr, "Cannot Proccess non-square images!\n"); + exit( -11); + } + // starting coeff. for 1st level decomp. + M1 = coeff_start_1; + // number of coeffs to alter + L1 = wm_length_1; + // alpha parameter + + // now the LL band + M2 = coeff_start_ll; + L2 = wm_length_ll; + + + i = dmatrix(N, N); + ll = dmatrix(N / 2, N / 2); + lh = dmatrix(N / 2, N / 2); + hl = dmatrix(N / 2, N / 2); + hh = dmatrix(N / 2, N / 2); + v1 = dvector(N * N / 4); + v2 = dvector(N * N / 4); + v3 = dvector(N * N / 4); + v99 = dvector(N * N / 4); + + matrix_i2d(image_i, i, N); + + //---------------------1o decomposition------------------- + add_hor_add_ver(i, N, ll); + add_hor_sub_ver(i, N, lh); + sub_hor_add_ver(i, N, hl); + sub_hor_sub_ver(i, N, hh); + //---------------------Detect Watermark from all bands---- + put_matrix_2_vector(lh, v1, N / 2); + put_matrix_2_vector(hl, v2, N / 2); + put_matrix_2_vector(hh, v3, N / 2); + put_matrix_2_vector(ll, v99, N / 2); + fct2d(v1, N / 2, N / 2); + fct2d(v2, N / 2, N / 2); + fct2d(v3, N / 2, N / 2); + fct2d(v99, N / 2, N / 2); + for (key = 1; key <= 1000; key++) { + m1 = detect_mark(v1, N / 2, key, L1, M1, a_other); + m2 = detect_mark(v2, N / 2, key, L1, M1, a_other); + m3 = detect_mark(v3, N / 2, key, L1, M1, a_other); + m99 = detect_mark(v99, N / 2, key, L2, M2, a_ll); + detect_value = (m1 + m2 + m3 + m99) / 4; + printf("%ld\t%f\t%f\t%f\t%f\t%f\n", key, m1, m2, m3, m99, detect_value); + } + //-------------------------------------------------------- + free(v1); + free(v2); + free(v3); + free(v99); + freematrix_d(ll, N / 2); + freematrix_d(hl, N / 2); + freematrix_d(lh, N / 2); + freematrix_d(hh, N / 2); + fclose(in); +} + + + + diff -r 000000000000 -r be303a3f5ea8 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,36 @@ +# Makefile + +WEBDIR = /home/scicomp/pmeerw/public-www/Watermarking/source + +all: meerwald fotopoulos + +meerwald: + cd Meerwald ; make + +fotopoulos: + cd Fotopoulos ; make + +install: + cd Meerwald ; make install + cd Fotopoulos ; make install + +clean: + cd Meerwald ; make clean + cd Fotopoulos ; make clean + +dist: + cp -v manual.pdf manual.ps $(WEBDIR) + cp -v ANNOUNCEMENT README $(WEBDIR) + cd linux_bin ; tar -czf ../wm_linux_bin.tar.gz * + mv -v wm_linux_bin.tar.gz $(WEBDIR) + cd win32_bin ; zip -9 ../wm_win32_bin.zip * + mv -v wm_win32_bin.zip $(WEBDIR) + tar -czf wm_source_bin.tar.gz * + mv -v wm_source_bin.tar.gz $(WEBDIR) + zip -9r wm_source_bin.zip * + mv -v wm_source_bin.zip $(WEBDIR) + tar -czf wm_source.tar.gz ANNOUNCEMENT Fotopoulos/* Meerwald/* Makefile README images/* make/* manual.* sigs/.dummy watermarked/.dummy wms/.dummy win32_bin/.dummy linux_bin/.dummy + mv -v wm_source.tar.gz $(WEBDIR) + zip -9r wm_source.zip ANNOUNCEMENT Fotopoulos/* Meerwald/* Makefile README images/* make/* manual.* sigs/.dummy watermarked/.dummy wms/.dummy linux_bin/.dummy win32_bin/.dummy + mv -v wm_source.zip $(WEBDIR) + chmod a+r $(WEBDIR)/* diff -r 000000000000 -r be303a3f5ea8 Meerwald/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/Makefile Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,423 @@ +# Makefile + +# choose build platform +include ../make/make.config + +all: tools \ + bruyn \ + koch \ + corvi \ + xia \ + xie \ + cox \ + zhu \ + dugad \ + wang \ + frid2 \ + kim + +.SUFFIXES: .c .o .1 .ps + +.c$(O): + $(CC) $(CFLAGS) $(INCLUDES) -o $@ -c $< + +.1.ps: + $(GROFF) $< > $@ + +# library containing general stuff + +$(LIBPREFIX)wm$(LIB): dct$(O) coeff$(O) gray$(O) sort$(O) signature$(O) coord$(O) wm$(O) + $(RM) $@ + ar -rc $@ dct$(O) coeff$(O) gray$(O) sort$(O) signature$(O) coord$(O) wm$(O) + +libraryclean: + $(RM) $(LIBPREFIX)wm$(LIB) + +# library containing wavelet transform stuff + +$(LIBPREFIX)wavelet$(LIB): wavelet$(O) dwt$(O) dwt_util$(O) + $(RM) $@ + ar -rc $@ wavelet$(O) dwt$(O) dwt_util$(O) + +waveletclean: + $(RM) $(LIBPREFIX)wavelet$(LIB) + +# some general tools to compute difference image, PSNR, ... + +tools: cmp_pgm$(EXE) cmp_dct8x8$(EXE) cmp_dct$(EXE) cmp_dwt$(EXE) + +toolstest: + +toolsinstall: tools + $(CP) cmp_pgm$(EXE) cmp_dct8x8$(EXE) cmp_dct$(EXE) cmp_dwt$(EXE) $(INSTALLDIR) + +toolsman: cmp_pgm.ps cmp_dct8x8.ps cmp_dct.ps + +toolsclean: + $(RM) cmp_pgm$(EXE) cmp_dct$(EXE) cmp_dct8x8$(EXE) + +cmp_pgm$(EXE): cmp_pgm$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_pgm$(O) $(WMLIB) $(PGMLIBS) + +cmp_dct$(EXE): cmp_dct$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_dct$(O) $(WMLIB) $(PGMLIBS) + +cmp_dwt$(EXE): cmp_dwt$(O) $(LIBPREFIX)wavelet$(LIB) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_dwt$(O) $(WAVELIB) $(WMLIB) $(PGMLIBS) + +cmp_dct8x8$(EXE): cmp_dct8x8$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_dct8x8$(O) $(WMLIB) $(PGMLIBS) + + +# Koch's algorithm (8x8 block DCT, blind, binary) + +koch: gen_koch_sig$(EXE) wm_koch_e$(EXE) wm_koch_d$(EXE) cmp_koch_sig$(EXE) + +kochtest: koch + gen_koch_sig$(EXE) -n 150 < gen_koch_sig.c > ../sigs/koch.sig + wm_koch_e$(EXE) -s ../sigs/koch.sig -o ../watermarked/koch_lena.pgm ../images/lena.pgm + wm_koch_d$(EXE) -s ../sigs/koch.sig -o ../wms/koch.wm ../watermarked/koch_lena.pgm + cmp_koch_sig$(EXE) -s ../sigs/koch.sig ../wms/koch.wm + +kochinstall: koch + $(CP) gen_koch_sig$(EXE) wm_koch_e$(EXE) wm_koch_d$(EXE) cmp_koch_sig$(EXE) $(INSTALLDIR) + +kochclean: + $(RM) gen_koch_sig$(EXE) wm_koch_e$(EXE) wm_koch_d$(EXE) cmp_koch_sig$(EXE) + +kochman: + +wm_koch_e$(EXE): wm_koch_e$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_koch_e$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +wm_koch_d$(EXE): wm_koch_d$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_koch_d$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +gen_koch_sig$(EXE): gen_koch_sig$(O) wm$(O) + $(CC) $(LDFLAGS) -o $@ gen_koch_sig$(O) wm$(O) $(LIBS) + +cmp_koch_sig$(EXE): cmp_koch_sig$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_koch_sig$(O) $(WMLIB) $(LIBS) + +# Fridrich's 2. scheme (full-frame DCT, blind, binary) + +frid2: gen_frid2_sig$(EXE) wm_frid2_e$(EXE) wm_frid2_d$(EXE) cmp_frid2_sig$(EXE) + +frid2test: frid2 + gen_frid2_sig$(EXE) -n 250 < gen_frid2_sig.c > ../sigs/frid2.sig + wm_frid2_e$(EXE) -s ../sigs/frid2.sig -o ../watermarked/frid2_lena.pgm ../images/lena.pgm + wm_frid2_d$(EXE) -s ../sigs/frid2.sig -o ../wms/frid2.wm ../watermarked/frid2_lena.pgm + cmp_frid2_sig$(EXE) -s ../sigs/frid2.sig ../wms/frid2.wm + +frid2install: frid2 + $(CP) gen_frid2_sig$(EXE) wm_frid2_e$(EXE) wm_frid2_d$(EXE) cmp_frid2_sig$(EXE) $(INSTALLDIR) + +frid2clean: + $(RM) gen_frid2_sig$(EXE) wm_frid2_e$(EXE) wm_frid2_d$(EXE) cmp_frid2_sig$(EXE) + +frid2man: + +wm_frid2_e$(EXE): wm_frid2_e$(O) $(LIBPREFIX)wm$(LIB) frid2_common$(O) + $(CC) $(LDFLAGS) -o $@ wm_frid2_e$(O) frid2_common$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +wm_frid2_d$(EXE): wm_frid2_d$(O) $(LIBPREFIX)wm$(LIB) frid2_common$(O) + $(CC) $(LDFLAGS) -o $@ wm_frid2_d$(O) frid2_common$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +gen_frid2_sig$(EXE): gen_frid2_sig$(O) wm$(O) + $(CC) $(LDFLAGS) -o $@ gen_frid2_sig$(O) wm$(O) $(LIBS) + +cmp_frid2_sig$(EXE): cmp_frid2_sig$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_frid2_sig$(O) $(WMLIB) $(LIBS) + + +# Bruyndonckx's algorithm (spatial domain, block classification, blind) + +bruyn: gen_bruyn_sig$(EXE) wm_bruyn_e$(EXE) wm_bruyn_d$(EXE) cmp_bruyn_sig$(EXE) + +bruyntest: bruyn + gen_bruyn_sig$(EXE) -n 400 < gen_bruyn_sig.c > ../sigs/bruyn.sig + wm_bruyn_e$(EXE) -s ../sigs/bruyn.sig -o ../watermarked/bruyn_lena.pgm ../images/lena.pgm + wm_bruyn_d$(EXE) -s ../sigs/bruyn.sig -o ../wms/bruyn.wm ../watermarked/bruyn_lena.pgm + cmp_bruyn_sig$(EXE) -s ../sigs/bruyn.sig ../wms/bruyn.wm + +bruyninstall: bruyn + $(CP) gen_bruyn_sig$(EXE) wm_bruyn_e$(EXE) wm_bruyn_d$(EXE) cmp_bruyn_sig$(EXE) $(INSTALLDIR) + +bruynclean: + $(RM) gen_bruyn_sig$(EXE) wm_bruyn_e$(EXE) wm_bruyn_d$(EXE) cmp_bruyn_sig$(EXE) + +bruynman: + +wm_bruyn_e$(EXE): wm_bruyn_e$(O) bruyn_common$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_bruyn_e$(O) bruyn_common$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +wm_bruyn_d$(EXE): wm_bruyn_d$(O) bruyn_common$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_bruyn_d$(O) bruyn_common$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +gen_bruyn_sig$(EXE): gen_bruyn_sig$(O) wm$(O) + $(CC) $(LDFLAGS) -o $@ gen_bruyn_sig$(O) wm$(O) $(LIBS) + +cmp_bruyn_sig$(EXE): cmp_bruyn_sig$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_bruyn_sig$(O) $(WMLIB) $(LIBS) + + +# Cox's algorithm (full-frame DCT, non-blind, spread-spectrum) + +cox: gen_cox_sig$(EXE) wm_cox_e$(EXE) wm_cox_d$(EXE) cmp_cox_sig$(EXE) + +coxtest: cox + gen_cox_sig$(EXE) > ../sigs/cox.sig + wm_cox_e$(EXE) -s ../sigs/cox.sig -o ../watermarked/cox_lena.pgm ../images/lena.pgm + wm_cox_d$(EXE) -s ../sigs/cox.sig -o ../wms/cox.wm -i ../images/lena.pgm ../watermarked/cox_lena.pgm + cmp_cox_sig$(EXE) -s ../sigs/cox.sig ../wms/cox.wm + +coxinstall: cox + $(CP) gen_cox_sig$(EXE) wm_cox_e$(EXE) wm_cox_d$(EXE) cmp_cox_sig$(EXE) $(INSTALLDIR) + +coxman: gen_cox_sig.ps wm_cox_e.ps wm_cox_d.ps + +wm_cox_e$(EXE): wm_cox_e$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_cox_e$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +wm_cox_d$(EXE): wm_cox_d$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_cox_d$(O) $(WMLIB) $(LIBS) $(PGMLIBS) + +gen_cox_sig$(EXE): gen_cox_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_cox_sig$(O) $(LIBS) + +cmp_cox_sig$(EXE): cmp_cox_sig$(O) + $(CC) $(LDFLAGS) -o $@ cmp_cox_sig$(O) $(LIBS) + +coxclean: + $(RM) gen_cox_sig$(EXE) wm_cox_e$(EXE) wm_cox_d$(EXE) cmp_cox_sig$(EXE) + + +# Corvi's algorithm (DWT, non-blind, spread-spectrum, approximation image) + +corvi: gen_corvi_sig$(EXE) wm_corvi_e$(EXE) wm_corvi_d$(EXE) cmp_corvi_sig$(EXE) + +corvitest: corvi + gen_corvi_sig$(EXE) > ../sigs/corvi.sig + wm_corvi_e$(EXE) -s ../sigs/corvi.sig -o ../watermarked/corvi_lena.pgm ../images/lena.pgm + wm_corvi_d$(EXE) -s ../sigs/corvi.sig -o ../wms/corvi.wm -i ../images/lena.pgm ../watermarked/corvi_lena.pgm + cmp_corvi_sig$(EXE) -s ../sigs/corvi.sig ../wms/corvi.wm + +corviinstall: corvi + $(CP) gen_corvi_sig$(EXE) wm_corvi_e$(EXE) wm_corvi_d$(EXE) cmp_corvi_sig$(EXE) $(INSTALLDIR) + +corviman: gen_corvi_sig.ps wm_corvi_e.ps wm_corvi_d.ps + +wm_corvi_e$(EXE): wm_corvi_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_corvi_e$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_corvi_d$(EXE): wm_corvi_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_corvi_d$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_corvi_sig$(EXE): gen_corvi_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_corvi_sig$(O) $(LIBS) + +cmp_corvi_sig$(EXE): cmp_corvi_sig$(O) + $(CC) $(LDFLAGS) -o $@ cmp_corvi_sig$(O) $(LIBS) + +corviclean: + $(RM) gen_corvi_sig$(EXE) wm_corvi_e$(EXE) wm_corvi_d$(EXE) cmp_corvi_sig$(EXE) + + +# Xia's algorithm (DWT, non-blind, spread-spectrum, detail subbands) + +xia: gen_xia_sig$(EXE) wm_xia_e$(EXE) wm_xia_d$(EXE) cmp_xia_sig$(EXE) + +xiatest: xia + gen_xia_sig$(EXE) > ../sigs/xia.sig + wm_xia_e$(EXE) -s ../sigs/xia.sig -o ../watermarked/xia_lena.pgm ../images/lena.pgm + wm_xia_d$(EXE) -s ../sigs/xia.sig -o ../wms/xia.wm -i ../images/lena.pgm ../watermarked/xia_lena.pgm + cmp_xia_sig$(EXE) -s ../sigs/xia.sig ../wms/xia.wm + +xiainstall: xia + $(CP) gen_xia_sig$(EXE) wm_xia_e$(EXE) wm_xia_d$(EXE) cmp_xia_sig$(EXE) $(INSTALLDIR) + +xiaman: gen_xia_sig.ps wm_xia_e.ps wm_xia_d.ps + +wm_xia_e$(EXE): wm_xia_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_xia_e$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_xia_d$(EXE): wm_xia_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_xia_d$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_xia_sig$(EXE): gen_xia_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_xia_sig$(O) $(LIBS) + +cmp_xia_sig$(EXE): cmp_xia_sig$(O) + $(CC) $(LDFLAGS) -o $@ cmp_xia_sig$(O) $(LIBS) + +xiaclean: + $(RM) gen_xia_sig$(EXE) wm_xia_e$(EXE) wm_xia_d$(EXE) cmp_xia_sig$(EXE) + +# Wang's algorithm (DWT, non-blind, spread-spectrum, detail subbands) + +wang: gen_wang_sig$(EXE) wm_wang_e$(EXE) wm_wang_d$(EXE) cmp_wang_sig$(EXE) + +wangtest: wang + gen_wang_sig$(EXE) -n 1000 > ../sigs/wang.sig + wm_wang_e$(EXE) -s ../sigs/wang.sig -o ../watermarked/wang_lena.pgm ../images/lena.pgm + wm_wang_d$(EXE) -s ../sigs/wang.sig -o ../wms/wang.wm -i ../images/lena.pgm ../watermarked/wang_lena.pgm + cmp_wang_sig$(EXE) -s ../sigs/wang.sig ../wms/wang.wm + +wanginstall: wang + $(CP) gen_wang_sig$(EXE) wm_wang_e$(EXE) wm_wang_d$(EXE) cmp_wang_sig$(EXE) $(INSTALLDIR) + +wangman: gen_wang_sig.ps wm_wang_e.ps wm_wang_d.ps + +wm_wang_e$(EXE): wm_wang_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) wang_common$(O) + $(CC) $(LDFLAGS) -o $@ wm_wang_e$(O) wang_common$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_wang_d$(EXE): wm_wang_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) wang_common$(O) + $(CC) $(LDFLAGS) -o $@ wm_wang_d$(O) wang_common$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_wang_sig$(EXE): gen_wang_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_wang_sig$(O) $(LIBS) + +cmp_wang_sig$(EXE): cmp_wang_sig$(O) + $(CC) $(LDFLAGS) -o $@ cmp_wang_sig$(O) $(LIBS) + +wangclean: + $(RM) gen_wang_sig$(EXE) wm_wang_e$(EXE) wm_wang_d$(EXE) cmp_wang_sig$(EXE) + +# Kim's algorithm (DWT, non-blind, spread-spectrum, approx. & detail subbands) + +kim: gen_kim_sig$(EXE) wm_kim_e$(EXE) wm_kim_d$(EXE) cmp_kim_sig$(EXE) + +kimtest: kim + gen_kim_sig$(EXE) -n 1000 > ../sigs/kim.sig + wm_kim_e$(EXE) -s ../sigs/kim.sig -o ../watermarked/kim_lena.pgm ../images/lena.pgm + wm_kim_d$(EXE) -s ../sigs/kim.sig -o ../wms/kim.wm -i ../images/lena.pgm ../watermarked/kim_lena.pgm + cmp_kim_sig$(EXE) -s ../sigs/kim.sig ../wms/kim.wm + +kiminstall: kim + $(CP) gen_kim_sig$(EXE) wm_kim_e$(EXE) wm_kim_d$(EXE) cmp_kim_sig$(EXE) $(INSTALLDIR) + +kimman: gen_kim_sig.ps wm_kim_e.ps wm_kim_d.ps + +wm_kim_e$(EXE): wm_kim_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) kim_common$(O) + $(CC) $(LDFLAGS) -o $@ wm_kim_e$(O) kim_common$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_kim_d$(EXE): wm_kim_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) kim_common$(O) + $(CC) $(LDFLAGS) -o $@ wm_kim_d$(O) kim_common$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_kim_sig$(EXE): gen_kim_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_kim_sig$(O) $(LIBS) + +cmp_kim_sig$(EXE): cmp_kim_sig$(O) + $(CC) $(LDFLAGS) -o $@ cmp_kim_sig$(O) $(LIBS) + +kimclean: + $(RM) gen_kim_sig$(EXE) wm_kim_e$(EXE) wm_kim_d$(EXE) cmp_kim_sig$(EXE) + +# Zhu's algorithm (DWT, non-blind, spread-spectrum, detail subbands) + +zhu: gen_zhu_sig$(EXE) wm_zhu_e$(EXE) wm_zhu_d$(EXE) cmp_zhu_sig$(EXE) + +zhutest: zhu + gen_zhu_sig$(EXE) > ../sigs/zhu.sig + wm_zhu_e$(EXE) -s ../sigs/zhu.sig -o ../watermarked/zhu_lena.pgm ../images/lena.pgm + wm_zhu_d$(EXE) -s ../sigs/zhu.sig -o ../wms/zhu.wm -i ../images/lena.pgm ../watermarked/zhu_lena.pgm + cmp_zhu_sig$(EXE) -s ../sigs/zhu.sig ../wms/zhu.wm + +zhuinstall: zhu + $(CP) gen_zhu_sig$(EXE) wm_zhu_e$(EXE) wm_zhu_d$(EXE) cmp_zhu_sig$(EXE) $(INSTALLDIR) + +zhuman: gen_zhu_sig.ps wm_zhu_e.ps wm_zhu_d.ps + +wm_zhu_e$(EXE): wm_zhu_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_zhu_e$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_zhu_d$(EXE): wm_zhu_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_zhu_d$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_zhu_sig$(EXE): gen_zhu_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_zhu_sig$(O) $(LIBS) + +cmp_zhu_sig$(EXE): cmp_zhu_sig$(O) + $(CC) $(LDFLAGS) -o $@ cmp_zhu_sig$(O) $(LIBS) + +zhuclean: + $(RM) gen_zhu_sig$(EXE) wm_zhu_e$(EXE) wm_zhu_d$(EXE) cmp_zhu_sig$(EXE) + +# Xie's algorithm (DWT, blind, binary, quantization, approximation image) + +xie: gen_xie_sig$(EXE) wm_xie_e$(EXE) wm_xie_d$(EXE) cmp_xie_sig$(EXE) + +xietest: xie + gen_xie_sig$(EXE) -n 800 gen_xie_sig.c > ../sigs/xie.sig + wm_xie_e$(EXE) -s ../sigs/xie.sig -o ../watermarked/xie_lena.pgm ../images/lena.pgm + wm_xie_d$(EXE) -s ../sigs/xie.sig -o ../wms/xie.wm ../watermarked/xie_lena.pgm + cmp_xie_sig$(EXE) -s ../sigs/xie.sig ../wms/xie.wm + +xieinstall: xie + $(CP) gen_xie_sig$(EXE) wm_xie_e$(EXE) wm_xie_d$(EXE) cmp_xie_sig$(EXE) $(INSTALLDIR) + +xieman: gen_xie_sig.ps wm_xie_e.ps wm_xie_d.ps + +wm_xie_e$(EXE): wm_xie_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_xie_e$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_xie_d$(EXE): wm_xie_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_xie_d$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_xie_sig$(EXE): gen_xie_sig$(O) wm$(O) + $(CC) $(LDFLAGS) -o $@ gen_xie_sig$(O) wm$(O) $(LIBS) + +cmp_xie_sig$(EXE): cmp_xie_sig$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_xie_sig$(O) $(WMLIB) $(LIBS) + +xieclean: + $(RM) gen_xie_sig$(EXE) wm_xie_e$(EXE) wm_xie_d$(EXE) cmp_xie_sig$(EXE) + +# Dugad's algorithm (DWT, blind) + +dugad: gen_dugad_sig$(EXE) wm_dugad_e$(EXE) wm_dugad_d$(EXE) cmp_dugad_sig$(EXE) + +dugadtest: dugad + gen_dugad_sig$(EXE) -o ../sigs/dugad.sig + wm_dugad_e$(EXE) -s ../sigs/dugad.sig -o ../watermarked/dugad_lena.pgm ../images/lena.pgm + wm_dugad_d$(EXE) -s ../sigs/dugad.sig -o ../wms/dugad.wm ../watermarked/dugad_lena.pgm + cmp_dugad_sig$(EXE) -s ../sigs/dugad.sig ../wms/dugad.wm + +dugadinstall: dugad + $(CP) gen_dugad_sig$(EXE) wm_dugad_e$(EXE) wm_dugad_d$(EXE) cmp_dugad_sig$(EXE) $(INSTALLDIR) + +dugadman: gen_dugad_sig.ps wm_dugad_e.ps wm_dugad_d.ps + +wm_dugad_e$(EXE): wm_dugad_e$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_dugad_e$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +wm_dugad_d$(EXE): wm_dugad_d$(O) $(LIBPREFIX)wm$(LIB) $(LIBPREFIX)wavelet$(LIB) + $(CC) $(LDFLAGS) -o $@ wm_dugad_d$(O) $(WMLIB) $(WAVELIB) $(LIBS) $(PGMLIBS) + +gen_dugad_sig$(EXE): gen_dugad_sig$(O) + $(CC) $(LDFLAGS) -o $@ gen_dugad_sig$(O) $(LIBS) + +cmp_dugad_sig$(EXE): cmp_dugad_sig$(O) $(LIBPREFIX)wm$(LIB) + $(CC) $(LDFLAGS) -o $@ cmp_dugad_sig$(O) $(WMLIB) $(LIBS) + +dugadclean: + $(RM) gen_dugad_sig$(EXE) wm_dugad_e$(EXE) wm_dugad_d$(EXE) cmp_dugad_sig$(EXE) + + + +clean: coxclean bruynclean kochclean corviclean xiaclean zhuclean xieclean \ + dugadclean kimclean wangclean frid2clean toolsclean libraryclean waveletclean + $(RM) *$(O) *.ps ../sigs/* ../wms/* ../watermarked/* + + +man: coxman bruynman kochman corviman xiaman xieman toolsman + +test: coxtest bruyntest kochtest corvitest xiatest xietest dugadtest zhutest \ + wangtest frid2test kimtest toolstest + +install: coxinstall bruyninstall kochinstall corviinstall xiainstall xieinstall \ + dugadinstall zhuinstall wanginstall frid2install kiminstall toolsinstall + +depend: + $(MAKEDEP) *.h *.c + diff -r 000000000000 -r be303a3f5ea8 Meerwald/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/README Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,157 @@ +This package provides source code for some watermarking algorithms in portable +C code. Currently it includes the following + + watermarking algorithms + + Bruyndonckx + refer to + O. Bruyndonckx, Jean-Jacques Quisquater, and Benoit M. Macq. + Spatial method for copyright labeling of digital images. + In IEEE Workshop on Nonlinear Signal and Image Processing '95, + Thessaloniki, Greece, pages 456 - 459, 1995. + + Corvi + refer to + Marco Corvi and Gianluca Nicchiotti. + Wavelet-based image watermarking for copyright protection. + In Scandinavian Conference on Image Analysis SCIA '97, Lappeenranta, + Finland, June 1997. + + Cox + refer to + Ingemar J. Cox, Joe Kilian, Tom Leighton, and Talal G. Shamoon. + Secure spread spectrum watermarking for multimedia. + In Proceedings of the IEEE ICIP '97, + volume 6, pages 1673 - 1687, Santa Barbara, California, USA, 1997. + + Dugad + refer to + Rakesh Dugad, Krishna Ratakonda, and Narendra Ahuja. + A new wavelet-based scheme for watermarking images. In Proceedings of + the IEEE International Conference on Image Processing, ICIP '98, + Chicago, IL, USA, October 1998. + + Fridrich (2. scheme) + refer to + Jiri Fridrich. + Combining low-frequency and spread spectrum watermarking. In + Proceedings of the SPIE Symposium on Optical Science, Engineering and + Instrumentation, San Diego, USA, July 1998. + + Koch + refer to + Eckhard Koch and Jian Zhao. + Towards robust and hidden image copyright labeling. + In Proceedings of the IEEE International Workshop on Nonlinear + Signal and Image Processing, pages 452 - 455, Halkidiki, Marmaras, + Greece, June 1995. + + Kim + refer to + Jong Ryul Kim and Young Shik Moon. + A robust wavelet-based digital watermark using level-adaptive + thresholding. In Proceedings of the 6th IEEE International + Conference on Image Processing ICIP '99, page 202, + Kobe, Japan, October 1999. + + Wang + refer to + Houng-Jyh Wang, Po-Chyi Su, and C.-C. Jay Kuo. + Wavelet-based digital image watermarking. Optics Express, 3 + pp. 497, December 1998. + + Xia + refer to + Xiang-Gen Xia, Charles G. Boncelet, and Gonzalo R. Arce. + Wavelet transform based watermark for digital images. Optics Express, 3 + pp. 497, December 1998. + + Xie + refer to + Liehua Xie and Gonzalo R. Arce. + Joint wavelet compression and authentication watermarking. In + Proceedings of the IEEE International Conference on Image Processing, + ICIP '98, Chicago, IL, USA, 1998. + + Zhu + refer to + Wenwu Zhu, Zixiang Xiong, and Ya-Qin Zhang. + Multiresolution watermarking for images and video: a unified approach. + In Proceedings of the IEEE International Conference o + + many more algorithms to come! + see what is in stock: http://www.cosy.sbg.ac.at/~pmeerw/Watermarking + + and utility programs + + cmp_pgm - compute difference image, PSNR, ... + cmp_dct - compute full-frame DCT domain difference image + cmp_dct8x8 - compute 8x8 block-based DCT difference image + cmp_dwt - compute DWT domain difference image + +What do I need? + +Unix (Linux), a reasonable C compiler (GCC), and the netpbm library which you +can get at http://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/ + + +Directions: How do I use the stuff? + +look at the MAKEFILE... +each algorithms has at least 4 files: gen_algo_sig.c, wm_algo_e.c, wm_algo_d.c, +cmp_algo_sig.c where 'algo' is the name of the actual watermarking algorithm +(usually the principal author's name), where might also be some common files +for each algorithm, algo_common.{c|h}, and some support files for sorting, +the DCT, ... + +just try + + make + make test + +next, try to run each program with the -h parameter to find out what options +are supported - the programs are pretty consistent and have reasonable +default settings + +e.g. + + wm_cox_e -h + +The programs all support standard input and standard output, the only +supported image file format is PGM for grayscale images and PPM for color +images; most programs have only been tested with 512x512 images. +You can find the Lena image in PGM format in the images/ sub-directory. + + +Disclaimer: #include + +Feel free to use the accompaigning code for your research! However, I do +not guarantee for anything, in particular parts of the provided code may +be covered by copyrights of a third party or by patent claims. I do not +guarantee for any functionality, bla-bla, ... + +If you use the accompanying code, please cite my thesis: + + Peter Meerwald, Digital Image Watermarking in the Wavelet Transform Domain, + Master's Thesis, Department of Scientific Computing, University of Salzburg, + Austria, January 2001. + + +Contact: Comments are welcome! + +More algorithms will be added over time, I have implemented about 13 +watermarking algorithms in the spatial-, DCT-, and wavelet domain so far. +Please report what problems you have, suggestions, ... + +Peter Meerwald + +Dept. of Scientific Computing +University of Salzburg +Jakob-Haringer-Str. 2 +A-5020 Salzburg +AUSTRIA + +pmeerw@cosy.sbg.ac.at +http://www.cosy.sbg.ac.at/~pmeerw/Watermarking + ++43-662-8044-6327 diff -r 000000000000 -r be303a3f5ea8 Meerwald/bruyn_common.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/bruyn_common.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,44 @@ +#include "bruyn_common.h" + +gray lookup_pattern(int pattern, int c, int r) { +#define A CATEGORY_A +#define B CATEGORY_B + + gray pattern1[4][4] = + {{A, A, B, B}, + {A, A, B, B}, + {B, B, A, A}, + {B, B, A, A}}; + + gray pattern2[8][8] = + {{B, B, B, B, A, A, A, A}, + {B, B, B, B, A, A, A, A}, + {B, B, B, B, A, A, A, A}, + {B, B, B, B, A, A, A, A}, + {A, A, A, A, B, B, B, B}, + {A, A, A, A, B, B, B, B}, + {A, A, A, A, B, B, B, B}, + {A, A, A, A, B, B, B, B}}; + + gray pattern3[2][2] = + {{A, B}, {B, A}}; + +#undef A +#undef B + + switch (pattern) { + case 1: + return pattern1[r % 4][c % 4]; + break; + case 2: + return pattern2[r % 8][c % 8]; + break; + case 3: + return pattern3[r % 2][c % 2]; + break; + } + + return CATEGORY_VOID; +} + + diff -r 000000000000 -r be303a3f5ea8 Meerwald/bruyn_common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/bruyn_common.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,41 @@ +#ifndef BRUYN_COMMON_H +#define BRUYN_COMMON_H + +#include "pgm.h" + +// for block type classification +#define BLOCKTYPE_UNKNOWN 0 +#define BLOCKTYPE_HARD 1 +#define BLOCKTYPE_PROGRESSIVE 2 +#define BLOCKTYPE_NOISE 3 + +// thresholds +#define THRESHOLD_NOISE 10.0 +#define THRESHOLD_SLOPE 5.0 +#define THRESHOLD_NOISE_USAGE "10.0" +#define THRESHOLD_SLOPE_USAGE "5.0" + +// zone classification +#define ZONE_VOID 0 +#define ZONE_1 1 +#define ZONE_2 2 + +// category classification +#define CATEGORY_VOID 0 +#define CATEGORY_A 4 +#define CATEGORY_B 8 + +// classifiction = zone | category +#define CLASSIFICATION_1A (ZONE_1 | CATEGORY_A) +#define CLASSIFICATION_1B (ZONE_1 | CATEGORY_B) +#define CLASSIFICATION_2A (ZONE_2 | CATEGORY_A) +#define CLASSIFICATION_2B (ZONE_2 | CATEGORY_B) +#define CLASSIFICATION_A CATEGORY_A +#define CLASSIFICATION_B CATEGORY_B + +#define NPATTERN 3 +#define NPATTERN_USAGE "3" + +gray lookup_pattern(int pattern, int c, int r); + +#endif BRUYN_COMMON_H diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_bruyn_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_bruyn_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,150 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, i; + int pattern1, pattern2; + double quality; + double threshold1, threshold2; + int blocksize; + int corr = 0, match = 0; + int verbose = 0; + int skipping = 0; + + int correlation_only = 0; + + int seed; + char line[32]; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + fgets(line, sizeof(line), sig); + if (strspn(line, "BRSG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature1); + fscanf(sig, "%d\n", &skipping); + fscanf(sig, "%d\n", &pattern1); + fscanf(sig, "%d\n", &pattern2); + fscanf(sig, "%lf\n", &quality); + fscanf(sig, "%lf\n", &threshold1); + fscanf(sig, "%lf\n", &threshold2); + fscanf(sig, "%d\n", &blocksize); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature1 = NBITSTOBYTES(nbit_signature1); + fread(signature1, sizeof(char), n_signature1, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + close(sig); + } + else { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "BRWM") >= 4) { + fscanf(in, "%d\n", &nbit_signature2); + n_signature2 = NBITSTOBYTES(nbit_signature2); + fread(signature2, sizeof(char), n_signature2, in); + fscanf(in, "\n"); + } + else { + fprintf(stderr, "%s: invalid watermark file %s\n", progname, input_name); + exit(1); + } + + if (verbose > 0) { + fprintf(stderr, "signature length: %d\n", nbit_signature1); + fprintf(stderr, "watermark length: %d\n", nbit_signature2); + } + + for (i = 0; i < nbit_signature2; i++) + if (get_signature1_bit(i % nbit_signature1) == get_signature2_bit(i)) + corr++, match++; + else + corr--; + + if (correlation_only) + fprintf(out, "%lf\n", (double) corr / nbit_signature2); + else { + fprintf(out, "bit matches: %d/%d\n", match, nbit_signature2); + fprintf(out, "correlation: %lf\n", (double) corr / nbit_signature2); + } + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_corvi_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_corvi_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,159 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c; + int sig_n, in_n; + double s1, s2, s3; + char line[32]; + int matches; + + int verbose = 0; + int correlation_only = 0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?o:s:v:C")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + case 'C': + correlation_only = 1; + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!sig) { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), sig); + if (strspn(line, "CVSG") < 4) { + fprintf(stderr, "%s: original signature file %s invalid\n", progname, signature_name); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "CVWM") < 4) { + fprintf(stderr, "%s: signature file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(sig, "%d\n", &sig_n); + fscanf(in, "%d\n", &in_n); + if (sig_n != in_n) { + fprintf(stderr, "%s: watermark length mismatch (original %d, input %d)\n", progname, sig_n, in_n); + exit(1); + } + if (sig_n <= 0 || sig_n > 1000) { + fprintf(stderr, "%s: invalid original watermark length %d\n", progname, sig_n); + exit(1); + } + if (in_n <= 0 || in_n > 1000) { + fprintf(stderr, "%s: invalid watermark length %d\n", progname, in_n); + exit(1); + } + + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*d\n"); + fscanf(sig, "%*d\n"); + fscanf(sig, "%*[^\n\r]\n"); + + /* + * normalized correlation + * Craver, S., "Can Invisible Watermarks Resolve Rightful Ownership?", IBM Research Report, 1996, p. 5 + */ + + s1 = s2 = s3 = 0.0; + matches = 0; + while (in_n > 0) { + double sig_x, in_x; + + fscanf(sig, "%lf\n", &sig_x); + fscanf(in, "%lf\n", &in_x); + + matches += SIGN(sig_x * in_x); + + if (verbose >= 1) { + fprintf(stderr, "orig %f input %f\n", sig_x, in_x); + } + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + + in_n--; + } + + if (!correlation_only) { + fprintf(out, "%s: correlation %f, hamming distance %f\n", progname, s1 / sqrt(s2 * s3), (double) matches / sig_n); + } + else + fprintf(out, "%f\n", (double) matches / sig_n); + + fclose(sig); + fclose(out); + fclose(in); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_cox_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_cox_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,153 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c; + int sig_n, in_n; + double sig_a, in_a; + double sig_mean, sig_variance; + double s1, s2, s3; + char line[32]; + + int verbose = 0; + int correlation_only = 0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!sig) { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), sig); + if (strspn(line, "CXSG") < 4) { + fprintf(stderr, "%s: original signature file %s invalid\n", progname, signature_name); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "CXWM") < 4) { + fprintf(stderr, "%s: watermark file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(sig, "%d\n", &sig_n); + fscanf(in, "%d\n", &in_n); + if (sig_n != in_n) { + fprintf(stderr, "%s: watermark length mismatch (original %d, input %d)\n", progname, sig_n, in_n); + exit(1); + } + if (sig_n <= 0 || sig_n > 32000) { + fprintf(stderr, "%s: invalid original watermark length %d\n", progname, sig_n); + exit(1); + } + if (in_n <= 0 || in_n > 32000) { + fprintf(stderr, "%s: invalid watermark length %d\n", progname, in_n); + exit(1); + } + + fscanf(sig, "%lf\n", &sig_a); + + fscanf(sig, "%lf\n", &sig_mean); + fscanf(sig, "%lf\n", &sig_variance); + + /* + * normalized correlation + * Craver, S., "Can Invisible Watermarks Resolve Rightful Ownership?", IBM Research Report, 1996, p. 5 + */ + + s1 = s2 = s3 = 0.0; + while (in_n > 0) { + double sig_x, in_x; + + fscanf(sig, "%lf\n", &sig_x); + fscanf(in, "%lf\n", &in_x); + + if (verbose >= 1) { + fprintf(stderr, "orig %f input %f\n", sig_x, in_x); + } + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + + in_n--; + } + + fprintf(out, "%f\n", s1 / sqrt(s2 * s3)); + + fclose(sig); + fclose(out); + fclose(in); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_dct.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_dct.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,79 @@ +.\" +.\" cmp_dct.1 - the *roff document processor man page source +.\" +.TH cmp_dct 1 "98/07/08" "Watermarking, Version 1.0" +.SH NAME +cmp_dct \- a program to create the difference image of the +frequency domain of two PGM images +.SH SYNOPSIS +.B cmp_dct +[ +.B \-h +] +[ +.BI \-m \ number +] +[ +.BI \-o \ ofile +] +.BI \-i \ ifile +.I file +.SH DESCRIPTION +.B cmp_dct +is a program to create the difference image of the +frequency domain of two PGM (portable graymap) grayscale +images. To compare images in the spatial domain, either in +PPM (portable pixmap) format for RGB color images or in PGM (portable +graymap) format for grayscale images, use the +.B cmp_ppm +program or the +.B cmp_pgm +program, respectively. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. Mandatory. +.TP +.BI \-m \ number +Multiplication factor to magnify differences between the to +original and input image. +Default value: 16. +.TP +.BI \-o \ ofile +Output image file to contain the difference image in PGM format. +.TP +.I file +Input image that is compared against +.I ifile. +Default: standard input. +.SH OUTPUT +The difference image in PGM format is written to standard output or, +optionally, to +.I ofile. +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B cmp_dct +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.B cmp_pgm +(1), +.B cmp_ppm +(1), +.B cmp_dct8x8 +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_dct.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_dct.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,197 @@ +#include "wm.h" +#include "dct.h" +#include "gray.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-m n] [-o file] [-pP] -i file file\n\n", progname); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-m n\t\tmultiplication factor (default 16)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-p\t\tprint PSNR, RMS and MSE\n"); + fprintf(stderr, "\t-P\t\tonly print PSNR, RMS and MSE, no difference image\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + + gray **input_image; + gray **orig_image; + double **input_dcts; + double **orig_dcts; + gray **output; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int in_cols, in_rows, in_format; + gray in_maxval; + int orig_cols, orig_rows, orig_format; + gray orig_maxval; + int cols, rows, format; + gray maxval; + int col, row; + + int no_orig = 0; + int c; + + double error = 0.0; + int print_psnr = 0; + int print_psnr_only = 0; + int m = 16; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "h?i:m:o:pP")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'i': + if (!strcmp(optarg, "-")) { + no_orig = 1; + strcpy(orig_name, "(zero)"); + } + else { + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + } + break; + case 'm': + m = atoi(optarg); + if (m <= 0) { + fprintf(stderr, "%s: multiplication factor %d out of range\n", progname, m); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + print_psnr = 1; + break; + case 'P': + print_psnr_only = 1; + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig && !no_orig) { + fprintf(stderr, "%s: original image file not specified, using zero image\n", progname); + strcpy(orig_name, "(zero)"); + no_orig = 1; + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + + if (!no_orig) { + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + } + + cols = in_cols; + rows = in_rows; + format = in_format; + maxval = in_maxval; + + input_image = pgm_allocarray(cols, rows); + orig_image = pgm_allocarray(cols, rows); + + init_dct_NxN(cols, rows); + input_dcts = alloc_coeffs(cols, rows); + orig_dcts = alloc_coeffs(cols, rows); + output = alloc_grays(cols, rows); + + if (no_orig) { + for (row = 0; row < rows; row++) { + pgm_readpgmrow(in, input_image[row], cols, maxval, format); + bzero(orig_image[row], sizeof(gray) * cols); + } + } + else { + for (row = 0; row < rows; row++) { + pgm_readpgmrow(in, input_image[row], cols, maxval, format); + pgm_readpgmrow(orig, orig_image[row], cols, maxval, format); + } + } + + fclose(in); + if (!no_orig) + fclose(orig); + + fdct_NxN(input_image, input_dcts); + fdct_NxN(orig_image, orig_dcts); + + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) { + error += sqr(input_dcts[row][col] - orig_dcts[row][col]); + output[row][col] = PIXELRANGE(fabs(input_dcts[row][col] - orig_dcts[row][col]) * m); + } + + if (!print_psnr_only) { + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, output[row], cols, maxval, 0); + + fclose(out); + } + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + free_coeffs(input_dcts); + free_coeffs(orig_dcts); + free_grays(output); + + if (print_psnr || print_psnr_only) { + double mse = error / (double) (cols * rows); + double rmse = sqrt(mse); + double psnr = 20.0 * log(255.0 / rmse) / log(10.0); + FILE *print = print_psnr_only ? out : stderr; + if (mse > 0.0) + fprintf(print, "PSNR: %lf dB\n", psnr); + else + fprintf(print, "PSNR: inf\n"); + fprintf(print, "RMS: %lf\n", rmse); + fprintf(print, "MSE: %lf\n", mse); + } + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_dct8x8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_dct8x8.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,79 @@ +.\" +.\" cmp_dct8x8.1 - the *roff document processor man page source +.\" +.TH cmp_dct8x8 1 "98/07/08" "Watermarking, Version 1.0" +.SH NAME +cmp_dct8x8 \- a program to create the difference image of the +8x8 DCT blocks of two PGM images +.SH SYNOPSIS +.B cmp_dct8x8 +[ +.B \-h +] +[ +.BI \-m \ number +] +[ +.BI \-o \ ofile +] +.BI \-i \ ifile +.I file +.SH DESCRIPTION +.B cmp_dct8x8 +is a program to create the difference image of the 8x8 DCT blocks +(frequency domain) of two PGM (portable graymap) grayscale +images. To compare images in the spatial domain, either in +PPM (portable pixmap) format for RGB color images or in PGM (portable +graymap) format for grayscale images, use the +.B cmp_ppm +program or the +.B cmp_pgm +program, respectively. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. Mandatory. +.TP +.BI \-m \ number +Multiplication factor to magnify differences between the to +original and input image. +Default value: 16. +.TP +.BI \-o \ ofile +Output image file to contain the difference image in PGM format. +.TP +.I file +Input image that is compared against +.I ifile. +Default: standard input. +.SH OUTPUT +The difference image in PGM format is written to standard output or, +optionally, to +.I ofile. +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B cmp_dct8x8 +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.B cmp_pgm +(1), +.B cmp_ppm +(1), +.B cmp_dct +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_dct8x8.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_dct8x8.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,196 @@ +#include "wm.h" +#include "dct.h" +#include "gray.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-m n] [-o file] [-pP] -i file file\n\n", progname); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-m n\t\tmultiplication factor (default 16)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-p\t\tprint PSNR, RMS and MSE\n"); + fprintf(stderr, "\t-P\t\tonly print PSNR, RMS and MSE, no difference image\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + + gray **input_image; + gray **orig_image; + double **input_dcts; + double **orig_dcts; + gray **output; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int in_cols, in_rows, in_format; + gray in_maxval; + int orig_cols, orig_rows, orig_format; + gray orig_maxval; + int cols, rows, format; + gray maxval; + int col, row; + + int i, j; + int c; + + int m = 16; + + int print_psnr = 0; + int print_psnr_only = 0; + double error = 0.0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "h?i:m:o:pP")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'm': + m = atoi(optarg); + if (m <= 0) { + fprintf(stderr, "%s: multiplication factor %d out of range\n", progname, m); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + print_psnr = 1; + break; + case 'P': + print_psnr_only = 1; + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + if (cols % NJPEG) { + fprintf(stderr, "%s: image width %d not a multiple of %d\n", progname, cols, NJPEG); + exit(1); + } + + if (rows % NJPEG) { + fprintf(stderr, "%s: image height %d not a multiple of %d\n", progname, rows, NJPEG); + exit(1); + } + + cols = in_cols; + rows = in_rows; + format = in_format; + maxval = in_maxval; + + input_image = pgm_allocarray(cols, NJPEG); + orig_image = pgm_allocarray(cols, NJPEG); + + init_dct_8x8(); + input_dcts = alloc_coeffs_8x8(); + orig_dcts = alloc_coeffs_8x8(); + output = alloc_grays(cols, NJPEG); + + if (!print_psnr_only) + pgm_writepgminit(out, cols, rows, maxval, 0); + + for (row = 0; row < rows; row += NJPEG) { + + for (i = 0; i < NJPEG; i++) { + pgm_readpgmrow(in, input_image[row % NJPEG], cols, maxval, format); + pgm_readpgmrow(orig, orig_image[row % NJPEG], cols, maxval, format); + } + + for (col = 0; col < cols; col += NJPEG) { + fdct_block_8x8(input_image, col, 0, input_dcts); + fdct_block_8x8(orig_image, col, 0, orig_dcts); + + for (i = 0; i < NJPEG; i++) + for (j = 0; j < NJPEG; j++) + error += sqr(input_dcts[j][i + cols] - orig_dcts[j][i + cols]); + output[j][i + col] = PIXELRANGE(fabs(input_dcts[j][i + cols] - orig_dcts[j][i + cols]) * m); + } + + if (!print_psnr_only) { + for (i = 0; i < NJPEG; i++) + pgm_writepgmrow(out, output[i], cols, maxval, 0); + } + + } + fclose(in); + fclose(orig); + if (!print_psnr_only) + fclose(out); + + pgm_freearray(input_image, NJPEG); + pgm_freearray(orig_image, NJPEG); + free_coeffs(input_dcts); + free_coeffs(orig_dcts); + free_grays(output); + + if (print_psnr || print_psnr_only) { + double mse = error / (double) (cols * rows); + double rmse = sqrt(mse); + double psnr = 20.0 * log(255.0 / rmse) / log(10.0); + FILE *print = print_psnr_only ? out : stderr; + if (mse > 0.0) + fprintf(print, "PSNR: %lf dB\n", psnr); + else + fprintf(print, "PSNR: inf\n"); + fprintf(print, "RMS: %lf\n", rmse); + fprintf(print, "MSE: %lf\n", mse); + } + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_dugad_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_dugad_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,147 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-s file] [-C] [-o file] [-v] file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tignored\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, i, n, ok; + int levels; + double alpha; + double diff; + char line[32]; + + int correlation_only = 0; + int verbose = 0; + double corr; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:v:s:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 's': + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + fgets(line, sizeof(line), in); + if (strspn(line, "DGWM") < 4) { + fprintf(stderr, "%s: watermark file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(in, "%d\n", &levels); + fscanf(in, "%lf\n", &alpha); + + n = 3 * levels; + ok = 0; + diff = 0.0; + for (i = 0; i < levels; i++) { + int m; + double z, v; + + // HL subband + fscanf(in, "%d %lf %lf\n", &m, &z, &v); + if (verbose && !correlation_only) + if (m) + fprintf(out, "%f %f\n", z / (double) m, (v * alpha) / (double) (1.0 * m)); + else + fprintf(out, "0.0 0.0\n"); + if (m) { + ok += (z > v * alpha / (double) 1.0) ? 1 : 0; + diff += ((z - v * alpha) / (double) (1.0 * m)); + } + else + n--; + + // LH subband + fscanf(in, "%d %lf %lf\n", &m, &z, &v); + if (verbose && !correlation_only) + if (m) + fprintf(out, "%f %f\n", z / (double) m, (v * alpha) / (double) (1.0 * m)); + else + fprintf(out, "0.0 0.0\n"); + if (m) { + ok += (z > v * alpha / (double) 1.0) ? 1 : 0; + diff += ((z - v * alpha) / (double) (1.0 * m)); + } + else + n--; + + // HH subband + fscanf(in, "%d %lf %lf\n", &m, &z, &v); + if (verbose && !correlation_only) + if (m) + fprintf(out, "%f %f\n", z / (double) m, (v * alpha) / (double) (1.0 * m)); + else + fprintf(out, "0.0 0.0\n"); + + if (m) { + ok += (z > v * alpha / (double) 1.0) ? 1 : 0; + diff += ((z - v * alpha) / (double) (1.0 * m)); + } + else + n--; + } + + if (!correlation_only) + fprintf(out, "%d/%d, diff %f\n", ok, n, diff); + fprintf(out, "%f\n", (double) ok / (double) n); + + fclose(out); + fclose(in); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_dwt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_dwt.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,390 @@ +#include "wm.h" +#include "dwt.h" +#include "coeff.h" +#include "gray.h" +#include "pgm.h" +#include "dwt_util.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-e n] [-f n] [-F file] [-h] [-l n] [-o file] [-pP] [-s name,..] -i file file\n\n", progname); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default: 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default: 2)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default: filter.dat\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-l n\t\tmax. decomposition level (default: 0 = max)\n"); + fprintf(stderr, "\t-m n\t\tmultiplication factor (default: 0 = auto)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-p\t\tprint PSNR, RMS and MSE\n"); + fprintf(stderr, "\t-P\t\tonly print PSNR, RMS and MSE, no difference image\n"); + fprintf(stderr, "\t-q\t\tprint PSNR, RMS and MSE per subband\n"); + fprintf(stderr, "\t-s name,...\tsubband/level (default: all subbands)\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +void process_subband_var(gray **output, int cols, int rows, Image_tree p, Image_tree q, int type, double min, double max, gray maxval) { + int i; + int col, row, startcol, startrow; + + if (!p || !q) return; + + calc_subband_location(cols, rows, type, p->level, &startcol, &startrow); + + for (row = 0; row < p->image->height; row++) + for (col = 0; col < p->image->width; col++) { + double diff = fabs(get_pixel(p->image, col, row) - get_pixel(q->image, col, row)); + output[startrow + row][startcol + col] = PIXELRANGE((double) (diff - min) / (double) (max - min) * maxval); + } +} + +void process_subband_fixed(gray **output, int cols, int rows, Image_tree p, Image_tree q, int type, double m) { + int i; + int col, row, startcol, startrow; + + if (!p || !q) return; + + calc_subband_location(cols, rows, type, p->level, &startcol, &startrow); + + for (row = 0; row < p->image->height; row++) + for (col = 0; col < p->image->width; col++) { + double diff = fabs(get_pixel(p->image, col, row) - get_pixel(q->image, col, row)); + output[startrow + row][startcol + col] = PIXELRANGE(diff * m); + } +} + +void print_subband_psnr(int type, int level, double error, int cols, int rows, double min, double max, FILE *print) { + double mse = error / (double) (cols * rows); + double rmse = sqrt(mse); + double psnr = 20.0 * log(255.0 / rmse) / log(10.0); + int startcol, startrow; + + calc_subband_location(cols << level, rows << level, type, level, &startcol, &startrow); + fprintf(print, "%s%d (%d x %d) at %d x %d\n", subband_name(type), level, cols, rows, startcol, startrow); + if (mse > 0.0) + fprintf(print, " PSNR: %lf dB\n", psnr); + else + fprintf(print, " PSNR: inf\n"); + fprintf(print, " RMS: %lf\n", rmse); + fprintf(print, " MSE: %lf\n", mse); + fprintf(print, " dmin, dmax: %lf, %lf\n", min, max); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *print; + + gray **input_image; + gray **orig_image; + Image_tree input_dwts, p; + Image_tree orig_dwts, q; + gray **output; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + char *subband_list = NULL; + + int in_cols, in_rows, in_format; + gray in_maxval; + int orig_cols, orig_rows, orig_format; + gray orig_maxval; + int cols, rows, format; + gray maxval; + int col, row; + + int no_orig = 0; + int m = 0; + int c; + int maxlevel = 0; + + int filter = 1; + int method = 2; + int levels; + char filter_name[MAXPATHLEN] = "filter.dat"; + + double error = 0.0; + int print_psnr = 0; + int print_psnr_subband = 0; + int print_psnr_only = 0; + + double min, max; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "e:f:F:h?i:l:m:o:pPqs:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'i': + if (!strcmp(optarg, "-")) { + no_orig = 1; + strcpy(orig_name, "(zero)"); + } + else { + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + } + break; + case 'l': + maxlevel = atoi(optarg); + if (maxlevel < 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, maxlevel); + exit(1); + } + break; + case 'm': + m = atoi(optarg); + if (m < -1) { + fprintf(stderr, "%s: multiplication factor %d out of range\n", progname, m); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + print_psnr = 1; + break; + case 'P': + print_psnr_only = 1; + break; + case 'q': + print_psnr = 1; + print_psnr_subband = 1; + case 's': + subband_list = optarg; + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + print = print_psnr_only ? out : stderr; + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig && !no_orig) { + fprintf(stderr, "%s: original image file not specified, using zero image\n", progname); + strcpy(orig_name, "(zero)"); + no_orig = 1; + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + + if (!no_orig) { + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + } + + cols = in_cols; + rows = in_rows; + format = in_format; + maxval = in_maxval; + + input_image = pgm_allocarray(cols, rows); + orig_image = pgm_allocarray(cols, rows); + + output = alloc_grays(cols, rows); + + if (no_orig) { + for (row = 0; row < rows; row++) { + pgm_readpgmrow(in, input_image[row], cols, maxval, format); + bzero(orig_image[row], sizeof(gray) * cols); + } + } + else { + for (row = 0; row < rows; row++) { + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + } + } + + fclose(in); + if (!no_orig) + fclose(orig); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (!maxlevel) maxlevel = levels; + if (maxlevel > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, maxlevel, levels, cols, rows); + exit(1); + } + + init_dwt(cols, rows, filter_name, filter, maxlevel, method); + + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + p = input_dwts; + q = orig_dwts; + min = 10000000.0; + max = 0.0; + error = 0.0; + while (p->coarse && q->coarse) { + double localmin, localmax, localerror; + + if (subband_in_list(subband_list, HORIZONTAL, p->horizontal->level)) { + calc_subband(p->horizontal, q->horizontal, HORIZONTAL, &localmin, &localmax, &localerror); + if (m == -1) process_subband_var(output, cols, rows, p->horizontal, q->horizontal, HORIZONTAL, localmin, localmax, maxval); + if (localmin < min) min = localmin; + if (localmax > max) max = localmax; + error += localerror; + if (print_psnr_subband) + print_subband_psnr(HORIZONTAL, p->horizontal->level, error, p->horizontal->image->width, p->horizontal->image->height, localmin, localmax, print); + } + else if (verbose > 5) + fprintf(stderr, "%s: subband %s%d skipped\n", progname, subband_name(HORIZONTAL), p->horizontal->level); + + if (subband_in_list(subband_list, VERTICAL, p->vertical->level)) { + calc_subband(p->vertical, q->vertical, VERTICAL, &localmin, &localmax, &localerror); + if (m == -1) process_subband_var(output, cols, rows, p->vertical, q->vertical, VERTICAL, localmin, localmax, maxval); + if (localmin < min) min = localmin; + if (localmax > max) max = localmax; + error += localerror; + if (print_psnr_subband) + print_subband_psnr(VERTICAL, p->vertical->level, error, p->vertical->image->width, p->vertical->image->height, localmin, localmax, print); + } + else if (verbose > 5) + fprintf(stderr, "%s: subband %s%d skipped\n", progname, subband_name(VERTICAL), p->vertical->level); + + if (subband_in_list(subband_list, DIAGONAL, p->diagonal->level)) { + calc_subband(p->diagonal, q->diagonal, DIAGONAL, &localmin, &localmax, &localerror); + if (m == -1) process_subband_var(output, cols, rows, p->diagonal, q->diagonal, DIAGONAL, localmin, localmax, maxval); + if (localmin < min) min = localmin; + if (localmax > max) max = localmax; + error += localerror; + if (print_psnr_subband) + print_subband_psnr(DIAGONAL, p->vertical->level, error, p->diagonal->image->width, p->diagonal->image->height, localmin, localmax, print); + } + else if (verbose > 5) + fprintf(stderr, "%s: subband %s%d skipped\n", progname, subband_name(DIAGONAL), p->diagonal->level); + + p = p->coarse; + q = q->coarse; + + if (!p->coarse) { + if (subband_in_list(subband_list, COARSE, p->level)) { + calc_subband(p, q, COARSE, &localmin, &localmax, &localerror); + if (m == -1) process_subband_var(output, cols, rows, p, q, COARSE, localmin, localmax, maxval); + if (localmin < min) min = localmin; + if (localmax > max) max = localmax; + error += localerror; + if (print_psnr_subband) + print_subband_psnr(COARSE, p->level, error, p->image->width, p->image->height, localmin, localmax, print); + } + else if (verbose > 5) + fprintf(stderr, "%s: subband %s%d skipped\n", progname, subband_name(COARSE), p->level); + } + } + + p = input_dwts; + q = orig_dwts; + while (p->coarse && q->coarse) { + if (m > 0) { + process_subband_fixed(output, cols, rows, p->horizontal, q->horizontal, HORIZONTAL, m); + process_subband_fixed(output, cols, rows, p->vertical, q->vertical, VERTICAL, m); + process_subband_fixed(output, cols, rows, p->diagonal, q->diagonal, DIAGONAL, m); + } + else if (m == 0) { + process_subband_var(output, cols, rows, p->horizontal, q->horizontal, HORIZONTAL, min, max, maxval); + process_subband_var(output, cols, rows, p->vertical, q->vertical, VERTICAL, min, max, maxval); + process_subband_var(output, cols, rows, p->diagonal, q->diagonal, DIAGONAL, min, max, maxval); + } + + p = p->coarse; + q = q->coarse; + + if (!p->coarse) { + if (m > 0) + process_subband_fixed(output, cols, rows, p, q, COARSE, m); + else if (m == 0) + process_subband_var(output, cols, rows, p, q, COARSE, min, max, maxval); + } + } + + if (!print_psnr_only) { + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, output[row], cols, maxval, 0); + + fclose(out); + } + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + free_grays(output); + + if (print_psnr || print_psnr_only) { + double mse = error / (double) (cols * rows); + double rmse = sqrt(mse); + double psnr = 20.0 * log(255.0 / rmse) / log(10.0); + if (mse > 0.0) + fprintf(print, "PSNR: %lf dB\n", psnr); + else + fprintf(print, "PSNR: inf\n"); + fprintf(print, "RMS: %lf\n", rmse); + fprintf(print, "MSE: %lf\n", mse); + fprintf(print, "dmin, dmax: %lf, %lf\n", min, max); + } + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_frid2_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_frid2_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,154 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int correlation_only = 0; + + int c, i; + int corr1 = 0, match1 = 0; + int corr2 = 0, match2 = 0; + int verbose = 0; + char filter_name[MAXPATHLEN] = ""; + + int seed; + char line[32]; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + fgets(line, sizeof(line), sig); + if (strspn(line, "FR2SG") >= 5) { + fscanf(sig, "%d\n", &nbit_signature); + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*d\n"); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + close(sig); + } + else { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "FR2WM") >= 5) { + fscanf(in, "%d\n", &nbit_signature1); + n_signature1 = NBITSTOBYTES(nbit_signature1); + fread(signature1, sizeof(char), n_signature1, in); +// fscanf(in, "\n"); + fscanf(in, "%d\n", &nbit_signature2); + n_signature2 = NBITSTOBYTES(nbit_signature2); + fread(signature2, sizeof(char), n_signature2, in); + fscanf(in, "\n"); + } + else { + fprintf(stderr, "%s: invalid watermark file %s\n", progname, input_name); + exit(1); + } + + if (verbose > 0) { + fprintf(stderr, "signature length: %d\n", nbit_signature); + fprintf(stderr, "watermark length (low. freq.): %d\n", nbit_signature1); + fprintf(stderr, "watermark length (med. freq.): %d\n", nbit_signature2); + } + + for (i = 0; i < nbit_signature; i++) { + if (get_signature_bit(i) == get_signature1_bit(i)) + corr1++, match1++; + else + corr1--; + if (get_signature_bit(i) == get_signature2_bit(i)) + corr2++, match2++; + else + corr2--; + } + + if (correlation_only) + fprintf(out, "%lf\n", (double) (corr1 + corr2) / (nbit_signature1 + nbit_signature2)); + else { + fprintf(out, "bit matches (low freq.): %d/%d\n", match1, nbit_signature1); + fprintf(out, "correlation (low. freq.): %lf\n", (double) corr1 / nbit_signature1); + fprintf(out, "bit matches (med. freq.): %d/%d\n", match2, nbit_signature2); + fprintf(out, "correlation (med. freq.): %lf\n", (double) corr2 / nbit_signature2); + fprintf(out, "total correlation: %lf\n", (double) (corr1 + corr2) / (nbit_signature1 + nbit_signature2)); + } + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_kim_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_kim_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,164 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, i, j, n; + int in_level; + double *input_watermark, *orig_watermark; + int sig_n, in_n; + double sig_a; + double sig_A; + int sig_l; + int sig_e, sig_f; + double s1, s2, s3; + double correlation; + char line[32]; + + int verbose = 0; + int correlation_only = 0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!sig) { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), sig); + if (strspn(line, "KISG") < 4) { + fprintf(stderr, "%s: original signature file %s invalid\n", progname, signature_name); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "KIWM") < 4) { + fprintf(stderr, "%s: watermark file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(sig, "%d\n", &sig_n); + fscanf(in, "%d\n", &in_n); + + if (sig_n <= 0 || sig_n > 32000) { + fprintf(stderr, "%s: invalid original watermark length %d\n", progname, sig_n); + exit(1); + } + + fscanf(sig, "%lf\n", &sig_a); + fscanf(sig, "%lf\n", &sig_A); + fscanf(sig, "%d\n", &sig_l); + fscanf(sig, "%d\n", &sig_e); + fscanf(sig, "%d\n", &sig_f); + fscanf(sig, "%*[^\n\r]\n"); + + orig_watermark = malloc(sig_n * sizeof(double)); + for (i = 0; i < sig_n; i++) + fscanf(sig, "%lf\n", &orig_watermark[i]); + fclose(sig); + + fscanf(in, "%d\n", &in_level); + input_watermark = malloc(in_n * sizeof(double)); + for (i = 0; i < in_n; i++) + fscanf(in, "%lf\n", &input_watermark[i]); + fclose(in); + + /* + * normalized correlation + * Craver, S., "Can Invisible Watermarks Resolve Rightful Ownership?", IBM Research Report, 1996, p. 5 + */ + + s1 = s2 = s3 = 0.0; + for (i = 0; i < in_n; i++) { + double in_x, sig_x; + + in_x = input_watermark[i]; + sig_x = orig_watermark[i % sig_n]; + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + } + + correlation = s1 / sqrt(s2 * s3); + + if (!correlation_only) + fprintf(out, "%s: correlation: %f\n", progname, correlation); + else + fprintf(out, "%f\n", correlation); + + fclose(out); + + free(orig_watermark); + free(input_watermark); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_koch_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_koch_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,142 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, i; + double quality = 0.0; + int quantization = 0; + int corr = 0, match = 0; + int verbose = 0; + + int correlation_only = 0; + + int seed; + char line[32]; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + fgets(line, sizeof(line), sig); + if (strspn(line, "KCSG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature1); + fscanf(sig, "%lf\n", &quality); + fscanf(sig, "%d\n", &quantization); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature1 = NBITSTOBYTES(nbit_signature1); + fread(signature1, sizeof(char), n_signature1, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + close(sig); + } + else { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "KCWM") >= 4) { + fscanf(in, "%d\n", &nbit_signature2); + n_signature2 = NBITSTOBYTES(nbit_signature2); + fread(signature2, sizeof(char), n_signature2, in); + fscanf(in, "\n"); + } + else { + fprintf(stderr, "%s: invalid watermark file %s\n", progname, input_name); + exit(1); + } + + if (verbose > 0) { + fprintf(stderr, "signature length: %d\n", nbit_signature1); + fprintf(stderr, "watermark length: %d\n", nbit_signature2); + } + + for (i = 0; i < nbit_signature2; i++) + if (get_signature1_bit(i % nbit_signature1) == get_signature2_bit(i)) + corr++, match++; + else + corr--; + + if (correlation_only) + fprintf(out, "%lf\n", (double) corr / nbit_signature2); + else { + fprintf(out, "bit matches: %d/%d\n", match, nbit_signature2); + fprintf(out, "correlation: %lf\n", (double) corr / nbit_signature2); + } + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_pgm.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_pgm.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,69 @@ +.\" +.\" cmp_pgm.1 - the *roff document processor man page source +.\" +.TH cmp_pgm 1 "98/07/08" "Watermarking, Version 1.0" +.SH NAME +cmp_pgm \- a program to create the difference image of two PGM images +.SH SYNOPSIS +.B cmp_pgm +[ +.B \-h +] +[ +.BI \-m \ number +] +[ +.BI \-o \ ofile +] +.BI \-i \ ifile +.I file +.SH DESCRIPTION +.B cmp_pgm +is a program to create the difference image of two PGM (portable graymap) +grayscale images. To compare PPM (portable pixmap) RGB color images, use the +.B cmp_ppm +program. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. Mandatory. +.TP +.BI \-m \ number +Multiplication factor to magnify differences between the to +original and input image. +Default value: 16. +.TP +.BI \-o \ ofile +Output image file to contain the difference image in PGM format. +.TP +.I file +Input image that is compared against +.I ifile. +Default: standard input. +.SH OUTPUT +The difference image in PGM format is written to standard output or, +optionally, to +.I ofile. +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B cmp_pgm +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.B cmp_ppm +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_pgm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_pgm.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,262 @@ +#include "wm.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-C] [-h] [-m n] [-o file] [-pP] [-r file] -i file file\n\n", progname); + fprintf(stderr, "\t-C\t\tprint PSNR value only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-m n\t\tmultiplication factor (default auto)\n"); + fprintf(stderr, "\t-o file\t\toutput file for difference image\n"); + fprintf(stderr, "\t-p\t\tprint PSNR, RMS and MSE\n"); + fprintf(stderr, "\t-P\t\tonly print PSNR, RMS and MSE, no difference image\n"); + fprintf(stderr, "\t-r file\t\tROI (region-of-interest) mask (default none)\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *roi = NULL; + + gray **input_image; + gray **orig_image; + gray **roi_image; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + char roi_name[MAXPATHLEN]; + + int in_cols, in_rows, in_format; + gray in_maxval; + int roi_cols, roi_rows, roi_format; + gray roi_maxval; + int orig_cols, orig_rows, orig_format; + gray orig_maxval; + int cols, rows, format; + gray maxval; + int col, row; + + int roisize = 0; + + int i; + int c; + + int m = 0; + int min, max; + + int print_psnr = 0; + int print_psnr_only = 0; + int print_psnr_value_only = 0; + double error = 0.0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "h?i:m:o:r:pPC")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'r': + if ((roi = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open ROI image file %s\n", progname, optarg); + exit(1); + } + strcpy(roi_name, optarg); + break; + case 'm': + m = atoi(optarg); + if (m <= 0) { + fprintf(stderr, "%s: multiplication factor %d out of range\n", progname, m); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + print_psnr = 1; + break; + case 'P': + print_psnr_only = 1; + break; + case 'C': + print_psnr_value_only = 1; + print_psnr_only = 1; + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + + if (orig) { + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + } + + if (roi) { + pgm_readpgminit(roi, &roi_cols, &roi_rows, &roi_maxval, &roi_format); + + if (in_cols != roi_cols || in_rows != roi_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of ROI image %s\n", progname, input_name, roi_name); + exit(1); + } + } + + cols = in_cols; + rows = in_rows; + format = in_format; + maxval = in_maxval; + + input_image = pgm_allocarray(cols, rows); + orig_image = pgm_allocarray(cols, rows); + roi_image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) { + pgm_readpgmrow(in, input_image[row], cols, in_maxval, in_format); + if (orig) + pgm_readpgmrow(orig, orig_image[row], cols, orig_maxval, orig_format); + else + memset(orig_image[row], cols, 0); + if (roi) + pgm_readpgmrow(roi, roi_image[row], cols, roi_maxval, roi_format); + else + memset(roi_image[row], cols, PGM_MAXMAXVAL); + } + + fclose(in); + if (orig) fclose(orig); + if (roi) fclose(roi); + + max = 0; + min = PGM_MAXMAXVAL; + + for (row = 0; row < rows; row++) { + gray *pi = input_image[row]; + gray *po = orig_image[row]; + gray *pr = roi_image[row]; + + for (col = 0; col < cols; col++) { + int diff = abs(*pi - *po); + int inroi = (!roi || *pr > 0); + + pi++; + po++; + pr++; + + if (roi && !inroi) + continue; + + roisize++; + + error += sqr(diff); + if (diff < min) min = diff; + if (diff > max) max = diff; + + } + } + + for (row = 0; row < rows; row++) { + gray *pi = input_image[row]; + gray *po = orig_image[row]; + gray *pr = roi_image[row]; + + for (col = 0; col < cols; col++) { + int diff = abs(*pi - *po); + int inroi = (!roi || *pr > 0); + + if (!inroi) { + *pi = 0; + } + else { + if (m > 0) + *pi = PIXELRANGE(diff * m); + else + *pi = PIXELRANGE((double) (diff - min) / (double) (max - min) * maxval); + } + + pi++; + po++; + pr++; + + } + } + + if (!print_psnr_only) { + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, input_image[row], cols, maxval, 0); + + fclose(out); + } + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + pgm_freearray(roi_image, rows); + + if (print_psnr || print_psnr_only) { + double mse = (roisize) ? error / (double) roisize : 0; + double rmse = sqrt(mse); + double psnr = (rmse) ? 20.0 * log(255.0 / rmse) / log(10.0) : 0; + FILE *print = print_psnr_only ? out : stderr; + if (!print_psnr_value_only) { + if (roi) + fprintf(print, "ROI size: %d\n", roisize); + if (mse > 0.0) + fprintf(print, "PSNR: %lf dB\n", psnr); + else + fprintf(print, "PSNR: inf\n"); + fprintf(print, "RMSE: %lf\n", rmse); + fprintf(print, "MSE: %lf\n", mse); + fprintf(print, "dmin, dmax: %d, %d\n", min, max); + } + else + fprintf(print, "%lf\n", mse > 0.0 ? psnr : 100.0); + } + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_ppm.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_ppm.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,100 @@ +.\" +.\" cmp_ppm.1 - the *roff document processor man page source +.\" +.TH cmp_ppm 1 "98/07/08" "Watermarking, Version 1.0" +.SH NAME +cmp_ppm \- a program to create the difference image of two PGM images +.SH SYNOPSIS +.B cmp_ppm +[ +.BI \-c \ name +] +[ +.B \-h +] +[ +.BI \-m \ number +] +[ +.BI \-o \ ofile +] +.BI \-i \ ifile +.I file +.SH DESCRIPTION +.B cmp_ppm +is a program to create the difference image of two PPM (portable pixmap) +RGB color images. To compare PGM (portable graymap) grayscale images, use +the +.B cmp_pgm +program. +.PP +The color components to compare are specified with the +.BI \-c \ name +option, where +.I name +is one of the following: +.TP +.B red +The red color component. +.TP +.B green +The green color component. +.TP +.B blue +The blue color component. +.PP +Multiple color components are allowed. Specifying only the inital letter +of a color component is sufficient. +Per default +.B cmp_ppm +compares the luminance value of the images. This operation may be +selected explicitly with the +.BI \-c \ luminance +option. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.SH OPTIONS +.TP +.BI \-c \ name +Specifies color component(s) or luminance to compare. Default: luminance. +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. Mandatory. +.TP +.BI \-m \ number +Multiplication factor to magnify differences between the to +original and input image. +Default value: 16. +.TP +.BI \-o \ ofile +Output image file to contain the difference image in PPM format. +.TP +.I file +Input image that is compared against +.I ifile. +Default: standard input. +.SH OUTPUT +The difference image in PPM format is written to standard output or, +optionally, to +.I ofile. +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B cmp_ppm +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.B cmp_ppm +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_wang_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_wang_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,154 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c; + int sig_n, in_n; + double sig_a, sig_b; + int sig_e, sig_f; + double s1, s2, s3; + char line[32]; + + int verbose = 0; + int correlation_only = 0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!sig) { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), sig); + if (strspn(line, "WGSG") < 4) { + fprintf(stderr, "%s: original signature file %s invalid\n", progname, signature_name); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "WGWM") < 4) { + fprintf(stderr, "%s: watermark file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(sig, "%d\n", &sig_n); + fscanf(in, "%d\n", &in_n); + if (sig_n != in_n) { + fprintf(stderr, "%s: watermark length mismatch (original %d, input %d)\n", progname, sig_n, in_n); + exit(1); + } + if (sig_n <= 0 || sig_n > 32000) { + fprintf(stderr, "%s: invalid original watermark length %d\n", progname, sig_n); + exit(1); + } + if (in_n != sig_n) { + fprintf(stderr, "%s: invalid watermark length %d, does not match signature length\n", progname, in_n); + exit(1); + } + + fscanf(sig, "%lf\n", &sig_a); + fscanf(sig, "%lf\n", &sig_b); + fscanf(sig, "%d\n", &sig_e); + fscanf(sig, "%d\n", &sig_f); + fscanf(sig, "%*[^\n\r]\n"); + + /* + * normalized correlation + * Craver, S., "Can Invisible Watermarks Resolve Rightful Ownership?", IBM Research Report, 1996, p. 5 + */ + + s1 = s2 = s3 = 0.0; + while (in_n > 0) { + double sig_x, in_x; + + fscanf(sig, "%lf\n", &sig_x); + fscanf(in, "%lf\n", &in_x); + + if (verbose >= 1) { + fprintf(stderr, "orig %f input %f\n", sig_x, in_x); + } + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + + in_n--; + } + + fprintf(out, "%f\n", s1 / sqrt(s2 * s3)); + + fclose(sig); + fclose(out); + fclose(in); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_xia_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_xia_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,212 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, i, j, n; + int in_level; + double *cumul_watermark, *orig_watermark; + int *cumul_watermark_count; + int sig_n, in_n; + double sig_a; + int sig_l; + int sig_e, sig_f; + double s1, s2, s3; + double correlation, maxcorrelation; + char line[32]; + + int verbose = 0; + int correlation_only = 0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!sig) { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), sig); + if (strspn(line, "XASG") < 4) { + fprintf(stderr, "%s: original signature file %s invalid\n", progname, signature_name); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "XAWM") < 4) { + fprintf(stderr, "%s: watermark file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(sig, "%d\n", &sig_n); + fscanf(in, "%d\n", &in_n); + if (sig_n != in_n) { + fprintf(stderr, "%s: watermark length mismatch (original %d, input %d)\n", progname, sig_n, in_n); + exit(1); + } + if (sig_n <= 0 || sig_n > 32000) { + fprintf(stderr, "%s: invalid original watermark length %d\n", progname, sig_n); + exit(1); + } + if (in_n != sig_n) { + fprintf(stderr, "%s: invalid watermark length %d, does not match signature length\n", progname, in_n); + exit(1); + } + + fscanf(sig, "%lf\n", &sig_a); + fscanf(sig, "%d\n", &sig_l); + fscanf(sig, "%d\n", &sig_e); + fscanf(sig, "%d\n", &sig_f); + fscanf(sig, "%*[^\n\r]\n"); + + orig_watermark = malloc(sig_n * sizeof(double)); + for (i = 0; i < sig_n; i++) + fscanf(sig, "%lf\n", &orig_watermark[i]); + fclose(sig); + + fscanf(in, "%d\n", &in_level); + + cumul_watermark = malloc(in_n * sizeof(double)); + cumul_watermark_count = malloc(in_n * sizeof(int)); + + for (i = 0; i < in_n; i++) { + cumul_watermark_count[i] = 0; + cumul_watermark[i] = 0.0; + } + + /* + * normalized correlation + * Craver, S., "Can Invisible Watermarks Resolve Rightful Ownership?", IBM Research Report, 1996, p. 5 + */ + + maxcorrelation = -10000.0; + for (i = 0; i < in_level; i++) { + fscanf(in, "%d\n", &n); + + s1 = s2 = s3 = 0.0; + for (j = 0; j < n; j++) { + double in_x, sig_x; + + sig_x = orig_watermark[j % sig_n]; + fscanf(in, "%lf\n", &in_x); + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + + if (verbose > 2) + fprintf(stderr, "%s: level %d; orig %f input %f\n", progname, i, sig_x, in_x); + + cumul_watermark[j % in_n] += in_x; + cumul_watermark_count[j % in_n]++; + } + + correlation = s1 / sqrt(s2 * s3); + if (correlation > maxcorrelation) + maxcorrelation = correlation; + + if (!correlation_only) + fprintf(out, "%s: correlation subband %d: %f\n", progname, i, correlation); + } + + s1 = s2 = s3 = 0.0; + for (i = 0; i < in_n; i++) { + double in_x, sig_x; + + if (cumul_watermark_count[i] <= 0) continue; + in_x = cumul_watermark[i] / (double) cumul_watermark_count[i]; + sig_x = orig_watermark[i]; + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + } + + correlation = s1 / sqrt(s2 * s3); + if (!correlation_only) + fprintf(out, "%s: cumultative correlation: %f\n", progname, correlation); + + if (correlation > maxcorrelation) + maxcorrelation = correlation; + + if (!correlation_only) + fprintf(out, "%s: max. correlation: %f\n", progname, maxcorrelation); + else + fprintf(out, "%f\n", maxcorrelation); + + fclose(out); + fclose(in); + + free(orig_watermark); + free(cumul_watermark); + free(cumul_watermark_count); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_xie_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_xie_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,150 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int correlation_only = 0; + + int c, i; + int corr = 0, match = 0; + int verbose = 0; + int filter = 0; + int method = 0; + int level = 0; + double alpha = 0.0; + double intensity = 0.0; + int subband = 0; + char filter_name[MAXPATHLEN] = ""; + + int seed; + char line[32]; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + fgets(line, sizeof(line), sig); + if (strspn(line, "XESG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature1); + fscanf(sig, "%lf\n", &alpha); + fscanf(sig, "%d\n", &method); + fscanf(sig, "%d\n", &filter); + fscanf(sig, "%[^\n\r]\n", &filter_name); + fscanf(sig, "%d\n", &level); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature1 = NBITSTOBYTES(nbit_signature1); + fread(signature1, sizeof(char), n_signature1, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + close(sig); + } + else { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "XEWM") >= 4) { + fscanf(in, "%d\n", &nbit_signature2); + n_signature2 = NBITSTOBYTES(nbit_signature2); + fread(signature2, sizeof(char), n_signature2, in); + fscanf(in, "\n"); + } + else { + fprintf(stderr, "%s: invalid watermark file %s\n", progname, input_name); + exit(1); + } + + if (verbose > 0) { + fprintf(stderr, "signature length: %d\n", nbit_signature1); + fprintf(stderr, "watermark length: %d\n", nbit_signature2); + } + + for (i = 0; i < nbit_signature2; i++) + if (get_signature1_bit(i % nbit_signature1) == get_signature2_bit(i)) + corr++, match++; + else + corr--; + + if (correlation_only) + fprintf(out, "%lf\n", (double) corr / nbit_signature2); + else { + fprintf(out, "bit matches: %d/%d\n", match, nbit_signature2); + fprintf(out, "correlation: %lf\n", (double) corr / nbit_signature2); + } + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/cmp_zhu_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/cmp_zhu_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,210 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-C] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-C\t\toutput correlation only\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, i, j, n; + int in_level; + double *cumul_watermark, *orig_watermark; + int *cumul_watermark_count; + int sig_n, in_n; + double sig_a; + int sig_l; + int sig_e, sig_f; + char line[32]; + double correlation, maxcorrelation; + double s1, s2, s3; + + int verbose = 0; + int correlation_only = 0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "h?Co:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'C': + correlation_only = 1; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "r")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!sig) { + fprintf(stderr, "%s: original signature file not specified, use -s file option\n", progname); + exit(1); + } + + fgets(line, sizeof(line), sig); + if (strspn(line, "ZHSG") < 4) { + fprintf(stderr, "%s: original signature file %s invalid\n", progname, signature_name); + exit(1); + } + + fgets(line, sizeof(line), in); + if (strspn(line, "ZHWM") < 4) { + fprintf(stderr, "%s: watermark file %s invalid\n", progname, input_name); + exit(1); + } + + fscanf(sig, "%d\n", &sig_n); + fscanf(in, "%d\n", &in_n); + if (sig_n != in_n) { + fprintf(stderr, "%s: watermark length mismatch (original %d, input %d)\n", progname, sig_n, in_n); + exit(1); + } + if (sig_n <= 0 || sig_n > 32000) { + fprintf(stderr, "%s: invalid original watermark length %d\n", progname, sig_n); + exit(1); + } + if (in_n != sig_n) { + fprintf(stderr, "%s: invalid watermark length %d, does not match signature length\n", progname, in_n); + exit(1); + } + + fscanf(sig, "%lf\n", &sig_a); + fscanf(sig, "%d\n", &sig_l); + fscanf(sig, "%d\n", &sig_e); + fscanf(sig, "%d\n", &sig_f); + fscanf(sig, "%*[^\n\r]\n"); + + orig_watermark = malloc(sig_n * sizeof(double)); + for (i = 0; i < sig_n; i++) + fscanf(sig, "%lf\n", &orig_watermark[i]); + fclose(sig); + + fscanf(in, "%d\n", &in_level); + + cumul_watermark = malloc(in_n * sizeof(double)); + cumul_watermark_count = malloc(in_n * sizeof(int)); + + for (i = 0; i < in_n; i++) { + cumul_watermark_count[i] = 0; + cumul_watermark[i] = 0.0; + } + + /* + * normalized correlation + * Craver, S., "Can Invisible Watermarks Resolve Rightful Ownership?", IBM Research Report, 1996, p. 5 + */ + maxcorrelation = -10000.0; + for (i = 0; i < in_level; i++) { + fscanf(in, "%d\n", &n); + + s1 = s2 = s3 = 0.0; + for (j = 0; j < n; j++) { + double in_x, sig_x; + + sig_x = orig_watermark[j]; + fscanf(in, "%lf\n", &in_x); + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + + if (verbose > 2) + fprintf(stderr, "%s: level %d; orig %f input %f\n", progname, i, sig_x, in_x); + + cumul_watermark[j % in_n] += in_x; + cumul_watermark_count[j % in_n]++; + } + + correlation = s1 / sqrt(s2 * s3); + if (correlation > maxcorrelation) + maxcorrelation = correlation; + + if (!correlation_only) + fprintf(out, "%s: correlation level %d: %f\n", progname, i, correlation); + } + + s1 = s2 = s3 = 0.0; + for (i = 0; i < in_n; i++) { + double in_x, sig_x; + + in_x = cumul_watermark[i] / (double) cumul_watermark_count[i]; + sig_x = orig_watermark[i]; + + s1 += sig_x * in_x; + s2 += in_x * in_x; + s3 += sig_x * sig_x; + } + + correlation = s1 / sqrt(s2 * s3); + if (!correlation_only) + fprintf(out, "%s: cumultative correlation: %f\n", progname, correlation); + + if (correlation > maxcorrelation) + maxcorrelation = correlation; + + if (!correlation_only) + fprintf(out, "%s: max. correlation: %f\n", progname, maxcorrelation); + else + fprintf(out, "%f\n", maxcorrelation); + + fclose(out); + fclose(in); + + free(orig_watermark); + free(cumul_watermark); + free(cumul_watermark_count); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/coeff.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/coeff.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,72 @@ +#include "wm.h" +#include "coeff.h" + +double **alloc_coeffs(int cols, int rows) { + double **p; + int i; + + p = (double **)malloc(rows * sizeof(double *)); + if (!p) { +#ifdef DEBUG + fprintf(stderr, "alloc_coeffs(): malloc() failed\n"); + exit(1); +#else + return NULL; +#endif + } + p[0] = (double *) malloc(rows * cols * sizeof(double)); + if (!p[0]) { +#ifdef DEBUG + fprintf(stderr, "alloc_coeffs(): malloc() failed\n"); + exit(1); +#else + free(p); + return NULL; +#endif + } + for (i = 1; i < rows; i++) { + p[i] = &(p[0][i * cols]); + } + + return p; +} + +void free_coeffs(double **coeffs) { + free(coeffs[0]); + free(coeffs); +} + +double **alloc_coeffs_8x8() { + return alloc_coeffs(8, 8); +} + +void print_coeffs_8x8(double **coeffs) { + int i, j; + + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) + fprintf(stderr, "%8.2f ", coeffs[i][j]); + fprintf(stderr, "\n"); + } +} + +void print_coeffs(double **coeffs, int c, int r, int w, int h) { + int i, j; + double *p; + +#ifdef DEBUG + if (!coeffs) { + fprintf(stderr, "print_coeffs(): NULL pixels\n"); + } + if (w <= 0 || h <= 0 || c < 0 || r < 0) { + fprintf(stderr, "print_coeffs(): block dimension out of range\n"); + } +#endif + + for (j = r; j < r + h; j++) { + p = &coeffs[j][c]; + for (i = 0; i < w; i++) + fprintf(stderr, "%8.2f ", *(p++)); + fprintf(stderr, "\n"); + } +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/coeff.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/coeff.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,12 @@ +#ifndef COEFF_H +#define COEFF_H + +#include "wm.h" + +double **alloc_coeffs(int cols, int rows); +double **alloc_coeffs_8x8(); +void free_coeffs(double **coeffs); +void print_coeffs_8x8(double **coeffs); +void print_coeffs(double **coeffs, int c, int r, int w, int h); + +#endif diff -r 000000000000 -r be303a3f5ea8 Meerwald/coord.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/coord.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,75 @@ +#include +#include +#include "coord.h" + +struct coords *alloc_coords(int n) { + struct coords *c; + + if (c = malloc(sizeof(struct coords))) + init_coords(c, n); +#ifdef DEBUG + else + fprintf(stderr, "alloc_coords(): malloc failed\n"); +#endif + + return c; +} + +void free_coords(struct coords *c) { + +#ifdef DEBUG + if (!c) + fprintf(stderr, "free_coords(): got NULL pointer\n"); +#endif + + free(c->values); + free(c); +} + +int init_coords(struct coords *c, int n) { + +#ifdef DEBUG + if (!c) + fprintf(stderr, "init_coords(): got NULL poiner\n"); + + if (n <= 0) + fprintf(stderr, "init_coords(): n out of range\n"); +#endif + + c->count = 0; + c->max = n; + + if (c->values = malloc(n * sizeof(struct coord))) + return 0; + else + return -1; +} + +int add_coord(struct coords *c, int x, int y) { + struct coord *v; + int n; + +#ifdef DEBUG + if (!c) + fprintf(stderr, "add_coord(): got NULL pointer\n"); + + if (c->count >= c->max) + fprintf(stderr, "add_coord(): maximum reached\n"); +#endif + + v = c->values; + + for (n = 0; n < c->count; v++, n++) + if (v->x == x && v->y == y) break; + + if (n == c->count) { + v->x = x; + v->y = y; + c->count++; + return 0; + } + else + return -1; +} + + diff -r 000000000000 -r be303a3f5ea8 Meerwald/coord.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/coord.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,20 @@ +#ifndef COORD_H +#define COORD_H + +struct coord { + int x; + int y; +}; + +struct coords { + int count; + int max; + struct coord *values; +}; + +struct coords *alloc_coords(int n); +void free_coords(struct coords *c); +int init_coords(struct coords *c, int n); +int add_coord(struct coords *c, int x, int y); + +#endif diff -r 000000000000 -r be303a3f5ea8 Meerwald/dct.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/dct.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,643 @@ +#include "wm.h" +#include "dct.h" + +#define INVROOT2 0.7071067814 +#define SWAP(A, B) {double t = A; A = B; B = t;} + +int N; +int M; + +double *dct_NxN_tmp = NULL; +double *dct_NxN_costable = NULL; +int dct_NxN_log2N = 0; + +static const unsigned int JPEG_lumin_quant_table[NJPEG][NJPEG] = { + {16, 11, 10, 16, 24, 40, 51, 61}, + {12, 12, 14, 19, 26, 58, 60, 55}, + {14, 13, 16, 24, 40, 57, 69, 56}, + {14, 17, 22, 29, 51, 87, 80, 62}, + {18, 22, 37, 56, 68, 109, 103, 77}, + {24, 35, 55, 64, 81, 104, 113, 92}, + {49, 64, 78, 87, 103, 121, 120, 101}, + {72, 92, 95, 98, 112, 100, 103, 99}}; + +static const unsigned int JPEG_chromin_quant_table[NJPEG][NJPEG] = { + {17, 18, 24, 47, 99, 99, 99, 99}, + {18, 21, 26, 66, 99, 99, 99, 99}, + {24, 26, 56, 99, 99, 99, 99, 99}, + {47, 66, 99, 99, 99, 99, 99, 99}, + {99, 99, 99, 99, 99, 99, 99, 99}, + {99, 99, 99, 99, 99, 99, 99, 99}, + {99, 99, 99, 99, 99, 99, 99, 99}, + {99, 99, 99, 99, 99, 99, 99, 99}}; + +static void initcosarray() +{ + int i,group,base,item,nitems,halfN; + double factor; + + dct_NxN_log2N = -1; + do{ + dct_NxN_log2N++; + if ((1<N){ + fprintf(stderr, "dct_NxN: %d not a power of 2\n", N); + exit(1); + } + }while((1<>1; + while(j>m){ + j=j-m; + m=(m+1)>>1; + } + j=j+m; + } +} + +static void inv_sums(double *f) +{ + int stepsize,stage,curptr,nthreads,thread,step,nsteps; + + for(stage=1; stage <=dct_NxN_log2N-1; stage++){ + nthreads = 1<<(stage-1); + stepsize = nthreads<<1; + nsteps = (1<<(dct_NxN_log2N-stage)) - 1; + for(thread=1; thread<=nthreads; thread++){ + curptr=N-thread; + for(step=1; step<=nsteps; step++){ + f[curptr] += f[curptr-stepsize]; + curptr -= stepsize; + } + } + } +} + +static void fwd_sums(double *f) +{ + int stepsize,stage,curptr,nthreads,thread,step,nsteps; + + for(stage=dct_NxN_log2N-1; stage >=1; stage--){ + nthreads = 1<<(stage-1); + stepsize = nthreads<<1; + nsteps = (1<<(dct_NxN_log2N-stage)) - 1; + for(thread=1; thread<=nthreads; thread++){ + curptr=nthreads +thread-1; + for(step=1; step<=nsteps; step++){ + f[curptr] += f[curptr+stepsize]; + curptr += stepsize; + } + } + } +} + +static void scramble(double *f,int len){ + int i,ii1,ii2; + + bitrev(f,len); + bitrev(&f[0], len>>1); + bitrev(&f[len>>1], len>>1); + ii1=len-1; + ii2=len>>1; + for(i=0; i<(len>>2); i++){ + SWAP(f[ii1], f[ii2]); + ii1--; + ii2++; + } +} + +static void unscramble(double *f,int len) +{ + int i,ii1,ii2; + + ii1 = len-1; + ii2 = len>>1; + for(i=0; i<(len>>2); i++){ + SWAP(f[ii1], f[ii2]); + ii1--; + ii2++; + } + bitrev(&f[0], len>>1); + bitrev(&f[len>>1], len>>1); + bitrev(f,len); +} + +static void inv_butterflies(double *f) +{ + int stage,ii1,ii2,butterfly,ngroups,group,wingspan,increment,baseptr; + double Cfac,T; + + for(stage=1; stage<=dct_NxN_log2N;stage++){ + ngroups=1<<(dct_NxN_log2N-stage); + wingspan=1<<(stage-1); + increment=wingspan<<1; + for(butterfly=1; butterfly<=wingspan; butterfly++){ + Cfac = dct_NxN_costable[wingspan+butterfly-1]; + baseptr=0; + for(group=1; group<=ngroups; group++){ + ii1=baseptr+butterfly-1; + ii2=ii1+wingspan; + T=Cfac * f[ii2]; + f[ii2]=f[ii1]-T; + f[ii1]=f[ii1]+T; + baseptr += increment; + } + } + } +} + +static void fwd_butterflies(double *f) +{ + int stage,ii1,ii2,butterfly,ngroups,group,wingspan,increment,baseptr; + double Cfac,T; + + for(stage=dct_NxN_log2N; stage>=1;stage--){ + ngroups=1<<(dct_NxN_log2N-stage); + wingspan=1<<(stage-1); + increment=wingspan<<1; + for(butterfly=1; butterfly<=wingspan; butterfly++){ + Cfac = dct_NxN_costable[wingspan+butterfly-1]; + baseptr=0; + for(group=1; group<=ngroups; group++){ + ii1=baseptr+butterfly-1; + ii2=ii1+wingspan; + T= f[ii2]; + f[ii2]=Cfac *(f[ii1]-T); + f[ii1]=f[ii1]+T; + baseptr += increment; + } + } + } +} + +static void ifct_noscale(double *f) +{ + f[0] *= INVROOT2; + inv_sums(f); + bitrev(f,N); + inv_butterflies(f); + unscramble(f,N); +} + +static void fct_noscale(double *f) +{ + scramble(f,N); + fwd_butterflies(f); + bitrev(f,N); + fwd_sums(f); + f[0] *= INVROOT2; +} + +void fdct_NxN(gray **pixels, double **dcts) { + int u,v; + double two_over_sqrtncolsnrows = 2.0/sqrt((double) N*M); + + for (u=0; u < N; u++) + for (v=0; v < M; v++) + dcts[u][v] = ((int) pixels[u][v]-128); + + for (u=0; u<=M-1; u++){ + fct_noscale(dcts[u]); + } + for (v=0; v<=N-1; v++){ + for (u=0; u<=M-1; u++){ + dct_NxN_tmp[u] = dcts[u][v]; + } + fct_noscale(dct_NxN_tmp); + for (u=0; u<=M-1; u++){ + dcts[u][v] = dct_NxN_tmp[u]*two_over_sqrtncolsnrows; + } + } +} + +void idct_NxN(double **dcts, gray **pixels) { + int u,v; + double two_over_sqrtncolsnrows = 2.0/sqrt((double) N*M); + + double **tmp; + + tmp = alloc_coeffs(N, N); + for (u=0;u rint(log(MIN(cols, rows))/log(2.0)) - 2) { + fprintf(stderr, "init_dwt(): level parameter does not match image width/height\n"); + return; + } +#endif + + if (dwt_filters && level != dwt_levels) { + free(dwt_filters); + dwt_filters = NULL; + } + + dwt_levels = level; + + if (!dwt_filters) + dwt_filters = calloc(level + 1, sizeof(FilterGH)); + + for (i = 0; i < level + 1; i++) + dwt_filters[i] = (dwt_allfilters->filter)[filter]; + + dwt_filter = filter; + dwt_method = method; + dwt_cols = cols; + dwt_rows = rows; +} + +Image_tree fdwt(gray **pixels) { + Image image; + Image_tree tree; + int i, j; + + image = new_image(dwt_cols, dwt_rows); + + for (i = 0; i < dwt_rows; i++) + for (j = 0; j < dwt_cols; j++) + set_pixel(image, j, i, pixels[i][j]); + + tree = wavelettransform(image, dwt_levels, dwt_filters, dwt_method); + free_image(image); + + return tree; +} + +Image_tree fdwt_wp(gray **pixels) { + Image image; + Image_tree tree; + int i, j; + + image = new_image(dwt_cols, dwt_rows); + + for (i = 0; i < dwt_rows; i++) + for (j = 0; j < dwt_cols; j++) + set_pixel(image, j, i, pixels[i][j]); + + tree = wavelettransform_wp(image, dwt_levels, dwt_filters, dwt_method); + free_image(image); + + return tree; +} + +void idwt(Image_tree dwts, gray **pixels) { + Image image; + int i, j; + + image = inv_transform(dwts, dwt_filters, dwt_method + 1); + + for (i = 0; i < dwt_rows; i++) + for (j = 0; j < dwt_cols; j++) + pixels[i][j] = PIXELRANGE((int) (get_pixel(image, j, i) + 0.5)); + + free_image(image); +} + +void idwt_wp(Image_tree dwts, gray **pixels) { + Image image; + int i, j; + + image = inv_transform(dwts, dwt_filters, dwt_method + 1); + + for (i = 0; i < dwt_rows; i++) + for (j = 0; j < dwt_cols; j++) + pixels[i][j] = PIXELRANGE((int) (get_pixel(image, j, i) + 0.5)); + + free_image(image); +} + +int gen_pollen_filter(double *filter, double alpha, double beta, int which) { + int i, j, k, filterlength; + double tf[6]; + + /* parameter alpha, beta have to be in range -Pi .. Pi */ + if (alpha < -M_PI || alpha >= M_PI) { + fprintf(stderr, "alpha %f out of range\n", alpha); + return -1; + } + + if (beta < -M_PI || beta >= M_PI) { + fprintf(stderr, "beta %f out of range\n", beta); + return -1; + } + + /* generate Pollen filter coefficients, see http://www.dfw.net/~cody for details */ + tf[0] = ((1.0 + cos(alpha) + sin(alpha)) * (1.0 - cos(beta) - sin(beta)) + 2.0 * sin(beta) * cos(alpha)) / 4.0; + tf[1] = ((1.0 - cos(alpha) + sin(alpha)) * (1.0 + cos(beta) - sin(beta)) - 2.0 * sin(beta) * cos(alpha)) / 4.0; + tf[2] = (1.0 + cos(alpha - beta) + sin(alpha - beta)) / 2.0; + tf[3] = (1.0 + cos(alpha - beta) - sin(alpha - beta)) / 2.0; + tf[4] = 1.0 - tf[0] - tf[2]; + tf[5] = 1.0 - tf[1] - tf[3]; + + /* set close-to-zero filter coefficients to zero */ + for (i = 0; i < 6; i++) + if (fabs(tf[i]) < 1.0e-15) tf[i] = 0.0; + + /* find the first non-zero wavelet coefficient */ + i = 0; + while (tf[i] == 0.0) i++; + + /* find the last non-zero wavelet coefficient */ + j = 5; + while (tf[j] == 0.0) j--; + + filterlength = j - i + 1; + for (k = 0; k < filterlength; k++) + switch (which) { + case FILTERH: + filter[k] = tf[j--] / 2.0; + break; + case FILTERG: + filter[k] = (double) (((i & 0x01) * 2) - 1) * tf[i++] / 2.0; + break; + case FILTERHi: + filter[k] = tf[j--]; + break; + case FILTERGi: + filter[k] = (double) (((i & 0x01) * 2) - 1) * tf[i++]; + break; + default: + return -1; + } + + while (k < 6) + filter[k++] = 0.0; + + return filterlength; +} + +void dwt_pollen_filter(double alpha, double beta) { + FilterGH filter; + int i; + + filter = malloc(sizeof(struct FilterGHStruct)); +#ifdef DEBUG + if (!filter) { + fprintf(stderr, "dwt_pollen_filter(): malloc failed()\n"); + return; + } +#endif + + filter->type = FTOther; + filter->name = "pollen"; + + filter->g = new_filter(6); + filter->g->type = FTSymm; + filter->g->hipass = 1; + filter->g->len = gen_pollen_filter(filter->g->data, alpha, beta, FILTERG); + filter->g->start = -filter->g->len / 2; + filter->g->end = filter->g->len / 2 - 1; + + filter->h = new_filter(6); + filter->h->type = FTSymm; + filter->h->hipass = 0; + filter->h->len = gen_pollen_filter(filter->h->data, alpha, beta, FILTERH); + filter->h->start = -filter->h->len / 2; + filter->h->end = filter->h->len / 2 - 1; + + filter->gi = new_filter(6); + filter->gi->type = FTSymm; + filter->gi->hipass = 1; + filter->gi->len = gen_pollen_filter(filter->gi->data, alpha, beta, FILTERGi); + filter->gi->start = -filter->gi->len / 2; + filter->gi->end = filter->gi->len / 2 - 1; + + filter->hi = new_filter(6); + filter->hi->type = FTSymm; + filter->hi->hipass = 0; + filter->hi->len = gen_pollen_filter(filter->hi->data, alpha, beta, FILTERHi); + filter->hi->start = -filter->hi->len / 2; + filter->hi->end = filter->hi->len / 2 - 1; + +#ifdef DEBUG + if (dwt_levels <= 0) { + fprintf(stderr, "dwt_pollen_filter(): level invalid - set to zero\n"); + return; + } +#endif + +#ifdef DEBUG + if (!dwt_filters) { + fprintf(stderr, "dwt_pollen_filter(): wm_dwt not initialized, call init_dwt() first\n"); + return; + } +#endif + + for (i = 0; i < dwt_levels + 1; i++) + dwt_filters[i] = filter; +} + +int gen_param_filter(double *filter, int n, double alpha[], int which) { + int i, j, k, filterlength; + double *tf, *t; + + tf = malloc(2 * (n + 1) * sizeof(double)); + t = malloc(2 * (n + 1) * sizeof(double)); + if (!tf) { + fprintf(stderr, "gen_param_filter(): malloc() failed\n"); + return -1; + } + + tf[0] = 1.0 / sqrt(2.0); + tf[1] = 1.0 / sqrt(2.0); + + for (k = 0; k < n; k++) { + for (i = 0; i < 2 * (k + 2); i++) { + +#define H(X) (((X) < 0 || (X) >= 2 * (k + 1)) ? 0.0 : tf[X]) + + t[i] = 0.5 * (H(i - 2) + H(i) + + cos(alpha[k]) * (H(i - 2) - H(i)) + + (i & 1 ? -1.0 : 1.0) * sin(alpha[k]) * (H(2 * (k + 2) - i - 1) - H(2 * (k + 2) - i - 3))); + } + for (i = 0; i < 2 * (k + 2); i++) tf[i] = t[i]; + } + + /* set close-to-zero filter coefficients to zero */ + for (i = 0; i < 2 * (n + 1) ; i++) + if (fabs(tf[i]) < 1.0e-15) tf[i] = 0.0; + + /* find the first non-zero wavelet coefficient */ + i = 0; + while (tf[i] == 0.0) i++; + + /* find the last non-zero wavelet coefficient */ + j = 2 * (n + 1) - 1; + while (tf[j] == 0.0) j--; + + filterlength = j - i + 1; + for (k = 0; k < filterlength; k++) + switch (which) { + case FILTERG: + case FILTERGi: + filter[k] = (double) (((i+1 & 0x01) * 2) - 1) * tf[i++]; + break; + case FILTERH: + case FILTERHi: + filter[k] = tf[j--]; + break; + default: + return -1; + } + + while (k < 2 * (n + 1)) + filter[k++] = 0.0; + + return filterlength; +} + +void dwt_param_filter(double alpha[], int n) { + FilterGH filter; + int i; + + filter = malloc(sizeof(struct FilterGHStruct)); +#ifdef DEBUG + if (!filter) { + fprintf(stderr, "dwt_param_filter(): malloc failed()\n"); + return; + } +#endif + + filter->type = FTOrtho; + filter->name = "param"; + + filter->g = new_filter(2 * (n + 1)); + filter->g->type = FTSymm; + filter->g->hipass = 1; + filter->g->len = gen_param_filter(filter->g->data, n, alpha, FILTERG); + filter->g->start = -filter->g->len / 2; + filter->g->end = filter->g->len / 2 - 1; + + filter->h = new_filter(2 * (n + 1)); + filter->h->type = FTSymm; + filter->h->hipass = 0; + filter->h->len = gen_param_filter(filter->h->data, n, alpha, FILTERH); + filter->h->start = -filter->h->len / 2; + filter->h->end = filter->h->len / 2 - 1; + +#ifdef DEBUG + if (dwt_levels <= 0) { + fprintf(stderr, "dwt_pollen_filter(): level invalid - set to zero\n"); + return; + } +#endif + +#ifdef DEBUG + if (!dwt_filters) { + fprintf(stderr, "dwt_pollen_filter(): wm_dwt not initialized, call init_dwt() first\n"); + return; + } +#endif + + for (i = 0; i < dwt_levels + 1; i++) + dwt_filters[i] = filter; +} + +void done_dwt() { +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/dwt.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/dwt.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,24 @@ +#ifndef DWT_H +#define DWT_H + +#include "wm.h" +#include "pgm.h" +#include "wavelet.h" + +#define FILTERG 1 +#define FILTERH 2 +#define FILTERGi 3 +#define FILTERHi 4 + +void init_dwt(int cols, int rows, const char *filter_name, int filter, int level, int method); +Image_tree fdwt(gray **input); +Image_tree fdwt_wp(gray **input); +void idwt(Image_tree dwts, gray **output); +void idwt_wp(Image_tree dwts, gray **output); +int gen_pollen_filter(double *filter, double alpha, double beta, int which); +void dwt_pollen_filter(double alpha, double beta); +int gen_param_filter(double *filter, int n, double alpha[], int which); +void dwt_param_filter(double alpha[], int n); +void done_dwt(); + +#endif diff -r 000000000000 -r be303a3f5ea8 Meerwald/dwt_util.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/dwt_util.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,159 @@ +#include "wm.h" +#include "dwt_util.h" +#include + +void copy_coeffs_from_dwt(double ** block_coeffs, double ** dwt_coeffs, +int level, int band, int width, int height) { + int i, j; + int size = width >> level; + int h = (band > 2) ? size : 0; + int w = (band & 1) ? 0 : size; + + for (i = 0; i < size; i++) + for (j = 0; j < size; j++) + block_coeffs[i][j] = dwt_coeffs[h + i][w + j]; +} + +void copy_coeffs_to_dwt(double ** dwt_coeffs, double ** block_coeffs, +int level, int band, int width, int height) { + int i, j; + int size = width >> level; + int h = (band > 2) ? size : 0; + int w = (band & 1) ? 0 : size; + + for (i = 0; i < size; i++) + for (j = 0; j < size; j++) + dwt_coeffs[h + i][w + j] = block_coeffs[i][j]; +} + +char *subband_name(int type) { + switch (type) { + case LL: return "LL"; + case HL: return "HL"; + case LH: return "LH"; + case HH: return "HH"; + default: return "XX"; + } +} + +int subband_in_list(char *list, int type, int level) { + return 1; +} + +int subband_wp_in_list(char *list, char *name) { + return 1; +} + +int calc_subband_wp_level(char *name){ + return strlen(name); +} + +void calc_subband_location(int cols, int rows, int type, int level, int *col, int *row) { + *col = *row = 0; + + if (level <= 0 || level > find_deepest_level(cols, rows) - 1) return; + + switch (type) { + case LL: + break; + case HL: + *col = 0; + *row = rows >> level; + break; + case LH: + *col = cols >> level; + *row = 0; + break; + case HH: + *col = cols >> level; + *row = rows >> level; + break; + default: + break; + } +} + +void calc_subband_wp_location(int cols, int rows, char *name, int *col, int *row) { + char *p = name; + int level = 0; + *col = *row = 0; + + while (*p) { + level++; + switch (toupper(*p)) { + case 'A': + break; + case 'H': + *col += (cols >> level); + break; + case 'V': + *row += (rows >> level); + break; + case 'D': + *col += (cols >> level); + *row += (rows >> level); + break; + default: + break; + } + p++; + } +} + +Pixel *get_dwt_data(Image_tree dwt, int level, int type) { + return get_dwt_image(dwt, level, type)->data; +} + +Image get_dwt_image(Image_tree dwt, int level, int type) { + return get_dwt_subband(dwt, level, type)->image; +} + +Image_tree get_dwt_subband(Image_tree dwt, int level, int type) { + while (--level) + dwt = dwt->coarse; + + switch (type) { + case LL: + return dwt->coarse; + case HL: + return dwt->vertical; + case LH: + return dwt->horizontal; + case HH: + return dwt->diagonal; + } + + return NULL; +} + +Pixel get_dwt_coeff(Image_tree dwt, int level, int type, int coeff) { + return get_dwt_data(dwt, level, type)[coeff]; +} + +Pixel get_dwt_location(Image_tree dwt, int level, int type, int col, int row) { + return get_pixel(get_dwt_image(dwt, level, type), col, row); +} + +static void calc__subband(Image_tree p, Image_tree q, double *min, double *max, double *error) { + int i; + + if (!p || !q) return; + + *error = 0; + *min = *max = fabs(p->image->data[0] - q->image->data[0]); + for (i = 0; i < p->image->size; i++) { + double diff = fabs(p->image->data[i] - q->image->data[i]); + + *error += sqr(diff); + if (diff < *min) *min = diff; + if (diff > *max) *max = diff; + } +} + +void calc_subband(Image_tree p, Image_tree q, int type, double *min, double *max, double *error) { + calc__subband(p, q, min, max, error); +} + +void calc_subband_wp(Image_tree p, Image_tree q, char *name, double *min, double *max, double *error) { + calc__subband(p, q, min, max, error); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/dwt_util.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/dwt_util.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,41 @@ +#ifndef DWT_UTIL_H +#define DWT_UTIL_H + +#include "dwt.h" + +#define LL 1 +#define LH 2 +#define HL 3 +#define HH 4 + +#define COARSE LL +#define HORIZONTAL LH +#define VERTICAL HL +#define DIAGONAL HH + +void copy_coeffs_from_dwt(double ** block_coeffs, double ** dwt_coeffs, + int level, int band, int width, int height); + +void copy_coeffs_to_dwt(double ** dwt_coeffs, double ** block_coeffs, + int level, int band, int width, int height); + +char *subband_name(int type); + +int subband_in_list(char *list, int type, int level); +int subband_wp_in_list(char *list, char *name); + +void calc_subband_location(int cols, int rows, int type, int level, int *col, int *row); +void calc_subband_wp_location(int cols, int rows, char *name, int *col, int *row); +int calc_subband_wp_level(char *name); + +Pixel *get_dwt_data(Image_tree dwt, int level, int type); +Image get_dwt_image(Image_tree dwt, int level, int type); +Image_tree get_dwt_subband(Image_tree dwt, int level, int type); +Pixel get_dwt_coeff(Image_tree dwt, int level, int type, int coeff); +Pixel get_dwt_location(Image_tree dwt, int level, int type, int col, int row); + +void calc_subband(Image_tree p, Image_tree q, int type, double *min, double *max, double *error); +void calc_subband_wp(Image_tree p, Image_tree q, char *name, double *min, double *max, double *error); + + +#endif diff -r 000000000000 -r be303a3f5ea8 Meerwald/filter.dat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/filter.dat Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,774 @@ +{ + Name biortho nr. 1 + Type biorthogonal + { + Type symm + Length 3 + Start 0 + End 2 + 0.353553 + -0.707107 + 0.353553 + } + { + Type symm + Length 5 + Start -2 + End 2 + -0.176777 + 0.353553 + 1.060660 + 0.353553 + -0.176777 + } + { + Type symm + Length 5 + Start -1 + End 3 + 0.176777 + 0.353553 + -1.060660 + 0.353553 + 0.176777 + } + { + Type symm + Length 3 + Start -1 + End 1 + 0.353553 + 0.707107 + 0.353553 + } +} + +{ + Name biortho nr. 2 + Type biorthogonal + { + Type symm + Length 7 + Start -4 + End 2 + -0.064539 + 0.040689 + 0.418092 + -0.788486 + 0.418092 + 0.040689 + -0.064539 + } + { + Type symm + Length 9 + Start -4 + End 4 + 0.037828 + -0.023849 + -0.110624 + 0.377402 + 0.852699 + 0.377402 + -0.110624 + -0.023849 + 0.037828 + } + { + Type symm + Length 9 + Start -5 + End 3 + -0.037828 + -0.023849 + 0.110624 + 0.377402 + -0.852699 + 0.377402 + 0.110624 + -0.023849 + -0.037828 + } + { + Type symm + Length 7 + Start -3 + End 3 + -0.064539 + -0.040689 + 0.418092 + 0.788486 + 0.418092 + -0.040689 + -0.064539 + } +} +{ + Name Daubechies 4 + Type orthogonal + { + Type symm + Length 4 + Start -1 + End 2 + + -0.129409522551 + -0.224143868042 + 0.836516303737 + -0.482962913144 + + } + { + Type symm + Length 4 + Start -1 + End 2 + + 0.482962913144 + 0.836516303737 + 0.224143868042 + -0.129409522551 + + } +} + +{ + Name Daubechies 6 + Type orthogonal + { + Type symm + Length 6 + Start -3 + End 2 + + 0.035226291882 + 0.085441273882 + -0.135011020010 + -0.459877502118 + 0.806891509311 + -0.332670552950 + + + } + { + Type symm + Length 6 + Start -1 + End 4 + + 0.332670552950 + 0.806891509311 + 0.459877502118 + -0.135011020010 + -0.085441273882 + 0.035226291882 + + } +} +{ + Name Daubechies 8 + Type orthogonal + { + Type symm + Length 8 + Start -1 + End 6 + + + -0.010597401785 + -0.032883011667 + 0.030841381836 + 0.187034811719 + -0.027983769417 + -0.630880766793 + 0.714846570553 + -0.230377813309 + + } + { + Type symm + Length 8 + Start -1 + End 6 + + 0.230377813309 + 0.714846570553 + 0.630880766793 + -0.027983769417 + -0.187034811719 + 0.030841381836 + 0.032883011667 + -0.010597401785 + + } +} +{ + Name Daubechies 10 + Type orthogonal + { + Type symm + Length 10 + Start -2 + End 7 + + 0.0033357252854738 + 0.0125807519990820 + -0.0062414902127983 + -0.0775714938400459 + -0.0322448695846381 + 0.2422948870663823 + 0.1384281459013203 + -0.7243085284377726 + 0.6038292697971895 + -0.1601023979741929 + + } + { + Type symm + Length 10 + Start -2 + End 7 + + 0.1601023979741929 + 0.6038292697971895 + 0.7243085284377726 + 0.1384281459013203 + -0.2422948870663823 + -0.0322448695846381 + 0.0775714938400459 + -0.0062414902127983 + -0.0125807519990820 + 0.0033357252854738 + + } +} + +{ + Name Daubechies 12 + Type orthogonal + { + Type symm + Length 12 + Start -1 + End 10 + + -0.0010773010853085 + -0.0047772575119455 + 0.0005538422011614 + 0.0315820393184862 + 0.0275228655303053 + -0.0975016055873225 + -0.1297668675672625 + 0.2262646939654400 + 0.3152503517091982 + -0.7511339080210959 + 0.4946238903984533 + -0.1115407433501095 + + } + { + Type symm + Length 12 + Start -1 + End 10 + + 0.1115407433501095 + 0.4946238903984533 + 0.7511339080210959 + 0.3152503517091982 + -0.2262646939654400 + -0.1297668675672625 + 0.0975016055873225 + 0.0275228655303053 + -0.0315820393184862 + 0.0005538422011614 + 0.0047772575119455 + -0.0010773010853085 + + } +} + +{ + Name Daubechies 14 + Type orthogonal + { + Type symm + Length 14 + Start -1 + End 12 + + 0.0003537138 + 0.001801640704 + 0.000429577973 + -0.012550998556 + -0.016574541631 + 0.038029936935 + 0.0806112609151 + -0.071309219267 + -0.224036184994 + 0.143906003929 + 0.469782287405 + -0.729132090846 + 0.396539319482 + -0.077852054085 + + } + { + Type symm + Length 14 + Start -1 + End 12 + + 0.077852054085 + 0.396539319482 + 0.729132090846 + 0.469782287405 + -0.143906003929 + -0.224036184994 + 0.071309219267 + 0.0806112609151 + -0.038029936935 + -0.016574541631 + 0.012550998556 + 0.000429577973 + -0.001801640704 + 0.0003537138 + + } +} + + +{ + Name Daubechies 20 + Type orthogonal + { + Type symm + Length 20 + Start -1 + End 18 + + -0.000013264203 + -0.000093588670 + -0.000116466855 + 0.000685856695 + 0.001992405295 + 0.001395351747 + -0.010733175483 + -0.003606553567 + 0.033212674059 + 0.029457536822 + -0.071394147166 + -0.093057364604 + 0.127369340336 + 0.195946274377 + -0.249846424327 + -0.281172343661 + 0.688459039454 + -0.527201188932 + 0.188176800078 + -0.026670057901 + + } + { + Type symm + Length 20 + Start -1 + End 18 + + 0.026670057901 + 0.188176800078 + 0.527201188932 + 0.688459039454 + 0.281172343661 + -0.249846424327 + -0.195946274377 + 0.127369340336 + 0.093057364604 + -0.071394147166 + -0.029457536822 + 0.033212674059 + 0.003606553567 + -0.010733175483 + 0.001395351747 + 0.001992405295 + -0.000685856695 + -0.000116466855 + 0.000093588670 + -0.000013264203 + } +} + + +{ + Name Beylkin 18 + Type orthogonal + { + Type symm + Length 18 + Start -1 + End 16 + + 0.00064048532852124535 + 0.0027360316262586061 + 0.0014842347824723461 + -0.01004041184463199 + -0.014365807968852611 + 0.017460408696028829 + 0.042916387274192273 + -0.01967986604432212 + -0.088543630622924835 + 0.017520746266529649 + 0.1555387318770938 + -0.02690030880369032 + -0.26449723144638482 + 0.1109275983482343 + 0.44971825114946867 + -0.69982521405660059 + 0.42421536081296141 + -0.099305765374353927 + + } + { + Type symm + Length 18 + Start -1 + End 16 + + 0.099305765374353927 + 0.42421536081296141 + 0.69982521405660059 + 0.44971825114946867 + -0.1109275983482343 + -0.26449723144638482 + 0.02690030880369032 + 0.1555387318770938 + -0.017520746266529649 + -0.088543630622924835 + 0.01967986604432212 + 0.042916387274192273 + -0.017460408696028829 + -0.014365807968852611 + 0.01004041184463199 + 0.0014842347824723461 + -0.0027360316262586061 + 0.00064048532852124535 + + } +} + + +{ + Name Vaidyanathan 24 + Type orthogonal + { + Type symm + Length 24 + Start -1 + End 22 + + 0.045799334110976718 + -0.25018412950466218 + 0.57279779321073432 + -0.63560105987221494 + 0.20161216177530866 + 0.26349480248845991 + -0.19445047176647817 + -0.13508422712948126 + 0.13197166141697772 + 0.08392888436611283 + -0.07770975090196941 + -0.055892523691373548 + 0.03874261929341144 + 0.035470398607283453 + -0.014853448005230099 + -0.019687215010072714 + 0.003153847055897004 + 0.008839103408613878 + 0.00070813750405244471 + -0.0028438345468355646 + -0.00094489713632194927 + 0.00045395661963721929 + 0.00034363190482102919 + 0.000062906118190737523 + + } + { + Type symm + Length 24 + Start -1 + End 22 + + -0.000062906118190737523 + 0.00034363190482102919 + -0.00045395661963721929 + -0.00094489713632194927 + 0.0028438345468355646 + 0.00070813750405244471 + -0.008839103408613878 + 0.003153847055897004 + 0.019687215010072714 + -0.014853448005230099 + -0.035470398607283453 + 0.03874261929341144 + 0.055892523691373548 + -0.07770975090196941 + -0.08392888436611283 + 0.13197166141697772 + 0.13508422712948126 + -0.19445047176647817 + -0.26349480248845991 + 0.20161216177530866 + 0.63560105987221494 + 0.57279779321073432 + 0.25018412950466218 + 0.045799334110976718 + } +} + + +{ + Name Coifman 6 + Type orthogonal + { + Type symm + Length 6 + Start -1 + End 4 + + 0.226584276197068560 + -0.745687558934434280 + 0.607391641385684120 + 0.077161555495773498 + -0.12696912539620520 + 0.038580777747886749 + + } + { + Type symm + Length 6 + Start -1 + End 4 + + 0.038580777747886749 + -0.12696912539620520 + -0.077161555495773498 + 0.607391641385684120 + 0.745687558934434280 + 0.226584276197068560 + } +} + + +{ + Name Coifman 12 + Type orthogonal + { + Type symm + Length 12 + Start -1 + End 10 + + -0.000720549445369115120 + 0.00182320887091009920 + 0.00561143481936598850 + -0.0236801719468767500 + -0.0594344186464712400 + 0.0764885990782645940 + 0.417005184423777600 + -0.812723635449606130 + 0.386110066823092900 + 0.0673725547222998740 + -0.0414649367819664850 + -0.0163873364631797850 + + } + { + Type symm + Length 12 + Start -1 + End 10 + + 0.0163873364631797850 + -0.0414649367819664850 + -0.0673725547222998740 + 0.386110066823092900 + 0.812723635449606130 + 0.417005184423777600 + -0.0764885990782645940 + -0.0594344186464712400 + 0.0236801719468767500 + 0.00561143481936598850 + -0.00182320887091009920 + -0.000720549445369115120 + + } +} + + +{ + Name Coifman 18 + Type orthogonal + { + Type symm + Length 18 + Start -1 + End 16 + + -0.000034599773197402695 + 0.000070983302505704928 + 0.00046621695982014403 + -0.00111751877082696180 + -0.0025745176881279692 + 0.0090079761367322896 + 0.0158805448636159010 + -0.0345550275733444640 + -0.082301927106320283 + 0.071799821619170590 + 0.428483476377618690 + -0.793777222625620340 + 0.405176902409616790 + 0.0611233900029556980 + -0.0657719112814312280 + -0.0234526961421191030 + 0.00778259642567178690 + 0.00379351286437787590 + + } + { + Type symm + Length 18 + Start -1 + End 16 + + -0.00379351286437787590 + 0.00778259642567178690 + 0.0234526961421191030 + -0.0657719112814312280 + -0.0611233900029556980 + 0.405176902409616790 + 0.793777222625620340 + 0.428483476377618690 + -0.071799821619170590 + -0.082301927106320283 + 0.0345550275733444640 + 0.0158805448636159010 + -0.0090079761367322896 + -0.0025745176881279692 + 0.00111751877082696180 + 0.00046621695982014403 + -0.000070983302505704928 + -0.000034599773197402695 + + } +} + +{ + Name Biorthogonal 1,3 + Type biorthogonal + { + Type symm + Length 6 + Start -1 + End 4 + + -0.08838834764832 + -0.08838834764832 + 0.707106781 + -0.707106781 + 0.08838834764832 + 0.08838834764832 + + } + { + Type symm + Length 2 + Start 1 + End 2 + 0.707106781 + 0.707106781 + + } + + { + Type symm + Length 2 + Start 1 + End 2 + 0.707106781 + -0.707106781 + } + { + Type symm + Length 6 + Start -1 + End 4 + + -0.08838834764832 + 0.08838834764832 + 0.707106781 + 0.707106781 + 0.08838834764832 + -0.08838834764832 + + } +} + +{ + Name Biorthogonal 1,5 + Type biorthogonal + { + Type symm + Length 10 + Start -1 + End 8 + + 0.01657281518406 + 0.01657281518406 + -0.1215339780164 + -0.1215339780164 + 0.707106781 + -0.707106781 + 0.1215339780164 + 0.1215339780164 + -0.01657281518406 + -0.01657281518406 + + } + { + Type symm + Length 2 + Start 3 + End 4 + + 0.707106781 + 0.707106781 + } + + { + Type symm + Length 2 + Start 3 + End 4 + + 0.707106781 + -0.707106781 + } + { + Type symm + Length 10 + Start -1 + End 8 + + 0.01657281518406 + -0.01657281518406 + -0.1215339780164 + 0.1215339780164 + 0.707106781 + 0.707106781 + 0.1215339780164 + -0.1215339780164 + -0.01657281518406 + 0.01657281518406 + + } +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/frid2_common.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/frid2_common.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,220 @@ +#include "frid2_common.h" +#include "signature.h" +#include "wm.h" + +extern char *progname; + +void embed_low_freq(double **dcts, int cols, int rows, double alpha, int verbose) { + int n; + int row, col, dir; + + n = 0; + row = col = 0; + dir = 1; + while (n < nbit_signature) { + double d, x; + int embed; + int out; + + col -= dir; + row += dir; + if (col < 0) { dir = -1; col = 0; } + if (col >= cols) { dir = 1; col = cols - 1; row += 2; } + if (row < 0) { dir = 1; row = 0; } + if (row >= rows) { dir = -1; row = rows - 1; col += 2; } + + d = dcts[row][col]; + if (fabs(d) <= 1.0) { + if (verbose > 3) + fprintf(stderr, "%s: bit #%d - skipped (%d/%d)\n", progname, n, col, row); + continue; + } + + embed = 2 * get_signature_bit(n) - 1; + + x = (d > 0.0) ? 1.0 : -1.0; + out = 1; + while (fabs(x) < fabs(d)) { + x *= FORWARD_STEP(alpha); + out =- out; + } + + if (out != embed) { + if (fabs(d - x) < fabs(d - x * BACKWARD_STEP(alpha))) + x *= FORWARD_STEP(alpha); + else + x *= BACKWARD_STEP(alpha); + } + + d = (x + x * BACKWARD_STEP(alpha)) / 2.0; + + if (verbose > 3) + fprintf(stderr, "%s: embedding bit #%d (= %d) at (%d/%d): %f -> %f\n", progname, n, get_signature_bit(n), col, row, dcts[row][col], d); + + dcts[row][col] = d; + + n++; + } +} + +void embed_med_freq(double **dcts, int cols, int rows, double gamma, int seed, int verbose) { + // select mid-frequency (30%) coefficients + int start = (int) (0.35 * rows * cols + 0.5); + int end = (int) (0.65 * rows * cols + 0.5); + + double *vector; + int x = 0, y = 0, dir = 1; + int i, j; + + vector = malloc((end - start) * sizeof(double)); + for (i = 0; i < (end - start); i++) + vector[i] = 0.0; + + // create pseudo-random vector + srandom(seed); + for (i = 0; i < nbit_signature; i++) { + if (get_signature_bit(i)) + random(); + for (j = 0; j < (end - start); j++) + vector[j] += (double) (random() & RAND_MAX) / (double) RAND_MAX - 0.5; + if (!get_signature_bit(i)) + random(); + } + + for (i = 0; i < (end - start); i++) + vector[i] /= sqrt(nbit_signature); + + for (i = 0; i < end; i++) { + // zig-zag scan + x -= dir; + y += dir; + if (x < 0) { dir = -1; x = 0; } + if (x >= cols) { dir = 1; x = cols - 1; y += 2; } + if (y < 0) { dir = 1; y = 0; } + if (y >= rows) { dir = -1; y = rows - 1; x += 2; } + + // embed vector + if ((i - start) >= 0) { +// fprintf(stderr, "%d/%d: %f -> %f\n", x, y, dcts[y][x], dcts[y][x] + gamma * vector[i - start]); + dcts[y][x] += gamma * vector[i - start]; + } + } + + free(vector); +} + +double detect_low_freq(double **dcts, int cols, int rows, double alpha, double beta, int verbose) { + int n; + int row, col, dir; + double sum1, sum2; + + n = 0; + row = col = 0; + dir = 1; + sum1 = sum2 = 0.0; + while (n < nbit_signature1) { + double d, x; + int detect; + int out; + + col -= dir; + row += dir; + if (col < 0) { dir = -1; col = 0; } + if (col >= cols) { dir = 1; col = cols - 1; row += 2; } + if (row < 0) { dir = 1; row = 0; } + if (row >= rows) { dir = -1; row = rows - 1; col += 2; } + + d = dcts[row][col]; + if (fabs(d) <= 1.0) { + if (verbose > 3) + fprintf(stderr, "%s: bit #%d - skipped (%d/%d)\n", progname, n, col, row); + continue; + } + + detect = 2 * get_signature1_bit(n) - 1; + + x = (d > 0.0) ? 1.0 : -1.0; + out = 1; + while (fabs(x) < fabs(d)) { + x *= FORWARD_STEP(alpha); + out =- out; + } + + if (verbose > 3) + fprintf(stderr, "%s: detected bit #%d (= %d) at (%d/%d): %f\n", progname, n, out > 0 ? 1 : 0, col, row, d); + + set_signature2_bit(n, out > 0 ? 1 : 0); + sum1 += pow(fabs(d), beta) * out * detect; + sum2 += pow(fabs(d), beta); + + n++; + } + + return sum1 / sum2; +} + +double detect_med_freq(double **dcts, int cols, int rows, int seed, int verbose) { + int i, j, k; + int start= (int) (0.35 * rows * cols + 0.5); + int end = (int) (.65 * rows * cols + 0.5); + + int sum, sum1, sum2; + int x = 0, y = 0, dir = 1; + double *vector; + int startx, starty, startdir; + double corr[2]; + double correlation; + + // locate start positions + for (i = 0; i < start; i++) { + x -= dir; + y += dir; + if (x < 0) { dir = -1; x = 0; } + if (x >= cols) { dir = 1; x = cols - 1; y += 2; } + if (y < 0) { dir = 1; y = 0; } + if (y >= rows) { dir = -1; y = rows - 1; x += 2; } + } + + // save start positions + startx = x; + starty = y; + startdir = dir; + srandom(seed); + + vector = malloc((end - start) * sizeof(double)); + + for (i = 0; i < nbit_signature1; i++) { + + for (j = 0; j <= (end - start); j++) + vector[j] = (double) (random() & RAND_MAX) / (double) RAND_MAX - 0.5; + + for (j = 0; j <= 1; j++) { + x = startx; + y = starty; + dir = startdir; + corr[j] = 0; + + for (k = 0; start + k < end; k++) { + x -= dir; + y += dir; + if (x < 0) { dir = -1; x = 0; } + if (x >= cols) { dir = 1; x = cols - 1; y += 2; } + if (y < 0) { dir = 1; y = 0; } + if (y >= rows) { dir = -1; y = rows - 1; x += 2; } + corr[j] += dcts[y][x] * vector[k + j]; + } + } + + set_signature2_bit(i, (corr[0] >= corr[1]) ? 0 : 1); + } + + sum = 0; sum1 = 0; sum2 = 0; + for (i = 0; i < nbit_signature1; i++) { + sum += get_signature1_bit(i) * get_signature2_bit(i); + sum1 += get_signature1_bit(i) * get_signature1_bit(i); + sum2 += get_signature2_bit(i) * get_signature2_bit(i); + } + correlation = (double) sum / (sqrt(sum1) * sqrt(sum2)); + + return correlation; +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/frid2_common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/frid2_common.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,12 @@ +#ifndef FRID2_COMMON_H +#define FRID2_COMMON_H + +#define FORWARD_STEP(A) ((1.0 + A) / (1.0 - A)) +#define BACKWARD_STEP(A) ((1.0 - A) / (1.0 + A)) + +void embed_low_freq(double **dcts, int cols, int rows, double alpha, int verbose); +void embed_med_freq(double **dcts, int cols, int rows, double gamma, int seed, int verbose); +double detect_low_freq(double **dcts, int cols, int rows, double alpha, double beta, int verbose); +double detect_med_freq(double **dcts, int cols, int rows, int seed, int verbose); + +#endif diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_bruyn_sig.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_bruyn_sig.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,89 @@ +.\" +.\" gen_bruyn_sig.1 - the *roff document processor man page source +.\" +.TH gen_bruyn_sig 1 "98/06/30" "Watermarking, Version 1.0" +.SH NAME +gen_bruyn_sig \- an man page source template +.SH SYNOPSIS +.B gen_bruyn_sig +[ +.B \-abcdef +] +[ +.BI \-d opt +] +[ +.BI \-o file +] +[ +.IR files \|.\|.\|.\| +] +.SH DESCRIPTION +.B gen_bruyn_sig +is a program. +.PP +the +.B \-d +option is one of the following: +.TP +.B opt1 for option 1 +.TP +.B opt2 for option 2 +.TP +.B opt3 for option 3 +.LP +I hope you can guess the purpose of the program. +.LP +Can you? +.P +.SH OPTIONS +.TP +.B \-a +option a +.TP +.B \-b +option b +.TP +.B \-c +option c +.TP +.B \-d +option d +.TP +.B \-e +option e +.TP +.B \-f +option f +.PP +These are all the options, now on with some environment variables: +.TP +.SM +.B ENV_VAR1 +environment variable 1 +.TP +.SM +.B ENV_VAR2 +environment variable 2 +.TP +.SM +.B ENV_VAR3 +environment variable 2 +.SH FILES +.SH AUTHOR +Peter Meerwald +.SH NOTES +.SH BUGS +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH COPYRIGHT +Copyright \(co 1998 Peter Meerwald +.SH AVAILABILITY +The most recent released version of +.B gen_bruyn_sig +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR program1, +.BR program2, +.BR program3 diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_bruyn_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_bruyn_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,231 @@ +#include "wm.h" +#include "signature.h" +#include "bruyn_common.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-b n] [-k] [-n n] [-o file] [-pP n] [-q n] [-s file] [-S n] [-tT n] file\n\n", progname); + fprintf(stderr, "\t-b n\t\tblock size (default 8)\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-k\t\tdisable block skipping\n"); + fprintf(stderr, "\t-n n\t\twatermark bit length\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-p n\t\tpattern type for zone 1 (default 1, 1.." NPATTERN_USAGE ")\n"); + fprintf(stderr, "\t-P n\t\tpattern type for zone 2 (default 2, 1.." NPATTERN_USAGE ")\n"); + fprintf(stderr, "\t-q n\t\tsignature strength (default 7.0)\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + fprintf(stderr, "\t-t n\t\tthreshold for noise (default " THRESHOLD_NOISE_USAGE ")\n"); + fprintf(stderr, "\t-T n\t\tthreshold for slope (default " THRESHOLD_SLOPE_USAGE ")\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int b = 8; + int n = 0; + int nb; + int s = 0; + int p1 = 1; + int p2 = 2; + double t1 = THRESHOLD_NOISE; + double t2 = THRESHOLD_SLOPE; + double q = 7.0; + int skipping = 0; + + progname = argv[0]; + wm_init(); + + while ((c = getopt(argc, argv, "b:h?n:o:p:P:q:s:S:t:T:k")) != EOF) { + switch (c) { + case 'b': + b = atoi(optarg); + if (b <= 0) { + fprintf(stderr, "%s: block size %d out of range\n", progname, b); + exit(1); + } + break; + case 'k': + skipping = 1; + break; + case 'h': + case '?': + usage(); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + p1 = atoi(optarg); + if (p1 <= 0 || p1 > NPATTERN) { + fprintf(stderr, "%s: pattern type out of range\n", progname); + exit(1); + } + break; + case 'P': + p2 = atoi(optarg); + if (p2 <= 0 || p2 > NPATTERN) { + fprintf(stderr, "%s: pattern type out of range\n", progname); + exit(1); + } + break; + case 'q': + q = atof(optarg); + if (q <= 0.0) { + fprintf(stderr, "%s: signature strength factor %f out of range\n", progname, q); + exit(1); + } + break; + case 't': + t1 = atof(optarg); + if (t1 <= 0) { + fprintf(stderr, "%s: noise threshold %f out of range\n", progname, t1); + } + break; + case 'T': + t2 = atof(optarg); + if (t2 <= 0) { + fprintf(stderr, "%s: slope threshold %f out of range\n", progname, t2); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (b % 2 > 0 || b <= 2) { + fprintf(stderr, "%s: block size has to be even and greater than 2\n"); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + // read signature file and set options + // command line options override signature file options + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "BRSG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (skipping == 0) + fscanf(sig, "%d\n", &skipping); + else + fscanf(sig, "%*d\n"); + if (p1 == 0) + fscanf(sig, "%d\n", &p1); + else + fscanf(sig, "%*d\n"); + if (p2 == 0) + fscanf(sig, "%d\n", &p2); + else + fscanf(sig, "%*d\n"); + if (q == 0.0) + fscanf(sig, "%lf\n", &q); + else + fscanf(sig, "%*lf\n"); + if (t1 == 0.0) + fscanf(sig, "%lf\n", &t1); + else + fscanf(sig, "%*lf\n"); + if (t2 == 0.0) + fscanf(sig, "%lf\n", &t2); + else + fscanf(sig, "%*lf\n"); + if (b == 0) + fscanf(sig, "%d\n", &b); + else + fscanf(sig, "%*d\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + if (n > 0) { + nb = fread(signature, sizeof(char), i = NBITSTOBYTES(n), in); + if (nb < i) { + fprintf(stderr, "%s: failed to read all %d signature bits from %s\n", progname, n, input_name); + exit(1); + } + } + else { + if (fscanf(in, "%128[^\n\r]", signature) == EOF) { + fprintf(stderr, "%s: failed to read signature bits from %s\n", progname, input_name); + exit(1); + } + nb = strlen(signature); + n = NBYTESTOBITS(nb); + fprintf(stderr, "%s: got %d signature bits\n", progname, n); + } + + + fprintf(out, "BRSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%d\n", skipping); + fprintf(out, "%d\n", p1); + fprintf(out, "%d\n", p2); + fprintf(out, "%f\n", q); + fprintf(out, "%f\n", t1); + fprintf(out, "%f\n", t2); + fprintf(out, "%d\n", b); + fprintf(out, "%d\n", random()); + fwrite(signature, sizeof(char), nb, out); + fprintf(out, "\n"); + + fclose(out); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_corvi_sig.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_corvi_sig.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,161 @@ +.\" +.\" gen_corvi_sig.1 - the *roff document processor man page source +.\" +.TH gen_corvi_sig 1 "98/07/17" "Watermarking, Version 1.0" +.SH NAME +.B gen_corvi_sig +\- a program to generate a signature for +the +.B wm_corvi_e +watermarking program +.SH SYNOPSIS +.B gen_corvi_sig +[ +.BI \-a \ number +] +[ +.BI \-d \ number +] +[ +.BI \-e \ number +] +[ +.BI \-f \ number +] +[ +.BI \-F \ ffile +] +[ +.BI \-g \ number +] +.br +[ +.B \-h +] +[ +.BI \-m \ number +] +[ +.BI \-n \ number +] +[ +.BI \-o \ file +] +[ +.BI \-q \ number +] +[ +.BI \-s \ number +] +.SH DESCRIPTION +.B gen_corvi_sig +is a program to generate a signature to be +embedded with the +.B wm_corvi_e +watermarking program and extracted with the +.B wm_corvi_d +program. The +.B cmp_corvi_sig +program is used to compare and test an +extracted signature with the original signature. +.PP +Please refer to Marco Corvi's paper "Wavlet-based image watermarking +for copyright protection", to get an idea of the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. Default +value 0.3. +.TP +.BI \-d \ number +Deviation for the normal distributed signature values, default 1.0. +.TP +.BI \-e \ number +The filtering method for the forward wavelet transform. Default value +1. +.TP +.BI \-F \ ffile +The filter definition file. Default +.I filter.dat. +.TP +.BI \-f \ number +Use the +.I number +filter from the filter definition file, +.I ffile. Default: 1. +.TP +.BI \-g \ number +The filtering method for the inverse wavelet transform. Default value +2. +.TP +.B \-h +Print a help message. +.TP +.BI \-m \ number +Mean of the normal distributed signature values, default 0.0. +.TP +.BI \-n \ number +Length of the watermark. Default value 100. +.TP +.BI \-o \ file +Output signature to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Quantization/quality factor. Default value 3. +.TP +.BI \-s \ number +Specify a seed value to initialize the pseudo-random number +generator; if not specified, time and pid (process id) are used +to initialize the pseudo-random number generator. +.PP +.SH OUTPUT +The output file has the following format: +.TP +.B CVSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The alpha factor (embedding strength). +.TP +.I number +The quantization/quality factor. +.TP +.I number +The wavelet forward transform filtering method. +.TP +.I number +The wavelet filter number. +.TP +.I file +The wavelet filter definition file name. +.TP +.I number +The wavelet inverse transform filtering method. +.TP +.I numbers +The actual normal distributed signature values, one per line. +.PP +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B gen_corvi_sig +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR wm_corvi_e +(1), +.BR wm_corvi_d +(1), +.BR wm_corvi_s +(1), +.BR cmp_corvi_sig +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_corvi_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_corvi_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,143 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-d n] [-e n] [-f n] [-F file] [-m n] [-n n] [-o file] [-s n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.1)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-m n \t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 1000)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + + char output_name[MAXPATHLEN] = "(stdout)"; + + int c; + int i; + int n = 1000; + int s = 0; + int e = 2; + int f = 1; + char F[MAXPATHLEN] = "filter.dat"; + double a = 0.1; + double m = 0.0; + double d = 1.0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:d:e:f:F:h?m:n:o:s:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "CVSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_cox_sig.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_cox_sig.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,115 @@ +.\" +.\" gen_cox_sig.1 - the *roff document processor man page source +.\" +.TH gen_cox_sig 1 "98/06/30" "Watermarking, Version 1.0" +.SH NAME +.B gen_cox_sig +\- a program to generate a signature for +the +.B wm_cox_e +watermarking program +.SH SYNOPSIS +.B gen_cox_sig +[ +.BI \-a \ number +] +[ +.BI \-d \ number +] +[ +.B \-h +] +[ +.BI \-m \ number +] +[ +.BI \-n \ number +] +[ +.BI \-o \ file +] +[ +.BI \-q \ number +] +[ +.BI \-s \ number +] +.SH DESCRIPTION +.B gen_cox_sig +is a program to generate a signature to be +embedded with the +.B wm_cox_e +watermarking program and extracted with the +.B wm_cox_d +program. The +.B cmp_cox_sig +program is used to compare and test an +extracted signature with the original signature. +.PP +Please refer to Ingemar J. Cox's paper "Secure Spread Spectrum +Watermarking for Multimedia", 1995, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. Default +value 0.3. +.TP +.BI \-d \ number +Deviation for the normal distributed signature values, default 1.0. +.TP +.B \-h +Print a help message. +.TP +.BI \-m \ number +Mean of the normal distributed signature values, default 0.0. +.TP +.BI \-n \ number +Length of the watermark. Default value 100. +.TP +.BI \-o \ file +Output signature to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Quantization/quality factor. Default value 3. +.TP +.BI \-s \ number +Specify a seed value to initialize the pseudo-random number +generator; if not specified, time and pid (process id) are used +to initialize the pseudo-random number generator. +.PP +.SH OUTPUT +The output file has the following format: +.TP +.B CXSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The alpha factor (embedding strength). +.TP +.I number +The quantization/quality factor. +.TP +.I numbers +The actual normal distributed signature values, one per line. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B gen_cox_sig +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR wm_cox_e +(1), +.BR wm_cox_d +(1), +.BR cmp_cox_sig +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_cox_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_cox_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,158 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-d n] [-m n] [-n n] [-o file] [-s file] [-S n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.3)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-m n \t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 100)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 100; + int s = 0; + double a = 0.3; + double m = 0.0; + double d = 1.0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:d:h?m:n:o:s:S:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + case 'h': + case '?': + usage(); + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "CXSG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (m == 0.0) + fscanf(sig, "%lf\n", &m); + else + fscanf(sig, "%*lf\n"); + if (d == 0.0) + fscanf(sig, "%lf\n", &d); + else + fscanf(sig, "%*lf\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + close(sig); + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "CXSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%f\n", m); + fprintf(out, "%f\n", d); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_dugad_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_dugad_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,227 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F file] [-l n] [-n n] [-o file] [-s file] [-S n] [-t n] [-T n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.2)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition levels (default 3)\n"); + fprintf(stderr, "\t-m n \t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 1000)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + fprintf(stderr, "\t-t n\t\tcasting threshold (default 40.0)\n"); + fprintf(stderr, "\t-T n\t\tdetection threshold (default 50.0)\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 1000; + int s = 0; + int e = 2; + int f = 1; + int l = 3; + char F[MAXPATHLEN] = "filter.dat"; + double a = 0.2; + double t1 = 40.0; + double t2 = 50.0; + double m = 0.0; + double d = 1.0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:b:d:e:f:F:h?l:m:n:o:s:S:t:T:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'l': + l = atoi(optarg); + if (l <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", l); + exit(1); + } + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + case 't': + t1 = atof(optarg); + if (t1 <= 0.0) { + fprintf(stderr, "%s: casting threshold %f out of range\n", progname, t1); + exit(1); + } + break; + case 'T': + t2 = atof(optarg); + if (t2 <= 0.0) { + fprintf(stderr, "%s: detection threshold %f out of range\n", progname, t2); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "DGSG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (l == 0) + fscanf(sig, "%d\n", &l); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (t1 == 0.0) + fscanf(sig, "%lf\n", &t1); + else + fscanf(sig, "%*lf\n"); + if (t2 == 0.0) + fscanf(sig, "%lf\n", &t2); + else + fscanf(sig, "%*lf\n"); + if (e < 0) + fscanf(sig, "%d\n", &e); + else + fscanf(sig, "%*d\n"); + if (f == 0) + fscanf(sig, "%d\n", &f); + else + fscanf(sig, "%*d\n"); + if (!strcmp(F, "")) + fscanf(sig, "%[^\n\r]\n", &F); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "DGSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%d\n", l); + fprintf(out, "%f\n", a); + fprintf(out, "%f\n", t1); + fprintf(out, "%f\n", t2); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_frid2_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_frid2_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,149 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-g n] [-o file] [-s n] file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.25)\n"); + fprintf(stderr, "\t-g n\t\tgamma factor (default 1.0)\n"); + fprintf(stderr, "\t-s n\t\tseed (default 0)\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 100)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 100, nb; + double a = 0.25; + double g = 1.0; + int s = 0; + + progname = argv[0]; + +#ifdef __EMX__ + _fsetmode(in, "b"); + _fsetmode(out, "b"); +#endif + + while ((c = getopt(argc, argv, "a:g:h?n:o:s:S:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'g': + g = atof(optarg); + if (g <= 0.0) { + fprintf(stderr, "%s: gamma factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'h': + case '?': + usage(); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!s) + s = time(NULL) * getpid(); + srandom(s); + + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "FR2SG") >= 5) { + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + + if (n > 0) { + nb = fread(signature, sizeof(char), i = NBITSTOBYTES(n), in); + if (nb < i) { + fprintf(stderr, "%s: failed to read all %d signature bits from %s\n", progname, n, input_name); + exit(1); + } + } + else { + if (fscanf(in, "%128[^\n\r]", signature) == EOF) { + fprintf(stderr, "%s: failed to read signature bits from %s\n", progname, input_name); + exit(1); + } + nb = strlen(signature); + n = NBYTESTOBITS(nb); + fprintf(stderr, "%s: got %d signature bits\n", progname, n); + } + + fprintf(out, "FR2SG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%f\n", g); + fprintf(out, "%d\n", s); + fwrite(signature, sizeof(char), nb, out); + fprintf(out, "\n"); + + fclose(out); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_kim_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_kim_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,212 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-A n] [-d n] [-e n] [-f n] [-F file] [-l n] [-m n] [-n n] [-o file] [-s file] [-S n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor for detail subbands (default 0.1)\n"); + fprintf(stderr, "\t-A n\t\talpha factor for approximation subband (default 0.02)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level (default 4)\n"); + fprintf(stderr, "\t-m n \t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 1000)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 1000; + int s = 0; + int e = 2; + int f = 1; + char F[MAXPATHLEN] = "filter.dat"; + double a = 0.1; + double A = 0.02; + int l = 4; + double m = 0.0; + double d = 1.0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:A:l:d:e:f:F:h?m:n:o:s:S:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'A': + A = atof(optarg); + if (A <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'l': + l = atoi(optarg); + if (l <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, l); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KISG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (A == 0.0) + fscanf(sig, "%lf\n", &A); + else + fscanf(sig, "%*lf\n"); + if (l == 0) + fscanf(sig, "%d\n", &l); + else + fscanf(sig, "%*d\n"); + if (e < 0) + fscanf(sig, "%d\n", &e); + else + fscanf(sig, "%*d\n"); + if (f == 0) + fscanf(sig, "%d\n", &f); + else + fscanf(sig, "%*d\n"); + if (!strcmp(F, "")) + fscanf(sig, "%[^\n\r]\n", &F); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "KISG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%f\n", A); + fprintf(out, "%d\n", l); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_koch_sig.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_koch_sig.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,110 @@ +.\" +.\" gen_koch_sig.1 - the *roff document processor man page source +.\" +.TH gen_koch_sig 1 "98/06/30" "Watermarking, Version 1.0" +.SH NAME +.B gen_koch_sig +\- a program to generate a signature for +the +.B wm_koch_e +watermarking program +.SH SYNOPSIS +.B gen_koch_sig +[ +.B \-h +] +[ +.BI \-n \ number +] +[ +.BI \-o \ file +] +[ +.BI \-q \ number +] +[ +.BI \-s \ number +] +[ +.IR file +] +.SH DESCRIPTION +.B gen_koch_sig +is a program to generate a signature to be +embedded with the +.B wm_koch_e +watermarking program and extracted with the +.B wm_koch_d +program. The +.B cmp_koch_sig +program is used to compare and test an +extracted signature with the original signature. +.PP +Please refer to E. Koch's paper "Towards Robust and Hidden +Image Copyright", 1995, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-n \ number +Limit the signature length to +.I number +bits (0 < +.I number +<= 1024) unless reading from standard input. When reading from +standard input, the signature is terminated by the first +carriage return character. +.TP +.BI \-o \ file +Output signature to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Quality/robustness factor used to embed signature into image. +Default value: 3.0. +.TP +.BI \-s \ number +Specify a seed value to initialize the pseudo-random number +generator; if not specified, time and pid (process id) are used +to initialize the pseudo-random number generator. +.TP +.IR file +Input file to read raw signature data from. Default: standard +input. +.PP +.SH OUTPUT +The output file has the following format: +.TP +.B KCSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The quality/robustness factor. +.TP +.I number +The seed value for the pseudo-random number generator. +.TP +.I string +The actual signature bytes. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B gen_koch_sig +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR wm_koch_e +(1), +.BR wm_koch_d +(1), +.BR cmp_koch_sig +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_koch_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_koch_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,157 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-l n] [-n n] [-o file] [-q n] [-s file] [-S n] file\n\n", progname); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tsignature strength factor (default 5.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark bit length\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-q n\t\tquantization (JPEG quality) factor (default 90)\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 0; + int nb; + int s = 0; + int q = 90; + double l = 5.0; + + progname = argv[0]; wm_init(); + + while ((c = getopt(argc, argv, "h?l:n:o:q:s:S:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'l': + l = atof(optarg); + if (l <= 0.0) { + fprintf(stderr, "%s: signature strength factor %f out of range\n", progname, l); + exit(1); + } + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'q': + q = atoi(optarg); + if (q <= 0 || q > 100) { + fprintf(stderr, "%s: quantization factor %f out of range\n", progname, q); + exit(1); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KCSG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (l == 0.0) + fscanf(sig, "%lf\n", &l); + else + fscanf(sig, "%*lf\n"); + if (q == 0) + fscanf(sig, "%d\n", &q); + else + fscanf(sig, "%*d\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + + if (n > 0) { + nb = fread(signature, sizeof(char), i = NBITSTOBYTES(n), in); + if (nb < i) { + fprintf(stderr, "%s: failed to read all %d signature bits from %s\n", progname, n, input_name); + exit(1); + } + } + else { + if (fscanf(in, "%128[^\n\r]", signature) == EOF) { + fprintf(stderr, "%s: failed to read signature bits from %s\n", progname, input_name); + exit(1); + } + nb = strlen(signature); + n = NBYTESTOBITS(nb); + fprintf(stderr, "%s: got %d signature bits\n", progname, n); + } + + fprintf(out, "KCSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", l); + fprintf(out, "%d\n", q); + fprintf(out, "%d\n", random()); + fwrite(signature, sizeof(char), nb, out); + fprintf(out, "\n"); + + fclose(out); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_kutter_sig.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_kutter_sig.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,131 @@ +.\" +.\" gen_kutter_sig.1 - the *roff document processor man page source +.\" +.TH gen_kutter_sig 1 "98/06/30" "Watermarking, Version 1.0" +.SH NAME +.B gen_kutter_sig +\- a program to generate a signature for +the +.B wm_kutter_e +watermarking program +.SH SYNOPSIS +.B gen_kutter_sig +[ +.B \-h +] +[ +.BI \-n \ number +] +[ +.BI \-o \ file +] +[ +.BI \-p \ number +] +[ +.BI \-q \ number +] +[ +.BI \-r \ number +] +.br +[ +.BI \-s \ number +] +[ +.I file +] +.SH DESCRIPTION +.B gen_kutter_sig +is a program to generate a signature to be +embedded with the +.B wm_kutter_e +watermarking program and extracted with the +.B wm_kutter_d +program. The +.B cmp_kutter_sig +program is used to compare and test an +extracted signature with the original signature. +.PP +Please refer to M. Kutter's paper "Digital Signature of Color Images +using Amplitude Modulation", 1997, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-n \ number +Limit the signature length to +.I number +bits (0 < +.I number +<= 1024) unless reading from standard input. When reading from +standard input, the signature is terminated by the first +carriage return character. +.TP +.BI \-o \ file +Output signature to the specified +.TP +.BI \-p \ number +Density parameter in the range 0.0 < +.I number +<= 1.0. Default value 0.01. +.TP +.BI \-q \ number +Signature strength. Default value 0.1. +.TP +.BI \-r \ number +Signature bit repetition factor. Specifies how often a single +signature bit is embedded. Default value 8. +.I file +instead of standard output. +.TP +.BI \-s \ number +Specify a seed value to initialize the pseudo-random number +generator; if not specified, time and pid (process id) are used +to initialize the pseudo-random number generator. +.TP +.I file +Input file to read raw signature data from. Default: standard +input. +.PP +.SH OUTPUT +The output file has the following format: +.TP +.B KTSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The density parameter. +.TP +.I number +The signature strength. +.TP +.I number +The bit repetition parameter. +.TP +.I number +The seed value for the pseudo-random number generator. +.TP +.I string +The actual signature bytes. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B gen_kutter_sig +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR wm_kutter_e +(1), +.BR wm_kutter_d +(1), +.BR cmp_kutter_sig +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_wang_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_wang_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,198 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-b n] [-d n] [-e n] [-f n] [-F file] [-m n] [-n n] [-o file] [-s file] [-S n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.3)\n"); + fprintf(stderr, "\t-b n\t\tbeta factor (default 1.0)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-m n \t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 1000)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 1000; + int s = 0; + int e = 2; + int f = 1; + char F[MAXPATHLEN] = "filter.dat"; + double a = 0.3; + double b = 1.0; + double m = 0.0; + double d = 1.0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:b:d:e:f:F:h?m:n:o:s:S:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'b': + b = atof(optarg); + if (b <= 0.0) { + fprintf(stderr, "%s: beta factor %f out of range\n", progname, b); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "WGSG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (b == 0.0) + fscanf(sig, "%lf\n", &b); + else + fscanf(sig, "%*lf\n"); + if (e < 0) + fscanf(sig, "%d\n", &e); + else + fscanf(sig, "%*d\n"); + if (f == 0) + fscanf(sig, "%d\n", &f); + else + fscanf(sig, "%*d\n"); + if (!strcmp(F, "")) + fscanf(sig, "%[^\n\r]\n", &F); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "WGSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%f\n", b); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_xia_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_xia_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,198 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-d n] [-e n] [-f n] [-F file] [-l n] [-m n] [-n n] [-o file] [-s file] [-S n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.2)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level (default 2)\n"); + fprintf(stderr, "\t-m n \t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 1000)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 1000; + int s = 0; + int e = 2; + int f = 1; + char F[MAXPATHLEN] = "filter.dat"; + double a = 0.2; + int l = 2; + double m = 0.0; + double d = 1.0; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:l:d:e:f:F:h?m:n:o:s:S:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'l': + l = atoi(optarg); + if (l <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, l); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "XASG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (l == 0) + fscanf(sig, "%d\n", &l); + else + fscanf(sig, "%*d\n"); + if (e < 0) + fscanf(sig, "%d\n", &e); + else + fscanf(sig, "%*d\n"); + if (f == 0) + fscanf(sig, "%d\n", &f); + else + fscanf(sig, "%*d\n"); + if (!strcmp(F, "")) + fscanf(sig, "%[^\n\r]\n", &F); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "XASG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%d\n", l); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_xie_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_xie_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,203 @@ +#include "wm.h" +#include "signature.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F file] [-l n] [-n n] [-o file] [-s file] [-S n] [-v n] file\n\n", progname); + fprintf(stderr, "\t-a n\t\tembedding strength (default 0.5)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tembedding level (default 5)\n"); + fprintf(stderr, "\t-n n\t\twatermark bit length\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int verbose = 0; + int c; + int i; + double a = 0.5; + int l = 5; + int n = 0, nb; + int s = 0; + int e = 2; + int f = 1; + char F[MAXPATHLEN] = "filter.dat"; + + progname = argv[0]; + wm_init(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?l:n:o:s:S:v:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: embedding strength %f out of range\n", progname, a); + exit(1); + } + break; + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'l': + l = atoi(optarg); + if (l < 1) { + fprintf(stderr, "%s: embedding level out of range\n", progname); + exit(1); + } + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "XESG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (e < 0) + fscanf(sig, "%d\n", &e); + else + fscanf(sig, "%*d\n"); + if (f == 0) + fscanf(sig, "%d\n", &f); + else + fscanf(sig, "%*d\n"); + if (!strcmp(F, "")) + fscanf(sig, "%[^\n\r]\n", &F); + else + fscanf(sig, "%*[^\n\r]\n"); + if (l == 0) + fscanf(sig, "%d\n", &l); + else + fscanf(sig, "%*d\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + close(sig); + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + if (n > 0) { + nb = fread(signature, sizeof(char), i = NBITSTOBYTES(n), in); + if (nb < i) { + fprintf(stderr, "%s: failed to read all %d signature bits from %s\n", progname, n, input_name); + exit(1); + } + } + else { + if (fscanf(in, "%128[^\n\r]", signature) == EOF) { + fprintf(stderr, "%s: failed to read signature bits from %s\n", progname, input_name); + exit(1); + } + nb = strlen(signature); + n = NBYTESTOBITS(nb); + fprintf(stderr, "%s: got %d signature bits\n", progname, n); + } + + fprintf(out, "XESG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + fprintf(out, "%d\n", l); + fprintf(out, "%d\n", random()); + fwrite(signature, sizeof(char), nb, out); + fprintf(out, "\n"); + + fclose(out); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/gen_zhu_sig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gen_zhu_sig.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,198 @@ +#include "wm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-d n] [-e n] [-f n] [-F file] [-l n] [-m n] [-n n] [-o file] [-s file] [-S n]\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.2)\n"); + fprintf(stderr, "\t-d n\t\tdeviation (default 1.0)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method (default 2)\n"); + fprintf(stderr, "\t-f n\t\tfilter number (default 1)\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file (default 'filter.dat')\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level (default 7)\n"); + fprintf(stderr, "\t-m n\t\tmean value (default 0.0)\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 1000)\n"); + fprintf(stderr, "\t-o file\t\toutput file\n"); + fprintf(stderr, "\t-s file\t\tuse signature file's embedding information\n"); + fprintf(stderr, "\t-S n\t\tseed\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char signature_name[MAXPATHLEN]; + + int c; + int i; + int n = 1000; + int s = 0; + int e = 2; + int f = 1; + char F[MAXPATHLEN] = "filter.dat"; + double a = 0.2; + double m = 0.0; + double d = 1.0; + int l = 7; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "a:d:e:f:F:h?l:m:n:o:s:S:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + break; + case 'l': + l = atoi(optarg); + if (l <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, l); + exit(1); + } + break; + case 'd': + d = atof(optarg); + if (d <= 0.0) { + fprintf(stderr, "%s: deviation %f out of range\n", progname, d); + exit(1); + } + break; + case 'e': + e = atoi(optarg); + if (e < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, e); + } + break; + case 'f': + f = atoi(optarg); + if (f <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, f); + exit(1); + } + break; + case 'F': + strcpy(F, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'm': + m = atof(optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'S': + s = atoi(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 0) { + usage(); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "ZHSG") >= 4) { + if (n == 0) + fscanf(sig, "%d\n", &n); + else + fscanf(sig, "%*d\n"); + if (a == 0.0) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + if (l == 0) + fscanf(sig, "%d\n", &l); + else + fscanf(sig, "%*d\n"); + if (e < 0) + fscanf(sig, "%d\n", &e); + else + fscanf(sig, "%*d\n"); + if (f == 0) + fscanf(sig, "%d\n", &f); + else + fscanf(sig, "%*d\n"); + if (!strcmp(F, "")) + fscanf(sig, "%[^\n\r]\n", &F); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + + if (s) + srandom(s); + else + srandom(time(NULL) * getpid()); + + fprintf(out, "ZHSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", a); + fprintf(out, "%d\n", l); + fprintf(out, "%d\n", e); + fprintf(out, "%d\n", f); + fprintf(out, "%s\n", F); + + n >>= 1; + while (n > 0) { + double x; + double x1, x2; + + /* + * Algorithm P (Polar method for normal deviates), + * Knuth, D., "The Art of Computer Programming", Vol. 2, 3rd Edition, p. 122 + */ + do { + x1 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x2 = 2.0 * ((random() & RAND_MAX) / ((double) RAND_MAX + 1.0)) - 1.0; + x = x1 * x1 + x2 * x2; + } while (x >= 1.0); + x1 *= sqrt((-2.0) * log(x) / x); + x2 *= sqrt((-2.0) * log(x) / x); + + fprintf(out, "%f\n", m + d * x1); + fprintf(out, "%f\n", m + d * x2); + + n--; + } + + fclose(out); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/gray.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gray.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,117 @@ +#include "wm.h" +#include "gray.h" + +gray **alloc_grays_8x8() { + return alloc_grays(8, 8); +} + +gray **alloc_grays(int cols, int rows) { + gray **p; + int i; + + p = (gray **)malloc(rows * sizeof(gray *)); + if (!p) { +#ifdef DEBUG + fprintf(stderr, "alloc_grays(): malloc() failed\n"); + exit(1); +#else + return NULL; +#endif + } + + p[0] = (gray *)malloc(rows * cols * sizeof(gray)); + if (!p[0]) { +#ifdef DEBUG + fprintf(stderr, "alloc_grays(): malloc() failed\n"); + exit(1); +#else + free(p); + return NULL; +#endif + } + + for (i = 1; i < rows; i++) { + p[i] = &(p[0][i * cols]); + } + + return p; +} + +void free_grays(gray **grays) { + free(grays[0]); + free(grays); +} + +void copy_grays_to_block(gray ** block_grays, gray ** image_grays, int c, int r, int w, int h) { + int i, j; + +#ifdef DEBUG + if (!image_grays) { + fprintf(stderr, "copy_grays_to_block(): NULL image pixels\n"); + } + if (!block_grays) { + fprintf(stderr, "copy_grays_to_block(): NULL block pixels\n"); + } + if (w <= 0 || h <= 0 || c < 0 || r < 0) { + fprintf(stderr, "copy_grays_to_block(): block dimension out of range\n"); + } +#endif + + for (i = 0; i < w; i++) { + for (j = 0; j < h; j++) + block_grays[j][i] = image_grays[r + j][c + i]; + } +} + +void copy_grays_from_block(gray ** image_grays, gray ** block_grays, int +c, int r, int w, int h) { + int i, j; + +#ifdef DEBUG + if (!image_grays) { + fprintf(stderr, "copy_grays_from_block(): NULL image pixels\n"); + } + if (!block_grays) { + fprintf(stderr, "copy_grays_from_block(): NULL block pixels\n"); + } + if (w <= 0 || h <= 0 || c < 0 || r < 0) { + fprintf(stderr, "copy_grays_from_block(): block dimension out of range\n"); + } +#endif + + for (i = 0; i < w; i++) { + for (j = 0; j < h; j++) + image_grays[r + j][c + i] = block_grays[j][i]; + } +} + +void print_grays(gray **grays, int c, int r, int w, int h) { + int i, j; + gray *p; + +#ifdef DEBUG + if (!grays) { + fprintf(stderr, "print_grays(): NULL pixels\n"); + } + if (w <= 0 || h <= 0 || c < 0 || r < 0) { + fprintf(stderr, "print_grays(): block dimension out of range\n"); + } +#endif + + for (j = r; j < r + h; j++) { + p = &grays[j][c]; + for (i = 0; i < w; i++) + fprintf(stderr, "%3d ", *(p++)); + fprintf(stderr, "\n"); + } +} + +void print_grays_8x8(gray **grays) { + int i, j; + + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) + fprintf(stderr, "%3d ", grays[i][j]); + fprintf(stderr, "\n"); + } +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/gray.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/gray.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,14 @@ +#ifndef GRAY_H +#define GRAY_H + +#include "wm.h" +#include "pgm.h" + +gray **alloc_grays(int cols, int rows); +gray **alloc_grays_8x8(); +void free_grays(gray **grays); +void copy_grays_to_block(gray ** block_grays, gray ** image_grays, int col, int row, int width, int height); +void copy_grays_from_block(gray ** image_grays, gray ** block_grays, int col, int row, int width, int height); +void print_grays(gray **grays, int col, int row, int width, int height); +void print_grays_8x8(gray **grays); +#endif diff -r 000000000000 -r be303a3f5ea8 Meerwald/kim.wm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/kim.wm Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,1357 @@ +KIWM +1355 +0.962332 +0.556667 +0.082221 +-0.633609 +0.096048 +-0.194063 +0.123496 +0.122363 +0.146482 +0.391184 +-0.526367 +-1.877353 +-1.372872 +-0.561188 +-0.281722 +1.638267 +-1.229134 +0.160058 +0.472432 +0.221371 +0.702672 +0.048673 +0.989222 +-1.919514 +-0.754875 +2.555153 +0.588800 +-0.230591 +-1.268933 +-0.432563 +-1.148047 +1.357527 +-2.171152 +-1.224077 +0.738547 +-0.744086 +-2.065068 +-0.247288 +-0.340216 +-0.375178 +-1.423221 +1.810807 +-0.424804 +2.377079 +-0.327323 +-1.021380 +-0.523512 +-1.836423 +1.165727 +-0.504592 +0.809199 +-0.000000 +1.526998 +-0.849962 +0.150998 +0.012201 +0.636885 +-0.887091 +0.951992 +-0.141332 +0.012882 +2.134151 +0.530619 +1.086284 +-0.077457 +0.151248 +0.472596 +0.111207 +-1.814436 +-2.183967 +-1.219403 +-0.151640 +-1.809015 +1.220303 +0.306635 +1.195953 +1.020683 +-0.162146 +-0.570420 +0.670643 +-0.546657 +0.675466 +0.344063 +0.911147 +-0.604959 +-0.143986 +0.344271 +1.647242 +-0.985017 +0.780793 +0.449889 +-1.545793 +1.597551 +-0.851752 +-0.218907 +-0.716190 +0.190646 +-0.992265 +0.994210 +-1.308444 +-0.773073 +0.102998 +0.223968 +-0.382646 +-1.252377 +0.813933 +-0.915755 +0.056218 +-0.203382 +-0.111543 +-1.336821 +0.449946 +1.740969 +-1.707382 +0.731193 +-1.303742 +-0.710640 +0.984013 +-0.410900 +-0.564259 +1.234480 +1.160097 +-1.103943 +-1.142045 +0.576878 +-0.181864 +-0.485015 +-0.192903 +0.018258 +-0.995477 +0.341180 +1.766650 +1.924044 +1.247036 +-1.184311 +0.340864 +-0.765852 +0.711104 +-2.257150 +0.171806 +1.255734 +0.946823 +1.014442 +0.549990 +0.444585 +0.345394 +-1.583237 +-0.365796 +0.241952 +0.292189 +-0.979635 +-0.107870 +-0.380929 +-1.064084 +-2.073624 +0.134566 +1.408207 +0.438263 +-1.423864 +1.025784 +0.770359 +-1.198515 +1.465579 +0.090389 +-0.429007 +-0.786517 +0.238290 +0.266943 +0.496165 +0.945898 +1.238995 +-0.187096 +0.899346 +0.505563 +0.305432 +-0.277959 +0.643918 +-1.165478 +-0.146899 +0.240230 +0.333667 +-0.572118 +0.177290 +-0.534499 +0.743019 +-0.684625 +-1.649618 +0.354437 +1.560532 +0.368007 +0.649749 +0.955202 +2.480710 +0.446286 +1.202847 +-1.204399 +-2.191566 +-0.010944 +0.722918 +-0.892965 +-0.881475 +-1.050047 +-0.434134 +2.116337 +-0.356573 +1.175708 +0.234469 +-0.739920 +-0.648118 +0.539135 +-1.775614 +-1.661253 +-0.412639 +-0.790764 +0.177378 +-0.074719 +0.069769 +2.054109 +-0.965241 +0.289114 +-0.280887 +-0.403755 +1.128699 +-1.975665 +1.304009 +1.933895 +0.215058 +-0.492331 +2.718813 +-0.803870 +0.413460 +1.072356 +1.442729 +1.270637 +1.203333 +0.393772 +-1.326521 +-0.776050 +-0.574517 +-0.705867 +-1.437651 +-0.640251 +0.885677 +-0.471762 +1.668912 +-0.813074 +0.914347 +-1.185763 +-0.986176 +-0.915537 +-0.369830 +-0.276946 +-0.448809 +-0.346480 +-2.005974 +1.595203 +0.163654 +-0.293149 +-1.153530 +-1.774225 +0.893254 +-1.062011 +0.629967 +-1.271504 +-0.322958 +0.261003 +-0.032646 +0.267219 +-0.892035 +-0.462762 +-0.549258 +1.183236 +1.197246 +-1.693596 +0.502211 +-1.319969 +0.007531 +-0.696435 +0.907949 +1.601883 +-0.488034 +0.157065 +0.256474 +1.080514 +-1.005948 +0.823408 +0.367914 +0.859020 +0.508878 +1.009951 +0.676905 +1.410009 +-0.931537 +1.861433 +0.123460 +-0.350943 +0.821319 +0.590396 +0.681364 +-0.685216 +0.516104 +0.552966 +-0.608172 +-0.146709 +0.109984 +0.253258 +-2.250772 +1.062844 +0.931289 +1.731681 +0.159618 +-1.106649 +0.225650 +1.377349 +0.647308 +-0.413768 +2.115625 +0.263609 +0.988429 +1.796713 +-0.754644 +-1.024075 +-0.884133 +1.317469 +1.854804 +-0.597290 +-0.192368 +-0.194233 +-2.206987 +1.450779 +-0.758369 +-0.797507 +-0.528943 +0.557464 +0.095253 +-0.648942 +0.049879 +-1.025507 +0.363632 +-0.404161 +-0.556897 +-1.104042 +-0.727984 +-0.500627 +-0.510666 +0.001622 +0.969936 +-0.228339 +1.479599 +0.888408 +-0.228277 +0.657491 +1.071187 +0.211604 +-0.014905 +0.342410 +0.766951 +1.608364 +0.327121 +-0.893321 +0.505270 +-0.553077 +-1.695186 +-0.146973 +-1.348171 +-0.556646 +0.974448 +2.579097 +0.374829 +1.932532 +1.216651 +0.173396 +-0.253070 +0.362591 +-0.794043 +-0.843569 +0.509245 +1.285380 +1.327135 +0.901422 +1.716964 +-1.230809 +0.485979 +-1.417534 +-0.454355 +-0.199235 +-0.317006 +0.722096 +-1.569581 +1.433715 +-1.445786 +1.543912 +-1.516668 +0.172061 +0.097022 +-0.649209 +0.364013 +-0.190471 +0.312249 +1.935630 +0.921477 +-0.580349 +1.832545 +0.087918 +0.398211 +-0.091384 +0.682236 +0.137163 +0.152337 +-0.572804 +0.493609 +-1.947580 +1.569860 +0.232433 +0.231307 +1.495536 +-0.240642 +1.083944 +-0.177901 +-1.087129 +-1.588726 +-1.327508 +0.070794 +-1.956181 +-0.905052 +1.408029 +1.018116 +0.111809 +0.997380 +1.613238 +0.595723 +-1.036768 +1.082797 +1.144363 +-1.461671 +-1.187270 +0.522118 +0.562675 +-0.392964 +0.355249 +0.506514 +-0.008255 +1.534232 +-1.399326 +0.697663 +-0.824827 +-1.095458 +1.181808 +-1.400085 +1.075670 +-0.776688 +-1.791683 +0.405204 +-0.064481 +1.173024 +0.042371 +-1.456490 +1.365541 +-1.936723 +-0.633273 +0.018991 +-0.559432 +-1.938210 +0.346755 +0.958718 +-0.687103 +-0.802676 +-0.075698 +0.699671 +1.030273 +-1.485057 +-2.241910 +-0.774622 +-0.327114 +-2.311965 +1.164833 +1.335756 +-1.300271 +1.294052 +0.077326 +0.077266 +0.159941 +-0.000000 +-1.626692 +-1.138459 +1.974884 +-0.845371 +1.029784 +-0.353462 +0.162361 +1.274496 +-0.529787 +-1.350163 +0.647513 +1.251816 +-1.047685 +-0.627875 +-0.262224 +-1.139110 +0.040953 +0.571867 +-0.561651 +-0.231005 +0.354954 +0.368241 +1.868675 +-0.165666 +-1.499194 +-0.470659 +-0.243620 +-0.627829 +-0.422844 +-1.410118 +0.261456 +0.979537 +0.027163 +-0.116895 +-0.240002 +-2.097195 +-0.712792 +0.103366 +-0.108797 +0.583712 +0.700059 +-0.180130 +0.642766 +-0.691701 +-0.922612 +-0.906579 +0.237463 +-0.912041 +0.459539 +-1.552557 +0.977236 +0.865687 +-0.232066 +0.562247 +0.057908 +-0.105468 +-0.494112 +0.933916 +0.055251 +0.356051 +1.073339 +0.833233 +-0.218228 +0.817913 +1.134855 +-1.293821 +-0.003103 +0.383705 +2.600835 +-0.293719 +1.321608 +1.348991 +0.265581 +-0.111605 +0.570303 +-0.720707 +0.712688 +0.171599 +-0.805356 +-1.204556 +0.092175 +1.937029 +-0.248083 +1.130669 +2.216255 +-0.208008 +-0.598859 +-0.475199 +-0.703773 +1.061720 +-0.366410 +0.736291 +-2.175200 +-0.618288 +0.366664 +0.022255 +2.448268 +0.972673 +0.773316 +-0.929258 +-1.448055 +1.326897 +-0.033220 +1.400053 +0.085527 +1.475316 +-2.523901 +-0.562970 +0.077428 +1.305169 +-1.845645 +0.536509 +0.913856 +-1.998615 +1.785089 +0.085965 +-0.153676 +-0.684244 +-0.264492 +0.634034 +0.706441 +-0.182099 +-0.056047 +-0.008010 +0.448742 +-0.823136 +1.823259 +-1.949795 +-0.001492 +0.570050 +0.920788 +-2.458473 +1.744821 +-0.199208 +-0.163441 +-1.972016 +0.783169 +1.484371 +0.838996 +0.199467 +2.068226 +1.118419 +-0.082664 +0.875158 +0.153034 +0.334282 +0.626632 +1.057521 +-0.330643 +0.547296 +0.129792 +-2.459100 +-1.150473 +-2.271778 +0.929821 +0.587366 +1.249803 +-0.815444 +-0.114226 +-1.591833 +1.457586 +-0.145794 +0.608559 +-0.889411 +1.604052 +-1.260099 +-2.189924 +0.857393 +-0.465808 +-1.767197 +0.010157 +-1.356003 +0.875180 +-0.088985 +-0.728166 +-0.500725 +0.790471 +1.129603 +-0.805891 +-0.545498 +-0.375471 +1.647759 +0.102118 +-0.511146 +0.403103 +0.021988 +0.517253 +0.629728 +-1.376084 +-2.325633 +-0.542278 +2.060301 +-0.658047 +-0.294551 +0.054392 +0.030098 +0.055687 +-0.041833 +0.172909 +0.381885 +0.499665 +-0.274878 +0.300686 +0.426879 +0.571290 +-0.151969 +0.093513 +0.822162 +-1.447117 +-0.437842 +-0.077609 +0.346521 +-0.506714 +-1.165304 +-0.410199 +-0.697889 +0.714022 +-0.838594 +1.011880 +-0.146804 +-0.021718 +-0.958048 +0.044506 +-0.632981 +-0.148508 +-0.800510 +0.297188 +-0.573323 +-1.199200 +-0.135732 +-1.073606 +-0.587947 +0.139860 +0.244110 +0.056004 +-0.987948 +0.261046 +-0.762227 +-0.473150 +-0.901566 +-1.345361 +-0.416543 +0.107324 +0.070963 +-0.991099 +1.121917 +-0.198889 +0.979131 +-0.706490 +0.318302 +-1.006848 +-0.045405 +-0.819774 +-1.734816 +0.263146 +0.559066 +-1.324734 +-1.503505 +-0.317212 +-1.213582 +-0.472405 +-0.398811 +-0.084117 +0.042810 +0.018063 +0.126446 +-0.300849 +-1.438995 +1.059823 +0.905066 +-1.191017 +-0.412561 +1.401556 +1.682639 +1.235175 +1.510889 +-0.478064 +0.787609 +-0.248825 +1.095951 +-2.025804 +-0.073810 +1.297199 +0.205603 +-1.625678 +0.037104 +2.478620 +0.260394 +-1.412734 +0.379282 +-1.097277 +0.345453 +0.562203 +-0.967125 +0.723834 +-0.536682 +0.511301 +-0.241997 +1.809698 +-0.856378 +-0.686157 +1.065629 +1.237332 +-0.483861 +-1.124981 +1.145046 +-2.257304 +-1.398478 +0.380329 +0.388370 +1.364487 +-1.661558 +-0.932519 +2.584794 +-0.834474 +0.507069 +-0.075090 +-0.500025 +-0.796710 +-0.328448 +0.040379 +1.668595 +0.031868 +1.093909 +-0.839879 +-0.773817 +-0.214583 +-0.148545 +0.029929 +0.558572 +3.001701 +-1.234879 +0.298178 +-0.063330 +0.221258 +0.505887 +1.093529 +-0.133752 +0.472158 +-0.784292 +1.898582 +-0.797994 +0.838201 +1.079857 +-0.555587 +-1.174358 +0.439672 +1.019777 +-0.251591 +1.938149 +1.961025 +1.393031 +1.157179 +0.143640 +0.162219 +-1.654668 +-0.391720 +-0.850136 +-0.843736 +-1.098856 +-0.426070 +1.031232 +0.185338 +-2.378791 +0.785136 +-0.472527 +1.356798 +-0.048270 +-1.219499 +-0.000014 +0.000000 +1.653761 +0.926627 +-0.183265 +0.541314 +-0.792713 +1.132386 +0.061920 +0.377768 +-1.729287 +1.409065 +1.362526 +1.237328 +0.275936 +-0.173801 +-0.792286 +0.898927 +0.841566 +0.455687 +-0.787783 +-0.918078 +-0.051485 +1.545538 +-0.548565 +-1.232519 +0.485778 +-1.145190 +-1.205461 +-0.376026 +1.146577 +0.163427 +-0.170428 +-0.254409 +1.727431 +2.004142 +0.573157 +-0.580318 +0.039385 +-1.473294 +0.578885 +-0.531143 +0.242427 +0.134932 +-0.063548 +0.108608 +-0.703366 +0.046938 +-0.195253 +1.128167 +-1.244153 +0.013840 +1.426704 +2.175085 +0.852291 +-0.629366 +1.205126 +1.587903 +-0.225055 +0.730826 +0.199188 +0.262757 +-2.026036 +2.548802 +0.067432 +0.337652 +-1.200474 +0.390289 +0.724912 +-0.728293 +-0.400125 +1.057730 +0.284512 +1.356845 +1.262961 +0.715332 +0.219038 +0.838986 +-0.079223 +1.207940 +-0.864689 +-1.403007 +0.702135 +0.304981 +-0.715290 +-0.179093 +-0.654140 +-0.592485 +-0.203102 +0.641075 +-1.160231 +0.137886 +0.044852 +0.814669 +0.474713 +0.578984 +1.339580 +-0.704257 +2.218421 +-0.053910 +-0.300057 +-1.115984 +-0.283288 +0.837244 +-0.649886 +0.544806 +0.390755 +-0.678420 +0.774365 +0.230305 +-1.233942 +-0.558171 +0.641170 +-0.212701 +0.839399 +-0.145086 +-1.133135 +0.950919 +-0.019963 +-0.666213 +-1.468022 +0.043254 +0.592090 +-0.503930 +0.136585 +0.713911 +1.020836 +0.163338 +-0.167977 +1.189986 +-0.925863 +0.942145 +1.931373 +2.410760 +1.502377 +0.480816 +-0.410125 +-1.754269 +1.771161 +1.138513 +-0.439610 +0.519642 +-0.514121 +-0.184253 +-0.554452 +-0.906019 +-0.051763 +-0.466834 +1.056017 +0.486042 +-0.013974 +-0.604122 +-0.034387 +-0.391313 +0.137949 +0.178621 +0.168726 +0.384911 +-0.516506 +-1.858138 +-1.272083 +-0.586784 +-0.210750 +1.565293 +-1.193789 +0.067808 +0.444774 +0.225569 +0.816752 +0.193715 +1.009110 +-1.966002 +-0.749950 +2.619986 +0.541126 +-0.248174 +-1.334370 +-0.546271 +-1.129650 +1.312073 +-2.186958 +-1.225178 +0.738282 +-0.704350 +-1.990512 +-0.263080 +-0.337961 +-0.339003 +-1.395911 +1.713285 +-0.442898 +2.271419 +-0.311727 +-1.007631 +-0.454274 +-1.939454 +1.047500 +-0.438382 +0.775041 +-0.190614 +1.490205 +-0.673372 +0.086851 +0.023908 +0.633164 +-0.955483 +0.991228 +-0.159539 +-0.110448 +2.114254 +0.576117 +1.021641 +-0.057840 +0.038827 +0.374448 +0.047520 +-1.832008 +-2.191160 +-1.225659 +-0.199752 +-1.994375 +1.179066 +0.276245 +1.145432 +0.949971 +-0.201142 +-0.592021 +0.602002 +-0.591986 +0.557764 +0.199068 +0.914678 +-0.628383 +-0.096795 +0.353055 +1.701438 +-1.104040 +0.784143 +0.372677 +-1.422581 +1.660286 +-0.982775 +-0.033252 +-0.673421 +-0.059739 +-0.976178 +0.966688 +-1.323452 +-0.745806 +0.242133 +0.232929 +-0.375061 +-1.086295 +0.801582 +-0.984452 +0.057480 +-0.259334 +-0.075078 +-1.292897 +0.439195 +1.845204 +-1.743856 +0.681346 +-1.269916 +-0.651877 +0.956892 +-0.489734 +-0.455425 +1.345978 +1.346358 +-1.034300 +-1.108306 +0.543621 +-0.178666 +-0.435083 +-0.285505 +0.152209 +-0.866159 +0.335573 +1.937581 +2.009012 +1.124180 +-1.110009 +0.391862 +-0.627807 +0.756705 +-2.222022 +0.259731 +1.221079 +0.895368 +1.039731 +0.558807 +0.409755 +0.325785 +-1.521218 +-0.461542 +0.212405 +0.135540 +-0.999926 +0.050023 +-0.441320 +-0.959328 +-2.117983 +0.127653 +1.397314 +0.465269 +-1.442558 +1.032142 +0.687093 +-1.157764 +1.454994 +0.176766 +-0.450301 +-0.845662 +0.254797 +0.300438 +0.499923 +0.841109 +1.189231 +-0.389316 +0.903121 +0.429228 +0.354709 +-0.278802 +0.569597 +-1.250894 +-0.078873 +0.262799 +0.408799 +-0.662547 +0.073364 +-0.539975 +0.697825 +-0.729300 +-1.667902 +0.404374 +1.508858 +0.457223 +0.600935 +0.926265 +2.371768 +0.400843 +1.152092 +-1.210325 +-2.236770 +-0.077011 +0.647857 +-0.916284 +-0.896387 +-1.059701 +-0.405193 +2.059824 +-0.378898 +1.139001 +0.299734 +-0.873416 +-0.713086 +0.475052 +-1.833489 +-1.521881 +-0.503475 +-0.813902 +0.342933 +0.084518 +0.203218 +2.225871 +-0.914185 +0.372621 +-0.461066 +-0.214351 +1.058619 +-1.990932 +1.379988 +1.978481 +0.049753 +-0.511893 +2.783136 +-0.771894 +0.388456 +1.012734 +1.413472 +1.307668 +1.082720 +0.367148 +-1.286758 +-0.747318 +-0.591471 +-0.768500 +-1.361262 +-0.508793 +0.848881 +-0.516767 +1.606654 +-0.789966 +0.873479 +-1.178956 +-0.846285 +-1.063528 +-0.347458 +-0.341720 +-0.493649 +-0.392845 +-2.026197 +1.678537 +0.178448 +-0.364740 +-1.083970 +-1.719471 +0.822012 +-1.028957 +0.494546 +-1.368308 +-0.254854 +0.239639 +0.071094 +0.280322 +-0.778433 +-0.358841 +-0.505919 +1.215691 +1.244249 +-1.763283 +0.489019 +-1.180686 +-0.114219 +-0.610462 +0.899572 +1.549260 +-0.510368 +0.117466 +0.146705 +1.075438 +-1.016334 +0.764884 +0.444672 +0.821124 +0.554229 +0.990804 +0.580272 +1.350343 +-1.034901 +1.859178 +0.151922 +-0.406281 +0.820652 +0.546970 +0.646543 +-0.565058 +0.587740 +0.639578 +-0.695414 +-0.156158 +0.000908 +0.390031 +-2.275600 +1.163262 +0.848753 +1.717367 +0.171598 +-1.172301 +0.228746 +1.469253 +0.589259 +-0.438635 +2.210261 +0.403187 +0.824944 +1.817292 +-0.788960 +-1.063290 +-0.752655 +1.362129 +1.906240 +-0.617246 +-0.150002 +-0.208212 +-2.255388 +1.377619 +-0.894031 +-0.745722 +-0.610713 +0.487531 +0.065207 +-0.690747 +0.045275 +-1.024638 +0.248709 +-0.470497 +-0.488711 +-0.968175 +-0.819445 +-0.474832 +-0.506707 +0.042432 +0.932488 +-0.232458 +1.559593 +0.777438 +-0.123535 +0.689403 +0.970863 +0.164986 +0.159591 diff -r 000000000000 -r be303a3f5ea8 Meerwald/kim_common.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/kim_common.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,60 @@ +#include "wm.h" +#include "kim_common.h" + + +// find the largest absolute coefficient of a subband +double find_subband_largest_coeff(Image_tree s, int subband, int verbose) { + int i, j; + double max; + + max = 0.0; + for (i = 5; i < s->image->height-5; i++) + for (j = 5; j < s->image->width-5; j++) { + double coeff; + + coeff = fabs(get_pixel(s->image, i, j)); + if (coeff > max) + max = coeff; + } + + if (verbose > 8) + fprintf(stderr, " subband %f\n", max); + + return max; +} + +// find largest absolute coefficient of the detail subbands (LH, HL, HH) of +// a decomposition level +double find_level_largest_coeff(Image_tree p, int verbose) { + double h, v, d; + + h = find_subband_largest_coeff(p->horizontal, HORIZONTAL, verbose); + v = find_subband_largest_coeff(p->vertical, VERTICAL, verbose); + d = find_subband_largest_coeff(p->diagonal, DIAGONAL, verbose); + + return MAX(h, MAX(v, d)); +} + +// calculate the significance threshold given the maximum absolute +// coefficient at a decomposition level +double calc_level_threshold(double max_coeff, int verbose) { + double threshold; + + threshold = pow(2.0, floor(log(max_coeff) / log(2.0)) - 1.0); + + if (verbose > 7) + fprintf(stderr, " max %f, threshold %f\n", max_coeff, threshold); + + return threshold; +} + +// calculate an appropriate embedding strength for a given decomposition level +// and a base alpha strength +double calc_level_alpha_detail(double alpha, int maxlevels, int level, int verbose) { + double level_alpha; + + level_alpha = alpha / pow(2.0, level - 1); + + return level_alpha; +} + diff -r 000000000000 -r be303a3f5ea8 Meerwald/kim_common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/kim_common.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,13 @@ +#ifndef KIM_COMMON_H +#define KIM_COMMON_H + +#include "dwt.h" +#include "dwt_util.h" + +double find_subband_largest_coeff(Image_tree p, int subband, int verbose); +double find_level_largest_coeff(Image_tree p, int verbose); + +double calc_level_threshold(double max_coeff, int verbose); +double calc_level_alpha_detail(double alpha, int maxlevels, int level, int verbose); + +#endif diff -r 000000000000 -r be303a3f5ea8 Meerwald/signature.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/signature.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,95 @@ +#include "signature.h" + +void init_signature_bits() { + bzero(signature, sizeof(signature)); +} + +void init_signature1_bits() { + bzero(signature1, sizeof(signature1)); +} + +void init_signature2_bits() { + bzero(signature2, sizeof(signature2)); +} + +int get_signature_bit(int n) { + int byte = n >> 3; + int bit = n & 7; + +#ifdef DEBUG + if (byte < 0 || byte >= NSIGNATURE) + fprintf(stderr, "get_signature_bit(): index out of range\n"); +#endif + + return (signature[byte] & (1 << bit)) >> bit; +} + +int get_signature1_bit(int n) { + int byte = n >> 3; + int bit = n & 7; + +#ifdef DEBUG + if (byte < 0 || byte >= NSIGNATURE) + fprintf(stderr, "get_signature1_bit(): index out of range\n"); +#endif + + return (signature1[byte] & (1 << bit)) >> bit; +} + +int get_signature2_bit(int n) { + int byte = n >> 3; + int bit = n & 7; + +#ifdef DEBUG + if (byte < 0 || byte >= NSIGNATURE) + fprintf(stderr, "get_signature2_bit(): index out of range\n"); +#endif + + return (signature2[byte] & (1 << bit)) >> bit; +} + +void set_signature_bit(int n, int v) { + int byte = n >> 3; + int bit = n & 7; + +#ifdef DEBUG + if (byte < 0 || byte >= NSIGNATURE) + fprintf(stderr, "get_signature_bit(): index out of range\n"); +#endif + + if (v) + signature[byte] |= (1 << bit); + else + signature[byte] &= ~(1 << bit); +} + +void set_signature1_bit(int n, int v) { + int byte = n >> 3; + int bit = n & 7; + +#ifdef DEBUG + if (byte < 0 || byte >= NSIGNATURE) + fprintf(stderr, "get_signature1_bit(): index out of range\n"); +#endif + + if (v) + signature1[byte] |= (1 << bit); + else + signature1[byte] &= ~(1 << bit); +} + +void set_signature2_bit(int n, int v) { + int byte = n >> 3; + int bit = n & 7; + +#ifdef DEBUG + if (byte < 0 || byte >= NSIGNATURE) + fprintf(stderr, "get_signature2_bit(): index out of range\n"); +#endif + + if (v) + signature2[byte] |= (1 << bit); + else + signature2[byte] &= ~(1 << bit); +} + diff -r 000000000000 -r be303a3f5ea8 Meerwald/signature.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/signature.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,32 @@ +#ifndef SIGNATURE_H +#define SIGNATURE_H + +#include "wm.h" + +#define NSIGNATURE 4096 +#define NBITSIGNATURE (NSIGNATURE * 8) + +int n_signature; +int nbit_signature; +int n_signature1; +int nbit_signature1; +int n_signature2; +int nbit_signature2; + +char signature[NSIGNATURE]; +char signature1[NSIGNATURE]; +char signature2[NSIGNATURE]; + +void init_signature_bits(); +int get_signature_bit(int n); +void set_signature_bit(int n, int v); + +void init_signature1_bits(); +int get_signature1_bit(int n); +void set_signature1_bit(int n, int v); + +void init_signature2_bits(); +int get_signature2_bit(int n); +void set_signature2_bit(int n, int v); + +#endif diff -r 000000000000 -r be303a3f5ea8 Meerwald/sort.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/sort.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,184 @@ +#include "sort.h" + +#define SWAP_GRAY(A, B) {gray t = A; A = B; B = t;} + +/* + * quicksort-alike, from the EMX library (emx/src/lib/misc/qsort.c) + * by Eberhard Mattes + * + * sort() is not stable, the order of equal elements is not defined + */ + +void _sort_grays(gray *l, gray *r) { + gray *i; + gray *j; + gray *x; + +redo: + i = l; + j = r; + x = l + sizeof(gray) * (((r-l) / sizeof(gray)) / 2); + + do { + while (i != x && *i < *x) + i++; + while (j != x && *j > *x) + j--; + if (i < j) { + SWAP_GRAY(*i, *j); + if (x == i) + x = j; + else if (x == j) + x = i; + } + if (i <= j) { + i++; + if (j > l) + j--; + } + } while (i <= j); + + if (j-l < r-i) { + if (l < j) + _sort_grays(l, j); + if (i < r) { + l = i; + goto redo; + } + } + else { + if (i < r) + _sort_grays(i, r); + if (l < j) { + r = j; + goto redo; + } + } +} + +void sort_grays(gray a[], int n) { + if (n > 1) + _sort_grays(&a[0], &a[n-1]); +} + +/* + * select_largest(), from the Numeric Recipes in C, Chapter 8, p. 344, + * see http://www.nr.com + * + * returns in largest[0..m-1] the largest m elements of array[0..n-1] + * with largest[0] guaranteed to be the mth largest element; largest[] is + * not sorted; the array[] is not altered; this function should be used + * only when m << n + */ + +void select_largest_grays(gray array[], int n, int m, gray largest[]) { + int i, j, k; + + if (m <= 0 || m > n/2) + return; + + for (i = 0; i < m; i++) + largest[i] = array[i]; + sort_grays(largest, m); + + for (i = m; i < n; i++) { + if (array[i] > largest[0]) { + largest[0] = array[i]; + j = 0; + k = 1; + while (k < m) { + if (k < m-1 && largest[k] > largest[k+1]) + k++; + if (largest[j] <= largest[k]) + break; + SWAP_GRAY(largest[k], largest[j]); + j = k; + k = k << 1; + } + } + } +} + +#define SWAP_DOUBLE(A, B) {double t = A; A = B; B = t;} + +void _sort_coeffs(double *l, double *r) { + double *i; + double *j; + double *x; + +redo: + i = l; + j = r; + x = l + sizeof(double) * (((r-l) / sizeof(double)) / 2); + + do { + while (i != x && *i < *x) + i++; + while (j != x && *j > *x) + j--; + if (i < j) { + SWAP_DOUBLE(*i, *j); + if (x == i) + x = j; + else if (x == j) + x = i; + } + if (i <= j) { + i++; + if (j > l) + j--; + } + } while (i <= j); + + if (j-l < r-i) { + if (l < j) + _sort_coeffs(l, j); + if (i < r) { + l = i; + goto redo; + } + } + else { + if (i < r) + _sort_coeffs(i, r); + if (l < j) { + r = j; + goto redo; + } + } +} + +void sort_coeffs(double a[], int n) { + if (n > 1) + _sort_coeffs(&a[0], &a[n-1]); +} + +void select_largest_coeffs(double array[], int n, int m, double largest[]) { + int i, j, k; + + if (m <= 0 || m > n/2) + return; + + for (i = 0; i < m; i++) + largest[i] = array[i]; + sort_coeffs(largest, m); + + for (i = m; i < n; i++) { + if (array[i] > largest[0]) { + largest[0] = array[i]; + j = 0; + k = 1; + while (k < m) { + if (k < m-1 && largest[k] > largest[k+1]) + k++; + if (largest[j] <= largest[k]) + break; + SWAP_DOUBLE(largest[k], largest[j]); + j = k; + k = k << 1; + } + } + } +} + + diff -r 000000000000 -r be303a3f5ea8 Meerwald/sort.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/sort.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,13 @@ +#ifndef SORT_H +#define SORT_H + +#include "wm.h" +#include "pgm.h" + +void sort_grays(gray a[], int n); +void select_largest_grays(gray array[], int n, int m, gray largest[]); + +void sort_coeffs(double a[], int n); +void select_largest_coeffs(double array[], int n, int m, double largest[]); + +#endif diff -r 000000000000 -r be303a3f5ea8 Meerwald/wang_common.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wang_common.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,176 @@ +#include "dwt_util.h" +#include "wang_common.h" + +void init_subbands(Image_tree tree) { + int levels = 0; + int i; + Image_tree p = tree; + + // determine # of detail subbands + while (p->coarse != NULL) { + levels++; + p = p->coarse; + } + + // there are 3 detail subbands per level + n_subbands = 3 * levels; + + // allocate memory for subband data + subbands = malloc(n_subbands * sizeof(Subband_data)); + + p = tree; + i = 0; + while (p->coarse != NULL) { + subbands[i++] = alloc_subband(HORIZONTAL, p->horizontal); + subbands[i++] = alloc_subband(VERTICAL, p->vertical); + subbands[i++] = alloc_subband(DIAGONAL, p->diagonal); + + p = p->coarse; + } + +} + +Subband_data alloc_subband(int type, Image_tree tree) { + int i; + Subband_data p = malloc(sizeof(struct Subband_data_struct)); + + p->T = 0.0; + p->beta = 0.0; + p->Cmax = 0.0; + p->tree = tree; + p->level = tree->level; + p->width = tree->image->width; + p->height = tree->image->height; + p->size = p->height * p->width; + p->image = tree->image; + p->type = type; + + p->selected = malloc(p->height * sizeof(char *)); + p->selected[0] = calloc(p->size, sizeof(char)); + for (i = 1; i < p->height; i++) + p->selected[i] = &(p->selected[0][i * p->width]); + + return p; +} + +void set_subband_beta(Subband_data subband, double beta) { + subband->beta = beta; +} + +void set_subbands_beta(double beta) { + int i; + + for (i = 0; i < n_subbands; i++) + set_subband_beta(subbands[i], beta); +} + +void set_subbands_type_beta(int type, double beta) { + int i; + + for (i = 0; i < n_subbands; i++) + if (subbands[i]->type == type) + set_subband_beta(subbands[i], beta); +} + +void calc_subband_threshold(Subband_data subband) { + double max; + int i, j; + + max = fabs(get_pixel(subband->image, 0, 0)); + for (i = 0; i < subband->height; i++) + for (j = 0; j < subband->width; j++) { + Pixel p = fabs(get_pixel(subband->image, i, j)); + if (p > max) + max = p; + } + + subband->Cmax = max; + subband->T = max / 2.0; +} + +void calc_subbands_threshold() { + int i; + + for (i = 0; i < n_subbands; i++) + calc_subband_threshold(subbands[i]); +} + +Subband_data select_subband() { + int max = 0; + int i; + + for (i = 0; i < n_subbands; i++) + if ((subbands[i]->beta * subbands[i]->T) > (subbands[max]->beta * subbands[max]->T)) + max = i; + + return subbands[max]; +} + +int subband_coeff_isselected(Subband_data subband, int coeff) { + return subband->selected[0][coeff]; +} + +Pixel get_subband_coeff(Subband_data subband, int coeff) { + return subband->image->data[coeff]; +} + +void set_subband_coeff(Subband_data subband, int coeff, Pixel data) { + subband->image->data[coeff] = data; +} + +int select_subband_coeff_from(Subband_data subband, int from) { + int i; + + for (i = from; i < subband->size; i++) + if (!subband_coeff_isselected(subband, i) && + get_subband_coeff(subband, i) > subband->T) + return i; + + return -1; +} + +int select_subband_coeff(Subband_data subband) { + select_subband_coeff_from(subband, 0); +} + +void mark_subband_coeff(Subband_data subband, int coeff) { + subband->selected[0][coeff] = 1; +} + +void free_subband(Subband_data subband) { + free(subband->selected[0]); + free(subband->selected); + free(subband); +} + +void free_subbands() { + int i; + + for (i = 0; i < n_subbands; i++) + free_subband(subbands[i]); + + free(subbands); +} + +#define LARGE DBL_MAX + +Pixel figure_orig_coeff(double T, double alpha, double beta, Pixel coeff) { + int p, p_min = 0; + double dist_min = LARGE; + double sign = (coeff >= 0) ? 1.0 : -1.0; + + for (p = 1; p < 1.0 / (2.0 * alpha); p++) { + double dist, delta; + + delta = (1.0 + 2.0 * p * alpha) * T; + dist = fabs(delta - fabs(coeff)); + + if (dist < dist_min) { + dist_min = dist; + p_min = p; + } + } + + if (!p_min) p_min = 1; + return sign * (1.0 + 2.0 * p_min * alpha) * T; +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wang_common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wang_common.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,46 @@ +#ifndef WANG_COMMON_H +#define WANG_COMMON_H + +#include "dwt.h" + +typedef struct Subband_data_struct { + double T; + double Cmax; + double beta; + Image_tree tree; + int level; + int type; + int width; + int height; + int size; + Image image; + char** selected; +} *Subband_data; + +Subband_data *subbands; +int n_subbands; + +void init_subbands(Image_tree tree); +Subband_data alloc_subband(int type, Image_tree tree); +void free_subband(Subband_data subband); +void free_subbands(); + +void set_subband_beta(Subband_data subband, double beta); +void set_subbands_beta(double beta); +void set_subbands_type_beta(int type, double beta); + +void calc_subband_threshold(Subband_data subband); +void calc_subbands_threshold(); + +int subband_coeff_isselected(Subband_data subband, int coeff); +Pixel get_subband_coeff(Subband_data subband, int coeff); +void set_subband_coeff(Subband_data subband, int coeff, Pixel data); + +Subband_data select_subband(); +int select_subband_coeff_from(Subband_data subband, int from); +int select_subband_coeff(Subband_data subband); +void mark_subband_coeff(Subband_data subband, int coeff); + +Pixel figure_orig_coeff(double T, double alpha, double beta, Pixel coeff); + +#endif diff -r 000000000000 -r be303a3f5ea8 Meerwald/wavelet.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wavelet.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,2999 @@ +#include +#include +#include +#include +#include "wavelet.h" +#include + +static int read_char(FILE *fp); +static int read_int(FILE *fp); + +IntImage new_intimage(int width, int height) +{ + IntImage image; + + image = (IntImage) calloc(1,sizeof(struct IntImage_struct)); + if (image==NULL) goto error; + image->data = (IntPixel*) calloc(width*height,sizeof(IntPixel)); + if (image->data==NULL) goto error; + image->width = width; + image->height = height; + image->size = width*height; + image->bpp = 0; + image->min_val = (IntPixel) 0; + image->max_val = (IntPixel) 0; + + return image; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return NULL; +} + +Image new_image(int width, int height) +{ + Image image; + + image = (Image) calloc(1,sizeof(struct Image_struct)); + if (image==NULL) goto error; + image->data = (Pixel*) calloc(width*height,sizeof(Pixel)); + if (image->data==NULL) goto error; + image->width = width; + image->height = height; + image->size = width*height; + image->bpp = 0; + image->min_val = (Pixel) 0; + image->max_val = (Pixel) 0; + + return image; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return NULL; +} + + +void free_intimage(IntImage img) +{ + if (img) { + if (img->data) free(img->data); + free(img); + } +} + +void free_image(Image img) +{ + if (img) { + if (img->data) free(img->data); + free(img); + } +} + +/************************************************************************ + * Functionname: load_intimage + * -------------------------------------------------------------------- + * PARAMETER: + * file: filename of image + * max_val: scaling of grey values to [0..max_val] + * + * RETURN: + * Image that shoud be loaded, if not possible return NULL + * -------------------------------------------------------------------- + * DESCRIPTION: + * This function loads an IntImage (PGM, ASCII or binary + * encoded (P5 or P3 format) ) from a file. + ************************************************************************/ + +IntImage load_intimage(char *file, int max_val) +{ + IntImage img; + FILE *fp; + IntPixel *data; + int width, height, i, max, ch1, ch2; + + fp=fopen(file,"rb"); + if (fp==NULL) goto error; + + ch1=getc(fp); + ch2=getc(fp); + if (ch1!='P' || (ch2!='5' && ch2!='2')) goto error1; + + width=read_int(fp); + height=read_int(fp); + if ((width==0) || (height==0) ) goto error1; + max=read_int(fp); + + img=new_intimage(width,height); + + img->bpp=8; + + data=img->data; + for (i=0; isize; i++) + { if (ch2=='5') + *data=getc(fp); + else + *data=read_int(fp); + data++; + } + fclose(fp); + return img; + + error1: + err_SimpleMessage(err_GetErrorMessage(Error_WrongFileFormat)); + return NULL; + error: + err_SimpleMessage(err_GetErrorMessage(Error_CantOpenFile)); + return NULL; +} + +/************************************************************************ + * Functionname: load_image + * -------------------------------------------------------------------- + * PARAMETER: + * file: filename of image + * max_val: scaling of grey values to [0..max_val] + * + * RETURN: + * Image that shoud be loaded, if not possible return NULL + * -------------------------------------------------------------------- + * DESCRIPTION: + * This function loads an IntImage with load_intimage + * and then converts to Image. + ************************************************************************/ +extern Image load_image(char *file, int max_val) +{ + Image img; + IntImage intimg; + + intimg = load_intimage(file, max_val); + if (!intimg) return NULL; + img = intimage_to_image(intimg); + if (!intimg) return NULL; + + return img; +} + +/************************************************************************/ +/* Functionname: save_image_P5 */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* img: Image that shoud be saved */ +/* file: filename of image */ +/* -------------------------------------------------------------------- */ +/* Description: save an image as PGM (P5 binary decoded) file */ +/* */ +/************************************************************************/ + +extern int save_image_P5(char *file, Image img) +{ FILE *fp; + Pixel *data; + long i; + int p; + + fp=fopen(file,"wb"); + if (fp==NULL) + goto error; + fprintf(fp,"P5\n"); + fprintf(fp,"%d %d\n%d ",img->width,img->height,255); + data=img->data; + for (i=0;isize;i++) { + p=floor(*data+0.5); + if (p<0) p=0; + if (p>255) p=255; +/* putc(*data,fp); */ + putc(p,fp); + data++; + } + fclose(fp); + return 1; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_CantOpenFile)); + return 0; +} + +void clear_image(Image img) +{ + int i; + + PreCondition(img!=NULL,"image==NULL"); + + for (i=0;isize;i++) + (img->data)[i]=(Pixel) 0; +} + +extern void copy_into_image(Image img1,Image img2,int x,int y) +/* copy img2 into img1 at position (x,y)*/ +{ + int start,i,j,aim; + Pixel *temp; + + temp=img2->data; + start=img1->width*y+x; + for (i=0;iheight;i++) { + for (j=0;jwidth;j++) { + aim=start+j+img1->width*i; + img1->data[aim]=*temp; + temp++; + } + } +} + +extern void copy_into_intimage(IntImage img1,IntImage img2,int x,int y) +{/* copy img2 into img1 at position (x,y)*/ + + int start,i,j,aim; + IntPixel *temp; + + temp=img2->data; + start=img1->width*y+x; + for (i=0;iheight;i++) + { + for (j=0;jwidth;j++) + { + aim=start+j+img1->width*i; + img1->data[aim]=*temp; + temp++; + } + } +} + +void copy_part_of_image_into_image(Image dest_img, int dest_x, int dest_y, + Image src_img, int src_x, int src_y, + int width, int height) +{ + Pixel *sp,*dp; + int y,siz; + + sp=get_pixel_adr(src_img,src_x,src_y); + dp=get_pixel_adr(dest_img,dest_x,dest_y); + + siz=width*sizeof(Pixel); + + for (y=0;ywidth; + dp+=dest_img->width; + } +} + +extern void copy_part_of_image(Image img1,Image img2,int x,int y) +/* copy part of img2 begining at position (x,y) into img1 */ +{ int i,j,width,height,start,step; + Pixel *data; + + width=img1->width; + height=img1->height; + start=img2->width*y+x; + data=img1->data; + for (i=0;iwidth; + for (j=0;jdata[start+j+step]; + data++; + } + } +} + + +extern void scale_image(Image img,int maximum) +/* scale image to [0..maximum]*/ +{ int i; + Pixel max,min,multi; + + for (i=0;isize;i++) { + if (img->data[i]data[i]; + else if (img->data[i]>max) max=img->data[i]; + } + + multi=(Pixel)maximum/(max-min); + for (i=0;isize;i++) img->data[i]=multi*(img->data[i]-min); + img->min_val=0; + img->max_val=maximum; +} + +int string_to_pixel(char *str, Pixel *p) +{ + float ppp; + if (sscanf(str,"%f",&ppp)==1) + { + *p=(Pixel) ppp; + return 1; + } + else + { + *p=0.0; + return 0; + } +} + +Image intimage_to_image(IntImage i) +{ Image img; + int j; + + img=new_image(i->width,i->height); + if (img==NULL) goto error; + for (j=0;jsize;j++) + img->data[j]=(Pixel)i->data[j]; + img->bpp=i->bpp; + return img; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return NULL; +} +IntImage image_to_intimage(Image i) +{ IntImage img; + int j,multi=1,max,min; + + img=(IntImage)calloc(1,sizeof(struct IntImage_struct)); + if (img==NULL) goto error; + img->data=(IntPixel *)calloc(i->size,sizeof(IntPixel)); + if (img->data==NULL) goto error; + img->width=i->width; + img->height=i->height; + img->size=i->size; + img->bpp=i->bpp; + + max=i->max_val; + min=i->min_val; + if ((max-min)!=0) + multi=255.0/(max-min); + + for (j=0;jsize;j++) + img->data[j]=(int)((i->data[j]-min)*multi+0.5); + return img; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return NULL; + +} + +static int read_char(FILE *fp) +/*read a character from file, but skip any comments*/ +{ int ch; + + ch=getc(fp); + if (ch=='#'){ + do { + ch=getc(fp); + } while (ch!='\n' && ch!=EOF); + } + return ch; +} + + +static int read_int(FILE *fp) +/*read an ascii integer from file, and skip leading tabstops,new lines ...*/ +{ int r,ch; + + do { + ch=read_char(fp); + } while (ch==' ' || ch=='\n' || ch=='\t'); + + if (ch<'0' || ch>'9') + goto error; + + r=ch-'0'; + while ( (ch=read_char(fp)) >='0' && (ch <= '9') ) { + r*=10; + r+=ch-'0'; + } + return r; + error: + return 0; +} + +Image_tree new_image_tree() +{ + Image_tree t; + t=(Image_tree) calloc(1,sizeof(struct Image_tree_struct)); + t->entropy=0.0; + t->image=NULL; + t->coarse=t->horizontal=t->vertical=t->diagonal=t->doubletree=NULL; + t->level=0; + t->codec_data=NULL; + t->significance_map=NULL; + return t; +} + +void free_image_tree(Image_tree t) +{ + if (t->coarse) free_image_tree(t->coarse); + if (t->horizontal) free_image_tree(t->horizontal); + if (t->vertical) free_image_tree(t->vertical); + if (t->diagonal) free_image_tree(t->diagonal); + if (t->doubletree) free_image_tree(t->doubletree); + if (t->image) free_image(t->image); + if (t->significance_map) free_intimage(t->significance_map); + if (t->codec_data) free(t->codec_data); + t->image=NULL; + free(t); +} + +/*********************************************************************** + * Functionname: get_image_infos + * -------------------------------------------------------------------- + * Parameter: + * Image image: input image + * Pixel *min,*max,*avg,*var: return minimum, maximum, + * average and variance of current image + * -------------------------------------------------------------------- + * Description: + * get statistical information of Image + ************************************************************************/ + +void get_image_infos(Image image, Image_info info) +{ + int x,y; + Pixel p,sp,sp2; + + sp=sp2=(Pixel)0.0; + + p=get_pixel(image,0,0); + + info->min=info->max=p; + + for (y=0;yheight;y++) + for (x=0;xwidth;x++) + { + p=get_pixel(image,x,y); + info->max=MAX(info->max,p); + info->min=MIN(info->min,p); + sp+=p; + sp2+=p*p; + } + sp=sp/image->width/image->height; + sp2=sp2/image->width/image->height; + + info->mean=sp; + info->var=sp2-sp*sp; + info->rms=sqrt(sp2); +} + +/*********************************************************************** + * Functionname: get_difference_image + * -------------------------------------------------------------------- + * Parameter: + * Image image1, image 2: input images + * + * Return: + * Image : difference of image1 and image 2, + * NULL if error occurs + ************************************************************************/ + +Image get_difference_image(Image image1, Image image2) +{ + Image diff; + int i,max,w,h; + Pixel *d,*i1,*i2; + + if ((!image1) || (!image2)) return NULL; + + w=image1->width; + h=image1->height; + + if (image2->width != w || image2->height != h) return NULL; + + diff=new_image(w,h); + max=w*h; + + d=diff->data; + i1=image1->data; + i2=image2->data; + + for (i=0;iheight;y++) + for (x=0;xwidth;x++) + { + p= (Pixel) get_intpixel(image,x,y); + *max=MAX(*max, (IntPixel) p); + *min=MIN(*min, (IntPixel) p); + sp+=p; + sp2+=p*p; + } + sp=sp/image->width/image->height; + sp2=sp2/image->width/image->height; + + *avg=sp; + *var=sp2-sp*sp; +} + +/************************************************************************/ +/* Functionname: init_zigzag */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* Zigzag_data_struct: */ +/* output: will be initialized, x/y hold coordinates of */ +/* the first pixel */ +/* int width,height: */ +/* input: width/height of image: */ +/* -------------------------------------------------------------------- */ +/* Description: */ +/* initializes Zigzag_data structure for use with next_zigzag */ +/************************************************************************/ + +void init_zigzag(Zigzag_data zz, int width, int height) +{ + zz->x=0; + zz->y=0; + zz->dir=zigzag_up; + zz->w=width; + zz->h=height; +} + +/************************************************************************/ +/* Functionname: next_zigzag */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* Zigzag_data_struct: */ +/* int x,y: */ +/* input: current position of zigzag-scan */ +/* output: next position of zigzag-scan */ +/* int w,h: width and height of image */ +/* enum zigzag_direction *dir: i/o: */ +/* direction moving thru the image */ +/* -------------------------------------------------------------------- */ +/* Description: */ +/* calculates the next point (x',y') of the zigzag-scan */ +/* through the image with size (w,h) */ +/************************************************************************/ + + +void next_zigzag(Zigzag_data zz) +{ + switch(zz->dir) + { + case zigzag_up: + if (zz->y==0) + { + if (zz->x==zz->w-1) + { + (zz->y)++; zz->dir=zigzag_down; + } + else + { + (zz->x)++; zz->dir=zigzag_down; + } + } + else + { + if (zz->x==zz->w-1) + { + (zz->y)++; zz->dir=zigzag_down; + } + else + { + (zz->x)++; (zz->y)--; + } + } + break; + + case zigzag_down: + + if (zz->x==0) + { + if (zz->y==zz->h-1) + { + (zz->x)++; zz->dir=zigzag_up; + } + else + { + (zz->y)++; zz->dir=zigzag_up; + } + } + else + { + if (zz->y==zz->h-1) + { + (zz->x)++; zz->dir=zigzag_up; + } + else + { + (zz->x)--;(zz->y)++; + } + } + break; + } +} + +Image get_absolute_image_scaled(Image img) +{ + Image out; + + int x,y; + + struct Image_info_struct info; + Pixel scale,p; + + out=new_image(img->width,img->height); + + get_image_infos(img, &info); + + scale=255/MAX(fabs(info.min),fabs(info.max)); + + for(y=0;yheight;y++) + for(x=0;xwidth;x++) + { + p=get_pixel(img,x,y)*scale; + set_pixel(out,x,y,p); + } + return out; +} + +#define FLOOR_HALF(x) ((x)&1 ? ((x)-1)/2 : (x)/2) +#define CEILING_HALF(x) ((x)&1 ? ((x)+1)/2 : (x)/2) + +#define MOD(a,b) ( (a)<0 ? ((b)-((-(a))%(b))) : (a)%(b) ) + +Filter new_filter(int size) +{ + Filter f; + + Entering; + f=(Filter) calloc(1,sizeof(struct FilterStruct)); + f->data=(Pixel *)calloc(size,sizeof(Pixel)); + f->len=size; + f->hipass=0; + + Leaving; + return f; +} + +Pixel get_filter_center(Filter f) +{ + int i; + Pixel p, sum, norm; + + if (f==NULL) return 0; + + sum=norm=0; + + for (i=0;ilen;i++) + { + p=f->data[i]; + p=p*p; + norm += p; + sum += (i+f->start)*p; + } + p=sum/norm; + + return p; +} +int filter_cutoff(Image in, int in_start, int in_len, int in_step, + Image out, int out_start, int out_len, int out_step, + Filter f) +{ + int i,i2,j; + Pixel *out_pix, *in_pix, *f_data; + int fstart,fend; /* Source interval */ + + Entering; + + PreCondition(out_len == in_len/2,"out_len != in_len/2 !!!"); + +/* convolution: out[i]=sum_{j=start}^{end} (in[2*i-j]*f[j]) + + boundaries: image in [in_start ... in_start + in_len-1] + image out [out_start ... out_start + out_len-1] + filter f [0..f->len-1] = [f->start .. f->end] + cutoff at: +*/ + + for (i=0;istart); + fend=MIN(i2,f->end); + +#ifdef TRACE + sprintf(dbgstr,"i=%d fstart=%d fend=%d\n",i,fstart,fend); + Trace(dbgstr); +#endif + + out_pix=out->data+out_start+i*out_step; + + in_pix=in->data+in_start+(i2-fstart)*in_step; + + f_data=f->data-f->start+fstart; + + for (j=fstart;j<=fend;j++,in_pix-=in_step,f_data++) + { + *out_pix += (*f_data) * (*in_pix); +#ifdef TRACE + + sprintf(dbgstr," j=%2d in: %4.2f filter: %4.2f [%4d] [%4d] opt : %4.2f %4.2f\n", + j, + in->data[in_start+in_step*(i2-j)], + f->data[j-f->start], + in_start+in_step*(i2-j), + j-f->start, + *in_pix, *f_data); + Trace(dbgstr); +#endif + } + } + + Leaving; + return 1; +} + + +int filter_inv_cutoff(Image in, int in_start, int in_len, int in_step, + Image out, int out_start, int out_len, int out_step, + Filter f) +{ + int i,j; + Pixel *out_pix, *in_pix, *f_data; + int fstart,fend; /* Source interval */ + Entering; + PreCondition(out_len == in_len*2,"out_len != in_len*2 !!!"); + +/* convolution: out[i]=sum_{j=start}^{end} (f[2*j-i]*in[j]) + + boundaries: image in [in_start ... in_start + in_len-1] + image out [out_start ... out_start + out_len-1] + filter f [0..f->len-1] = [f->start .. f->end] + cutoff at: +*/ + + for (i=0;istart+i); + fend=FLOOR_HALF(f->end+i); + fstart=MAX(fstart,0); + fend=MIN(fend,in_len-1); + +#ifdef TRACE + sprintf(dbgstr,"i=%d fstart=%d fend=%d\n",i,fstart,fend); + Trace(dbgstr); +#endif + out_pix=out->data+out_start+i*out_step; + + in_pix=in->data+in_start+fstart*in_step; + + f_data=f->data-f->start+2*fstart-i; + + for (j=fstart;j<=fend;j++,in_pix+=in_step,f_data+=2) + { + *out_pix += (*f_data) * (*in_pix); +#ifdef TRACE + sprintf(dbgstr," j=%2d in: %4.2f filter: %4.2f [%4d] [%4d] opt : %4.2f %4.2f\n", + j, + in->data[in_start+j*in_step], + f->data[2*j-i-f->start], + in_start+j*in_step, + 2*j-i-f->start, + *in_pix, *f_data); + Trace(dbgstr); +#endif + } + } + + Leaving; + return 1; +} + +int filter_periodical(Image in, int in_start, int in_len, int in_step, + Image out, int out_start, int out_len, int out_step, + Filter f) +{ + int i,i2,j; + Pixel *out_pix, *in_pix, *f_data; + int fstart,fend; + int istart; + int ipix_len; + + Entering; + PreCondition(out_len == in_len/2,"out_len != in_len/2 !!!"); + +/* convolution: out[i]=sum_{j=start}^{end} (in[2*i-j]*f[j]) + + boundaries: image in [in_start ... in_start + in_len-1] + image out [out_start ... out_start + out_len-1] + filter f [0..f->len-1] = [f->start .. f->end] +*/ + + ipix_len=in_len*in_step; + + for (i=0;istart; + fend=f->end; + + istart=(i2-fstart); + istart=MOD(istart,in_len); + +#ifdef TRACE + sprintf(dbgstr,"i=%d istart=%d\n",i,istart); + Trace(dbgstr); +#endif + + out_pix=out->data+out_start+i*out_step; + + in_pix=in->data+in_start+istart*in_step; + + f_data=f->data; + + for (j=fstart;j<=fend;j++,f_data++) + { + *out_pix += (*f_data) * (*in_pix); +#ifdef TRACE + + sprintf(dbgstr," j=%2d in: %4.2f filter: %4.2f [%4d] [%4d] opt : %4.2f %4.2f\n", + j, + in->data[in_start+in_step*((i2-j+in_len)%in_len)], + f->data[j-f->start], + in_start+in_step*((i2-j+in_len)%in_len), + j-f->start, + *in_pix, *f_data); + Trace(dbgstr); +#endif + in_pix-=in_step; + istart--; + if (istart<0) + { + istart+=in_len; + in_pix+=ipix_len; + } + } + } + + Leaving; + return 1; +} + +int filter_inv_periodical(Image in, int in_start, int in_len, int in_step, + Image out, int out_start, int out_len, int out_step, + Filter f) +{ + int i,j; + Pixel *out_pix, *in_pix, *f_data; + int fstart,fend; /* Source interval */ + int istart; + int ipix_len; + Entering; + PreCondition(out_len == in_len*2,"out_len != in_len*2 !!!"); + +/* convolution: out[i]=sum_{j=start}^{end} (f[2*j-i]*in[j]) + + boundaries: image in [in_start ... in_start + in_len-1] + image out [out_start ... out_start + out_len-1] + filter f [0..f->len-1] = [f->start .. f->end] +*/ + + ipix_len=in_len*in_step; + + for (i=0;istart+i); + fend=FLOOR_HALF(f->end+i); + + istart=MOD(fstart,in_len); +#ifdef TRACE + sprintf(dbgstr,"i=%d fstart=%d fend=%d istart=%d\n",i,fstart,fend,istart); + Trace(dbgstr); +#endif + out_pix=out->data+out_start+i*out_step; + + in_pix=in->data+in_start+istart*in_step; + + f_data=f->data-f->start+2*fstart-i; + + for (j=fstart;j<=fend;j++,f_data+=2) + { + *out_pix += (*f_data) * (*in_pix); +#ifdef TRACE + sprintf(dbgstr," j=%2d in: %4.2f filter: %4.2f [%4d] [%4d] opt : %4.2f %4.2f\n", + j, + in->data[in_start+(j % in_len)*in_step], + f->data[2*j-i-f->start], + in_start+(j%in_len)*in_step, + 2*j-i-f->start, + *in_pix, *f_data); + Trace(dbgstr); +#endif + in_pix+=in_step; + istart++; + if (istart>=in_len) + { + istart-=in_len; + in_pix-=ipix_len; + } + } + } + + Leaving; + return 1; +} + +int filter_mirror(Image in, int in_start, int in_len, int in_step, + Image out, int out_start, int out_len, int out_step, + Filter f) +{ + int i,i2,j; + Pixel *out_pix, *in_pix, *f_data; + int fstart,fend; + int in_pos; + + int in_dir,in_div,in_mod; + + Entering; + PreCondition(out_len == in_len/2,"out_len != in_len/2 !!!"); + +/* convolution: out[i]=sum_{j=start}^{end} (in[2*i-j]*f[j]) + + boundaries: image in [in_start ... in_start + in_len-1] + image out [out_start ... out_start + out_len-1] + filter f [0..f->len-1] = [f->start .. f->end] +*/ + + in_pix=in->data+in_start; + + for (i=0;istart; + fend=f->end; + + out_pix=out->data+out_start+i*out_step; + + f_data=f->data; + + for (j=fstart;j<=fend;j++) + { + in_pos=(i2-j); + if (in_pos<0) + { + in_pos=-in_pos; + if (in_pos>=in_len) continue; + } + if (in_pos>=in_len) + { + in_pos=2*in_len-2-in_pos; + if (in_pos<0) continue; + } + *out_pix += (f_data[j-fstart]) * (in_pix[in_pos*in_step]); + } + } + + Leaving; + return 1; +} + +int filter_inv_mirror(Image in, int in_start, int in_len, int in_step, + Image out, int out_start, int out_len, int out_step, + Filter f) +{ + int i,j; + Pixel *out_pix, *in_pix, *f_data; + int fstart,fend; /* Source interval */ + int in_pos,in_dir,in_div,in_mod; + + Entering; + PreCondition(out_len == in_len*2,"out_len != in_len*2 !!!"); + +/* convolution: out[i]=sum_{j=start}^{end} (f[2*j-i]*in[j]) + + boundaries: image in [in_start ... in_start + in_len-1] + image out [out_start ... out_start + out_len-1] + filter f [0..f->len-1] = [f->start .. f->end] +*/ + + /*fprintf(stderr,"inv started\n");*/ + for (i=0;istart+i); + fend=FLOOR_HALF(f->end+i); + + out_pix=out->data+out_start+i*out_step; + + in_pix=in->data+in_start; + +/* + printf("in: %4d - %4d flt: %4d - %4d [%s]\n",fstart,fend,2*fstart-i,2*fend-i, + (2*fstart-istart || 2*fend-i>f->end) ? "error":"ok"); +*/ + /*fprintf(stderr,"inv[%d]\n",i);*/ + for (j=fstart;j<=fend;j++) + { + in_pos=j; + if (in_pos<0) + { + if (f->hipass) + in_pos=-in_pos-1; + else + in_pos=-in_pos; + if (in_pos>=in_len) continue; + } + if (in_pos>=in_len) + { + if (f->hipass) + in_pos=2*in_len-2-in_pos; + else + in_pos=2*in_len-1-in_pos; + if (in_pos<0) continue; + } + /*fprintf(stderr,"out+= %7.2f * %7.2f = %7.2f\n",f->data[2*j-i-f->start],in_pix[in_pos*in_step],f->data[2*j-i-f->start]*in_pix[in_pos*in_step]);*/ + *out_pix += f->data[2*j-i-f->start] * (in_pix[in_pos*in_step]); + } + } + + Leaving; + return 1; +} + +#define MAX_LINE 256 + +#define skip_blank(str) { while(isspace(*(str))) (str)++; } + +static int get_next_line(FILE *f, char *c) +{ + char *str,string[200]; + int len; + do + { + str=string; + if (!fgets(str,200,f)) + { + Trace("get_next_line: eof\n"); + goto error; + } + len=strlen(str); + while (len>=1 && isspace(str[len-1])) str[--len]=0; + while (isspace(*str)) str++; + } + while (strlen(str)==0 || *str=='#'); + strcpy(c,str); + return 1; +error: + return 0; +} + +static int next_line_str(FILE *f, char *tag, char *out) +{ + char str[MAX_LINE],*t_str; + + if (!get_next_line(f,str)) goto error; + t_str=strtok(str," "); + if (!t_str || strcmp(t_str,tag)) goto error; + t_str=strtok(NULL,"\n"); + if (!t_str) goto error; + skip_blank(t_str); + + strcpy(out,t_str); + return 1; +error: + return 0; +} + +static int next_line_str_alloc(FILE *f, char *tag, char **out) +{ + char str[MAX_LINE]; + if (!next_line_str(f,tag,str)) goto error; + + *out=malloc(strlen(str)+1); + strcpy(*out,str); + + return 1; +error: + return 0; +} + +static int next_line_int(FILE *f, char *tag, int *out) +{ + char str[MAX_LINE]; + if (next_line_str(f,tag,str) && sscanf(str,"%d",out)==1) + return 1; + else + return 0; +} + + +static Filter read_filter(FILE *f) +{ + char str[MAX_LINE]; + Filter filter; + int i; + + Entering; + + filter=calloc(1,sizeof(struct FilterStruct)); + + if (!next_line_str(f,"Type",str)) goto error1; + + if (!strcmp(str,"nosymm")) + { + filter->type=FTNoSymm; + } + else if (!strcmp(str,"symm")) + { + filter->type=FTSymm; + } + else if (!strcmp(str,"antisymm")) + { + filter->type=FTAntiSymm; + } + else + goto error1; + + if (!next_line_int(f,"Length",&(filter->len))) goto error1; + if (!next_line_int(f,"Start",&(filter->start))) goto error1; + if (!next_line_int(f,"End",&(filter->end))) goto error1; + + if ((filter->end-filter->start+1!=filter->len)) + { + Trace("error: len != end-start+1\n"); + goto error1; + } + + filter->data=calloc(filter->len,sizeof(Pixel)); + + for (i=0;ilen;i++) + { + if (!get_next_line(f,str)) goto error2; + if (!string_to_pixel(str,filter->data+i)) + { + Trace("error: invalid filter-value\n"); + goto error2; + } + } + if (!get_next_line(f,str)) goto error2; + if (*str!='}') + { + Trace("error: '}' not found\n"); + goto error2; + } + + Leaving; + return filter; + +error2: + free(filter->data); + +error1: + free(filter); + + LeavingErr; + return NULL; + +} + +static FilterGH read_filter_gh(FILE *f) +{ + char str[MAX_LINE]; + FilterGH fgh; + Filter filter; + int i,max; + + Entering; + + fgh=calloc(1,sizeof(struct FilterGHStruct)); + + if (!next_line_str_alloc(f,"Name",&(fgh->name))) + { + Trace("error: 'Name' tag not found\n"); + goto error1; + } + + if (!next_line_str(f,"Type",str)) + { + Trace("error: 'Type' tag not found\n"); + goto error1; + } + + if (!strcmp(str,"orthogonal")) + { + fgh->type=FTOrtho; + max=2; + } + else if (!strcmp(str,"biorthogonal")) + { + fgh->type=FTBiOrtho; + max=4; + } + else if (!strcmp(str,"other")) + { + fgh->type=FTOther; + max=4; + } + else + { + Trace("error: expecting 'orthogonal', 'biorthogonal' or 'other' type-tag\n"); + goto error1; + } + + for (i=0;ihipass = !(i&1); + switch(i) + { + case 0: fgh->g=filter; break; + case 1: fgh->h=filter; break; + case 2: fgh->gi=filter; break; + case 3: fgh->hi=filter; break; + } + } + if (!get_next_line(f,str)) goto error2; + if (*str!='}') + { + Trace("error: '}' not found\n"); + goto error2; + } + + Leaving; + return fgh; + +error2: + if (fgh->g) free(fgh->g); + if (fgh->h) free(fgh->h); + if (fgh->gi) free(fgh->gi); + if (fgh->hi) free(fgh->hi); + +error1: + free(fgh); + + LeavingErr; + return NULL; +} + + +AllFilters load_filters(char *name) +{ + FILE *f; + char str[MAX_LINE]; + AllFilters a; + FilterGH fgh; + + Entering; + + PreCondition(name!=NULL,"name=NULL!"); + + f=fopen(name,"rt"); + if (!f) + { + Trace("error: fopen failed\n"); + goto error1; + } + + a=calloc(1,sizeof(struct AllFilterStruct)); + a->count=0; + + while (get_next_line(f,str)) + { + if (*str=='{') + { + fgh=read_filter_gh(f); + if (!fgh) + { + Trace("error: read_filter returned NULL\n"); + goto error2; + } + if (a->count) + a->filter=realloc(a->filter,(a->count+1)*sizeof(FilterGH)); + else + a->filter=malloc(sizeof(FilterGH)); + (a->filter)[a->count]=fgh; + a->count++; + } + else + { + Trace("error: '{' not found\n"); + goto error2; + } + } + + fclose(f); + + Leaving; + return a; + +error2: + fclose(f); +error1: + + LeavingErr; + return 0; +} + +#define doubletree_min 32 +#define best_basis_min 8 + +static int convolute_lines(Image output,Image input,Filter flt,enum FilterMethod method); +static int convolute_rows(Image output,Image input,Filter flt,enum FilterMethod method); +static int decomposition(Image t_img,Image coarse,Image horizontal,Image vertical, + Image diagonal,Filter g,Filter h,enum FilterMethod method); +static int compute_best(Image_tree tree,int level,int max_level,FilterGH *flt, + enum FilterMethod method,enum Information_Cost cost,double epsilon); +static double compute_entropy(Image img,enum Information_Cost cost,double epsilon); +static compute_levels(Image_tree tree,double *entropies,enum Information_Cost cost,double epsilon); +static free_levels(Image_tree tree,int best); + +static Pixel sumationq(Image img); +static Pixel normq(Image_tree tree); +static Pixel sumation_down(Image_tree tree, Pixel normq); +static Pixel compute_non_additive(Image_tree tree,int size,enum Information_Cost cost,double +epsilon,int down); + +/************************************************************************/ +/* Functionname: wavelettransform */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* original: Image that should be transformed */ +/* level: transform down to level */ +/* flt: transform with filters flt[0..level] */ +/* method: method of filtering */ +/* -------------------------------------------------------------------- */ +/* Description: Carries out the wavelettransform */ +/* */ +/************************************************************************/ +extern Image_tree wavelettransform(Image original,int level,FilterGH *flt,enum FilterMethod method) +{ int i,width,height,min,max_level,e; + Image coarsei,horizontali,verticali,diagonali,tempi; + Image_tree ret_tree,temp_tree; + + width=original->width; + height=original->height; + + tempi=new_image(width,height); + if(!tempi) goto error; + + copy_into_image(tempi,original,0,0); + + ret_tree=new_image_tree(); + if(!ret_tree) goto error; + + temp_tree=ret_tree; + ret_tree->level=0; + + min=original->width; + if (original->heightheight; + max_level=log(min)/log(2)-2; + if (max_levelimage=tempi; + return ret_tree; + } + + /* decomposition */ + + for (i=0;ig,flt[i]->h,method); + if (!e) return NULL; + + temp_tree->coarse=new_image_tree(); + temp_tree->horizontal=new_image_tree(); + temp_tree->vertical=new_image_tree(); + temp_tree->diagonal=new_image_tree(); + + temp_tree->coarse->level=i+1; + temp_tree->horizontal->level=i+1; + temp_tree->vertical->level=i+1; + temp_tree->diagonal->level=i+1; + + temp_tree->horizontal->image=horizontali; + temp_tree->vertical->image=verticali; + temp_tree->diagonal->image=diagonali; + free_image(tempi); + + if (i!=(level-1)) + { + tempi=new_image(width,height); + copy_into_image(tempi,coarsei,0,0); + free_image(coarsei); + /*if i=level coarsei is inserted into the image tree + so we should not free coarsei on level-1*/ + } + + temp_tree=temp_tree->coarse; + + } + + temp_tree->image=coarsei; + return ret_tree; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return NULL; +} + +static Image_tree wavelettransform__wp(Image original, int current_level, int level, FilterGH *flt, enum FilterMethod method) +{ + int i, width, height, min, max_level, e; + Image coarse_image,horizontal_image,vertical_image,diagonal_image,temp_image; + Image_tree return_tree, temp_tree; + + width = original->width; + height = original->height; + + temp_image = new_image(width, height); + if (!temp_image) goto error; + + copy_into_image(temp_image, original, 0, 0); + + temp_tree = return_tree = new_image_tree(); + if (!return_tree) goto error; + + temp_tree->level = current_level; + + min = original->width; + if (original->height < min) min = original->height; + max_level = log(min) / log(2) - 2; + if (max_level < level) level = max_level; + + if (current_level >= level) { + return_tree->image = temp_image; + return return_tree; + } + + for (i = current_level; i < level; i++) { + width = (width + 1) / 2; + height = (height + 1) / 2; + + coarse_image = new_image(width, height); + horizontal_image = new_image(width, height); + vertical_image = new_image(width, height); + diagonal_image = new_image(width, height); + + if (!coarse_image || !horizontal_image || + !vertical_image || !diagonal_image) goto error; + + e = decomposition(temp_image, coarse_image, horizontal_image, + vertical_image, diagonal_image, + flt[i]->g, flt[i]->h, method); + if (!e) return NULL; + + temp_tree->coarse = new_image_tree(); + temp_tree->coarse->level = i+1; + temp_tree->horizontal = wavelettransform__wp(horizontal_image, i+1, level, flt, method); + temp_tree->vertical = wavelettransform__wp(vertical_image, i+1, level, flt, method); + temp_tree->diagonal = wavelettransform__wp(diagonal_image, i+1, level, flt, method); + + free_image(horizontal_image); + free_image(vertical_image); + free_image(diagonal_image); + free_image(temp_image); + + if (i != (level - 1)) { + temp_image = new_image(width, height); + copy_into_image(temp_image, coarse_image, 0, 0); + free_image(coarse_image); + } + + temp_tree = temp_tree->coarse; + } + + temp_tree->image = coarse_image; + return return_tree; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return NULL; +} + +extern Image_tree wavelettransform_wp(Image original, int level, FilterGH *flt, enum FilterMethod method) { + wavelettransform__wp(original, 0, level, flt, method); +} + + +/************************************************************************/ +/* Functionname: best_basis */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* original: Image to be transformed */ +/* level: best basis selection down to this level */ +/* flt: transform with filters flt[0..level] */ +/* method: transform with filter method */ +/* cost: carry best basis selection out with this costfunc */ +/* epsilon: limit for threshold method */ +/* -------------------------------------------------------------------- */ +/* Description: carries best basis and near best basis selection */ +/* out */ +/************************************************************************/ +extern Image_tree best_basis(Image original,int level,FilterGH *flt, + enum FilterMethod method,enum Information_Cost cost,double epsilon) + +{ Image_tree tree; + Image img; + int min,max_level,e; + + tree=new_image_tree(); + if(!tree) goto error; + + img=new_image(original->width,original->height); + if(!img) goto error; + + copy_into_image(img,original,0,0); + + tree->image=img; + + min=original->width; + if (original->heightheight; + max_level=log10((float) min/best_basis_min)/log10(2); + if (max_level>level) max_level=level; + + e=compute_best(tree,0,max_level,flt,method,cost,epsilon); + + if (!tree->image) free(img); + + return tree; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return NULL; + +} +/************************************************************************/ +/* Functionname: best_level_selection */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* original: Image that should be transformed */ +/* maxlevel: transform down to level */ +/* flt: transform with filters flt[0..level] */ +/* method: transform with filter method */ +/* cost: carry best basis selection out with this costfunc */ +/* epsilon: limit for threshold method */ +/* -------------------------------------------------------------------- */ +/* Description: Carries out the best level selection */ +/* */ +/************************************************************************/ +extern Image_tree best_level(Image original,int maxlevel,int *bestlevel,FilterGH *flt,enum FilterMethod method, + enum Information_Cost cost,double epsilon) +{ Image_tree tree; + Image img; + double *entropies,min; + int best=0,i,e; + + img=new_image(original->width,original->height); + copy_into_image(img,original,0,0); + + tree=new_image_tree(); + tree->image=img; + + entropies=(double *)calloc(maxlevel+1,sizeof(double)); + if(!entropies) goto error; + + /* decompose down to maxlevel */ + e=decompose_all(tree,maxlevel,flt,method,cost,epsilon); + if (!e) return NULL; + + /* compute costs of each level and store it in entropies array*/ + compute_levels(tree,entropies,cost,epsilon); + + min=entropies[0]; + for (i=1;i<=maxlevel;i++) + { + if (entropies[i]level=level; + + /* non additive cost function*/ + if (cost>=shanon) + { + tree->entropy=compute_non_additive(tree,tree->image->size,cost,epsilon,0); + } + /*additive cost function*/ + else tree->entropy=compute_entropy(tree->image,cost,epsilon); + + if (levelimage->width+1)/2; + height=(tree->image->height+1)/2; + + tree->coarse=new_image_tree(); + tree->horizontal=new_image_tree(); + tree->vertical=new_image_tree(); + tree->diagonal=new_image_tree(); + + coarse=new_image(width,height); + horizontal=new_image(width,height); + vertical=new_image(width,height); + diagonal=new_image(width,height); + if(!coarse||!vertical||!horizontal||!diagonal) goto error; + + e=decomposition(tree->image,coarse,horizontal,vertical,diagonal,flt[0]->g,flt[0]->h,method); + if (!e) return 0; + + tree->coarse->image=coarse; + tree->horizontal->image=horizontal; + tree->vertical->image=vertical; + tree->diagonal->image=diagonal; + + e=compute_best(tree->coarse,level+1,max_level,flt+1,method,cost,epsilon); + e=compute_best(tree->horizontal,level+1,max_level,flt+1,method,cost,epsilon); + e=compute_best(tree->vertical,level+1,max_level,flt+1,method,cost,epsilon); + e=compute_best(tree->diagonal,level+1,max_level,flt+1,method,cost,epsilon); + if (!e) return 0; + + /*going back in recursion*/ + + if (cost>=shanon) { + sum=compute_non_additive(tree,tree->image->size,cost,epsilon,1); + } + else sum=(tree->coarse->entropy)+(tree->horizontal->entropy) + +(tree->vertical->entropy)+(tree->diagonal->entropy); + + if (tree->entropy>sum) + { + tree->entropy=sum; + free_image(tree->image); /* take down tree */ + tree->image=NULL; + + } + else + { /* delete the tree downwards */ + free_image_tree(tree->coarse); + free_image_tree(tree->horizontal); + free_image_tree(tree->vertical); + free_image_tree(tree->diagonal); + + tree->coarse=tree->vertical=tree->horizontal=tree->diagonal=NULL; + } + } + + return 1; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return 0; + +} + +/************************************************************************/ +/* Functionname: decompose_all */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* tree: Image tree to be decomposed */ +/* maxlevel: decompose down to level */ +/* flt: transform with filters flt[0..maxlevel] */ +/* method: transform with filter method */ +/* cost: cost function for entropy computing */ +/* epsilon: limit for threshold method */ +/* -------------------------------------------------------------------- */ +/* Description: whole decompositing down to maxlevel */ +/* The original image must be in tree->image */ +/************************************************************************/ +extern int decompose_all(Image_tree tree,int maxlevel,FilterGH *flt,enum FilterMethod method, + enum Information_Cost cost,double epsilon) +{ + Image original,coarse,horizontal,vertical,diagonal; + int e,width,height,level; + + if (tree->levelcoarse=new_image_tree(); + tree->horizontal=new_image_tree(); + tree->vertical=new_image_tree(); + tree->diagonal=new_image_tree(); + + original=tree->image; + width=(original->width+1)/2; + height=(original->height+1)/2; + level=tree->level; + + coarse=new_image(width,height); + horizontal=new_image(width,height); + vertical=new_image(width,height); + diagonal=new_image(width,height); + if(!coarse||!vertical||!horizontal||!diagonal) goto error; + + + e=decomposition(tree->image,coarse,horizontal,vertical,diagonal,flt[0]->g,flt[0]->h,method); + if (!e) return 0; + + tree->coarse->image=coarse; + tree->horizontal->image=horizontal; + tree->vertical->image=vertical; + tree->diagonal->image=diagonal; + + tree->coarse->entropy=compute_entropy(coarse,cost,epsilon); + tree->horizontal->entropy=compute_entropy(horizontal,cost,epsilon); + tree->vertical->entropy=compute_entropy(vertical,cost,epsilon); + tree->diagonal->entropy=compute_entropy(diagonal,cost,epsilon); + + tree->coarse->level=tree->horizontal->level= + tree->vertical->level=tree->diagonal->level=level+1; + + e=decompose_all(tree->coarse,maxlevel,flt+1,method,cost,epsilon); + e=decompose_all(tree->horizontal,maxlevel,flt+1,method,cost,epsilon); + e=decompose_all(tree->vertical,maxlevel,flt+1,method,cost,epsilon); + e=decompose_all(tree->diagonal,maxlevel,flt+1,method,cost,epsilon); + if (!e) return 0; + + } + + return 1; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return 0; +} + +/************************************************************************/ +/* Functionname: compute_levels */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* tree: Image tree where the entropy should be computed */ +/* entropies : array for entropy */ +/* cost: carry best basis selection out with this costfunc */ +/* epsilon: limit for threshold method */ +/* -------------------------------------------------------------------- */ +/* Description: Compute the entropies of all decomposition levels */ +/************************************************************************/ +static compute_levels(Image_tree tree,double *entropies,enum Information_Cost cost,double epsilon) +{ + if (tree->image){ + entropies[tree->level]+=compute_entropy(tree->image,cost,epsilon); + } + if (tree->coarse) compute_levels(tree->coarse,entropies,cost,epsilon); + if (tree->horizontal) compute_levels(tree->horizontal,entropies,cost,epsilon); + if (tree->vertical) compute_levels(tree->vertical,entropies,cost,epsilon); + if (tree->diagonal) compute_levels(tree->diagonal,entropies,cost,epsilon); + +} + +/************************************************************************/ +/* Functionname: free_levels */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* tree: Image tree which should be cleaned */ +/* best: best level */ +/* -------------------------------------------------------------------- */ +/* Description: clean the image tree except the best level */ +/************************************************************************/ +static free_levels(Image_tree tree,int best) +{ + if (tree->levelimage); + tree->image=NULL; + free_levels(tree->coarse,best); + free_levels(tree->horizontal,best); + free_levels(tree->vertical,best); + free_levels(tree->diagonal,best); + } + else + { + if (tree->coarse) + { + free_image_tree(tree->coarse); + free_image_tree(tree->horizontal); + free_image_tree(tree->vertical); + free_image_tree(tree->diagonal); + tree->coarse=tree->horizontal=tree->vertical=tree->diagonal=NULL; + } + } +} + +/************************************************************************/ +/* Functionname: decompose_to_level */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* original: original image */ +/* level: decompose to level */ +/* flt: decompos with filters[0..level] */ +/* method: transform with filter method */ +/* -------------------------------------------------------------------- */ +/* Description: Decomposes an image to an certain level and stores */ +/* only this level in the returned quadtree */ +/************************************************************************/ +extern Image_tree decompose_to_level(Image original,int level,FilterGH *flt,enum FilterMethod method) +{ Image_tree tree; + int e; + + tree=new_image_tree(); + tree->image=original; + + e=decompose_all(tree,level,flt,method,entropy,1); + if (!e) return NULL; + + free_levels(tree,level); + + return tree; + +} + +/************************************************************************/ +/* Functionname: decomposition */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* t_img: Image which should be decomposed */ +/* coarse,horizontal,vertical,diagonal: */ +/* decomposed images */ +/* method: transform with filter method */ +/* g,h: the transformation is carried out with these filters*/ +/* -------------------------------------------------------------------- */ +/* Description: This carries out one wavelettransformation */ +/* using waveletfilters. */ +/************************************************************************/ + +static int decomposition(Image t_img,Image coarse,Image horizontal,Image vertical, + Image diagonal,Filter g,Filter h,enum FilterMethod method) +{ Image temp1; + + /*coarse*/ + temp1=new_image(coarse->width,t_img->height); + if(!temp1) goto error; + convolute_lines(temp1,t_img,h,method); + convolute_rows(coarse,temp1,h,method); + + /*horizontal*/ + convolute_rows(horizontal,temp1,g,method); + free_image(temp1); + + /*vertical*/ + temp1=new_image(vertical->width,t_img->height); + if(!temp1) goto error; + convolute_lines(temp1,t_img,g,method); + convolute_rows(vertical,temp1,h,method); + + /*diagonal*/ + convolute_rows(diagonal,temp1,g,method); + free_image(temp1); + + return 1; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return 0; + +} + +/************************************************************************/ +/* Functionname: inv_decomposition */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* sum: reconstructed image */ +/* coarse,horizontal,vertical,diagonal: images to carry out*/ +/* the inverse transformation */ +/* flt_gh: transform with filters g and h */ +/* method: transform with filter method */ +/* -------------------------------------------------------------------- */ +/* Description: Carries out the wavelettransform */ +/* */ +/************************************************************************/ +static int inv_decomposition(Image sum,Image coarse,Image horizontal,Image vertical, + Image diagonal,FilterGH flt_gh,enum FilterMethod method) +{ Image temp1; + Filter g,h; + + if (flt_gh->type==FTOrtho) { + g=flt_gh->g; + h=flt_gh->h; + } + else { + g=flt_gh->gi; + h=flt_gh->hi; + } + + /*coarse*/ + temp1=new_image(coarse->width,sum->height); + if(!temp1) goto error; + convolute_rows(temp1,coarse,h,method); + + /*horizontal*/ + convolute_rows(temp1,horizontal,g,method); + convolute_lines(sum,temp1,h,method); + free_image(temp1); + + /*vertical*/ + temp1=new_image(vertical->width,sum->height); + if(!temp1) goto error; + convolute_rows(temp1,vertical,h,method); + + /*diagonal*/ + convolute_rows(temp1,diagonal,g,method); + convolute_lines(sum,temp1,g,method); + + free_image(temp1); + + return 1; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return 0; +} + +/************************************************************************/ +/* Functionname: build_image */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* quadtree: quadtree with decomposition information */ +/* width,height: image width and height */ +/* RETURN: returns the build up image */ +/* -------------------------------------------------------------------- */ +/* Description: builds up an image out of an Image_tree */ +/* */ +/************************************************************************/ +extern Image build_image(Image_tree quadtree,int width,int height) +{ Image ret_img,coarse,horizontal,vertical,diagonal; + + + ret_img=new_image(width,height); + if(!ret_img) goto error; + + width=(width+1)/2; + height=(height+1)/2; + + if (!(quadtree->image)) { + coarse=build_image(quadtree->coarse,width,height); + horizontal=build_image(quadtree->horizontal,width,height); + vertical=build_image(quadtree->vertical,width,height); + diagonal=build_image(quadtree->diagonal,width,height); + if (!coarse||!horizontal||!vertical||!diagonal) return NULL; + + copy_into_image(ret_img,coarse,0,0); + copy_into_image(ret_img,horizontal,width,0); + copy_into_image(ret_img,vertical,0,height); + copy_into_image(ret_img,diagonal,width,height); + + if (!quadtree->coarse->image) free_image(coarse); + if (!quadtree->horizontal->image) free_image(horizontal); + if (!quadtree->vertical->image) free_image(vertical); + if (!quadtree->diagonal->image) free_image(diagonal); + + return ret_img; + } + else return quadtree->image; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return NULL; +} + +/************************************************************************/ +/* Functionname: inv_transform */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* tree: tree with decomposition information */ +/* flt_gh: transform with filters g and h */ +/* method: transform with filter method */ +/* -------------------------------------------------------------------- */ +/* Description: Inverts the wavelettransform,best_basis,best_level */ +/* */ +/************************************************************************/ +extern Image inv_transform(Image_tree tree,FilterGH *flt, + enum FilterMethod method) + +{ int er,width,height; + Image ret_img,coarse,vertical,horizontal,diagonal; + + if (!tree->image) { + + coarse=inv_transform(tree->coarse,flt,method); + horizontal=inv_transform(tree->horizontal,flt,method); + vertical=inv_transform(tree->vertical,flt,method); + diagonal=inv_transform(tree->diagonal,flt,method); + if (!coarse||!horizontal||!vertical||!diagonal) return NULL; + + width=coarse->width+horizontal->width; + height=coarse->height+vertical->height; + + ret_img=new_image(width,height); + if(!ret_img) goto error; + + + if (tree->flag==0) /*if flag is set it is a doubletree tiling*/ + { +// er=inv_decomposition(ret_img,coarse,horizontal,vertical,diagonal,flt[1],method); + er=inv_decomposition(ret_img,coarse,horizontal,vertical,diagonal,flt[tree->level],method); + if (!er) return NULL; + } + else + { + copy_into_image(ret_img,coarse,0,0); + copy_into_image(ret_img,horizontal,coarse->width,0); + copy_into_image(ret_img,vertical,0,coarse->height); + copy_into_image(ret_img,diagonal,coarse->width,coarse->height); + } + + if (!tree->coarse->image) free_image(coarse); + if (!tree->horizontal->image) free_image(horizontal); + if (!tree->vertical->image) free_image(vertical); + if (!tree->diagonal->image) free_image(diagonal); + + return ret_img; + } + + else return tree->image; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return NULL; +} + +/************************************************************************/ +/* Functionname: find_deepest_level */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* -------------------------------------------------------------------- */ +/* Description: Finds the deepest possible level where width and */ +/* height can divided by two exactly. */ +/************************************************************************/ +extern int find_deepest_level(int width,int height) +{ + int level=0,w=width,h=height; + + while ( !((w%2)||(h%2))) + { + w=w/2; + h=h/2; + level++; + } + + return level-1; + +} + +/************************************************************************/ +/* Functionname: convolute_lines */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* output: output image of wavelettransformation */ +/* input: input image for decomposition */ +/* flt: transform with filter flt */ +/* method: transform with filter method */ +/* -------------------------------------------------------------------- */ +/* Description: Carries out the wavelettransform for all lines of */ +/* the input image */ +/************************************************************************/ +static int convolute_lines(Image output,Image input,Filter flt,enum FilterMethod method) +/*Convolute the lines with filter*/ +{ int i; + + for (i=0;iheight;i++) { + switch(method) { + case cutoff: + filter_cutoff(input,input->width*i,input->width,1, + output,output->width*i,output->width,1,flt); + break; + case inv_cutoff: + filter_inv_cutoff(input,input->width*i,input->width,1, + output,output->width*i,output->width,1,flt); + break; + case periodical: + filter_periodical(input,input->width*i,input->width,1, + output,output->width*i,output->width,1,flt); + break; + case inv_periodical: + filter_inv_periodical(input,input->width*i,input->width,1, + output,output->width*i,output->width,1,flt); + break; + case mirror: + filter_mirror(input,input->width*i,input->width,1, + output,output->width*i,output->width,1,flt); + break; + case inv_mirror: + filter_inv_mirror(input,input->width*i,input->width,1, + output,output->width*i,output->width,1,flt); + break; + + + } + } + + return 1; +} + +/************************************************************************/ +/* Functionname: convolute_rows */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* output: output image of wavelettransformation */ +/* input: input image for decomposition */ +/* flt: transform with filter flt */ +/* method: transform with filter method */ +/* -------------------------------------------------------------------- */ +/* Description: Carries out the wavelettransform for all rows of */ +/* the input image */ +/************************************************************************/ +static int convolute_rows(Image output,Image input,Filter flt,enum FilterMethod method) +/*Convolute the rows with filter*/ +{ int i; + + for (i=0;iwidth;i++) + { + switch (method) + { + case cutoff: + filter_cutoff(input,i,input->height,input->width, + output,i,output->height,output->width,flt); + break; + case inv_cutoff: + filter_inv_cutoff(input,i,input->height,input->width, + output,i,output->height,output->width,flt); + break; + case periodical: + filter_periodical(input,i,input->height,input->width, + output,i,output->height,output->width,flt); + break; + case inv_periodical: + filter_inv_periodical(input,i,input->height,input->width, + output,i,output->height,output->width,flt); + break; + case mirror: + filter_mirror(input,i,input->height,input->width, + output,i,output->height,output->width,flt); + break; + case inv_mirror: + filter_inv_mirror(input,i,input->height,input->width, + output,i,output->height,output->width,flt); + break; + + } + } + return 1; +} + +/************************************************************************/ +/* Functionname: sumationq */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* img: image to compute */ +/* -------------------------------------------------------------------- */ +/* Description: compute the sum of quadrats of all elements of */ +/* the input image */ +/************************************************************************/ +static Pixel sumationq(Image img) +{ Pixel sum=0; + int i; + + for (i=0;isize;i++) { + sum+=(*img->data+i)*(*img->data+i); + } + return sum; +} + +/************************************************************************/ +/* Functionname: normq */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* tree: tree to compute */ +/* -------------------------------------------------------------------- */ +/* Description: computes the quadratic norm over all images in */ +/* the input tree */ +/************************************************************************/ +static Pixel normq(Image_tree tree) +{ Pixel sum=0; + + if (tree->image) + { + sum=sumationq(tree->image); + } + else + { + if (tree->coarse) sum+=normq(tree->coarse); + if (tree->horizontal) sum+=normq(tree->horizontal); + if (tree->vertical) sum+=normq(tree->vertical); + if (tree->diagonal) sum+=normq(tree->diagonal); + } + + return sum; +} + +/************************************************************************/ +/* Functionname: sumation_down */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* tree: tree to compute */ +/* normq: norm of the images in the tree */ +/* -------------------------------------------------------------------- */ +/* Description: computes the Entropy over all (string aded) images */ +/* in the input tree */ +/************************************************************************/ +static Pixel sumation_down(Image_tree tree, Pixel normq) +{ Pixel sum=0,p; + int i; + Image img; + Pixel *data; + + if (tree->image) + { + img=tree->image; + data=img->data; + for (i=0;isize;i++,data++) + { + if (*data!=0) + { + p=(*data)*(*data)/normq; + sum+=p*log(1/p); + } + } + } + else + { + if (tree->coarse) sum+=sumation_down(tree->coarse,normq); + if (tree->horizontal) sum+=sumation_down(tree->horizontal,normq); + if (tree->vertical) sum+=sumation_down(tree->vertical,normq); + if (tree->diagonal) sum+=sumation_down(tree->diagonal,normq); + } + + return sum; +} + +/************************************************************************/ +/* Functionname: comp */ +/* -------------------------------------------------------------------- */ +/* Description: used for quicksort for decreasing order */ +/************************************************************************/ +int comp(const Pixel *x,const Pixel *y) +{ + if (*x<*y) return 1; + else if (*x==*y) return 0; + else return -1; +} + +/************************************************************************/ +/* Functionname: recarea */ +/* tree: Image tree to compute */ +/* list: target list */ +/* list_size: actual size of the list */ +/* -------------------------------------------------------------------- */ +/* Description: copies all elements within the tree into an list */ +/************************************************************************/ +static void recarea(Image_tree tree,Pixel *list,int *list_size) +{ Image img; + + if (tree->image) + { + img=tree->image; + memcpy(list+(*list_size),img->data,img->size*sizeof(Pixel)); + *list_size+=img->size; + } + else + { + if (tree->coarse) recarea(tree->coarse,list,list_size); + if (tree->horizontal) recarea(tree->horizontal,list,list_size); + if (tree->vertical) recarea(tree->vertical,list,list_size); + if (tree->diagonal) recarea(tree->diagonal,list,list_size); + } + +} + +static void abs_list(Pixel *list,int list_size) +{ + int i; + + for (i=0;imax) max=wlp; + } + + free(list); + + return max; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return 0; +} + +static Pixel comp_number(Image_tree tree,int size,int p,double f) +{ Pixel sum=0,*list,min,norm,npf,normf; + int *list_size=0,k; + + list_size=(int *)malloc(sizeof(int)); + if (!list_size) goto error; + *list_size=0; + + list=(Pixel *)calloc(size,sizeof(Pixel)); + if (!list) goto error; + recarea(tree,list,list_size); + abs_list(list,*list_size); + + qsort(list,*list_size, sizeof(Pixel), &comp); + + norm=sum_list(list,p,size); + normf=norm*f; + + for (k=0;kmaximum) maximum=x; + } + + free(list); + + return (1/(2*size)+maximum); + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return 0; +} + +static Pixel compute_discrepancy(Image_tree tree,int size) +{ Pixel *list,min,max,factor,maximum=0,minimum=0,x; + int *list_size=0,k; + + list_size=(int *)malloc(sizeof(int)); + if (!list_size) goto error; + *list_size=0; + + list=(Pixel *)calloc(size,sizeof(Pixel)); + if (!list) goto error; + + recarea(tree,list,list_size); + + qsort(list,*list_size, sizeof(Pixel), &comp); + + min=list[0]; + max=list[size-1]; + factor=1/(max-min); + + /*scaling to [0,1]*/ + for (k=0;kmaximum) maximum=x; + else if (xdata; + + switch(cost) { + + case threshold: + for(i=0;isize;i++) + if (fabs(img->data[i])>epsilon) sum++; + break; + + case log_energy: + for(i=0;isize;i++,data++) { + x=(*data) * (*data); + if (x!=0) sum+=(x*log(1/x)); + } + break; + + case norml: + for(i=0;isize;i++,data++) { + x=fabs(*data); + sum+=x; + } + break; + + case norml2: + for(i=0;isize;i++,data++) { + x=(*data) * (*data); + sum+=x; + } + sum=pow(sum,0.5); + break; + + case entropy: + for(i=0;isize;i++,data++) { + x=(*data)*(*data); + if (x!=0) sum-=(x*log(x)); + } + break; + + case gauss_markov: + for(i=0;isize;i++) { + x=(img->data[i])*(img->data[i]); + if (x!=0) sum+=log(x*x); + } + break; + + } + + return sum; +} + +/************************************************************************/ +/* Functionname: compute_non_additive */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* tree: Image tree from which the entropy should be */ +/* computed */ +/* size : size of the image */ +/* cost: choosen costfunction */ +/* epsilon: limit for threshold method */ +/* down: decides if only the first image should be computed*/ +/* -------------------------------------------------------------------- */ +/* Description: computes entropy of an image */ +/************************************************************************/ +static Pixel compute_non_additive(Image_tree tree,int size,enum Information_Cost cost,double epsilon,int down) +{ Pixel sum=0,normx; + Image img; + + if (down) + { + img=tree->image; + tree->image=NULL; + } + switch (cost) + { + case shanon: + normx=normq(tree); + sum=-sumation_down(tree,normx); + + break; + case weak_l: + sum=weak_lp(tree,size,1,epsilon); + break; + case weak_lq: + sum=weak_lp(tree,size,2,epsilon); + break; + case compression_number: + sum=comp_number(tree,size,1,epsilon); + break; + case compression_numberq: + sum=comp_number(tree,size,2,epsilon); + break; + case compression_area: + sum=comp_area(tree,size,1,epsilon); + break; + case compression_areaq: + sum=comp_area(tree,size,2,epsilon); + break; + case discrepancy: + sum=compute_discrepancy(tree,size); + break; + case sdiscrepancy: + sum=compute_sdiscrepancy(tree,size); + break; + case concentration: + sum=compute_concentration(tree,size); + break; + + + } + + if (down) tree->image=img; + + return sum; +} + +extern int rec_double(Image_tree dtree,int level,FilterGH *flt,enum FilterMethod method,enum Information_Cost cost,double epsilon) + +{ int min,width,height; + double sum=0; + Image c,h,v,d; + + dtree->level=0; + + if (cost>=shanon) + { + dtree->entropy=compute_non_additive(dtree,dtree->image->size,cost,epsilon,0); + } + else dtree->entropy=compute_entropy(dtree->image,cost,epsilon); + + dtree->doubletree=best_basis(dtree->image,level,flt,method,cost,epsilon); + + min=dtree->image->width; + if (dtree->image->heightimage->height; + + if (doubletree_minimage->width+1)/2; + height=(dtree->image->height+1)/2; + + dtree->coarse=new_image_tree(); + dtree->horizontal=new_image_tree(); + dtree->vertical=new_image_tree(); + dtree->diagonal=new_image_tree(); + + c=new_image(width,height); + h=new_image(width,height); + v=new_image(width,height); + d=new_image(width,height); + if(!c||!h||!v||!d) goto error; + + + copy_part_of_image(c,dtree->image,0,0); + copy_part_of_image(h,dtree->image,width,0); + copy_part_of_image(v,dtree->image,0,height); + copy_part_of_image(d,dtree->image,width,height); + + dtree->coarse->image=c; + dtree->horizontal->image=h; + dtree->vertical->image=v; + dtree->diagonal->image=d; + + rec_double(dtree->coarse,level,flt,method,cost,epsilon); + rec_double(dtree->horizontal,level,flt,method,cost,epsilon); + rec_double(dtree->vertical,level,flt,method,cost,epsilon); + rec_double(dtree->diagonal,level,flt,method,cost,epsilon); + + /* going back in recursion*/ + + sum=dtree->coarse->entropy+dtree->horizontal->entropy+ + dtree->vertical->entropy+dtree->diagonal->entropy; + + if (sum>dtree->entropy) + { + /*take image*/ + + free_image_tree(dtree->coarse); + free_image_tree(dtree->horizontal); + free_image_tree(dtree->vertical); + free_image_tree(dtree->diagonal); + dtree->coarse=dtree->horizontal=dtree->vertical=dtree->diagonal=NULL; + } + else + { /*take tiling*/ + dtree->entropy=sum; + free_image(dtree->image); + dtree->image=NULL; + } + + if (dtree->entropy>dtree->doubletree->entropy) + { + /*take best basis tree*/ + + dtree->entropy=dtree->doubletree->entropy; + + if(dtree->coarse) free_image_tree(dtree->coarse); + if(dtree->horizontal) free_image_tree(dtree->horizontal); + if(dtree->vertical) free_image_tree(dtree->vertical); + if(dtree->diagonal) free_image_tree(dtree->diagonal); + + dtree->coarse=dtree->doubletree->coarse; + dtree->horizontal=dtree->doubletree->horizontal; + dtree->vertical=dtree->doubletree->vertical; + dtree->diagonal=dtree->doubletree->diagonal; + + free_image(dtree->image); + dtree->image=NULL; + free(dtree->doubletree); + dtree->doubletree=NULL; + + } + else + { + dtree->flag=1; + if(dtree->doubletree) free_image_tree(dtree->doubletree); + dtree->doubletree=NULL; + } + } + + return 1; + + error: + err_SimpleMessage(err_GetErrorMessage(Error_NotEnoughMemory)); + return 0; +} + +static save_structur(Image_tree tree,FILE *fp,int pos) +{ + int shift,next_pos,max; + + if (tree->flag) + { + fprintf(fp,"%d ",pos); + + shift=pos-(pow(4,tree->level-1)-1)*4/3-1; + max=(int) ((pow(4,tree->level)-1)*4/3); + next_pos=max+4*shift+1; + if (tree->coarse) save_structur(tree->coarse,fp,next_pos); + if (tree->horizontal) save_structur(tree->horizontal,fp,next_pos+1); + if (tree->vertical) save_structur(tree->vertical,fp,next_pos+2); + if (tree->diagonal) save_structur(tree->diagonal,fp,next_pos+3); + } + +} + +static int is_in_list(int *list,int len, int x) +{ + int i,found=0; + + for (i=0;iflag=1; + + shift=pos-(pow(4,tree->level-1)-1)*4/3-1; + max=(int) ((pow(4,tree->level)-1)*4/3); + next_pos=max+4*shift+1; + + write_flags(tree->coarse,list,len,next_pos); + write_flags(tree->horizontal,list,len,next_pos+1); + write_flags(tree->vertical,list,len,next_pos+2); + write_flags(tree->diagonal,list,len,next_pos+3); + } +} + +static read_structur(Image_tree tree,FILE *fp) +{ + int e, flags[1000],len=0,i=0; + + do + { + e=fscanf(fp,"%d ",&flags[i++]); + if (e!=-1) len++; + } + while (e!=-1); + + write_flags(tree,flags,len,0); + +} + +/************************************************************************/ +/* Functionname: err_simple_message */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* char *: string that contains information about an */ +/* error the user should know. */ +/* -------------------------------------------------------------------- */ +/* Description: */ +/* Prints error messages for the user. */ +/************************************************************************/ + +void err_SimpleMessage(char *message) +{ + fprintf(stderr,"%s\n",message); +} + +/************************************************************************/ +/* Functionname: err_get_message */ +/* -------------------------------------------------------------------- */ +/* Return value: Errormessage for this specific error. */ +/* Parameter: */ +/* Error err: Error whose errormessage should be returned */ +/* -------------------------------------------------------------------- */ +/* Description: */ +/************************************************************************/ +char * err_GetErrorMessage(Error err) +{ + + switch (err) + { + case Error_NotImplemented: + return "Sorry, this is not implemented yet. "; + break; + + case Error_AssertionFailed: + return "Sorry, an internal assertion was violated.\n" + "This action can not be completed. :-("; + break; + + case Error_NotEnoughMemory: + return "Sorry, there is not enough memory"; + break; + + case Error_Limitation: + return "Some limitation of the program exceeded"; + break; + + /* - FILES - */ + + case Error_CantOpenFile: + return "Could not open file"; + break; + + case Error_CantCreateFile: + return "Could not create file"; + break; + + case Error_CantCloseFile: + return "Could not close file"; + break; + + case Error_InternalError: + return "Sorry, an internal error occured.\n" + "This action can not be completed. :-("; + break; + + default: + return "Sorry, but an unknown error ocurred.\n" + "This action can not be completed. :-("; + break; + + + } +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wavelet.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wavelet.h Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,334 @@ +#ifndef WAVELET_H + +#include + +extern char dbgstr[1000]; + +/* this are internal functions - don't use 'em! */ +extern void out_dbg_str(const char *str); +extern void start_trace(void); +extern void stop_trace(void); +extern void flush_trace_file(void); + +/* public functions / macros */ +#define StartTrace +#define StopTrace + +#define Trace(str) +#define TraceVar(str,var) + +#define Entering +#define Leaving +#define LeavingErr +#define FlushTrace + +#define Warning(str) + +#define PreCondition(exp,str) +#define PostCondition(exp,str) + +/* Note that if an error is added, an errormessage for this specific + error must also be added. Otherwise no appropriate message can + be displayed in an error window. ( Then "Unknown error ocurred" + will be displayed.) + The errormessage must be added to the case-construct in the + procedure err_GetErrorMessage +*/ + +typedef enum +{ + Error_NoError, /* No Error has happened. */ + Error_NotImplemented, /* A needed part has not (yet) been + implemented */ + Error_AssertionFailed, /* An assertion, pre- or postcondition failed. + Occurs only in buggy programs. */ + Error_NotEnoughMemory, /* We can't allocate the memory we need. */ + + Error_Limitation, /* Some limitation exceeded, e.g. a string + variable is too short */ + + + Error_CantOpenFile, /* The file cannot be opened */ + Error_CantCreateFile, + Error_CantWriteIntoFile, + Error_CantCloseFile, + Error_WrongFileFormat, + + Error_WidthOrHeightZero, + Error_CompressedZeroContent, + Error_OriginalZeroContent, + + Error_InternalError + +}Error; + + +/************************************************************************/ +/* Functionname: err_simple_message */ +/* -------------------------------------------------------------------- */ +/* Parameter: */ +/* char *: string that contains information about an */ +/* error the user should know. */ +/* -------------------------------------------------------------------- */ +/* Description: */ +/* Prints error messages for the user. */ +/************************************************************************/ +void err_SimpleMessage(char *message); + +/************************************************************************/ +/* Functionname: err_get_message */ +/* -------------------------------------------------------------------- */ +/* Return value: Errormessage for this specific error. */ +/* Parameter: */ +/* Error err: Error whose errormessage should be returned */ +/* -------------------------------------------------------------------- */ +/* Description: */ +/************************************************************************/ +char * err_GetErrorMessage(Error err); + +#include + +typedef double Pixel; + +typedef struct Image_struct { + Pixel *data; + int width,height; + + /* redundant, for our fun only :-) */ + Pixel min_val,max_val; /* range of pixel-values in data */ + /* [min_val..max_val] */ + int size; /* = width * height */ + int bpp; /* bits per pixel of original image */ + } *Image; + +typedef unsigned int IntPixel; + +typedef struct IntImage_struct { + IntPixel *data; + int width, height; + + /* redundant, for our fun only :-) */ + IntPixel min_val,max_val; /* range of values in data */ + /* [min_val..max_val] */ + int size; /* = width * height */ + int bpp; /* bits per pixel of original image */ + } *IntImage; + +typedef struct Image_tree_struct { + double entropy; + struct Image_tree_struct *coarse,*horizontal,*vertical,*diagonal,*doubletree; + Image image; + int level; + int flag; + + void *codec_data; + IntImage significance_map; + } *Image_tree; + +typedef struct Image_info_struct { + Pixel min,max,mean,var,rms; + } *Image_info; + +enum zigzag_direction {zigzag_up,zigzag_down,zigzag_right,zigzag_left}; + +typedef struct Zigzag_data_struct { + int x,y,w,h; + enum zigzag_direction dir; + } *Zigzag_data; + +#define get_intpixel(image,x,y) ( ((image)==NULL || \ + (x)<0 || (x)>=(image)->width || (y)<0 || (y)>=(image)->height) \ + ? (IntPixel) 0 : (image)->data[(x)+(y)*(image)->width]) + +#define set_intpixel(image,x,y,val) if (!((image)==NULL || \ + (x)<0 || (x)>=(image)->width || (y)<0 || (y)>=(image)->height)) \ + (image)->data[(x)+(y)*(image)->width]=(IntPixel) (val) + +#define get_pixel(image,x,y) ( ((image)==NULL || \ + (x)<0 || (x)>=(image)->width || (y)<0 || (y)>=(image)->height) \ + ? (Pixel) 0 : (image)->data[(x)+(y)*(image)->width]) + +#define set_pixel(image,x,y,val) if (!((image)==NULL || \ + (x)<0 || (x)>=(image)->width || (y)<0 || (y)>=(image)->height)) \ + (image)->data[(x)+(y)*(image)->width]=(Pixel) (val) + +#define get_pixel_adr(image,x,y) ( ((image)==NULL || \ + (x)<0 || (x)>=(image)->width || (y)<0 || (y)>=(image)->height) \ + ? (Pixel*) NULL : (image)->data+((x)+(y)*(image)->width)) + +/* functions: */ + +extern IntImage new_intimage(int width, int height); +extern IntImage load_intimage(char *file, int max_val); +extern void free_intimage(IntImage img); + +extern void clear_intimage(IntImage img); +extern void copy_into_intimage(IntImage img1,IntImage img2,int x,int y); +extern void copy_part_of_intimage(IntImage img1,IntImage img2,int x,int y); + +extern Image new_image(int width, int height); +extern void free_image(Image img); +extern void clear_image(Image img); +extern void copy_into_image(Image img1,Image img2,int x,int y); +extern void scale_image(Image img,int maximum); +extern void copy_part_of_image(Image img1,Image img2,int x,int y); + +extern void copy_part_of_image_into_image( + Image dest_img, int dest_x, int dest_y, + Image src_img, int src_x, int src_y, + int width, int height); + + +extern int string_to_pixel(char *str, Pixel *p); + +extern Image load_image(char *file, int max_val); +extern int save_image_P5(char *file, Image img); + +extern Image intimage_to_image(IntImage i); +extern IntImage image_to_intimage(Image i); + +extern Image_tree new_image_tree(); +extern void free_image_tree(Image_tree t); + +extern Image get_difference_image(Image image1, Image image2); + +extern void get_image_infos(Image image, Image_info info); + +extern void get_intimage_infos(IntImage image, IntPixel *min, IntPixel *max, Pixel *avg, Pixel *var); + +extern void init_zigzag(Zigzag_data zz, int width, int height); +extern void next_zigzag(Zigzag_data zz); +extern Image get_absolute_image_scaled(Image img); + +/* common macros */ + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +enum FilterType { FTNoSymm, FTSymm, FTAntiSymm}; + +typedef struct FilterStruct { + enum FilterType type; + int hipass; + Pixel * data; + int start,end; + + int len; + } *Filter; + +extern Filter new_filter(int size); + +extern int filter_cutoff(Image in, int in_start, int in_len, int in_step, + Image out, int out_start, int out_len, int out_step, + Filter f); + +extern int filter_inv_cutoff(Image in, int in_start, int in_len, int in_step, + Image out, int out_start, int out_len, int out_step, + Filter f); + +extern int filter_periodical(Image in, int in_start, int in_len, int in_step, + Image out, int out_start, int out_len, int out_step, + Filter f); + +extern int filter_inv_periodical(Image in, int in_start, int in_len, int in_step, + Image out, int out_start, int out_len, int out_step, + Filter f); + +extern int filter_mirror(Image in, int in_start, int in_len, int in_step, + Image out, int out_start, int out_len, int out_step, + Filter f); + +extern int filter_inv_mirror(Image in, int in_start, int in_len, int in_step, + Image out, int out_start, int out_len, int out_step, + Filter f); + +extern Pixel get_filter_center(Filter f); + +enum FilterGHType { FTOrtho, FTBiOrtho, FTOther}; + +typedef struct FilterGHStruct { + enum FilterGHType type; + Filter g, h, gi, hi; + char *name; + } *FilterGH; + +typedef struct AllFilterStruct { + FilterGH *filter; + int count; + } *AllFilters; + + +extern AllFilters load_filters(char *name); + +typedef struct SegmentsStruct { + int width,height; /* segment width & height*/ + int *data; + } *Segments; + +enum FilterMethod{cutoff,inv_cutoff,periodical,inv_periodical,mirror,inv_mirror}; + +enum Information_Cost{threshold,log_energy,entropy,norml,norml2,gauss_markov, + shanon,weak_l,weak_lq,compression_number,compression_numberq, + compression_area,compression_areaq,sdiscrepancy,discrepancy,concentration}; + +extern Image_tree wavelettransform(Image original,int level,FilterGH *flt,enum FilterMethod method); +extern Image_tree wavelettransform_wp(Image original,int level,FilterGH *flt,enum FilterMethod method); + +extern Image_tree best_basis(Image original,int level,FilterGH *flt, + enum FilterMethod method,enum Information_Cost cost,double epsilon); + +extern Image_tree best_level(Image original,int maxlevel,int *bestlevel,FilterGH *flt,enum FilterMethod method, + enum Information_Cost cost,double epsilon); + +extern Image build_image(Image_tree quadtree,int width,int height); + +extern Image inv_transform(Image_tree quadtree,FilterGH *flt, + enum FilterMethod method); + +extern Image inv_transform_wp(Image_tree quadtree,FilterGH *flt, + enum FilterMethod method); + +extern int rec_double(Image_tree dtree,int level,FilterGH *flt,enum FilterMethod method,enum Information_Cost cost,double epsilon); + +extern Image_tree decompose_to_level(Image original,int level,FilterGH *flt,enum FilterMethod method); + +extern decompose_all(Image_tree tree,int maxlevel,FilterGH *flt,enum FilterMethod method, + enum Information_Cost cost,double epsilon); + +extern int find_deepest_level(int width,int height); + + /*Selective methods*/ +extern int selectiv_tiling1(Image img,Segments seg,int filternumber,char *file, + enum Information_Cost cost,double epsilon); +extern Image inv_selectiv_tiling1(char *file); + +extern int selectiv_tiling2(Image img,Segments seg,int filternumber,char *file, + enum Information_Cost cost,double epsilon); +extern Image inv_selectiv_tiling2(char *file); + +extern int selectiv_quant1(Image img,IntImage area,int filternumber,char *file, + enum Information_Cost cost,double epsilon); +extern Image inv_selectiv_quant1(char *file); + +extern int selectiv_quant2(Image img,IntImage area,int filternumber,char *file, + enum Information_Cost cost,double epsilon); +extern Image inv_selectiv_quant2(char *file); + +extern int selectiv_quant3(Image img,IntImage area,int filternumber,char *file, + enum Information_Cost cost,double epsilon); +extern Image inv_selectiv_quant3(char *file); + +extern smooth_block(Image img,int x,int y, int width,int height); + +extern compute_map(Image_tree tree,IntImage map); + +extern int *pixelarray_to_intarray(Pixel *pdata,int size); +extern Pixel *intarray_to_pixelarray(int *idata,int size); + +#define WAVELET_H +#endif diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,38 @@ +#include "wm.h" + +#ifdef __MINGW32_VERSION +void bzero(char *b, size_t length) { + int i; + for (i=0; i +#include +#include +#include +#include +#include +#include + +#if defined(MINGW) +#define M_PI 3.1415926536 +#define rint floor +#define MAXPATHLEN 255 +void bzero(char *b, size_t length); +#elif defined(LINUX) +#include +#include +#else +#error platform not supported +#endif + +/* + * This macro is used to ensure correct rounding of integer values. + */ +#define ROUND(a) (((a) < 0) ? (int) ((a) - 0.5) : (int) ((a) + 0.5)) + +/* + * Macros to converts number of bytes to number of bits and vice verse + */ +#define NBITSTOBYTES(N) ((N & 7) ? (N >> 3) + 1 : N >> 3) +#define NBYTESTOBITS(N) (N << 3) + +#define GRAYRANGE(P) ((P > 255) ? 255 : (P < 0) ? 0 : P) +#define PIXELRANGE(P) ((P > 255) ? 255 : (P < 0) ? 0 : P) + +#ifndef sqr +#define sqr(X) ((X) * (X)) +#endif + +#ifndef MAX +#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) +#endif + +#ifndef MIN +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#endif + +#ifdef NEED_STRCASECMP +#define strcasecmp stricmp +#endif + +#ifndef SIGN +#define SIGN(X) (((X) > 0) ? ((X) == 0 ? 0 : 1) : -1) +#endif + +void wm_init(); +void wm_init1(); +void wm_init2(); + +#endif diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_bruyn_d.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_bruyn_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,503 @@ +#include "wm.h" +#include "signature.h" +#include "coord.h" +#include "gray.h" +#include "sort.h" +#include "bruyn_common.h" +#include "pgm.h" + +char *progname; + +// prints out program's parameters +void usage(void) { + fprintf(stderr, "usage: %s [-b n] [-h] [-k] [-n n] [-o file] [-pP n] [-q n] [-tT n] [-v n] -s file file\n", progname); + fprintf(stderr, "\t-b n\t\tblock size\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-k\t\tdisable block skipping\n"); + fprintf(stderr, "\t-n n\t\tnumber of signature bits to detect\n"); + fprintf(stderr, "\t-o file\t\textracted signature file\n"); + fprintf(stderr, "\t-p n\t\tpattern type for zone 1\n"); + fprintf(stderr, "\t-P n\t\tpattern type for zone 2\n"); + fprintf(stderr, "\t-q n\t\tsignature strength\n"); + fprintf(stderr, "\t-s file\t\tembedded signature\n"); + fprintf(stderr, "\t-t n\t\tthreshold for noise\n"); + fprintf(stderr, "\t-T n\t\tthreshold for slope\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + gray** image; + gray **block; + gray **zone; + gray **category1, **category2; + gray maxval; + double *slope; + int rows, cols, colors, format; + int c; + int i, j; + int r; + int n; + int col, row; + int bwidth, bheight; + int n_block; + + char signature_name[MAXPATHLEN]; + char input_name[MAXPATHLEN] = "(stdin)"; + char output_name[MAXPATHLEN] = "(stdout)"; + + double quality = 0.0; + double threshold_noise = 0.0; + double threshold_slope = 0.0; + int pattern1 = 0; + int pattern2 = 0; + int blocksize = 0; + int seed; + + int verbose = 0; + int skipping = 0; + + struct coords *coords; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + // parse command line and set options + while ((c = getopt(argc, argv, "b:h?n:o:p:P:q:s:t:T:v:k")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'k': + skipping = 1; + break; + case 'n': + nbit_signature = atoi(optarg); + if (nbit_signature <= 0 || nbit_signature > NBITSIGNATURE) { + fprintf(stderr, "%s: invalid signature length %d\n", progname, nbit_signature); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + pattern1 = atoi(optarg); + if (pattern1 <= 0 || pattern1 > NPATTERN) { + fprintf(stderr, "%s: pattern type out of range\n", progname); + exit(1); + } + break; + case 'P': + pattern2 = atoi(optarg); + if (pattern2 <= 0 || pattern2 > 3) { + fprintf(stderr, "%s: pattern type out of range\n", progname); + exit(1); + } + break; + case 'q': + quality = atof(optarg); + if (quality <= 0) { + fprintf(stderr, "%s: quality factor %f out of range\n", progname, quality); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 't': + threshold_noise = atof(optarg); + if (threshold_noise <= 0) { + fprintf(stderr, "%s: noise threshold %f out of range\n", progname, threshold_noise); + } + break; + case 'T': + threshold_slope = atof(optarg); + if (threshold_slope <= 0) { + fprintf(stderr, "%s: slope threshold %f out of range\n", progname, threshold_slope); + } + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n",progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + // open input image file or read from stdin + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + // read signature file and set options + // command line options override signature file options + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "BRSG") >= 4) { + if (nbit_signature == 0) + fscanf(sig, "%d\n", &nbit_signature); + else + fscanf(sig, "%*d\n"); + if (skipping == 0) + fscanf(sig, "%d\n", &skipping); + else + fscanf(sig, "%*d\n"); + if (pattern1 == 0) + fscanf(sig, "%d\n", &pattern1); + else + fscanf(sig, "%*d\n"); + if (pattern2 == 0) + fscanf(sig, "%d\n", &pattern2); + else + fscanf(sig, "%*d\n"); + if (quality == 0.0) + fscanf(sig, "%lf\n", &quality); + else + fscanf(sig, "%*lf\n"); + if (threshold_noise == 0.0) + fscanf(sig, "%lf\n", &threshold_noise); + else + fscanf(sig, "%*lf\n"); + if (threshold_slope == 0.0) + fscanf(sig, "%lf\n", &threshold_slope); + else + fscanf(sig, "%*lf\n"); + if (blocksize == 0) + fscanf(sig, "%d\n", &blocksize); + else + fscanf(sig, "%*d\n"); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + init_signature_bits(); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + if (pattern1 <= 0 || pattern2 <= 0 || pattern1 > NPATTERN || pattern2 > NPATTERN) { + fprintf(stderr, "%s: invalid pattern type specified\n"); + exit(1); + } + + // read dimensions of input image file + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + // see if we can extract all signature bits + // we want at least half of the blocks untouched + if (((rows / blocksize) * (cols / blocksize)) < nbit_signature / 2) { + fprintf(stderr, "%s: image not large enough to contain %d bits of signature\n", progname, nbit_signature); + exit(1); + } + n_block = blocksize * blocksize; + + // allocate structure to remember which blocks we already touched, + // allow plenty of room to skip over blocks + if ((coords = alloc_coords(nbit_signature * 2)) == NULL) { + fprintf(stderr, "%s: unable to allocate memory\n", progname); + exit(1); + } + + // read in input image file + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + row = 0; + col = 0; + + // allocate memory for one block + block = alloc_grays(blocksize, blocksize); + + // allocate memory for zone classification + zone = alloc_grays(blocksize, blocksize); + + // allocate memory for category classification + category1 = alloc_grays(blocksize, blocksize); + category2 = alloc_grays(blocksize, blocksize); + + // set up category classification array according to + // pattern type parameter + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + category1[j][i] = lookup_pattern(pattern1, i, j); + category2[j][i] = lookup_pattern(pattern2, i, j); + } + + // allocate memory for slope calculation + slope = malloc(sizeof(double) * n_block); + + fprintf(out, "BRWM\n"); + fprintf(out, "%d\n", nbit_signature); + + // extract all the signature bits, one by one + n = 0; + while (n < nbit_signature) { + int xb; + int yb; + int blocktype; + double smax; + int alpha, beta_minus, beta_plus; + double mean_1A, mean_1B, mean_2A, mean_2B, mean_1, mean_2; + double mean__1A, mean__1B, mean__2A, mean__2B; + int n_1A, n_1B, n_2A, n_2B, n_1, n_2; + double sigma, sigma_1, sigma_2; + int zone1_ok, zone2_ok; + + // find an unused block randomly, depending on seed + do { + xb = random() % (cols / blocksize); + yb = random() % (rows / blocksize); + } while (add_coord(coords, xb, yb) < 0); + + // copy image block + copy_grays_to_block(block, image, xb * blocksize, yb * blocksize, blocksize, blocksize); + + if (verbose > 0) + fprintf(stderr, "detecting bit #%d in block at (%d/%d)\n", n, xb * blocksize, yb * blocksize); + + // sort luminance values in block to represent increasing function F + sort_grays(block[0], n_block); + + // calculate slopes of F and determine smax, the max. slope of F + // the index where smax occures is called alpha + alpha = 0; + smax = 0.0; + for (i = 0; i < n_block - 1; i++) { + slope[i] = block[0][i + 1] - block[0][i]; + if (slope[i] > smax) { + smax = slope[i]; + alpha = i; + } + } + slope[n_block - 1] = 0; + + // block type classification + blocktype = BLOCKTYPE_UNKNOWN; + + if (smax < threshold_noise) { + // block has noise contrast + beta_minus = beta_plus = alpha; + blocktype = BLOCKTYPE_NOISE; + } + else { + // block has progressive or hard contrast, let's find out... + + beta_minus = alpha - 1; + while (beta_minus >= 0 && smax - slope[beta_minus] <= threshold_slope) + beta_minus--; + + beta_plus = alpha + 1; + while (beta_plus < n_block && smax - slope[beta_plus] <= threshold_slope) + beta_plus++; + + if (beta_minus + 1 == alpha && beta_plus - 1 == alpha) + blocktype = BLOCKTYPE_HARD; + else + blocktype = BLOCKTYPE_PROGRESSIVE; + } + + if (verbose > 1) { + fprintf(stderr, "blocktype: %d\n", blocktype); + fprintf(stderr, "Smax = %lf, alpha = %d, beta- = %d, beta+ = %d\n", smax, alpha, beta_minus, beta_plus); + } + + // block pixel classification + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + gray pixel = image[yb * blocksize + j][xb * blocksize + i]; + zone[j][i] = ZONE_VOID; + switch (blocktype) { + case BLOCKTYPE_PROGRESSIVE: + case BLOCKTYPE_HARD: + if (pixel < block[0][beta_minus]) + zone[j][i] = ZONE_1; + else if (pixel > block[0][beta_plus]) + zone[j][i] = ZONE_2; + break; + case BLOCKTYPE_NOISE: + if (pixel < block[0][n_block / 2]) + zone[j][i] = ZONE_1; + else if (pixel > block[0][n_block / 2]) + zone[j][i] = ZONE_2; + break; + default: + fprintf(stderr, "%s: invalid block type\n", progname); + break; + } + } + + // calculate mean values for zone/categories + mean_1A = mean_1B = mean_2A = mean_2B = mean_1 = mean_2 = 0.0; + n_1A = n_1B = n_2A = n_2B = n_1 = n_2 = 0; + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + gray pixel = image[yb * blocksize + j][xb * blocksize + i]; + int pixel_zone = zone[j][i]; + int pixel_category = CATEGORY_VOID; + if (pixel_zone == ZONE_1) + pixel_category = category1[j][i]; + else if (pixel_zone == ZONE_2) + pixel_category = category2[j][i]; + + switch (pixel_zone | pixel_category) { + case CLASSIFICATION_1A: + n_1++; + n_1A++; + mean_1A += pixel; + mean_1 += pixel; + break; + case CLASSIFICATION_1B: + n_1++; + n_1B++; + mean_1B += pixel; + mean_1 += pixel; + break; + case CLASSIFICATION_2A: + n_2++; + n_2A++; + mean_2A += pixel; + mean_2 += pixel; + break; + case CLASSIFICATION_2B: + n_2++; + n_2B++; + mean_2B += pixel; + mean_2 += pixel; + break; + } + } + + if (n_1 && n_1A && n_1B) { + mean_1 /= (double) n_1; + mean_1A /= (double) n_1A; + mean_1B /= (double) n_1B; + zone1_ok = 1; + } + else { + mean_1 = mean_1A = mean_1B = 0.0; + zone1_ok = 0; + if (verbose > 0) + fprintf(stderr, "zone 1 unusable\n"); + } + + if (n_2 && n_2A && n_2B) { + mean_2 /= (double) n_2; + mean_2A /= (double) n_2A; + mean_2B /= (double) n_2B; + zone2_ok = 1; + } + else { + mean_2 = mean_2A = mean_2B = 0.0; + zone2_ok = 0; + if (verbose > 0) + fprintf(stderr, "zone 2 unusable\n"); + } + + // bit extraction + if (zone1_ok && zone2_ok) { + sigma_1 = mean_1A - mean_1B; + sigma_2 = mean_2A - mean_2B; + + if (verbose > 2) { + fprintf(stderr, "m_1A = %lf, m_1B = %lf\n", mean_1A, mean_1B); + fprintf(stderr, "m_2A = %lf, m_2B = %lf\n", mean_2A, mean_2B); + fprintf(stderr, "sigma1 = %lf, sigma2 = %lf\n", sigma_1, sigma_2); + } + +#define EPSILON 0.001 + if (fabs(sigma_1 * sigma_2) < EPSILON) { + // case 3 + sigma = MAX(fabs(sigma_1), fabs(sigma_2)); + set_signature_bit(n, sigma > 0.0); + if (verbose > 0) + fprintf(stderr, "case 3, bit #%d = %d\n", n, sigma > 0.0); + } + else if (sigma_1 * sigma_2 > 0.0) { + // case 1 + set_signature_bit(n, sigma_1 > 0.0); + if (verbose > 0) + fprintf(stderr, "case 1, bit #%d = %d\n", n, sigma_1 > 0.0); + } + else if (sigma_1 * sigma_2 < 0.0) { + // case 2 + sigma = (double) (n_1A + n_1B) * sigma_1 + (double) (n_2A + n_2B) * sigma_2; + set_signature_bit(n, sigma > 0.0); + if (verbose > 0) + fprintf(stderr, "case 2, bit #%d = %d\n", n, sigma > 0.0); + } + } + else if (zone1_ok) { + set_signature_bit(n, mean_1A > mean_1B); + if (verbose > 0) + fprintf(stderr, "case 4, bit #%d = %d\n", n, mean_1A > mean_1B); + } + else if (zone2_ok) { + set_signature_bit(n, mean_2A > mean_2B); + if (verbose > 0) + fprintf(stderr, "case 5, bit #%d = %d\n", n, mean_2A > mean_2B); + } + else { + // pathological case - can it ever happen? + if (verbose > 0) + fprintf(stderr, "block skipped\n"); + if (!skipping) continue; + } + + n++; + } + + free_grays(category2); + free_grays(category1); + free_grays(zone); + free_grays(block); + + // write extracted signature + + fwrite(signature, sizeof(char), n_signature, out); + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_bruyn_e.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_bruyn_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,551 @@ +#include "wm.h" +#include "signature.h" +#include "coord.h" +#include "gray.h" +#include "sort.h" +#include "bruyn_common.h" +#include "pgm.h" + +char *progname; + +// prints out program's parameters +void usage(void) { + fprintf(stderr, "usage: %s [-b n] [-h] [-k] [-n n] [-o file] [-pP n] [-q n] [-tT n] [-v n] -s file file\n", progname); + fprintf(stderr, "\t-b n\t\tblock size\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-k\t\tdisable block skipping\n"); + fprintf(stderr, "\t-n n\t\tnumber of signature bits to embed\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-p n\t\tpattern type for zone 1\n"); + fprintf(stderr, "\t-P n\t\tpattern type for zone 2\n"); + fprintf(stderr, "\t-q n\t\tsignature strength\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-t n\t\tthreshold for noise\n"); + fprintf(stderr, "\t-T n\t\tthreshold for slope\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + gray** image; + gray **block; + gray **zone; + gray **category1, **category2; + gray maxval; + double *slope; + int rows, cols, colors, format; + int c; + int i, j; + int r; + int n; + int col, row; + int bwidth, bheight; + int n_block; + int skipping = 0; + + char signature_name[MAXPATHLEN]; + char input_name[MAXPATHLEN] = "(stdin)"; + char output_name[MAXPATHLEN] = "(stdout)"; + + double quality = 0.0; + double threshold_noise = 0.0; + double threshold_slope = 0.0; + int pattern1 = 0; + int pattern2 = 0; + int blocksize = 0; + int seed; + + int verbose = 0; + + struct coords *coords; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + // parse command line and set options + while ((c = getopt(argc, argv, "b:h?n:o:p:P:q:s:t:T:v:k")) != EOF) { + switch (c) { + case 'k': + skipping = 1; + break; + case 'h': + case '?': + usage(); + break; + case 'n': + nbit_signature = atoi(optarg); + if (nbit_signature <= 0 || nbit_signature > NBITSIGNATURE) { + fprintf(stderr, "%s: invalid signature length %d\n", progname, nbit_signature); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'p': + pattern1 = atoi(optarg); + if (pattern1 <= 0 || pattern1 > NPATTERN) { + fprintf(stderr, "%s: pattern type out of range\n", progname); + exit(1); + } + break; + case 'P': + pattern2 = atoi(optarg); + if (pattern2 <= 0 || pattern2 > 3) { + fprintf(stderr, "%s: pattern type out of range\n", progname); + exit(1); + } + break; + case 'q': + quality = atof(optarg); + if (quality <= 0) { + fprintf(stderr, "%s: quality factor %f out of range\n", progname, quality); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 't': + threshold_noise = atof(optarg); + if (threshold_noise <= 0) { + fprintf(stderr, "%s: noise threshold %f out of range\n", progname, threshold_noise); + } + break; + case 'T': + threshold_slope = atof(optarg); + if (threshold_slope <= 0) { + fprintf(stderr, "%s: slope threshold %f out of range\n", progname, threshold_slope); + } + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n",progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + // open input image file or read from stdin + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + // read signature file and set options + // command line options override signature file options + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "BRSG") >= 4) { + if (nbit_signature == 0) + fscanf(sig, "%d\n", &nbit_signature); + else + fscanf(sig, "%*d\n"); + if (skipping == 0) + fscanf(sig, "%d\n", &skipping); + else + fscanf(sig, "%*d\n"); + if (pattern1 == 0) + fscanf(sig, "%d\n", &pattern1); + else + fscanf(sig, "%*d\n"); + if (pattern2 == 0) + fscanf(sig, "%d\n", &pattern2); + else + fscanf(sig, "%*d\n"); + if (quality == 0.0) + fscanf(sig, "%lf\n", &quality); + else + fscanf(sig, "%*lf\n"); + if (threshold_noise == 0.0) + fscanf(sig, "%lf\n", &threshold_noise); + else + fscanf(sig, "%*lf\n"); + if (threshold_slope == 0.0) + fscanf(sig, "%lf\n", &threshold_slope); + else + fscanf(sig, "%*lf\n"); + if (blocksize == 0) + fscanf(sig, "%d\n", &blocksize); + else + fscanf(sig, "%*d\n"); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + if (pattern1 <= 0 || pattern2 <= 0 || pattern1 > NPATTERN || pattern2 > NPATTERN) { + fprintf(stderr, "%s: invalid pattern type specified\n"); + exit(1); + } + + // read dimensions of input image file + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + // see if we can embed all signature bits + // we want at least half of the blocks untouched + if (((rows / blocksize) * (cols / blocksize)) < nbit_signature / 2) { + fprintf(stderr, "%s: image not large enough to embed %d bits of signature\n", progname, nbit_signature); + exit(1); + } + n_block = blocksize * blocksize; + + // allocate structure to remember which blocks we already touched, + // allow plenty of room to skip over blocks + if ((coords = alloc_coords(nbit_signature * 2)) == NULL) { + fprintf(stderr, "%s: unable to allocate memory\n", progname); + exit(1); + } + + // read in input image file + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + row = 0; + col = 0; + + // allocate memory for one block + block = alloc_grays(blocksize, blocksize); + + // allocate memory for zone classification + zone = alloc_grays(blocksize, blocksize); + + // allocate memory for category classification + category1 = alloc_grays(blocksize, blocksize); + category2 = alloc_grays(blocksize, blocksize); + + // set up category classification array according to + // pattern type parameter + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + category1[j][i] = lookup_pattern(pattern1, i, j); + category2[j][i] = lookup_pattern(pattern2, i, j); + } + + // allocate memory for slope calculation + slope = malloc(sizeof(double) * n_block); + + // embed all the signature bits, one by one + n = 0; + while (n < nbit_signature) { + int xb; + int yb; + int blocktype; + double smax; + int alpha, beta_minus, beta_plus; + double mean_1A, mean_1B, mean_2A, mean_2B, mean_1, mean_2; + double mean__1A, mean__1B, mean__2A, mean__2B; + int n_1A, n_1B, n_2A, n_2B, n_1, n_2; + int var_1A, var_1B, var_2A, var_2B; + int zone1_ok, zone2_ok; + + // find an unused block randomly, depending on seed + do { + xb = random() % (cols / blocksize); + yb = random() % (rows / blocksize); + } while (add_coord(coords, xb, yb) < 0); + + // copy image block + copy_grays_to_block(block, image, xb * blocksize, yb * blocksize, blocksize, blocksize); + + if (verbose > 0) + fprintf(stderr, "embedding bit #%d (= %d) in block at (%d/%d)\n", n, get_signature_bit(n), xb * blocksize, yb * blocksize); + if (verbose > 8) { + print_grays(image, xb * blocksize, yb * blocksize, blocksize, blocksize); + fprintf(stderr, "\n"); + } + + // sort luminance values in block to represent increasing function F + sort_grays(block[0], n_block); + + if (verbose > 8) { + print_grays(block, 0, 0, blocksize, blocksize); + fprintf(stderr, "\n"); + } + + // calculate slopes of F and determine smax, the max. slope of F + // the index where smax occures is called alpha + alpha = 0; + smax = 0.0; + for (i = 0; i < n_block - 1; i++) { + slope[i] = block[0][i + 1] - block[0][i]; + if (slope[i] > smax) { + smax = slope[i]; + alpha = i; + } + } + slope[n_block - 1] = 0; + + // block type classification + blocktype = BLOCKTYPE_UNKNOWN; + + if (smax < threshold_noise) { + // block has noise contrast + + blocktype = BLOCKTYPE_NOISE; + beta_minus = beta_plus = alpha; + } + else { + // block has progressive or hard contrast, let's find out... + + beta_minus = alpha - 1; + while (beta_minus >= 0 && smax - slope[beta_minus] <= threshold_slope) + beta_minus--; + + beta_plus = alpha + 1; + while (beta_plus < n_block && smax - slope[beta_plus] <= threshold_slope) + beta_plus++; + + if (beta_minus + 1 == alpha && beta_plus - 1 == alpha) + blocktype = BLOCKTYPE_HARD; + else + blocktype = BLOCKTYPE_PROGRESSIVE; + } + + if (verbose > 1) { + fprintf(stderr, "blocktype: %d\n", blocktype); + fprintf(stderr, "Smax = %lf, alpha = %d, beta- = %d, beta+ = %d\n", smax, alpha, beta_minus, beta_plus); + } + + // block pixel classification + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + gray pixel = image[yb * blocksize + j][xb * blocksize + i]; + zone[j][i] = ZONE_VOID; + switch (blocktype) { + case BLOCKTYPE_PROGRESSIVE: + case BLOCKTYPE_HARD: + if (pixel < block[0][beta_minus]) + zone[j][i] = ZONE_1; + else if (pixel > block[0][beta_plus]) + zone[j][i] = ZONE_2; + break; + case BLOCKTYPE_NOISE: + if (pixel < block[0][n_block / 2]) + zone[j][i] = ZONE_1; + else if (pixel > block[0][n_block / 2]) + zone[j][i] = ZONE_2; + break; + default: + fprintf(stderr, "%s: invalid block type\n", progname); + break; + } + } + + if (verbose > 8) { + print_grays(zone, 0, 0, blocksize, blocksize); + fprintf(stderr, "\n"); + } + + // calculate mean values for zone/categories + mean_1A = mean_1B = mean_2A = mean_2B = mean_1 = mean_2 = 0.0; + n_1A = n_1B = n_2A = n_2B = n_1 = n_2 = 0; + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + gray pixel = image[yb * blocksize + j][xb * blocksize + i]; + int pixel_zone = zone[j][i]; + int pixel_category = CATEGORY_VOID; + if (pixel_zone == ZONE_1) + pixel_category = category1[j][i]; + else if (pixel_zone == ZONE_2) + pixel_category = category2[j][i]; + + switch (pixel_zone | pixel_category) { + case CLASSIFICATION_1A: + n_1++; + n_1A++; + mean_1A += pixel; + mean_1 += pixel; + break; + case CLASSIFICATION_1B: + n_1++; + n_1B++; + mean_1B += pixel; + mean_1 += pixel; + break; + case CLASSIFICATION_2A: + n_2++; + n_2A++; + mean_2A += pixel; + mean_2 += pixel; + break; + case CLASSIFICATION_2B: + n_2++; + n_2B++; + mean_2B += pixel; + mean_2 += pixel; + break; + } + } + + if (n_1 && n_1A && n_1B) { + mean_1 /= (double) n_1; + mean_1A /= (double) n_1A; + mean_1B /= (double) n_1B; + zone1_ok = 1; + } + else { + mean_1 = mean_1A = mean_1B = 0.0; + zone1_ok = 0; + if (verbose > 0) + fprintf(stderr, "zone 1 unusable\n"); + } + + if (n_2 && n_2A && n_2B) { + mean_2 /= (double) n_2; + mean_2A /= (double) n_2A; + mean_2B /= (double) n_2B; + zone2_ok = 1; + } + else { + mean_2 = mean_2A = mean_2B = 0.0; + zone2_ok = 0; + if (verbose > 0) + fprintf(stderr, "zone 2 unusable\n"); + } + + if (!skipping && !zone1_ok && !zone2_ok) { + // pathological case - can it ever happen? + if (verbose > 0) + fprintf(stderr, "block skipped\n"); + continue; + } + + if (verbose > 2) { + fprintf(stderr, "m_1 = %lf, m_1A = %lf, m_1B = %lf\n", mean_1, mean_1A, mean_1B); + fprintf(stderr, "m_2 = %lf, m_2A = %lf, m_2B = %lf\n", mean_2, mean_2A, mean_2B); + } + + // calculate new mean values required by embedding rule + if (get_signature_bit(n)) { + if (zone1_ok) { + mean__1A = (mean_1 * (double) (n_1A + n_1B) + (double) n_1B * quality) / (double) (n_1A + n_1B); + mean__1B = mean__1A - quality; + } + if (zone2_ok) { + mean__2A = (mean_2 * (double) (n_2A + n_2B) + (double) n_2B * quality) / (double) (n_2A + n_2B); + mean__2B = mean__2A - quality; + } + } + else { + if (zone1_ok) { + mean__1A = (mean_1 * (double) (n_1A + n_1B) - (double) n_1B * quality) / (double) (n_1A + n_1B); + mean__1B = mean__1A + quality; + } + if (zone2_ok) { + mean__2A = (mean_2 * (double) (n_2A + n_2B) - (double) n_2B * quality) / (double) (n_2A + n_2B); + mean__2B = mean__2A + quality; + } + } + + // calculate luminance variations + if (zone1_ok) { + var_1A = rint(mean__1A - mean_1A); + var_1B = rint(mean__1B - mean_1B); + } + else var_1A = var_1B = 0; + + if (zone2_ok) { + var_2A = rint(mean__2A - mean_2A); + var_2B = rint(mean__2B - mean_2B); + } + else var_2A = var_2B = 0; + + if (verbose > 2) { + if (zone1_ok) + fprintf(stderr, "m*_1A = %lf, m*_1B = %lf\n", mean__1A, mean__1B); + if (zone2_ok) + fprintf(stderr, "m*_2A = %lf, m*_2B = %lf\n", mean__2A, mean__2B); + fprintf(stderr, "var %d %d %d %d\n", var_1A, var_1B, var_2A, var_2B); + } + + // apply luminance variations to image pixels + for (i = 0; i < blocksize; i++) + for (j = 0; j < blocksize; j++) { + int pixel = image[yb * blocksize + j][xb * blocksize + i]; + int pixel_zone = zone[j][i]; + int pixel_category = CATEGORY_VOID; + if (pixel_zone == ZONE_1) + pixel_category = category1[j][i]; + else if (pixel_zone == ZONE_2) + pixel_category = category2[j][i]; + + switch (pixel_zone | pixel_category) { + case CLASSIFICATION_1A: + pixel = GRAYRANGE(pixel + var_1A); + break; + case CLASSIFICATION_1B: + pixel = GRAYRANGE(pixel + var_1B); + break; + case CLASSIFICATION_2A: + pixel = GRAYRANGE(pixel + var_2A); + break; + case CLASSIFICATION_2B: + pixel = GRAYRANGE(pixel + var_2B); + break; + } + image[yb * blocksize + j][xb * blocksize + i] = pixel; + } + + n++; + } + + free_grays(category2); + free_grays(category1); + free_grays(zone); + free_grays(block); + + // write output image dimensions to output file + pgm_writepgminit(out, cols, rows, maxval, 0); + + // write output image + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_corvi_d.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_corvi_d.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,173 @@ +.\" +.\" wm_corvi_d.1 - the *roff document processor man page source +.\" +.TH wm_corvi_d 1 "98/07/29" "Watermarking, Version 1.0" +.SH NAME +.B wm_corvi_d +\- a program to extract a signature from the DWT residue of a watermarked +image +.SH SYNOPSIS +.B wm_corvi_d +[ +.BI \-a \ number +] +[ +.BI \-e \ number +] +[ +.BI \-f \ number +] +[ +.BI \-F \ ffile +] +[ +.BI \-g \ number +] +[ +.B \-h +] +[ +.BI \-i \ ifile +] +.br +[ +.BI \-n \ number +] +[ +.BI \-o \ ofile +] +[ +.BI \-q \ number +] +[ +.BI \-v \ number +] +.BI \-s \ sfile +.I file +.SH DESCRIPTION +.B wm_corvi_d +is a program to extract a signature from the DWT residue of +a watermarked image +.I file. +The +.B cmp_corvi_sig +program is used to test the extracted signature against the original signature. +The input image is in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.B gen_corvi_sig +is used to generate a signature file, +.B wm_corvi_e +embeds the signature into an image. +.PP +Please refer to Marco Corvi's paper "Wavelet-based image watermarking +for copyright protection", to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. +Allows to override the setting in the signature file. +.TP +.BI \-e \ number +Wavelet filtering method for forward transformation. +Allows to override the setting in the signature file. +.TP +.BI \-f \ number +Wavelet filter number. +Allows to override the setting in the signature file. +.TP +.BI \-F \ ffile +Wavelet filter definition file. +Allows to override the setting in the signature file. +.TP +.BI \-g \ number +Wavelet filtering method for inverse transformation. +Allows to override the setting in the signature file. +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. +.TP +.BI \-o \ ofile +Output watermarked image to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Set quantization/quality factor. Overrides the setting in the signature +file. +.TP +.BI \-v \ number +Verbosity level. Default value: 0. +.TP +.BI \-s \ sfile +The signature file to embed into the input image. See +.B gen_corvi_sig +(1) for a description of the file format. Mandatory parameter. +.IR file +Input image in PGM format to sign (watermark). Default: standard input. +.TP +.I file +The watermarked image in PGM format. +.PP +.SH OUTPUT +The signed (watermarked) image in PGM format is written to standard output +or, optionally, to +.I ofile. +.PP +The output file has the following format: +.TP +.B CVSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The alpha factor (embedding strength). +.TP +.I number +The quantization/quality factor. +.TP +.I number +The wavelet forward transform filtering method. +.TP +.I number +The wavelet filter number. +.TP +.I file +The wavelet filter definition file name. +.TP +.I number +The wavelet inverse transform filtering method. +.TP +.I numbers +The actual normal distributed signature values, one per line. +.PP +.SH AUTHOR +Peter Meerwald +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_corvi_d +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_corvi_sig +(1), +.BR wm_corvi_e +(1), +.BR wm_corvi_s +(1), +.BR cmp_corvi_sig +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_corvi_d.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_corvi_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,310 @@ +#include "dwt.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-h] [-n n] [-o file] [-s file] [-v n] -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-n n\t\twatermark length\n"); + fprintf(stderr, "\t-o file\t\textracted signature file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c; + int i; + int n = 0; + int method = -1; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + int level; + double alpha = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + Image_tree input_dwts; + Image_tree orig_dwts; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?i:n:o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "CVSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + + fclose(in); + + for (row = 0; row < orig_rows; row++) + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + + fclose(orig); + + level = 0; + row = rows; + col = cols; + while (n < row * col / 4.0 && row >= 2 && col >= 2) { + row /= 2; + col /= 2; + level++; + } + + if (verbose >= 2) { + fprintf(stderr, "%s: extracting from coarse image (x %d/y %d) at level %d\n", progname, col, row, level); + } + + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + fprintf(out, "CVWM\n"); + fprintf(out, "%d\n", n); + + { + Image_tree p = input_dwts; + Image_tree q = orig_dwts; + Image input_img; + Image orig_img; + double input_med; + double orig_med; + double input_var; + double orig_var; + + while (!p->image) + p = p->coarse; + + while (!q->image) + q = q->coarse; + + input_img = p->image; + orig_img = q->image; + + input_med = 0.0; + for (row = 0; row < input_img->height; row++) + for (col = 0; col < input_img->width; col++) + input_med += get_pixel(input_img, col, row); + input_med /= (double) (input_img->height * input_img->width); + + orig_med = 0.0; + for (row = 0; row < orig_img->height; row++) + for (col = 0; col < orig_img->width; col++) + orig_med += get_pixel(orig_img, col, row); + orig_med /= (double) (orig_img->height * orig_img->width); + + orig_var = 0.0; + for (row = 0; row < orig_img->height; row++) + for (col = 0; col < orig_img->width; col++) + orig_var += sqr(get_pixel(orig_img, col, row) - orig_med); + orig_var /= (double) (orig_img->height * orig_img->width); + + input_var = 0.0; + for (row = 0; row < input_img->height; row++) + for (col = 0; col < input_img->width; col++) + input_var += sqr(get_pixel(input_img, col, row) - input_med); + input_var /= (double) (input_img->height * input_img->width); + + orig_var = sqrt(orig_var); + input_var = sqrt(input_var); + + if (verbose > 3) + fprintf(stderr, "%s: mean (input, orig): %f, %f,\n variance (input, orig): %f, %f\n", progname, input_med, orig_med, input_var, orig_var); + + row = 0; + col = 0; + while (n > 0) { + double input_pix; + double orig_pix; + double x; + + input_pix = get_pixel(input_img, col, row); + orig_pix = get_pixel(orig_img, col, row); + + x = (((input_pix - input_med) * (orig_var / input_var) - (orig_pix / orig_med)) / (orig_pix - orig_med) - 1.0) / alpha; + + fprintf(out, "%f\n", x); + + if (++col == orig_img->width) { col = 0; row++; } + n--; + } + } + + fclose(out); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_corvi_e.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_corvi_e.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,142 @@ +.\" +.\" wm_corvi_e.1 - the *roff document processor man page source +.\" +.TH wm_corvi_e 1 "98/07/29" "Watermarking, Version 1.0" +.SH NAME +.B wm_corvi_e +\- a program to embed a signature in the DWT residue of an image +.SH SYNOPSIS +.B wm_corvi_e +[ +.BI \-a \ number +] +[ +.BI \-e \ number +] +[ +.BI \-f \ number +] +[ +.BI \-F \ ffile +] +[ +.BI \-g \ number +] +[ +.B \-h +] +[ +.BI \-o \ ofile +] +.br +[ +.BI \-q \ number +] +[ +.BI \-v \ number +] +.BI \-s \ sfile +.I file +.SH DESCRIPTION +.B wm_corvi_e +is a program to embed a signature (watermark) from +.I sfile +into the DWT residue of an image +.I file +and output a signed (watermarked) image +.I ofile. +Both, input and output image, +are in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. The signature +.I sfile +is a mandatory parameter however. +.PP +.B gen_corvi_sig +is used to generate a signature file, +.B wm_corvi_d +extracts a signature from a watermarked image and +.B cmp_corvi_sig +allows to compare and test an extracted watermark against the original +signature. +.PP +Please refer to Marco Corvi's paper "Wavelet-based image watermarking +for copyright protection", to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. +Allows to override the setting in the signature file. +.TP +.BI \-e \ number +Wavelet filtering method for forward transformation. +Allows to override the setting in the signature file. +.TP +.BI \-f \ number +Wavelet filter number. +Allows to override the setting in the signature file. +.TP +.BI \-F \ ffile +Wavelet filter definition file. +Allows to override the setting in the signature file. +.TP +.BI \-g \ number +Wavelet filtering method for inverse transformation. +Allows to override the setting in the signature file. +.TP +.B \-h +Print a help message. +.TP +.BI \-o \ ofile +Output watermarked image to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Set quantization/quality factor. Overrides the setting in the signature +file. +.TP +.BI \-s \ sfile +The signature file to embed into the input image. See +.B gen_corvi_sig +(1) for a description of the file format. Mandatory parameter. +.IR file +Input image in PGM format to sign (watermark). Default: standard input. +.TP +.BI \-v \ number +Verbosity level. Specify higher numbers for more informatative +output. Default value: 0. +.TP +.I file +The image in PGM format to be watermarked. +.PP +.SH OUTPUT +The signed (watermarked) image in PGM format is written to standard output +or, optionally, to +.I ofile. +The length of the signature (watermark) determines the level of the +image residue (coarse image) where the signature is embedded. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_corvi_e +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_corvi_sig +(1), +.BR wm_corvi_d +(1), +.BR wm_corvi_s +(1), +.BR cmp_corvi_sig +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_corvi_e.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_corvi_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,236 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F n] [-h] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int row, col; + + int n; + + double alpha = 0.0; + + int filter = 0; + int method = -1; + int level; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree dwts; + + gray maxval; + int rows, cols, colors, format; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "CVSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + level = 0; + row = rows; + col = cols; + while (n < row * col / 4.0 && row >= 2 && col >= 2) { + row /= 2; + col /= 2; + level++; + } + + if (verbose >= 2) { + fprintf(stderr, "%s: embedding into coarse image (x %d/y %d) at level %d\n", progname, col, row, level); + } + + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + { + Image_tree p = dwts; + Image img; + double med; + + while (!p->image) + p = p->coarse; + + img = p->image; + + med = 0.0; + for (row = 0; row < img->height; row++) + for (col = 0; col < img->width; col++) + med += get_pixel(img, col, row); + + med /= (double) (img->height * img->width); + + row = 0; + col = 0; + while (n > 0) { + double pix; + double g; + + fscanf(sig, "%lf\n", &g); + + pix = get_pixel(img, col, row); + pix = med + (pix - med) * (1.0 + alpha * g); + set_pixel(img, col, row, pix); + + if (++col == img->width) { col = 0; row++; } + n--; + } + } + + fclose(sig); + + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_corvi_s.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_corvi_s.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,171 @@ +.\" +.\" wm_corvi_s.1 - the *roff document processor man page source +.\" +.TH wm_corvi_s 1 "98/07/29" "Watermarking, Version 1.0" +.SH NAME +.B wm_corvi_s +\- a program to extract a signature from the DWT residue of a watermarked +image +.SH SYNOPSIS +.B wm_corvi_s +[ +.BI \-a \ number +] +[ +.BI \-e \ number +] +[ +.BI \-f \ number +] +[ +.BI \-F \ ffile +] +[ +.BI \-g \ number +] +[ +.B \-h +] +[ +.BI \-i \ ifile +] +.br +[ +.BI \-n \ number +] +[ +.BI \-o \ ofile +] +[ +.BI \-q \ number +] +[ +.BI \-v \ number +] +.BI \-s \ sfile +.I file +.SH DESCRIPTION +.B wm_corvi_s +is a program to extract a signature from the DWT residue of +a watermarked image +.I file. +The +.B cmp_corvi_sig +program is used to test the extracted signature against the original signature. +The input image is in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.B gen_corvi_sig +is used to generate a signature file, +.B wm_corvi_e +embeds the signature into an image. +.PP +Please refer to Marco Corvi's paper "Wavelet-based image watermarking +for copyright protection", to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. +Allows to override the setting in the signature file. +.TP +.BI \-e \ number +Wavelet filtering method for forward transformation. +Allows to override the setting in the signature file. +.TP +.BI \-f \ number +Wavelet filter number. +Allows to override the setting in the signature file. +.TP +.BI \-F \ ffile +Wavelet filter definition file. +Allows to override the setting in the signature file. +.TP +.BI \-g \ number +Wavelet filtering method for inverse transformation. +Allows to override the setting in the signature file. +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. +.TP +.BI \-o \ ofile +Output watermarked image to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Set quantization/quality factor. Overrides the setting in the signature +file. +.TP +.BI \-v \ number +Verbosity level. Default value: 0. +.TP +.BI \-s \ sfile +The signature file to embed into the input image. See +.B gen_corvi_sig +(1) for a description of the file format. Mandatory parameter. +.IR file +Input image in PGM format to sign (watermark). Default: standard input. +.TP +.I file +The watermarked image in PGM format. +.PP +.SH OUTPUT +The signed (watermarked) image in PGM format is written to standard output +or ,optionally, to +.I ofile. +.PP +The output file has the following format: +.TP +.B CVSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The alpha factor (embedding strength). +.TP +.I number +The quantization/quality factor. +.TP +.I number +The wavelet forward transform filtering method. +.TP +.I number +The wavelet filter number. +.I file +The wavelet filter definition file name. +.TP +.I number +The wavelet inverse transform filtering method. +.TP +.I numbers +The actual normal distributed signature values, one per line. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_corvi_s +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_corvi_sig +(1), +.BR wm_corvi_e +(1), +.BR wm_corvi_d +(1), +.BR cmp_corvi_sig +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_corvi_s.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_corvi_s.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,295 @@ +#include "wm.h" +#include "wm_dwt.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-h] [-n n] [-o file] [-q n] [-s file] [-v n] -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-n n\t\twatermark length\n"); + fprintf(stderr, "\t-o file\t\textracted signature file\n"); + fprintf(stderr, "\t-q n\t\tquantization/quality factor\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c; + int i; + int quantization = 0; + int n = 0; + int method = -1; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + int level; + double alpha = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + Image_tree input_dwts; + Image_tree orig_dwts; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?i:n:o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "CVSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (quantization == 0) + fscanf(sig, "%d\n", &quantization); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + + fclose(in); + + for (row = 0; row < orig_rows; row++) + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + + fclose(orig); + + level = 0; + row = rows; + col = cols; + while (n < row * col / 4.0 && row >= 2 && col >= 2) { + row /= 2; + col /= 2; + level++; + } + + if (verbose >= 2) { + fprintf(stderr, "%s: extracting from coarse image (x %d/y %d) at level %d\n", progname, col, row, level); + } + + init_dwt(cols, rows, filter_name, filter, level, method); + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + fprintf(out, "CVSG\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%f\n", alpha); + fprintf(out, "%d\n", quantization); + fprintf(out, "%d\n", method); + fprintf(out, "%d\n", filter); + fprintf(out, "%s\n", filter_name); + + { + Image_tree p = input_dwts; + Image_tree q = orig_dwts; + Image input_img; + Image orig_img; + double input_med; + double orig_med; + + while (!p->image) + p = p->coarse; + + while (!q->image) + q = q->coarse; + + input_img = p->image; + orig_img = q->image; + + input_med = 0.0; + for (row = 0; row < input_img->height; row++) + for (col = 0; col < input_img->width; col++) + input_med += get_pixel(input_img, col, row); + input_med /= input_img->height * input_img->width; + + orig_med = 0.0; + for (row = 0; row < orig_img->height; row++) + for (col = 0; col < orig_img->width; col++) + orig_med += get_pixel(orig_img, col, row); + orig_med /= orig_img->height * orig_img->width; + + row = 0; + col = 0; + while (n > 0) { + Pixel input_pix; + Pixel orig_pix; + double x; + + input_pix = get_pixel(input_img, col, row); + orig_pix = get_pixel(orig_img, col, row); + + x = ((input_pix - orig_pix) / (orig_pix - orig_med)) / alpha; + + fprintf(out, "%f\n", x); + + if (++col == orig_img->width) { col = 0; row++; } + n--; + } + } + + fclose(out); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_cox_d.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_cox_d.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,132 @@ +.\" +.\" wm_cox_d.1 - the *roff document processor man page source +.\" +.TH wm_cox_d 1 "98/07/05" "Watermarking, Version 1.0" +.SH NAME +.B wm_cox_d +\- a program to extract a signature from the DCT coefficients of a watermarked image +.SH SYNOPSIS +.B wm_cox_d +[ +.BI \-a \ number +] +[ +.B \-h +] +[ +.BI \-i \ ifile +] +[ +.BI \-n \ number +] +[ +.BI \-o \ ofile +] +[ +.BI \-q \ number +] +[ +.BI \-v \ number +] +.br +.BI \-s \ sfile +.I file +.SH DESCRIPTION +.B wm_cox_d +is a program to extract a signature from the DCT coefficients of the watermarked image +.I file. +The +.B cmp_cox_sig +program is used to test the extracted signature against the original signature. +The input image is in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. +.PP +.B gen_cox_sig +is used to generate a signature file, +.B wm_cox_e +embeds the signature into an image. +.PP +Please refer to Ingemar J. Cox's paper "Secure Spread Spectrum +Watermarking for Multimedia", 1995, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. +Allows to override the setting in the signature file. +.TP +.B \-h +Print a help message. +.TP +.BI \-i \ ifile +The original image. +.TP +.BI \-o \ ofile +Output watermarked image to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Set quantization/quality factor. Overrides the setting in the signature +file. +.TP +.BI \-v \ number +Verbosity level. Default value: 0. +.TP +.BI \-s \ sfile +The signature file to embed into the input image. See +.B gen_cox_sig +(1) for a description of the file format. Mandatory parameter. +.IR file +Input image in PGM format to sign (watermark). Default: standard input. +.TP +.I +The watermarked image file in PGM format. +.PP +.SH OUTPUT +The signed (watermarked) image in PGM format is written to standard output +or ,optionally, to +.I ofile. +The embedding process may take some time on large images since the DCT +is performed on the whole image in one step (not block-wise). +.PP +.PP +The output file has the following format: +.TP +.B CXSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The alpha factor (embedding strength). +.TP +.I number +The quantization/quality factor. +.TP +.I numbers +The actual normal distributed signature values, one per line. +.PP +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_cox_d +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_cox_sig +(1), +.BR wm_cox_e +(1), +.BR cmp_cox_sig +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_cox_d.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_cox_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,227 @@ +#include "wm.h" +#include "dct.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-h] [-n n] [-o file] [-s file] [-v n] -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor (default 0.3)\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-n n\t\twatermark length (default 100)\n"); + fprintf(stderr, "\t-o file\t\textracted signature file\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c; + int r; + int i, j; + int n = 100; + + double a = 0.3; + + int warn_n = 1; + int warn_a = 1; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + double threshold; + double *largest; + + double **input_dcts; + double **orig_dcts; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "h?i:n:o:s:v:")) != EOF) { + switch (c) { + case 'a': + a = atof(optarg); + if (a <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, a); + exit(1); + } + warn_a = 0; + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 1000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + warn_n = 0; + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "CXSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (warn_a) + fscanf(sig, "%lf\n", &a); + else + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + if (warn_a) + fprintf(stderr, "%s: warning - alpha factor not specified, using default %f\n", progname, a); + if (warn_n) + fprintf(stderr, "%s: warning - watermark length not specified, using default %d\n", progname, n); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + init_dct_NxN(cols, rows); + + input_image = pgm_allocarray(in_cols, in_rows); + + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + + fclose(in); + + for (row = 0; row < orig_rows; row++) + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + + fclose(orig); + + input_dcts = alloc_coeffs(cols, rows); + orig_dcts = alloc_coeffs(cols, rows); + + fdct_NxN(input_image, input_dcts); + fdct_NxN(orig_image, orig_dcts); + + largest = malloc((n + 1) * sizeof(double)); + select_largest_coeffs(orig_dcts[0], cols * rows, n+1, largest); + threshold = largest[0]; + free(largest); + + fprintf(out, "CXWM\n"); + fprintf(out, "%d\n", n); + + j = 0; + for (i = 0; i < n; i++) { + double d, o, p; + + while ((o = orig_dcts[j / cols][j % cols]) < threshold) j++; + + p = input_dcts[j / cols][j % cols]; + + d = (p / o - 1.0) / a; + if (verbose >= 1) + fprintf(stderr, "input %f orig %f alpha %f d %f\n", p, o, a, d); + fprintf(out, "%f\n", d); + j++; + } + + fclose(out); + + free_coeffs(input_dcts); + free_coeffs(orig_dcts); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_cox_e.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_cox_e.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,110 @@ +.\" +.\" wm_cox_e.1 - the *roff document processor man page source +.\" +.TH wm_cox_e 1 "98/07/01" "Watermarking, Version 1.0" +.SH NAME +.B wm_cox_e +\- a program to embed a signature in the DCT coefficients of an image +.SH SYNOPSIS +.B wm_cox_e +[ +.BI \-a \ number +] +[ +.B \-h +] +[ +.BI \-o \ ofile +] +[ +.BI \-q \ number +] +.BI \-s \ sfile +.I file +.SH DESCRIPTION +.B wm_cox_e +is a program to embed a signature (watermark) from +.I sfile +into the DCT coefficients of an image +.I file +and output a signed (watermarked) image +.I ofile. +Both, input and output image, +are in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. The signature +.I sfile +is a mandatory parameter however. +.PP +.B gen_cox_sig +is used to generate a signature file, +.B wm_cox_d +extracts a signature from a watermarked image and +.B cmp_cox_sig +allows to compare and test an extracted watermark against the original +signature. +.PP +Please refer to Ingemar J. Cox's paper "Secure Spread Spectrum +Watermarking for Multimedia", 1995, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.BI \-a \ number +Alpha factor that determines embedding strength of the signature. +Allows to override the setting in the signature file. +.TP +.B \-h +Print a help message. +.TP +.BI \-o \ ofile +Output watermarked image to the specified +.I file +instead of standard output. +.TP +.BI \-q \ number +Set quantization/quality factor. Overrides the setting in the signature +file. +.TP +.BI \-s \ sfile +The signature file to embed into the input image. See +.B gen_cox_sig +(1) for a description of the file format. Mandatory parameter. +.IR file +Input image in PGM format to sign (watermark). Default: standard input. +.TP +.I file +The input image in PGM format. +.PP +.SH OUTPUT +The signed (watermarked) image in PGM format is written to standard output +or, optionally, to +.I ofile. +The embedding process may take some time on large images since the DCT +is performed on the whole image in one step (not block-wise). +.PP +The +.I n +largest coefficients are pulsed to embed the +.I n +bit watermark. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_cox_e +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_cox_sig +(1), +.BR wm_cox_d +(1), +.BR cmp_cox_sig +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_cox_e.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_cox_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,164 @@ +#include "wm.h" +#include "dct.h" +#include "pgm.h" +#include "sort.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-h] [-o file] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int row, col; + int i,j; + + int n; + + double alpha = 0.0; + double threshold; + + double *largest; + gray **input_image; + gray **output_image; + double **dcts; + + gray maxval; + int rows, cols, colors, format; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:h?o:s:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "CXSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + init_dct_NxN(cols, rows); + + dcts = alloc_coeffs(cols, rows); + input_image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, input_image[row], cols, maxval, format); + + fclose(in); + + output_image = pgm_allocarray(cols, rows); + + fdct_NxN(input_image, dcts); + + largest = malloc((n + 1) * sizeof(double)); + select_largest_coeffs(dcts[0], cols * rows, n+1, largest); + threshold = largest[0]; + free(largest); + + j = 0; + for (i = 0; i < n; i++) { + double v; + + while (dcts[j / cols][j % cols] < threshold) j++; + + fscanf(sig, "%lf\n", &v); + dcts[j / cols][j % cols] *= (1.0 + alpha * v); + j++; + } + + idct_NxN(dcts, output_image); + free_coeffs(dcts); + + pgm_writepgminit(out, cols, rows, maxval, 0); + + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, output_image[row], cols, maxval, 0); + + fclose(out); + + fclose(sig); + + pgm_freearray(output_image, rows); + pgm_freearray(input_image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_dugad_d.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_dugad_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,260 @@ +#include "wm.h" +#include "dwt.h" +#include "dwt_util.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F file] [-h] [-l n] [-n n] [-o file] [-v n] [-t n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition levels\n"); + fprintf(stderr, "\t-n n\t\twatermark length\n"); + fprintf(stderr, "\t-o file\t\tfile for extracted watermark\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-t n\t\tdetection threshold\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +void wm_subband(Image s, double *w, int n, double t2, int *m, double *z, double *v) { + int i; + + *m = 0; + *z = 0.0; + *v = 0.0; + for (i = 0; i < s->width * s->height; i++) + if (s->data[i] > t2) { + (*z) += (s->data[i] * w[i % n]); + (*v) += fabs(s->data[i]); + (*m)++; + } +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + gray **input_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + + int c, w; + int i; + int n = 0; + int method = -1; + int levels = 0; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + double alpha = 0.0; + double t2 = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int rows, cols; + int row, col; + + double *watermark; + + Image_tree dwts, s; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?l:n:o:s:v:t")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'l': + levels = atoi(optarg); + if (levels <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", levels); + exit(1); + } + break; + + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 't': + t2 = atof(optarg); + if (t2 <= 0.0) { + fprintf(stderr, "%s: detection threshold %f out of range\n", progname, t2); + exit(1); + } + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "DGSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (levels == 0) + fscanf(sig, "%d\n", &levels); + else + fscanf(sig, "%*d\n"); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + if (t2 == 0.0) + fscanf(sig, "%lf\n", &t2); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + + for (row = 0; row < in_rows; row++) { + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + } + + fclose(in); + + init_dwt(cols, rows, filter_name, filter, levels, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(input_image); + + fprintf(out, "DGWM\n"); + fprintf(out, "%d\n", levels); + fprintf(out, "%f\n", alpha); + + for (i = 0, s = dwts; i < levels; i++, s = s->coarse) { + int m; + double z, v; + + wm_subband(s->horizontal->image, watermark, n, t2, &m, &z, &v); + fprintf(out, "%d %f %f\n", m, z, v); + wm_subband(s->vertical->image, watermark, n, t2, &m, &z, &v); + fprintf(out, "%d %f %f\n", m, z, v); + wm_subband(s->diagonal->image, watermark, n, t2, &m, &z, &v); + fprintf(out, "%d %f %f\n", m, z, v); + } + + fclose(out); + + free(watermark); + + pgm_freearray(input_image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_dugad_e.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_dugad_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,240 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F file] [-h] [-l n] [-o file] [-t n] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition levels\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-t n\t\tcasting threshold\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +// actual watermarking procedure: embeds a watermark of n normally +// distributed values into a coefficients > threshold t1 of a subband +void wm_subband(Image s, double *w, int n, double a, double t1) { + int i; + + for (i = 0; i < s->width * s->height; i++) + if (fabs(s->data[i]) > t1) + s->data[i] += (a * fabs(s->data[i]) * w[i % n]); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int i, c; + int row, col; + + int n; + + double alpha = 0.0; + double t1 = 0.0; + + int levels = 0; + int filter = 0; + int method = -1; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree dwts, s; + + gray maxval; + int rows, cols, colors, format; + + double *watermark; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?l:o:s:t:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'l': + levels = atoi(optarg); + if (levels <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", levels); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 't': + t1 = atof(optarg); + if (t1 <= 0.0) { + fprintf(stderr, "%s: casting threshold %f out of range\n", progname, t1); + exit(1); + } + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "DGSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (levels == 0) + fscanf(sig, "%d\n", &levels); + else + fscanf(sig, "%*d\n"); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (t1 == 0.0) + fscanf(sig, "%lf\n", &t1); + else + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + // wavelet transform + init_dwt(cols, rows, filter_name, filter, 3, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + // embed watermark in all subbands of a decomposition level + for (i = 0, s = dwts; i < 3; i++, s = s->coarse) { + wm_subband(s->horizontal->image, watermark, n, alpha, t1); + wm_subband(s->vertical->image, watermark, n, alpha, t1); + wm_subband(s->diagonal->image, watermark, n, alpha, t1); + } + + free(watermark); + + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_frid2_d.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_frid2_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,212 @@ +#include "wm.h" +#include "dct.h" +#include "pgm.h" +#include "signature.h" +#include "frid2_common.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-h] [-b n] [-n n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor low freq. embedding strength\n"); + fprintf(stderr, "\t-b n\t\tbeta factor for weighted correlation (default 0)\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-n n\t\tnormalisation factor (default 1024.0)\n"); + fprintf(stderr, "\t-o file\t\tfile for extracted watermark information\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int row, col; + int n; + double normalization = 1024.0; + int seed, format; + + double alpha = 0.0; + double beta = 0.0; + + double correlation; + + gray **image; + double **coeffs; + + double mean, derivation, mult_factor; + int rows, cols; + + gray maxval; + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:b:n:h?s:o:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'b': + beta = atof(optarg); + if (beta <= 0.0) { + fprintf(stderr, "%s: beta factor %f out of range\n", progname, beta); + exit(1); + } + break; + case 'n': + normalization = atof(optarg); + if (normalization < 0) { + fprintf(stderr, "%s: normalisation factor %f out of range\n", progname, normalization); + exit(1); + } + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "FR2SG") >= 5) { + fscanf(sig, "%d\n", &nbit_signature1); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + fscanf(sig, "%*lf\n"); + fscanf(sig, "%d\n", &seed); + n_signature1 = NBITSTOBYTES(nbit_signature1); + fread(signature1, sizeof(char), n_signature1, sig); + fscanf(sig, "\n"); + srandom(seed); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // calculate mean malue + mean = 0.0; + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + mean += image[row][col]; + + mean /= cols * rows; + + // calculate derivation + derivation = 0.0; + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + derivation += sqr(image[row][col] - mean); + + derivation = sqrt(derivation / (cols * rows - 1)); + mult_factor = normalization / (sqrt(cols * rows) * derivation); + + if (verbose > 5) + fprintf(stderr, "%s: mean %f, derivation %f, mult_factor %f\n", progname, mean, derivation, mult_factor); + + // normalize image + coeffs = alloc_coeffs(cols, rows); + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + coeffs[row][col] = (image[row][col] - mean) * mult_factor; + + if (rows == cols) { + init_dct_NxN(cols, rows); + fdct_inplace_NxN(coeffs); + } +// else { +// init_dct_NxM(cols, rows); +// fdct_NxM(coeffs); +// } + + + fprintf(out, "FR2WM\n"); + + fprintf(out, "%d\n", nbit_signature1); + correlation = detect_low_freq(coeffs, cols, rows, alpha, beta, verbose); + if (verbose > 2) + fprintf(stderr, "low_freq correlation: %f\n", correlation); + fwrite(signature2, sizeof(char), NBITSTOBYTES(nbit_signature1), out); + fprintf(out, "\n"); + + fprintf(out, "%d\n", nbit_signature1); + correlation = detect_med_freq(coeffs, cols, rows, seed, verbose); + if (verbose > 2) + fprintf(stderr, "med_freq correlation: %f\n", correlation); + fwrite(signature2, sizeof(char), NBITSTOBYTES(nbit_signature1), out); + fprintf(out, "\n"); + + fclose(out); + + free_coeffs(coeffs); + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_frid2_e.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_frid2_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,218 @@ +#include "wm.h" +#include "dct.h" +#include "pgm.h" +#include "signature.h" +#include "frid2_common.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-g n] [-n n] [-h] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor low freq. embedding strength\n"); + fprintf(stderr, "\t-g n\t\tgamma factor med freq. embedding strength\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-n n\t\tnormalisation factor (default 1024.0)\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c; + int row, col; + int n; + double normalization = 1024.0; + int seed, format; + + double alpha = 0.0; + double gamma = 0.0; + + gray **image; + double **coeffs; + + double mean, derivation; + double mult_factor; + + int rows, cols; + int verbose = 0; + gray maxval; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:g:n:h?o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'g': + gamma = atof(optarg); + if (gamma <= 0.0) { + fprintf(stderr, "%s: gamma factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'n': + normalization = atof(optarg); + if (normalization < 0) { + fprintf(stderr, "%s: normalisation factor %f out of range\n", progname, normalization); + exit(1); + } + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "FR2SG") >= 5) { + fscanf(sig, "%d\n", &nbit_signature); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (gamma == 0.0) + fscanf(sig, "%lf\n", &gamma); + else + fscanf(sig, "%*lf\n"); + + fscanf(sig, "%d\n", &seed); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + fscanf(sig, "\n"); + srandom(seed); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + if (rows == cols) + init_dct_NxN(cols, rows); + else + init_dct_NxM(cols, rows); + + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // calculate mean value + mean = 0.0; + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + mean += image[row][col]; + + mean /= cols * rows; + + // calculate derivation + derivation = 0.0; + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + derivation += sqr(image[row][col] - mean); + + derivation = sqrt(derivation / (cols * rows - 1)); + mult_factor = normalization / (sqrt(cols * rows) * derivation); + + if (verbose > 5) + fprintf(stderr, "%s: mean %f, derivation %f, mult_factor %f\n", progname, mean, derivation, mult_factor); + + // normalize image + coeffs = alloc_coeffs(cols, rows); + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + coeffs[row][col] = (image[row][col] - mean) * mult_factor; + + if (cols == rows) + fdct_inplace_NxN(coeffs); +// else +// fdct_NxM(image, dcts); + + embed_low_freq(coeffs, cols, rows, alpha, verbose); + embed_med_freq(coeffs, cols, rows, gamma, seed, verbose); + + if (cols == rows) + idct_inplace_NxN(coeffs); +// else +// idct_NxM(dcts, image); + + for (row = 0; row < rows; row++) + for (col = 0; col < cols; col++) + image[row][col] = PIXELRANGE(coeffs[row][col] / mult_factor + mean + 0.5); + + free_coeffs(coeffs); + + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_kim_a.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_kim_a.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,292 @@ +#include "wm.h" +#include "wm_dwt.h" +#include "pgm.h" +#include "dwt_util.h" +#include "kim_common.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-A n] [-e n] [-f n] [-F n] [-h] [-l n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength for detail subbands\n"); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength for approximation subband\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int mark_subband(Image_tree s, int name, double alpha, double watermark[], double threshold, int w, int n, int verbose) { + int i, j; + double last = 0.0; + + for (i = 5; i < s->image->height-5; i++) + for (j = 5; j < s->image->width-5; j++) { + double coeff, newcoeff; + + coeff = get_pixel(s->image, i, j); + if (fabs(coeff) > threshold / 1.5 ) { + newcoeff = coeff - coeff * alpha * watermark[w++ % n]; + set_pixel(s->image, i, j, newcoeff); + + fprintf(stderr, "%s: (%d/%d) %f: %f -> %f; a=%f\n", progname, j, i, watermark[w % n], coeff, newcoeff, alpha); + w++; + } + } + + if (verbose > 5) + fprintf(stderr, "%s: watermarking %s%d, size %d x %d; embedded %d coeffs. total\n", + progname, subband_name(name), s->level, s->image->width, s->image->height, w); + + return w; +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int i, c, w; + int row, col; + + int n; + + double alpha_detail = 0.0; + double alpha_approx = 0.0; + int level; + + int filter = 0; + int method = -1; + int levels; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree p, dwts; + + gray maxval; + int rows, cols, colors, format; + + double *watermark; + + progname = argv[0]; + + pgm_init(&argc, argv); + +#ifdef __EMX__ + _fsetmode(in, "b"); + _fsetmode(out, "b"); +#endif + + while ((c = getopt(argc, argv, "a:A:e:f:F:h?o:l:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha_detail = atof(optarg); + if (alpha_detail <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha_detail); + exit(1); + } + break; + case 'A': + alpha_approx = atof(optarg); + if (alpha_approx <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha_approx); + exit(1); + } + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KISG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha_detail == 0.0) + fscanf(sig, "%lf\n", &alpha_detail); + else + fscanf(sig, "%*lf\n"); + if (alpha_approx == 0.0) + fscanf(sig, "%lf\n", &alpha_approx); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + // wavelet transform + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + p = dwts; + w = 0; + + // process each decomposition level + while (p->coarse) { + int current_level; + double threshold; + double max_coeff; + double alpha; + + // get current decomposition level number + current_level = p->horizontal->level; + + // find largest absolute coefficient in detail subbands of current decomposition level + max_coeff = find_level_largest_coeff(p, verbose); + + // calculate significance threshold for current decomposition level + threshold = calc_level_threshold(max_coeff, verbose); + + // calculate embedding strength alpha for current decomposition level + alpha = calc_level_alpha_detail(alpha_detail, level, current_level, verbose); + + if (verbose > 1) + fprintf(stderr, "%s: level %d, threshold %f, alpha %f\n", progname, current_level, threshold, alpha); + + // embed watermark sequence into detail subbands of current decomposition level + w = mark_subband(p->horizontal, HORIZONTAL, alpha, watermark, threshold, w, n, verbose); + w = mark_subband(p->vertical, VERTICAL, alpha, watermark, threshold, w, n, verbose); + w = mark_subband(p->diagonal, DIAGONAL, alpha, watermark, threshold, w, n, verbose); + + p = p->coarse; + } + + // mark approximation image using calculated significance threshold and embedding strength + w = mark_subband(p, COARSE, alpha_approx, watermark, calc_level_threshold(find_subband_largest_coeff(p, COARSE, verbose), verbose), w, n, verbose); + + free(watermark); + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_kim_d.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_kim_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,326 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" +#include "dwt_util.h" +#include "kim_common.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-A n] [-e n] [-f n] [-F file] [-h] [-l n] [-o file] [-v n] -s file -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor for detail subband\n"); + fprintf(stderr, "\t-A n\t\talpha factor for approximation image\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\tfile for extracted watermark\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int extract_subband(Image_tree s, Image_tree t, int name, double alpha, double watermark[], double threshold, int w, int n, int verbose) { + int i, j; + + for (i = 5; i < s->image->height-5; i++) + for (j = 5; j < s->image->width-5; j++) { + double orig_coeff, input_coeff; + + orig_coeff = get_pixel(s->image, i, j); + input_coeff = get_pixel(t->image, i, j); + if (fabs(orig_coeff) > threshold) { + watermark[w++] = (input_coeff - orig_coeff) / (alpha * orig_coeff); + } + } + + if (verbose > 5) + fprintf(stderr, "%s: extracted %s%d, size %d x %d; %d coeffs. total\n", + progname, subband_name(name), s->level, s->image->width, s->image->height, w); + + return w; +} + +void write_mark(FILE *out, double watermark[], int n) { + int i; + + fprintf(out, "%d\n", n); + for (i = 0; i < n; i++) + fprintf(out, "%f\n", watermark[i]); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c, w; + int i; + int n = 0; + int method = -1; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + int level = 0, levels; + double alpha_detail = 0.0; + double alpha_approx = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + double *watermark; + + Image_tree input_dwts, orig_dwts, p, q; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:A:e:f:F:h?i:l:o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha_detail = atof(optarg); + if (alpha_detail <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha_detail); + exit(1); + } + break; + case 'A': + alpha_approx = atof(optarg); + if (alpha_approx <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha_approx); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KISG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha_detail == 0.0) + fscanf(sig, "%lf\n", &alpha_detail); + else + fscanf(sig, "%*lf\n"); + if (alpha_approx == 0.0) + fscanf(sig, "%lf\n", &alpha_approx); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) { + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + } + + fclose(in); + fclose(orig); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + watermark = malloc((rows * cols) * sizeof(double)); + if (!watermark) { + fprintf(stderr, "%s: malloc() failed\n\n", progname); + exit(1); + } + + p = input_dwts; + q = orig_dwts; + w = 0; + while (p->coarse && q->coarse) { + int current_level; + double threshold; + double max_coeff; + double alpha; + + // get current decomposition level number + current_level = q->horizontal->level; + + // find largest absolute coefficient in detail subbands of current decomposition level + max_coeff = find_level_largest_coeff(q, verbose); + + // calculate significance threshold for current decomposition level + threshold = calc_level_threshold(max_coeff, verbose); + + // calculate embedding strength alpha for current decomposition level + alpha = calc_level_alpha_detail(alpha_detail, level, current_level, verbose); + + if (verbose > 1) + fprintf(stderr, "%s: level %d, threshold %f, alpha %f\n", progname, current_level, threshold, alpha); + + w = extract_subband(q->horizontal, p->horizontal, HORIZONTAL, alpha, watermark, threshold, w, n, verbose); + w = extract_subband(q->vertical, p->vertical, VERTICAL, alpha, watermark, threshold, w, n, verbose); + w = extract_subband(q->diagonal, p->diagonal, DIAGONAL, alpha, watermark, threshold, w, n, verbose); + + p = p->coarse; + q = q->coarse; + } + + // extract watermark from approximation image using calculated significance threshold and embedding strength + w = extract_subband(q, p, COARSE, alpha_approx, watermark, calc_level_threshold(find_subband_largest_coeff(q, COARSE, verbose), verbose), w, n, verbose); + + fprintf(out, "KIWM\n"); + write_mark(out, watermark, w); + + fclose(out); + + free(watermark); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_kim_e.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_kim_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,288 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" +#include "dwt_util.h" +#include "kim_common.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-A n] [-e n] [-f n] [-F n] [-h] [-l n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength for detail subbands\n"); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength for approximation subband\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int mark_subband(Image_tree s, int name, double alpha, double watermark[], double threshold, int w, int n, int verbose) { + int i, j; + + for (i = 5; i < s->image->height-5; i++) + for (j = 5; j < s->image->width-5; j++) { + double coeff, newcoeff; + + coeff = get_pixel(s->image, i, j); + if (fabs(coeff) > threshold) { + newcoeff = coeff + alpha * coeff * watermark[w % n]; + set_pixel(s->image, i, j, newcoeff); + + if (verbose >= 9) + fprintf(stderr, "%s: (%d/%d) %f: %f -> %f\n", progname, j, i, watermark[w % n], coeff, newcoeff); + + w++; + } + } + + if (verbose > 5) + fprintf(stderr, "%s: watermarking %s%d, size %d x %d; embedded %d coeffs. total\n", + progname, subband_name(name), s->level, s->image->width, s->image->height, w); + + return w; +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int i, c, w; + int row, col; + + int n; + + double alpha_detail = 0.0; + double alpha_approx = 0.0; + int level = 0; + + int filter = 0; + int method = -1; + int levels; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree p, dwts; + + gray maxval; + int rows, cols, colors, format; + + double *watermark; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:A:e:f:F:h?o:l:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha_detail = atof(optarg); + if (alpha_detail <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha_detail); + exit(1); + } + break; + case 'A': + alpha_approx = atof(optarg); + if (alpha_approx <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha_approx); + exit(1); + } + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KISG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha_detail == 0.0) + fscanf(sig, "%lf\n", &alpha_detail); + else + fscanf(sig, "%*lf\n"); + if (alpha_approx == 0.0) + fscanf(sig, "%lf\n", &alpha_approx); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + // wavelet transform + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + p = dwts; + w = 0; + + // process each decomposition level + while (p->coarse) { + int current_level; + double threshold; + double max_coeff; + double alpha; + + // get current decomposition level number + current_level = p->horizontal->level; + + // find largest absolute coefficient in detail subbands of current decomposition level + max_coeff = find_level_largest_coeff(p, verbose); + + // calculate significance threshold for current decomposition level + threshold = calc_level_threshold(max_coeff, verbose); + + // calculate embedding strength alpha for current decomposition level + alpha = calc_level_alpha_detail(alpha_detail, level, current_level, verbose); + + if (verbose > 1) + fprintf(stderr, "%s: level %d, threshold %f, alpha %f\n", progname, current_level, threshold, alpha); + + // embed watermark sequence into detail subbands of current decomposition level + w = mark_subband(p->horizontal, HORIZONTAL, alpha, watermark, threshold, w, n, verbose); + w = mark_subband(p->vertical, VERTICAL, alpha, watermark, threshold, w, n, verbose); + w = mark_subband(p->diagonal, DIAGONAL, alpha, watermark, threshold, w, n, verbose); + + p = p->coarse; + } + + // mark approximation image using calculated significance threshold and embedding strength + w = mark_subband(p, COARSE, alpha_approx, watermark, calc_level_threshold(find_subband_largest_coeff(p, COARSE, verbose), verbose), w, n, verbose); + + free(watermark); + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_koch_d.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_koch_d.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,114 @@ +.\" +.\" wm_koch_d.1 - the *roff document processor man page source +.\" +.TH wm_koch_d 1 "98/07/05" "Watermarking, Version 1.0" +.SH NAME +.B wm_koch_d +\- a program to extract signature bits that have been embedded into +the DCT coefficients of an image +.SH SYNOPSIS +.B wm_koch_d +[ +.B \-h +] +[ +.BI \-o \ ofile +] +[ +.BI \-q \ number +] +[ +.BI \-v \ number +] +.BI \-s \ sfile +.IR file +.SH DESCRIPTION +.B wm_koch_d +is a program to extract signature bits from the 8x8 DCT coefficients of +an image, embedded with the +.B wm_koch_e +watermarking program. +.B cmp_koch_sig +program compares and tests the extracted signature against the original signature. +.PP +The input image is in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. The signature +.I sfile +is a mandatory parameter however. +.PP +Please refer to E. Koch's paper "Towards Robust and Hidden +Image Copyright", 1995, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-o \ ofile +Output the extracted signature to +.I ofile +instead of standard output. +.TP +.BI \-q \ number +Quality/robustness factor used to extract the signature. +Overrides setting from signature file. +.TP +.BI \-s \ sfile +The original signature file. See +.B gen_koch_sig +(1) for a description of the file format. Mandatory parameter. +.BI \-v \ number +Verbosity level. 0 for quiet operation, higher numbers for more +output. Default value: 0. +.TP +.IR file +Signed (watermarked) input image in PGM format. Default: standard input. +.PP +.SH OUTPUT +The extracted signature is written to standard output +or, optionally, to +.I ofile. +.PP +The extraction algorithm examines the relationship between two random +coefficients of randomly selected 8x8 DCT blocks to reconstruct the +signature bits. +.PP +The output file has the following format: +.TP +.B KCSG +Magic to identify file type. +.TP +.I number +The length of the signature in bits. +.TP +.I number +The quality/robustness factor. +.TP +.I number +The seed value for the pseudo-random number generator. +.TP +.I string +The actual signature bytes. +.PP +.SH AUTHOR +Peter Meerwald. +Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_koch_d +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_koch_sig +(1), +.BR wm_koch_e +(1), +.BR cmp_koch_sig +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_koch_d.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_koch_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,238 @@ +#include "wm.h" +#include "dct.h" +#include "signature.h" +#include "coord.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-l n] [-o file] [-q n] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tsignature robustness factor\n"); + fprintf(stderr, "\t-o file\t\textracted signature file\n"); + fprintf(stderr, "\t-q n\t\tquantization (JPEG quality) factor\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + gray **image; + struct coords *coords; + + char signature_name[MAXPATHLEN]; + char input_name[MAXPATHLEN] = "(stdin)"; + char output_name[MAXPATHLEN] = "(stdout)"; + + int i; + int j; + int c; + int n; + int x; + int y; + + int rows, cols, format; + gray maxval; + int row, col; + + int seed; + int verbose = 0; + + double quality = 0.0; + int quantization = 0; + + double **dcts; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "h?i:l:o:q:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'l': + quality = atof(optarg); + if (quality <= 0.0) { + fprintf(stderr, "%s: signature strength factor %f out of range\n", progname, quality); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'q': + quantization = atoi(optarg); + if (quantization <= 0 || quantization > 100) { + fprintf(stderr, "%s: quantization factor %d out of range\n", progname, quantization); + exit(1); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KCSG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature); + n_signature = NBITSTOBYTES(nbit_signature); + if (quality == 0.0) + fscanf(sig, "%lf\n", &quality); + else + fscanf(sig, "%*lf\n"); + if (quantization == 0) + fscanf(sig, "%d\n", &quantization); + else + fscanf(sig, "%*d\n"); + fscanf(sig, "%d\n", &seed); + srandom(seed); + fread(signature, sizeof(char), n_signature, sig); + init_signature_bits(); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + if (cols % NJPEG) { + fprintf(stderr, "%s: image width %d not a multiple of %d\n", progname, cols, NJPEG); + exit(1); + } + + if (rows % NJPEG) { + fprintf(stderr, "%s: image height %d not a multiple of %d\n", progname, rows, NJPEG); + exit(1); + } + + if ((rows * cols) / (NJPEG * NJPEG) < nbit_signature) { + fprintf(stderr, "%s: image too small to extract %d bits of signature\n", progname, nbit_signature); + exit(1); + } + + init_dct_8x8(); + init_quantum_JPEG_lumin(quantization); + + dcts = alloc_coeffs_8x8(); + + if ((coords = alloc_coords(nbit_signature)) == NULL) { + fprintf(stderr, "%s: unable to allocate memory\n", progname); + exit(1); + } + + image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + n = 0; + while (n < nbit_signature) { + int xb; + int yb; + int c1, c2; + double v1, v2; + double q = 1.0; + + do { + xb = random() % (cols / NJPEG); + yb = random() % (rows / NJPEG); + } while (add_coord(coords, xb, yb) < 0); + + fdct_block_8x8(image, xb * NJPEG, yb * NJPEG, dcts); + + do { + c1 = (random() % (NJPEG * NJPEG - 2)) + 1; + c2 = (random() % (NJPEG * NJPEG - 2)) + 1; + } while (c1 == c2 || !is_middle_frequency_coeff_8x8(c1) || !is_middle_frequency_coeff_8x8(c2)); + + quantize_8x8(dcts); + + if (verbose >= 1) + fprintf(stderr, "%d: quantized DCT block (x %d/y %d), extracting (x %d/y %d), (x %d/y %d) ", n, xb * NJPEG, yb * NJPEG, c1 % NJPEG, c1 / NJPEG, c2 % NJPEG, c2 / NJPEG); + + v1 = dcts[c1 / NJPEG][c1 % NJPEG]; + v2 = dcts[c2 / NJPEG][c2 % NJPEG]; + + if (fabs(v1) > fabs(v2)) { + set_signature_bit(n, 1); + if (verbose >= 1) + fprintf(stderr, "HIGH\n"); + } + else { + set_signature_bit(n, 0); + if (verbose >= 1) + fprintf(stderr, "LOW\n"); + } + + if (verbose >= 2) + print_coeffs_8x8(dcts); + + n++; + } + + fprintf(out, "KCWM\n"); + fprintf(out, "%d\n", nbit_signature); + fwrite(signature, sizeof(char), n_signature, out); + fprintf(out, "\n"); + + fclose(out); + + free_coeffs(dcts); + + pbm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_koch_e.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_koch_e.1 Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,98 @@ +.\" +.\" wm_koch_e.1 - the *roff document processor man page source +.\" +.TH wm_koch_e 1 "98/07/05" "Watermarking, Version 1.0" +.SH NAME +.B wm_koch_e +\- a program to embed signature bits in the DCT coefficients of an image +.SH SYNOPSIS +.B wm_koch_e +[ +.B \-h +] +[ +.BI \-o \ ofile +] +[ +.BI \-q \ number +] +[ +.BI \-v \ number +] +.BI \-s \ sfile +.IR file +.SH DESCRIPTION +.B wm_koch_e +is a program to embed signature bits in 8x8 DCT coefficients of +an image. The signature has to be generated by the +.B gen_koch_sig +program. The +.B wm_koch_d +program is used to extract a signature from a signed (watermarked) image. The +.B cmp_koch_sig +program compares and tests the extracted signature against the original signature. +.PP +Both, input and output image, +are in PGM (portable graymap) format. +.PP +If +.I file +or +.I ofile +is not specified, then standard input or standard output is +used. The signature +.I sfile +is a mandatory parameter however. +.PP +Please refer to E. Koch's paper "Towards Robust and Hidden +Image Copyright", 1995, to get an idea about the algorithm. +.PP +.SH OPTIONS +.TP +.B \-h +Print a help message. +.TP +.BI \-o \ ofile +Output signed (watermarked) image to +.I ofile +instead of standard output. +.TP +.BI \-q \ number +Quality/robustness factor used to embed signature into image. +Overrides setting from signature file. +.TP +.BI \-s \ sfile +The signature file to embed into image. See +.B gen_koch_sig +(1) for a description of the file format. Mandatory parameter. +.TP +.BI \-v \ number +Verbosity level. 0 for quiet operation, higher numbers for more +output. Default value: 0. +.TP +.IR file +Input image in PGM format to sign (watermark). Default: standard input. +.PP +.SH OUTPUT +The signed (watermarked) image in PGM format is written to standard output +or, optionally, to +.I ofile. +.PP +Two coefficients of an 8x8 DCT block are selected at random to embed a +single signature bit. +.PP +.SH AUTHOR +Peter Meerwald. Email bug reports to pmeerw@cosy.sbg.ac.at. +.SH AVAILABILITY +The most recent released version of +.B wm_koch_e +is always available +at http://www.cosy.sbg.ac.at/~pmeerw/Watermarking or via anonymous ftp from ftp.cosy.sbg.ac.at in the +directory /pub/people/pmeerw/Watermarking. +.SH "SEE ALSO" +.BR gen_koch_sig +(1), +.BR wm_koch_d +(1), +.BR cmp_koch_sig +(1) diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_koch_e.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_koch_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,274 @@ +#include "wm.h" +#include "dct.h" +#include "signature.h" +#include "coord.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-h] [-l n] [-o file] [-q n] [-v n] -s file file\n", progname); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tsignature robustness factor\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-q n\t\tquantization (JPEG quality) factor\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char signature_name[MAXPATHLEN]; + char input_name[MAXPATHLEN] = "(stdin)"; + char output_name[MAXPATHLEN] = "(stdout)"; + + int i; + int j; + int c; + int n; + int x; + int y; + + int seed; + int verbose = 0; + + int rows, cols, format; + gray maxval; + int row, col; + + int quantization = 0; + double quality = 0.0; + + struct coords *coords; + + gray **image; + double **dcts; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "h?i:l:o:q:s:v:")) != EOF) { + switch (c) { + case 'h': + case '?': + usage(); + break; + case 'l': + quality = atof(optarg); + if (quality <= 0.0) { + fprintf(stderr, "%s: signature strength factor %f out of range\n", progname, quality); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'q': + quantization = atoi(optarg); + if (quantization <= 0 || quantization > 100) { + fprintf(stderr, "%s: quantization factor %d out of range\n", progname, quantization); + exit(1); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[128]; + fgets(line, sizeof(line), sig); + if (strspn(line, "KCSG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature); + if (quality == 0.0) + fscanf(sig, "%lf\n", &quality); + else + fscanf(sig, "%*lf\n"); + if (quantization == 0) + fscanf(sig, "%d\n", &quantization); + else + fscanf(sig, "%*d\n"); + fscanf(sig, "%d\n", &seed); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + fscanf(sig, "\n"); + srandom(seed); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + if (cols % NJPEG) { + fprintf(stderr, "%s: image width %d not a multiple of %d\n", progname, cols, NJPEG); + exit(1); + } + + if (rows % NJPEG) { + fprintf(stderr, "%s: image height %d not a multiple of %d\n", progname, rows, NJPEG); + exit(1); + } + + if ((cols * rows) / (NJPEG * NJPEG) < nbit_signature) { + fprintf(stderr, "%s: image not large enough to embed %d bits of signature\n", progname, nbit_signature); + exit(1); + } + + init_dct_8x8(); + init_quantum_JPEG_lumin(quantization); + + dcts = alloc_coeffs_8x8(); + + if ((coords = alloc_coords(nbit_signature)) == NULL) { + fprintf(stderr, "%s: unable to allocate memory\n", progname); + exit(1); + } + + image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + // embedding signature bits by modifying two coefficient relationship, + // one bit for each block + n = 0; + while (n < nbit_signature) { + int xb; + int yb; + int c1, c2; + double v1, v2; + double w1, w2; + double diff, abs_diff; + + // randomly select a block, check to get distinct blocks + // (don't watermark a block twice) + do { + xb = random() % (cols / NJPEG); + yb = random() % (rows / NJPEG); + } while (add_coord(coords, xb, yb) < 0); + + // do the forward 8x8 DCT of that block + fdct_block_8x8(image, xb * NJPEG, yb * NJPEG, dcts); + + // randomly select two distinct coefficients from block + // only accept coefficients in the middle frequency range + do { + c1 = (random() % (NJPEG * NJPEG - 2)) + 1; + c2 = (random() % (NJPEG * NJPEG - 2)) + 1; + } while (c1 == c2 || !is_middle_frequency_coeff_8x8(c1) || !is_middle_frequency_coeff_8x8(c2)); + + // quantize block according to quantization quality parameter + quantize_8x8(dcts); + + if (verbose > 0) + fprintf(stderr, "%d: quantized DCT block (x %d/y %d), modifying (x %d/y %d), (x %d/y %d) for %s\n", n, xb * NJPEG, yb * NJPEG, c1 % NJPEG, c1 / NJPEG, c2 % NJPEG, c2 / NJPEG, get_signature_bit(n) ? "HIGH" : "LOW"); + if (verbose > 5) + print_coeffs_8x8(dcts); + + v1 = dcts[c1 / NJPEG][c1 % NJPEG]; + v2 = dcts[c2 / NJPEG][c2 % NJPEG]; + + diff = fabs(v1) - fabs(v2); + abs_diff = (fabs(diff) + quality) / 2.0; + + // modify coefficient's relationship to embed signature bit + // using mean square error to minimize error + if (get_signature_bit(n)) { + if (diff < quality) { + // we have to impose the relationship, does not occur naturally + w1 = (v1 > 0.0) ? (v1 + abs_diff) : (v1 - abs_diff); + w2 = (v2 > 0.0) ? (v2 - abs_diff) : (v2 + abs_diff); + } + else { + w1 = v1; + w2 = v2; + } + } + else { + if (diff > -quality) { + // force the relationship + w1 = (v1 > 0.0) ? (v1 - abs_diff) : (v1 + abs_diff); + w2 = (v2 > 0.0) ? (v2 + abs_diff) : (v2 - abs_diff); + } + else { + w1 = v1; + w2 = v2; + } + } + + if (verbose > 1) + fprintf(stderr, " %f -> %f, %f -> %f\n", v1, w1, v2, w2); + + // put the changed coefficients back to black + dcts[c1 / NJPEG][c1 % NJPEG] = w1; + dcts[c2 / NJPEG][c2 % NJPEG] = w2; + + // the obvious :-) + dequantize_8x8(dcts); + + // do the inverse DCT on the modified 8x8 block + idct_block_8x8(dcts, image, xb * NJPEG, yb * NJPEG); + + n++; + } + + free_coeffs(dcts); + + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_wang_d.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_wang_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,302 @@ +#include "wm.h" +#include "dwt.h" +#include "wang_common.h" +#include "dwt_util.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-b n] [-e n] [-f n] [-F file] [-h] [-n n] [-o file] [-v n] -s file -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor\n"); + fprintf(stderr, "\t-b n\t\tbeta factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-n n\t\twatermark length\n"); + fprintf(stderr, "\t-o file\t\tfile for extracted watermark\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c, w; + int i; + int n = 0; + int method = -1; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + int level, levels; + double alpha = 0.0; + double beta = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + double *watermark; + + Image_tree input_dwts; + Image_tree orig_dwts; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:b:e:f:F:h?i:n:o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'b': + beta = atof(optarg); + if (beta <= 0.0) { + fprintf(stderr, "%s: beta factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'n': + n = atoi(optarg); + if (n < 1 || n > 32000) { + fprintf(stderr, "%s: watermark length %d out of range\n", progname, n); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "WGSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (beta == 0.0) + fscanf(sig, "%lf\n", &beta); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) { + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + } + + fclose(in); + fclose(orig); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + + init_dwt(cols, rows, filter_name, filter, levels, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + // build tree for subband selection, calculate subband thresholds + init_subbands(orig_dwts); + set_subbands_type_beta(HORIZONTAL, beta); + set_subbands_type_beta(VERTICAL, beta); + calc_subbands_threshold(); + + fprintf(out, "WGWM\n"); + fprintf(out, "%d\n", n); + + w = 0; + while (w < n) { + Subband_data s; + + // select subband with max. threshold + s = select_subband(); + if (verbose > 1) + fprintf(stderr, "%s: selected subband %s%d, T=%lf, beta=%lf\n", progname, subband_name(s->type), s->level, s->T, s->beta); + + // watermark significant coefficients and set them selected + // check is entire signature has been embedded + c = select_subband_coeff(s); + do { + Pixel p; + Pixel q; + if (c < 0) + // no more significant coefficients in subband + break; + + p = get_subband_coeff(s, c); + if (p < s->Cmax) { + q = get_dwt_coeff(input_dwts, s->level, s->type, c); + watermark[w] = (q - p) / (alpha * s->beta * s->T); + fprintf(out, "%lf\n", watermark[w]); + + if (verbose > 2) + fprintf(stderr, "%s: detected sig. coeff. #%d (= %lf)\n from %s%d coeff. #%d\n", + progname, w, watermark[w], subband_name(s->type), s->level, c); + + w++; + } + mark_subband_coeff(s, c); + + // select next significant coefficient + c = select_subband_coeff_from(s, c); + } while (w < n); + + // update subband threshold + s->T /= 2.0; + + } + + fclose(out); + + free_subbands(); + + free(watermark); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_wang_e.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_wang_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,262 @@ +#include "wm.h" +#include "dwt.h" +#include "wang_common.h" +#include "dwt_util.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-b n] [-e n] [-f n] [-F n] [-h] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength\n"); + fprintf(stderr, "\t-b n\t\tsubband weighting factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int i, c, w; + int row, col; + + int n; + + double alpha = 0.0; + double beta = 0.0; + + int filter = 0; + int method = -1; + int levels; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree dwts; + + gray maxval; + int rows, cols, colors, format; + + double *watermark; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:b:e:f:F:h?o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'b': + beta = atof(optarg); + if (beta <= 0.0) { + fprintf(stderr, "%s: beta factor %f out of range\n", progname, beta); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "WGSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (beta == 0.0) + fscanf(sig, "%lf\n", &beta); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + + // wavelet transform + init_dwt(cols, rows, filter_name, filter, levels, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + // build tree for subband selection, calculate subband thresholds + init_subbands(dwts); + set_subbands_type_beta(HORIZONTAL, beta); + set_subbands_type_beta(VERTICAL, beta); + calc_subbands_threshold(); + + w = 0; + while (w < n) { + Subband_data s; + + // select subband with max. threshold + s = select_subband(); + if (verbose > 1) + fprintf(stderr, "%s: selected subband %s%d, T=%lf, beta=%lf\n", progname, subband_name(s->type), s->level, s->T, s->beta); + + // watermark significant coefficients and set them selected + // check is entire signature has been embedded + c = select_subband_coeff(s); + do { + double p; + if (c < 0) + // no more significant coefficients in subband + break; + + p = get_subband_coeff(s, c); + if (p < s->Cmax) { + if (verbose > 2) + fprintf(stderr, "%s: embedding sig. coeff. #%d (= %lf)\n into %s%d coeff. #%d\n", + progname, w, watermark[w], subband_name(s->type), s->level, c); + + p = p + alpha * s->beta * s->T * watermark[w]; + set_subband_coeff(s, c, p); + w++; + } + mark_subband_coeff(s, c); + + // select next significant coefficient + c = select_subband_coeff_from(s, c); + } while (w < n); + + // update subband threshold + s->T /= 2.0; + + } + + free_subbands(); + + free(watermark); + + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_xia_d.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_xia_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,295 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" +#include "dwt_util.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F file] [-h] [-l n] [-o file] [-v n] -s file -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\tfile for extracted watermark\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int extract_subband(Image_tree s, Image_tree t, int name, double alpha, double watermark[], int n, int verbose) { + int i, j; + int w; + + w = 0; + for (i = 5; i < s->image->height-5; i++) + for (j = 5; j < s->image->width-5; j++) { + double input_coeff, orig_coeff; + + input_coeff = get_pixel(s->image, i, j); + orig_coeff = get_pixel(t->image, i, j); + if (fabs(orig_coeff) > 20.0) + watermark[w++] = (input_coeff - orig_coeff) / (alpha * pow(fabs(orig_coeff), 1.0 / 1.2)); + } + + if (verbose > 3) + fprintf(stderr, "%s: extracting %s%d, size %d x %d; extracted %d coeffs.\n", + progname, subband_name(name), s->level, s->image->width, s->image->height, w); + + return w; +} + +void write_mark(FILE *out, double watermark[], int n) { + int i; + + fprintf(out, "%d\n", n); + for (i = 0; i < n; i++) + fprintf(out, "%f\n", watermark[i]); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c, w; + int i; + int n = 0; + int method = -1; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + int level = 0, levels; + double alpha = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + double *watermark; + + Image_tree input_dwts, orig_dwts, p, q; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?i:l:o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "XASG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) { + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + } + + fclose(in); + fclose(orig); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + watermark = malloc((rows * cols / 4.0) * sizeof(double)); + if (!watermark) { + fprintf(stderr, "%s: malloc() failed\n\n", progname); + exit(1); + } + + fprintf(out, "XAWM\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%d\n", level * 3); + + p = input_dwts; + q = orig_dwts; + while (p->coarse && q->coarse) { + int size; + + size = extract_subband(p->horizontal, q->horizontal, HORIZONTAL, alpha, watermark, n, verbose); + write_mark(out, watermark, size); + size = extract_subband(p->vertical, q->vertical, VERTICAL, alpha, watermark, n, verbose); + write_mark(out, watermark, size); + size = extract_subband(p->diagonal, q->diagonal, DIAGONAL, alpha, watermark, n, verbose); + write_mark(out, watermark, size); + + p = p->coarse; + q = q->coarse; + } + + fclose(out); + + free(watermark); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_xia_e.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_xia_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,243 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" +#include "dwt_util.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F n] [-h] [-l n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +void mark_subband(Image_tree s, int name, double alpha, double watermark[], int n, int verbose) { + int i, j; + int w; + + w = 0; + for (i = 5; i < s->image->height-5; i++) + for (j = 5; j < s->image->width-5; j++) { + double coeff, newcoeff; + + coeff = get_pixel(s->image, i, j); + if (fabs(coeff) > 20.0) { + newcoeff = coeff + alpha * pow(fabs(coeff), 1.2) * watermark[w++ % n]; + set_pixel(s->image, i, j, newcoeff); + } + } + + if (verbose > 3) + fprintf(stderr, "%s: watermarking %s%d, size %d x %d; embedded %d coeffs.\n", + progname, subband_name(name), s->level, s->image->width, s->image->height, w); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int i, c, w; + int row, col; + + int n; + + double alpha = 0.0; + int level = 0; + + int filter = 0; + int method = -1; + int levels; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree p, dwts; + + gray maxval; + int rows, cols, colors, format; + + double *watermark; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?o:l:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "XASG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + // wavelet transform + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + p = dwts; + while (p->coarse) { + + mark_subband(p->horizontal, HORIZONTAL, alpha, watermark, n, verbose); + mark_subband(p->vertical, VERTICAL, alpha, watermark, n, verbose); + mark_subband(p->diagonal, DIAGONAL, alpha, watermark, n, verbose); + + p = p->coarse; + } + + free(watermark); + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_xie_d.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_xie_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,257 @@ +#include "wm.h" +#include "signature.h" +#include "dwt.h" +#include "pgm.h" + +char *progname; + +// inverse watermarking transformation, extract embedded bit, check quantization boundaries +double wm_transform(double alpha, double f1, double f2, double f3) { + double s = alpha * (fabs(f3) - fabs(f1)) / 2.0; + double l = f1; + int x; + + x = 0; + while (l < f2) { + l += s; + x++; + } + + if (fabs(l - s - f2) < fabs(l-f2)) + return (x+1) % 2; + else + return (x) % 2; +} + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F n] [-h] [-l n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\tembedding strength (default 0.05)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-l n\t\tembedding level\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\textracted signature file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c, n; + int row, col; + + double alpha = 0.0; + int filter = 0; + int method = -1; + int level = 0; + char filter_name[MAXPATHLEN] = ""; + + int seed; + int verbose = 0; + + gray **image; + Image_tree dwts, p; + + gray maxval; + int rows, cols, colors, format; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?l:o:s:v:")) != EOF) { + switch (c) { + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'l': + level = atoi(optarg); + if (level < 1) { + fprintf(stderr, "%s: embedding level out of range\n", progname); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: embedding strength factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "XESG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + if (verbose > 0) + fprintf(stderr, "%s: embedding %d bits with strength %f in\n" + " %d x %d host image, decomposition level %d\n", + progname, nbit_signature, alpha, cols, rows, level); + + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // decomposition of image + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + p = dwts; + + // consider each resolution level + while (p->level < level) + // descend one level + p = p->coarse; + + // repeat binary watermark by sliding a 3-pixel window of approximation image + n = 0; + for (row = 0; row < p->image->height; row++) { + for (col = 0; col < p->image->width - 3; col += 3) { + double b1, b2, b3; + double *f1 = &b1, *f2 = &b2, *f3 = &b3; + + // get all three approximation pixels in window + b1 = get_pixel(p->image, col + 0, row); + b2 = get_pixel(p->image, col + 1, row); + b3 = get_pixel(p->image, col + 2, row); + + // bring selected pixels in ascending order +#define SWAP(A, B) {double *t = A; A = B; B = t;} + if (*f1 > *f2) SWAP(f1, f2); + if (*f2 > *f3) SWAP(f2, f3); + if (*f1 > *f2) SWAP(f1, f2); + + set_signature_bit(n, wm_transform(alpha, *f1, *f2, *f3)); + + if (verbose > 1) + fprintf(stderr, "%s: extracting #%d (= %d) at (%d/%d); %f < %f < %f\n", + progname, n, get_signature_bit(n % nbit_signature), col, row, *f1, *f2, *f3); + + n++; + } + } + + fprintf(out, "XEWM\n"); + fprintf(out, "%d\n", n); + fwrite(signature, sizeof(char), NBITSTOBYTES(n), out); + fprintf(out, "\n"); + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_xie_e.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_xie_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,269 @@ +#include "wm.h" +#include "signature.h" +#include "dwt.h" +#include "pgm.h" + +char *progname; + +// watermarking transformation, set median pixel to quantization boundary +double wm_transform(double alpha, double f1, double f2, double f3, int x) { + double s = alpha * (fabs(f3) - fabs(f1)) / 2.0; + double l = x ? (f1 + s) : f1; + double f2new; + + while ((l + 2 * s) < f2) l += 2 * s; + f2new = ((f2 - l) < (l + 2 * s - f2)) ? l : (l + 2 * s); + + return f2new; +} + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F n] [-h] [-l n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\tembedding strength (default 0.05)\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-l n\t\tembedding level\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int c, n; + int row, col; + + double alpha = 0.0; + int filter = 0; + int method = -1; + int level = 0; + char filter_name[MAXPATHLEN] = ""; + + int seed; + int verbose = 0; + + gray **image; + Image_tree dwts, p; + + gray maxval; + int rows, cols, colors, format; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?l:o:s:v:")) != EOF) { + switch (c) { + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'l': + level = atoi(optarg); + if (level < 1) { + fprintf(stderr, "%s: embedding level out of range\n", progname); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: embedding strength factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "XESG") >= 4) { + fscanf(sig, "%d\n", &nbit_signature); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + fscanf(sig, "%d\n", &seed); + srandom(seed); + n_signature = NBITSTOBYTES(nbit_signature); + fread(signature, sizeof(char), n_signature, sig); + fscanf(sig, "\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + + if (verbose > 0) + fprintf(stderr, "%s: embedding %d bits with strength %f in\n" + " %d x %d host image, decomposition level %d\n", + progname, nbit_signature, alpha, cols, rows, level); + + image = pgm_allocarray(cols, rows); + + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + + fclose(in); + + // decomposition of image + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + p = dwts; + + // consider each resolution level + while (p->level < level) + // descend one level + p = p->coarse; + + // repeat binary watermark by sliding a 3-pixel window of approximation image + n = 0; + for (row = 0; row < p->image->height; row++) { + for (col = 0; col < p->image->width - 3; col += 3) { + double b1, b2, b3; + double *f1 = &b1, *f2 = &b2, *f3 = &b3; + double f2new; + + // get all three approximation pixels in window + b1 = get_pixel(p->image, col + 0, row); + b2 = get_pixel(p->image, col + 1, row); + b3 = get_pixel(p->image, col + 2, row); + + // bring selected pixels in ascending order +#define SWAP(A, B) {double *t = A; A = B; B = t;} + if (*f1 > *f2) SWAP(f1, f2); + if (*f2 > *f3) SWAP(f2, f3); + if (*f1 > *f2) SWAP(f1, f2); + + // apply watermarking transformation (modify median pixel) + f2new = wm_transform(alpha, *f1, *f2, *f3, get_signature_bit(n % nbit_signature)); + + if (verbose > 1) + fprintf(stderr, "%s: embedding #%d (= %d) at (%d/%d); %f < %f -> %f < %f\n", + progname, n, get_signature_bit(n % nbit_signature), col, row, *f1, *f2, f2new, *f3); + + *f2 = f2new; + + // write modified pixel + set_pixel(p->image, col + 0, row, b1); + set_pixel(p->image, col + 1, row, b2); + set_pixel(p->image, col + 2, row, b3); + + n++; + } + } + + + // skip over some pixels + + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_zhu_d.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_zhu_d.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,304 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F file] [-h] [-l n] [-o file] [-v n] -s file -i file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor\n"); + fprintf(stderr, "\t-b n\t\tbeta factor\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-i file\t\toriginal image file\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\tfile for extracted watermark\n"); + fprintf(stderr, "\t-s file\t\toriginal signature file\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +void write_mark(FILE *out, double watermark[], int n) { + int i; + + fprintf(out, "%d\n", n); + for (i = 0; i < n; i++) + fprintf(out, "%f\n", watermark[i]); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *orig = NULL; + FILE *sig = NULL; + + gray **input_image; + gray **orig_image; + + char signature_name[MAXPATHLEN]; + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char orig_name[MAXPATHLEN]; + + int c, w; + int i; + int n = 0; + int method = -1; + int filter = 0; + char filter_name[MAXPATHLEN] = ""; + + int level = 0, levels; + double alpha = 0.0; + + int in_rows, in_cols, in_format; + gray in_maxval; + int orig_rows, orig_cols, orig_format; + gray orig_maxval; + int rows, cols; + int row, col; + + double *watermark; + + Image_tree input_dwts, orig_dwts, p, q; + + int verbose = 0; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init2(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?i:l:o:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'i': + if ((orig = fopen(optarg, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open original image file %s\n", progname, optarg); + exit(1); + } + strcpy(orig_name, optarg); + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'o': + if ((out = fopen(optarg, "w")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (!orig) { + fprintf(stderr, "%s: original image file not specified, use -i file option\n", progname); + exit(1); + } + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "ZHSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + fclose(sig); + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + pgm_readpgminit(in, &in_cols, &in_rows, &in_maxval, &in_format); + pgm_readpgminit(orig, &orig_cols, &orig_rows, &orig_maxval, &orig_format); + + if (in_cols != orig_cols || in_rows != orig_rows) { + fprintf(stderr, "%s: input image %s does not match dimensions of original image %s\n", progname, input_name, orig_name); + exit(1); + } + + cols = in_cols; + rows = in_rows; + + input_image = pgm_allocarray(in_cols, in_rows); + orig_image = pgm_allocarray(orig_cols, orig_rows); + + for (row = 0; row < in_rows; row++) { + pgm_readpgmrow(in, input_image[row], in_cols, in_maxval, in_format); + pgm_readpgmrow(orig, orig_image[row], orig_cols, orig_maxval, orig_format); + } + + fclose(in); + fclose(orig); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + init_dwt(cols, rows, filter_name, filter, levels, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + input_dwts = fdwt(input_image); + orig_dwts = fdwt(orig_image); + + watermark = malloc(n * sizeof(double)); + if (!watermark) { + fprintf(stderr, "%s: malloc() failed\n\n", progname); + exit(1); + } + + fprintf(out, "ZHWM\n"); + fprintf(out, "%d\n", n); + fprintf(out, "%d\n", level); + + p = input_dwts; + q = orig_dwts; + while (p->coarse && q->coarse) { + double *collected_coeffs, *largest; + int subband_size = q->horizontal->image->size; + int maxselect = MIN(3 * subband_size, n + 1); + double threshold; + + collected_coeffs = malloc(3 * subband_size * sizeof(double)); + if (!collected_coeffs) { + fprintf(stderr, "%s: malloc() failed\n", progname); + exit(1); + } + + for (i = 0; i < subband_size; i++) { + collected_coeffs[3 * i + 0] = q->horizontal->image->data[i]; + collected_coeffs[3 * i + 1] = q->vertical->image->data[i]; + collected_coeffs[3 * i + 2] = q->diagonal->image->data[i]; + } + + largest = malloc(maxselect * sizeof(double)); + if (!largest) { + fprintf(stderr, "%s: malloc() failed\n", progname); + exit(1); + } + + select_largest_coeffs(collected_coeffs, 3 * subband_size, maxselect, largest); + threshold = largest[0]; + free(largest); + free(collected_coeffs); + + w = 0; + for (i = 0; i < subband_size && w < n; i++) { + if (q->horizontal->image->data[i] > threshold) + watermark[w++] = (p->horizontal->image->data[i] / q->horizontal->image->data[i] - 1.0) / alpha; + if (q->vertical->image->data[i] > threshold) + watermark[w++] = (p->vertical->image->data[i] / q->vertical->image->data[i] - 1.0) / alpha; + if (q->diagonal->image->data[i] > threshold) + watermark[w++] = (p->diagonal->image->data[i] / q->diagonal->image->data[i] - 1.0) / alpha; + } + + write_mark(out, watermark, w); + + p = p->coarse; + q = q->coarse; + } + + fclose(out); + + free(watermark); + + pgm_freearray(input_image, rows); + pgm_freearray(orig_image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 Meerwald/wm_zhu_e.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Meerwald/wm_zhu_e.c Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,260 @@ +#include "wm.h" +#include "dwt.h" +#include "pgm.h" +#include "sort.h" + +char *progname; + +void usage(void) { + fprintf(stderr, "usage: %s [-a n] [-e n] [-f n] [-F n] [-h] [-l n] [-o file] [-v n] -s file file\n\n", progname); + fprintf(stderr, "\t-a n\t\talpha factor/embedding strength\n"); + fprintf(stderr, "\t-e n\t\twavelet filtering method\n"); + fprintf(stderr, "\t-f n\t\tfilter number\n"); + fprintf(stderr, "\t-F file\t\tfilter definition file\n"); + fprintf(stderr, "\t-h\t\tprint usage\n"); + fprintf(stderr, "\t-l n\t\tdecomposition level\n"); + fprintf(stderr, "\t-o file\t\toutput (watermarked) file\n"); + fprintf(stderr, "\t-s file\t\tsignature to embed in input image\n"); + fprintf(stderr, "\t-v n\t\tverbosity level\n"); + exit(0); +} + +int main(int argc, char *argv[]) { + + FILE *in = stdin; + FILE *out = stdout; + FILE *sig = NULL; + + char output_name[MAXPATHLEN] = "(stdout)"; + char input_name[MAXPATHLEN] = "(stdin)"; + char signature_name[MAXPATHLEN]; + + int i, c, w; + int row, col; + + int n; + + double alpha = 0.0; + int level = 0; + + int filter = 0; + int method = -1; + int levels; + char filter_name[MAXPATHLEN] = ""; + + int verbose = 0; + + gray **image; + Image_tree p, dwts; + + gray maxval; + int rows, cols, colors, format; + + double *watermark; + + progname = argv[0]; + + pgm_init(&argc, argv); wm_init(); + + while ((c = getopt(argc, argv, "a:e:f:F:h?o:l:s:v:")) != EOF) { + switch (c) { + case 'a': + alpha = atof(optarg); + if (alpha <= 0.0) { + fprintf(stderr, "%s: alpha factor %f out of range\n", progname, alpha); + exit(1); + } + break; + case 'l': + level = atoi(optarg); + if (level <= 0) { + fprintf(stderr, "%s: decomposition level %d out of range\n", progname, level); + exit(1); + } + break; + case 'e': + method = atoi(optarg); + if (method < 0) { + fprintf(stderr, "%s: wavelet filtering method %d out of range\n", progname, method); + exit(1); + } + break; + case 'f': + filter = atoi(optarg); + if (filter <= 0) { + fprintf(stderr, "%s: filter number %d out of range\n", progname, filter); + exit(1); + } + break; + case 'F': + strcpy(filter_name, optarg); + break; + case 'h': + case '?': + usage(); + break; + case 'o': + if ((out = fopen(optarg, "wb")) == NULL) { + fprintf(stderr, "%s: unable to open output file %s\n", progname, optarg); + exit(1); + } + strcpy(output_name, optarg); + break; + case 's': + if ((sig = fopen(optarg, "r")) == NULL) { + fprintf(stderr, "%s: unable to open signature file %s\n", progname, optarg); + exit(1); + } + strcpy(signature_name, optarg); + break; + case 'v': + verbose = atoi(optarg); + if (verbose < 0) { + fprintf(stderr, "%s: verbosity level %d out of range\n", progname, verbose); + exit(1); + } + break; + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(); + exit(1); + } + + if (argc == 1 && *argv[0] != '-') + if ((in = fopen(argv[0], "rb")) == NULL) { + fprintf(stderr, "%s: unable to open input file %s\n", progname, argv[0]); + exit(1); + } + else + strcpy(input_name, argv[0]); + + if (sig) { + char line[32]; + fgets(line, sizeof(line), sig); + if (strspn(line, "ZHSG") >= 4) { + fscanf(sig, "%d\n", &n); + if (alpha == 0.0) + fscanf(sig, "%lf\n", &alpha); + else + fscanf(sig, "%*lf\n"); + if (level == 0) + fscanf(sig, "%d\n", &level); + else + fscanf(sig, "%*d\n"); + if (method < 0) + fscanf(sig, "%d\n", &method); + else + fscanf(sig, "%*d\n"); + if (filter == 0) + fscanf(sig, "%d\n", &filter); + else + fscanf(sig, "%*d\n"); + if (!strcmp(filter_name, "")) + fscanf(sig, "%[^\n\r]\n", &filter_name); + else + fscanf(sig, "%*[^\n\r]\n"); + } + else { + fprintf(stderr, "%s: invalid signature file %s\n", progname, signature_name); + exit(1); + } + } + else { + fprintf(stderr, "%s: signature file not specified, use -s file option\n", progname); + exit(1); + } + + watermark = malloc(n * sizeof(double)); + for (i = 0; i < n; i++) + fscanf(sig, "%lf\n", &watermark[i]); + fclose(sig); + + pgm_readpgminit(in, &cols, &rows, &maxval, &format); + image = pgm_allocarray(cols, rows); + for (row = 0; row < rows; row++) + pgm_readpgmrow(in, image[row], cols, maxval, format); + fclose(in); + + // complete decomposition + levels = find_deepest_level(cols, rows) - 1; + if (level > levels) { + fprintf(stderr, "%s: decomposition level %d not possible (max. %d), image size is %d x %d\n", progname, level, levels, cols, rows); + exit(1); + } + + // wavelet transform + init_dwt(cols, rows, filter_name, filter, level, method); +#ifdef POLLEN_STUFF +#include "pollen_stuff.xxx" +#endif +#ifdef PARAM_STUFF +#include "param_stuff.xxx" +#endif + + dwts = fdwt(image); + + p = dwts; + while (p->coarse) { + double *collected_coeffs, *largest; + int subband_size = p->horizontal->image->size; + int maxselect = MIN(3 * subband_size, n + 1); + double threshold; + + // allocate memory for coefficient vector + collected_coeffs = malloc(3 * subband_size * sizeof(double)); + if (!collected_coeffs) { + fprintf(stderr, "%s: malloc() failed\n", progname); + exit(1); + } + + // collect coefficients from all subbands of one level into one vector + for (i = 0; i < subband_size; i++) { + collected_coeffs[3 * i + 0] = p->horizontal->image->data[i]; + collected_coeffs[3 * i + 1] = p->vertical->image->data[i]; + collected_coeffs[3 * i + 2] = p->diagonal->image->data[i]; + } + + // allocate memory for largest coefficients + largest = malloc(maxselect * sizeof(double)); + if (!largest) { + fprintf(stderr, "%s: malloc() failed\n", progname); + exit(1); + } + + // select largest coefficients (involves sorting) + select_largest_coeffs(collected_coeffs, 3 * subband_size, maxselect, largest); + // threshold is the smallest of the largest coefficients + threshold = largest[0]; + free(largest); + free(collected_coeffs); + + w = 0; + for (i = 0; i < subband_size && w < n; i++) { + if (p->horizontal->image->data[i] > threshold) + p->horizontal->image->data[i] *= (1.0 + alpha * watermark[w++]); + if (p->vertical->image->data[i] > threshold) + p->vertical->image->data[i] *= (1.0 + alpha * watermark[w++]); + if (p->diagonal->image->data[i] > threshold) + p->diagonal->image->data[i] *= (1.0 + alpha * watermark[w++]); + } + + p = p->coarse; + } + + free(watermark); + idwt(dwts, image); + + pgm_writepgminit(out, cols, rows, maxval, 0); + for (row = 0; row < rows; row++) + pgm_writepgmrow(out, image[row], cols, maxval, 0); + fclose(out); + + pgm_freearray(image, rows); + + exit(0); +} diff -r 000000000000 -r be303a3f5ea8 README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,29 @@ +Watermarking source + +version 0.4 + * bug fixes + - wm_xia_{e|d}.c variable level uninitialized + - wm_zhu_{e|d}.c variable level uninitialized + - issue with random() vs. rand() and RAND_MAX in frid2_common.c + * added option to bruyn algorithm to disable block skipping + * added algorithm kim + +version 0.3 + * added nice manual/documentation + * added algorithms by Dugad, Wang, Zhu, Fridrich + * added Makefiles for Win32 plattform (mingw32) + +version 0.2 + * added contribution by Vassilis Fotopoulos (Piva's algorithm, + DCT, Hartley and subband domain) - see Fotopoulos/ subdirectory + * stuff moved to Meerwald/ subdirectory + * added Bruyndonckx, Corvi, Koch, Xia, Xie algorithms + +version 0.1 + * initial release + +Peter Meerwald +Dept. of Scientific Computing, University of Salzburg + +pmeerw@cosy.sbg.ac.at +http://www.cosy.sbg.ac.at/~pmeerw/Watermarking diff -r 000000000000 -r be303a3f5ea8 images/lena.pgm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/images/lena.pgm Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,4 @@ +P5 +512 512 +255 +¢¢¢¡¢£¡¦¢¢ ›£ ›œ¡¡šœš™š˜œššœšž› ž§ ¦¦¥¦¬«¯­ª¬¬§¯¨§¢¡“”™Œ‚wvjaa^\Xag`heiiiihnnlkihmmmljjlnmkmmnnlhjjlmovoqvywpzyz}zy|{‚{z„ƒ„‡€ƒƒ‡‰„†ƒƒ€‚†~~…‚ƒ€ƒ€‡…ˆ†€†‚‡……†‡„‡„ˆ†„……ˆ…††„…ƒ„…‡‰†…ƒ…ƒ‡ˆ„‡ˆ‰…Šˆ‡…‰‡ˆ„…Œ„ƒ‹†ƒ„ƒ~ƒƒ„ƒ„ƒ€‡……‡ƒ„……ƒ…‚ƒƒ…ˆ†„‡„‡†Šƒƒƒ……ŠŠŽ†„„€€…†„†…ƒ€ƒ„~‚‡†~‚ƒ†~„ƒ€ƒƒ}€‚~€„~y||ywzywuroqsifghptvz„‡‹Œ‘’—™˜™ŸŸŸ£ž¢¡››””™•š——›—›˜œššŸŸœžš™—™—š˜š™˜™˜——žšš˜˜™šžžššœ   œœ˜››ž±ÀÆÎÐÓÓÔ×ÚÚÚÚÜØÓÌÀ¬˜zkjeghoiqtuwuwvy{ywux}yv{z}€yw{vy|{xzyy{z|v|~|~~{{|}vv€z~~~‚|~~z‚|~w{rytwvsx|‰¢¨©«ª›€¢¢¢¡¢£¡¦¢¢ ›£ ›œ¡¡šœš™š˜œššœšž› ž§ ¦¦¥¦¬«¯­ª¬¬§¯¨§¢¡“”™Œ‚wvjaa^\Xag`heiiiihnnlkihmmmljjlnmkmmnnlhjjlmovoqvywpzyz}zy|{‚{z„ƒ„‡€ƒƒ‡‰„†ƒƒ€‚†~~…‚ƒ€ƒ€‡…ˆ†€†‚‡……†‡„‡„ˆ†„……ˆ…††„…ƒ„…‡‰†…ƒ…ƒ‡ˆ„‡ˆ‰…Šˆ‡…‰‡ˆ„…Œ„ƒ‹†ƒ„ƒ~ƒƒ„ƒ„ƒ€‡……‡ƒ„……ƒ…‚ƒƒ…ˆ†„‡„‡†Šƒƒƒ……ŠŠŽ†„„€€…†„†…ƒ€ƒ„~‚‡†~‚ƒ†~„ƒ€ƒƒ}€‚~€„~y||ywzywuroqsifghptvz„‡‹Œ‘’—™˜™ŸŸŸ£ž¢¡››””™•š——›—›˜œššŸŸœžš™—™—š˜š™˜™˜——žšš˜˜™šžžššœ   œœ˜››ž±ÀÆÎÐÓÓÔ×ÚÚÚÚÜØÓÌÀ¬˜zkjeghoiqtuwuwvy{ywux}yv{z}€yw{vy|{xzyy{z|v|~|~~{{|}vv€z~~~‚|~~z‚|~w{rytwvsx|‰¢¨©«ª›€¢¢¢¡¢£¡¦¢¢ ›£ ›œ¡¡šœš™š˜œššœšž› ž§ ¦¦¥¦¬«¯­ª¬¬§¯¨§¢¡“”™Œ‚wvjaa^\Xag`heiiiihnnlkihmmmljjlnmkmmnnlhjjlmovoqvywpzyz}zy|{‚{z„ƒ„‡€ƒƒ‡‰„†ƒƒ€‚†~~…‚ƒ€ƒ€‡…ˆ†€†‚‡……†‡„‡„ˆ†„……ˆ…††„…ƒ„…‡‰†…ƒ…ƒ‡ˆ„‡ˆ‰…Šˆ‡…‰‡ˆ„…Œ„ƒ‹†ƒ„ƒ~ƒƒ„ƒ„ƒ€‡……‡ƒ„……ƒ…‚ƒƒ…ˆ†„‡„‡†Šƒƒƒ……ŠŠŽ†„„€€…†„†…ƒ€ƒ„~‚‡†~‚ƒ†~„ƒ€ƒƒ}€‚~€„~y||ywzywuroqsifghptvz„‡‹Œ‘’—™˜™ŸŸŸ£ž¢¡››””™•š——›—›˜œššŸŸœžš™—™—š˜š™˜™˜——žšš˜˜™šžžššœ   œœ˜››ž±ÀÆÎÐÓÓÔ×ÚÚÚÚÜØÓÌÀ¬˜zkjeghoiqtuwuwvy{ywux}yv{z}€yw{vy|{xzyy{z|v|~|~~{{|}vv€z~~~‚|~~z‚|~w{rytwvsx|‰¢¨©«ª›€¢¢¢¡¢£¡¦¢¢ ›£ ›œ¡¡šœš™š˜œššœšž› ž§ ¦¦¥¦¬«¯­ª¬¬§¯¨§¢¡“”™Œ‚wvjaa^\Xag`heiiiihnnlkihmmmljjlnmkmmnnlhjjlmovoqvywpzyz}zy|{‚{z„ƒ„‡€ƒƒ‡‰„†ƒƒ€‚†~~…‚ƒ€ƒ€‡…ˆ†€†‚‡……†‡„‡„ˆ†„……ˆ…††„…ƒ„…‡‰†…ƒ…ƒ‡ˆ„‡ˆ‰…Šˆ‡…‰‡ˆ„…Œ„ƒ‹†ƒ„ƒ~ƒƒ„ƒ„ƒ€‡……‡ƒ„……ƒ…‚ƒƒ…ˆ†„‡„‡†Šƒƒƒ……ŠŠŽ†„„€€…†„†…ƒ€ƒ„~‚‡†~‚ƒ†~„ƒ€ƒƒ}€‚~€„~y||ywzywuroqsifghptvz„‡‹Œ‘’—™˜™ŸŸŸ£ž¢¡››””™•š——›—›˜œššŸŸœžš™—™—š˜š™˜™˜——žšš˜˜™šžžššœ   œœ˜››ž±ÀÆÎÐÓÓÔ×ÚÚÚÚÜØÓÌÀ¬˜zkjeghoiqtuwuwvy{ywux}yv{z}€yw{vy|{xzyy{z|v|~|~~{{|}vv€z~~~‚|~~z‚|~w{rytwvsx|‰¢¨©«ª›€¢¢¢¡¢£¡¦¢¢ ›£ ›œ¡¡šœš™š˜œššœšž› ž§ ¦¦¥¦¬«¯­ª¬¬§¯¨§¢¡“”™Œ‚wvjaa^\Xag`heiiiihnnlkihmmmljjlnmkmmnnlhjjlmovoqvywpzyz}zy|{‚{z„ƒ„‡€ƒƒ‡‰„†ƒƒ€‚†~~…‚ƒ€ƒ€‡…ˆ†€†‚‡……†‡„‡„ˆ†„……ˆ…††„…ƒ„…‡‰†…ƒ…ƒ‡ˆ„‡ˆ‰…Šˆ‡…‰‡ˆ„…Œ„ƒ‹†ƒ„ƒ~ƒƒ„ƒ„ƒ€‡……‡ƒ„……ƒ…‚ƒƒ…ˆ†„‡„‡†Šƒƒƒ……ŠŠŽ†„„€€…†„†…ƒ€ƒ„~‚‡†~‚ƒ†~„ƒ€ƒƒ}€‚~€„~y||ywzywuroqsifghptvz„‡‹Œ‘’—™˜™ŸŸŸ£ž¢¡››””™•š——›—›˜œššŸŸœžš™—™—š˜š™˜™˜——žšš˜˜™šžžššœ   œœ˜››ž±ÀÆÎÐÓÓÔ×ÚÚÚÚÜØÓÌÀ¬˜zkjeghoiqtuwuwvy{ywux}yv{z}€yw{vy|{xzyy{z|v|~|~~{{|}vv€z~~~‚|~~z‚|~w{rytwvsx|‰¢¨©«ª›€¤¤ž›¡ŸŸ ¡ ›Ÿššœšœœ™˜™™–œœššœ˜›™˜—Ÿ¡¥¥¨ªª«­°«ª°««¨§žž–“{wonf`\_Y_`afecdlhjjiklidjhljdihjliflhogikohloorwsvxxzwy|zz€}z}~||}|‚…ƒ…‚……€‡ƒƒ„„}€‚‚…ƒ‚‰‡‡…‚‡†‰‡ŠŠˆ††…‰†ˆˆ„††Š†ƒ„…‡~‚„ƒƒ…††…………†„‚‡†ˆ…„…„ˆƒ†‡‰€„€~€„ƒƒ„„~ƒ„Š{‚‚‚€€ˆ‚…ƒ‡„ƒ†ƒ†€‚„†‚„ˆ††„‚„}†€„‚~‚…€€ƒ‚€†„{z|€…ƒ‚~ƒƒ…~ƒ€~}{xz{||wtrrvloijhenmxz€€‹Š’——•™›¡Ÿ¤ŸŸ™———™˜—š—’™›”šœ—™š˜œž›šš˜˜š——˜˜™›–š•™žŸ›˜š›˜šœž›œŸš›œš˜–˜©ºÂÈÐÑÔÖ×ØÚÚÙÚÛ×ÑȺ£Œpgahfipooxtwuvxyx|zzuzz|z|{zy|vwt}yuzx{~{}|zx}{z|{vvzy|€|€~‚~|}y{wsr{zz~~ˆ”’‹|gM  £ž ¢ŸœŸ£ž£››œ˜™ ššž–›˜šš˜š—•™ ž››šŸŸ¤¦¨§©««««®¬­©§§¦Ÿœ”‘Š‚z~kkabY^[c\ca``hhmohfcjgjejfbfhlllekhjkhffsglkoqxxswuxx{€y|{{}w}|z„…‚†‡}~‡…„{„~……‚‚ƒ}†‚~‚‚‚‚†ƒˆ†‡…ˆ…„††„††Šƒ…‡ƒƒ†ƒ†…‚ƒƒ…‡†‡†…ƒ…ƒˆ†„……€……ˆ†ƒ‰…Š‚}„ƒ€~ƒ†€€ƒ‚…„ˆŠ€„ƒ‚~‚„ƒƒ„†‚‡„†…„„‚„ˆƒƒ‡†„…‚~ƒ}‚~~„ƒ{„€€~~€€ƒ…}ƒ€‚€~~‚€{}{{z|z{~wttpnongghffrvz~}„‰‘––šžžŸ£››š—˜˜˜™™˜——˜ž•š˜ž››œš™™—™™—™—šœ›š›˜š™˜—š˜šž›šœ›™žšœ›š—–˜¡®ÁÇËÏÓÔÖØÙÚÜÜÛÙÔÍò›‚ljdfgmiqutsw|vsxzyvyzzz|}~xxvy}y|z~vz}|{x}zzzv~}z}zz{~{}yz{}}~}~~|wxv~~‚~yp\O@:ŸŸ›žŸœŸ¢¢ ™™™—›šœ™›™˜˜šš™—˜˜™šœ˜™ž¤¢¨©©ª¯­­««¯ª¬¦¤£š––ˆ…|yrn^^ZSVVX]]daeinjmjhgecijlegfcjgikggkjjikimpppqsswyz}}~€|€}{zx{„€ƒ‚ƒ‚„~„†„†…†ƒ†ƒƒƒ†…€ƒƒƒ„„††„ˆ…‚‚…ˆ†ƒƒ„‚ƒ„†„„ƒ„„‚‚„†‚‡†ƒƒ„†…‚‚„†…‰‰Œˆ„‚‰ƒ‚‚‚€€ˆ‰‚„ƒ„~}€„…††„…………‚…‚}‚‡…„…ˆƒ„ƒ…‚‚€‚€†‚€}‚‚~€|…€‚„€ƒ‚‚‚ƒ}‚‚‚}~}‚|~zxuvyxtwpqsojjmceqtz{~ˆ‰‘”œ˜š›ž£ Ÿ ›žœ”˜•—›™“™š˜š˜™—›™™¡œ™›šœš™š™–™˜›š—š›———˜—›—›š˜š¡žžœ™œ™›—•–¥´ÂÉÍÐÓ×××ÙÙÚÚÚ×ÑÉ»©zfagholrqurvwrtwtwvyt{wvy|{~y~|{|w{z|||}}z€}x|{w~{y}yywz~~€€zƒ€€}}{|x€~|r^SFC27/››žžŸ £Ÿ Ÿšœ››¢ž™œ˜œ›—™˜—š›š™œ¡ ¨¥ªª°©¬©ª®­§¨ª¥¢ —““‰ˆ|xnra^ZWX\]_^gchighfinkghellffkikglgfmsgjkgrnqnrnrwuwxy|wxz~}‚|}}€z~~}…………„‚ƒ„€„‚‚„€ƒ‚†‹€…„‚………†„†…Š†‚…ƒ„ƒ‡…ˆ‚……~Œƒ‡€…ƒ„ƒ†…„„…‡†ƒ„‚‚ˆ„„{…ƒ†ƒˆ†‚€}€|‚‚†ˆ…‹„†„‚‚ƒ„ƒ„„†‚…‚‚…ƒ~„‚†††ƒ„ˆƒ…„€ƒ{„‚ƒ‚}|„|~ƒ€{~€{‚~‚ƒ€~€‚‚ƒ}~|€x~€z~zwztqpploqojfgkjsuyƒ†ˆŒ“™•˜šœœž¢Ÿžœš›™™™™—˜™›œ™œšššžœŸ›žŸ™šœœ˜™šš˜š˜šœ›šœœ™šœ›™™œ››™œ˜—š˜•œ©ºÃÊÍÓÓÔØØÚØÙÛØÕÌijŸ‚pgfmljposqtv{wv}wyuy}vwzwwv|||xvyzx|}|~}{v{~{y|~{{x|}{~||}€}€|€€€}€‚}€{l^I@02./1››ž›š›¡››˜œ›™™œ›™—š™›š—›˜–›££¢¤¦ª¨ª¨ª­©¬¬¬©¨ª ›š•ŒŠƒyyqja^[\Z[Y[a]fgbcefleigchipigkjihgfckgcdnimmmjsrttrut}wv|x|~|x~|~€~‚€}€ƒƒ€€€ˆ‚ƒƒ€ƒ€‚ƒ„€€‚€ƒ…‚„„…ƒ†‡‰†‰‡‰Š…„…€…‡Œ„…„‚ˆŠ…‰„„Œ…ƒ‚€|……ƒƒ‡„}ƒ€†ƒ‚}ƒ‚‚€|€€††‚ƒ„~||€€~ƒƒ‚€ƒ„ƒ„‚‚„€‚€€ƒ‚…ˆ‚„…€ƒ…€†€~‚}ƒ}|}{|€z|}‚{~€‚x{}‚}}||}twxxrspooqgoigflouv|‚‡Œ‹•–•›™ž¡¢ ˜›šœš˜š¡œŸ›œ›Ÿ›™˜™™šœœš™˜š˜š—›œ–—™šœšœ—ž™›šž›˜ž”™š™š›•–¡³¾ÇÍÑÓÕ×ØÙØØÙÚ×Ô̽¬”|nihhlnqpsuuuvwztxwyzw|ww~xzxwx{y}z{|~z{{}{uz~|y~~zz|~}|}~}~}ƒƒ|‚~}wiaR;5.1/.,œœœ œ››˜ŸŸŸšžš›ž™žœš—˜šš›ž–™›››Ÿ  §¥«§¨©«­­¦¨ª¥¨¤£ž•Ž„ˆƒ|qhaZZYZ[_ciabdddihgegihhcgfknjdggegifejnloplmmquxsw{|}y}y{{z{{}ƒ}…~€€†€„ƒ€ƒƒ…ƒ‡ƒ}ƒ|ƒ‚‚†‚€ƒ‡‡…Š‚„†…ƒƒ„……„‡‡…‚€„„„ƒ‡ƒ„Š‚‚ƒ…†‡‚†‚‚€‚ˆƒˆƒ‚~‚~€}„}…‚ƒƒ€†€€„„€‚…€„€ƒ‚€…„‚‚‚‚ƒƒ~~‚}€~~~€€|€|‚€„€€„~}xw{pvvzvpstqknjnjgdmqx|ˆŒŠ”–—›šŸ ¢Ÿ£›šžš—šœ˜—›› ¡žžŸ œ›ž›››››ššŸ™œ››™™˜žšž–™›™•›š—˜™š›––•—›¨¸ÂÊÎÑÕÕØ×ÙÙÚÛÙÖÐÆ·¥ojddjilmosnuu{zswvuz|yuyyvwxwxuyywwyxy||}z{v~z{zy{}~|z|||}‚{~}|„ˆƒƒ‚~rk[M=/04/.33œœœŸŸ›–” Ÿžžœ›ž›Ÿž˜››š›–˜šœ›š˜™œ¦¢¤¦¨©ª««««¬®«ª¦§§ “Š…‚~tjk`\Y[VWW^d^cf`dhfefiigilkkffhggjhhngdehhkqorrortttwwy~{|z}|€|ƒ~ƒ~ƒ}„€~‚€~€ˆ‚„†„‚‚†‚‚ƒ…~‚…ƒ‚ˆ„†„†„ƒƒ…„††ƒ…†††…~„ƒ‡„…ƒ„ˆ…„„€…‚ˆ„…€…ƒ‚„…‚ƒ‡„„‚‚ƒ‚‚…‚„……‚‚ˆ‚…€‚‡€ƒ„‚………†Œ…„…€‚‡|}‡…‡ƒ‡~…€‚‚‚€‚ƒ~ƒ~†€}„‚‚€|}€}}zwwzytqqulmmnhlhlijrw€…†‹‘–”—™™   ¡œœ›œš˜ ››™šœžŸ›žžŸ™žœ›Ÿžœœ™›—›šš™›ž˜™˜˜™™š•“—›››™ž™—–—™›–••—›­ºÆÊÐÔÔÖ×ØÚÚÝÚØÕÌÀ°™€khjhhjqprosuxyww{uzyxz}xuzxz{ywxuwx}xx{|x|{{|{|y|yz|}{|}}~}€~…†‡‡|wiWH85,,+0.-0žžœ™Ÿœ¡ž œ™œ«œ›¢›žž—›˜˜™š—œœ£¥¢£§¬ª©«ªª¥¥¬¤«§¦§¢Ÿ•‹‰‚}ulfd_TZYWa_Yaadegkiggijimklkhkdfaigefigfcilrrmtpsrvwxuxzy{z{€z‚‚y}~|‚|Š„ƒ„„†‚‡ƒ‚€ƒ€„ƒ~ƒ‡€€^ƒ‡ˆ…†„ƒ…„…‡†„ƒ…‚‚„†…‡ƒƒ…€„‚ƒ‡„„‚‡ƒ…ˆ…„„…‡ƒƒ‡‚…‚‚~}‚‚„„„‚„†„~‚„‚…‚ˆ‡‰………‡ƒ…Š‚ƒ‚ƒƒ†€ƒ‹†„€‚€€~„ƒ€€|ƒ€|†~{W}}€€{{‚€„„}y€}xxyzystpqqqookojgfinyy…‰“’––—™›£žŸ žžž˜›› ™›žž œžŸ¢£Ÿ¢  žžœ ›Ÿœ˜œšššš›š™š˜˜—˜™›š›š˜œ— š“———˜¦´ÃÉÍÒÔÕÚÙÜÙÛÚÛÙÒɺ§tigjgjknqpvsru{xxvxy{yy|zxuztvzv|wzy{yy{wwx{yy~zyz|€€}|x{|z€…ƒƒŠ€|n_I<22(.+0/02 œœŸ›šžœ›š Ÿ›ž˜ž –›š›˜››šŸŸ¤¦¦¦¨«©§­«©¨©¨©¦££žž”’Œˆ†{smig[W[`\\Y`cdgfckiiionjjmkqleiggkifdggjfioqpnrsrwzyttx{ywwyzz~~|}}€z€}€‚€€€ƒ„„ƒ†…ƒ…†…‚…‚ƒ€€„…†|‡„ƒ†„ƒ…†‡ŠŠ„ˆƒ‰…‚ƒ‰…ƒ‚‚ˆ…‡~‚‡„~ˆ†ƒ€ƒ†„€‡ƒ…„ƒ‚„†‚…„‚ƒ€€‚†„…‚|€‚‚†€„‰ˆ††‹……‚‡‚‚„ƒ‚ƒ„„„ƒ€‚ƒ~ƒ‹€ˆƒ~‚~†‚~€~ƒ}„ƒ~|X~€„~„‚‚|x|}z|uqxoinmqrppkgdgku|ƒ…ŽŽ”™š™›¢¡¡¢žœ ›œœœ¤Ÿ ¢¡£¢£ ŸŸžšŸš›¢˜››Ÿ›š›š–œšœ™–›˜—œ•–››™–™–˜–˜”“––›©ºÄÉÎÒÕÖ×ÙÚÛÛÝØØÎÅ´œ„kgkintsltspt|qwvv{wt|vzx{x}}wyz||vz}vzx{{{}|{|}vz|}‚‚~|‚~}~…‰……|tm_G9/10*(0+000-*15›Ÿ™–šœŸŸžš›œ›™™™œœ›–š˜˜ £Ÿ¡¥¦©¨¦¥§§¨¦¦£¨¤¥¦£ ¡žž˜“‘‰†zplh_X\ZTX^_W`idoedemhehigknkhjicjniegfdfhgfmoqpqtqyuuuxw}y~|z|xyƒ~}€~€„…‚‚€…ƒ„ƒ€‚„„„„„„†…}‚‚ƒ„ƒ‚ˆˆ…€†……‡„‡„…‘‰†……†~ƒ„ƒ…‡Š…„†„‚ƒŽƒ‡†„‚ƒ…‡‡†„‡‡‰‡‡…‚Œ€……{„}‚„‚ˆƒƒ‚~‚„‚‚„ƒŠŠ…‡‡‰ˆ…„ƒƒ…ƒ€‚ˆ€„ƒƒƒ„‡…„‚€ƒ€{‡ƒ~€~~|~}„ƒ…€ƒ‚…‚‚‚~ˆ€„€|~}~{tqrqqruxoomtiliifpsyŒ—”“–˜™š¢ ¡£¡¡¤£¡Ÿ¡ŸŸŸ££¤¢¥¡¢¡¢Ÿ¡œ¢¡ž¡¡œžžœž›˜›››–˜œ™ž•˜›•—•™›—–——–˜–””•’˜©·ÂÌÏÓ×ÙØØÙÜÚÜÛ×ÒÊ»«Žwdgpkhjnqtutswyywxv{w{y}wzz~~{yzyz~|~~{y~~~~}€‚}„ƒ„ˆ‰„ƒ|q`P=/-2+-.(02//,(-5Ÿ›žššŸšœŸ¡ŸžŸ ›™šœ™›šž  ¡¢¦¦§§¨¦¥©§ª§¦§§¢¡©¤£¡ ›™•…‚}tmd^d^W^X]a_cgkbdegejdhnigjgglfgigibbheehmnkntrrxryvvvvxz}yx{{x|€ƒ‚€ƒ~‚~ƒ„…‡‚„}ˆ‚„„„„‚…‚……ƒ„‚„‡‚‚€‡‚‡„ˆ„ƒ†‚Š‰†ƒ‚„ƒˆ€†‡ƒ…‚ˆ€ƒ‚‰‹„†…‡‚Šƒ‚„ƒ€‡…‚…ƒ‚‚~€€‡ƒˆ„‚€€€}…‚†„‰ˆˆˆˆ‡ˆ……ƒƒ…‡‚ƒ„‚‚‚……‡‚†„‚ƒ~{€‚‡„€ƒz}€~}}ƒ€ƒ‚‚~„„€|}€‚€}}}|{ytsuoqvtmplqhejfgnux€‰‹Ž–š›šž Ÿž¡¦¡ ¡ ¤¢ Ÿ¡Ÿ¦£¥£¥¡ž¤¢£¥ŸžŸœœž  ¡¡™œ›šš›—žš™š˜™›š——˜˜—š˜—––””“‘™¬»ÇÌÑÔ×ÚÙÚÙÜÛÛÜÔÍƱœ‡ifghmlkopuozrxytwxy}}x}ƒ}‚zw{{z{†y||y|~w}|‚~~€ƒ€‡‚„‡†Š‹‚{n]S92+(.4..+2.1.01.2ššš› œžžŸœ¡™ŸŸ Ÿ œž›œŸ›˜šš›Ÿ£¡¥¦¥¥¢¦©¤¨¦¦ª£¤ ¦¦£¡ššœ•“ˆ~q_cXVWY___c`bkcdcilnkirlkjfghhmgjmfnifejkorupusss{{}zxyxv}~zz{‚}€‚ƒƒƒ€ƒƒƒ„ƒ‚…‚…‰…ƒ…„‡‚€ƒ……‚€€…‚„€†ƒ€ƒ‡„‡†…„„€„…††ƒƒ‚ƒƒ€‚‚„‹‡‡†ƒ„„‚…†ƒƒƒ‚€„ˆ‡‚‚„†ˆ„„‚‚‡€‡„Œ€„…‚‚ƒ‡†ƒ…ŠŒ‡…†ˆ‚ƒ…‚††„ƒ‡‚‘€€ƒƒƒ‚‚ˆ}„|ƒ…}„†„„…~~‚ƒ€~yƒ{z~zvxvxsqtrlomqkleehnru{‚ˆ‹’˜•š™žžž¡¡¢£¢¢¡¥¡¢œ¢¢¡¡ §§£¢£¢£¡Ÿ›žŸŸ œŸž››šššœ››™™›–˜˜˜š——œ–•—˜›™—•“–’–Ÿ´ÀÉÏÓÖ×ÚÚÙÚÛÛÛØÓË¿­’uggfhjjmpprtprwuxy~x}wyy||z|z|{zx~{{y||‚||‚‚~}ƒ‡†‡ˆ†ˆˆ„~nbLA0&-22-2/1;13+*,-4œœ›¡›œœ™Ÿž ›žœŸ¢¢›Ÿ™™Ÿž™–› žž ¢£¤¥§¥¤§«¨¥¥¢£¥¤ž¡££¡›œ‘“Œ‡ˆƒtg^bUWZY_`_ebfjigjkmihnljegfeigeejldhggdilrpqrroszuuwwxvz~z|t{|€}|~€€‚€ƒƒ‚…ƒ€~€†„„‡„ƒ„……‚ƒƒ‚‚‚…ƒ‡…‚…€ƒ†„‚„…†~‚ƒƒ…‚‚‚…ƒ„„‚ˆ€ƒ„…†~ƒ…„…‚‰…€‚†€„…ƒ‹ˆ…€ƒ‚„…ƒƒ„~~†€……†‡‡……Œˆ…ƒ‚…‚„†ƒ}Š~††~……|€„€‚‚ˆ„€{{}~‚ƒƒ‚~~~‚}‚~y}z€{xŠyxwtosslnjimidfmqu{‚‡Š””“˜™žœœ£¤¡¢£¡¤¡£Ÿ¡Ÿ¥¥¤££¦¦ £¡ ¡ŸœœŸŸŸ›£Ÿ˜šžžœš™˜™—˜›—œ™›š™–•™˜•—–œ•˜ªºÅÌÏÒ×ØÙÙÛÜÞßÜÕÏƹ¢ˆqcppmkqurqmuxuwszyyyx{{{zx~uv~ztxzyy‚~~~}ƒ‚„„‡…†ŒŒ‡…~pdR?43++7C52-/92.2.5.4›››šœœœŸ™›¢ŸŸ›œžŸœ™™™šœ˜œ¡¢§§¦¨¦¨ £§£¦¦§¤¤¡¡Ÿ¤¡£ œ¡”’ˆ‚~yoid]cWV^]bc\gcgigfwkjjegimfini_dgbgmcgeghkpqqqsptqxrvzzx~zy}~|€{yy€ƒ~ƒƒ€„…‚‚~…ƒ„€„ƒ‚‚…‚‚…„„ƒƒ†ƒ‡†ƒ„„ƒƒ†€‚~…†€ƒˆ„‚€„‡…††ƒ€…€€ƒˆ‘ƒ„ƒ‚ƒ~‚ƒ‰ƒ†ƒƒ‚‚ƒ€€€ƒ„„ˆ‡‰ŒŠƒˆ‡‚ƒ~ƒ‡ƒˆ„…~€€ƒ|„ƒ€{|}~~€||{~ƒ|{€€ƒ~ƒ‚€‚~}~z{{{{{„|ypoprpojnjpkkgmoos€„‹‘›“™š™›Ÿ¡£¢£¢¤¦§ ¢ž¡Ÿ ¢ ¢¡£¡¡ž¢£ž¢ ˜ž›ž›™›››œ›˜ ™—–™˜˜™˜˜——˜™˜˜”˜™”–—”‘“ ²½ÉÏÑÔÕ×ÙÚÛÜÜÛØÖÌį“xhimqjiqrqnuwtxtwzsx{~u|s{{||x||~|€††}ƒ€ƒ‚‚†‚†‡Š…ŠŽ†p_I<4.--))1151,(+0/1/72ŸŸ›™—œžž™žžžŸŸ¢žžžž›–›š›¢¢§¤§ª¦¥¢¥¥¥¨£¥¢¢  œŸ ž˜•–‹ˆŠ„yyib[]WZa_``fbdcgahjggihdceglfadhdkfhhfhinonvsoouysw|uuxxwt€}|zz{~~}€‚ƒ…ƒƒ€„ƒ„€‚€~€ƒ‚‚€…€ƒ……ƒƒ…‚‚…„ƒƒ†…€„…ƒ€†„…ƒ€‚~„ƒ†‚ƒ‚…ˆƒ‚„ƒ‡ƒ|‚„„ƒ€~‚‚„~€„‚ƒ€„~‚‚€„‚ƒ……†ˆ…‡‚‚‚ƒƒƒ„ƒ„‚„ƒ‚†ƒ‚€~„~‚‚|}|}z~~|ƒ€€}€~€‚€}~~ƒ€~}~y{y|{xxxyrrupolqukjjfginnr~ƒˆ‹‘–˜šš››ž¤ž¤££¡¥ Ÿ££Ÿ ¡¢¢¢¥Ÿ££ ¢¡£ š—žžž›››˜œ›˜™š–—š˜˜™˜˜›––˜˜˜”•–—”––Ž–§¸ÄÉÑÑÖ×ØÙÚÛÜÛÜØÔÌ»¤‰ljfijlourmyqxwtvvrsry|~~|xwzwuzyu|€}…„…€ƒ‚†‚‡‡Š‡Ž…t[G615)*-,-65>/34+.11846œœ™˜œœœ£œ žž ›œžšŸšš›› ¢¦©§ª¦¦ªŸ¤¥¤¤¤££ £¡ ¥¤››—˜Ž‹„…~tec`VYWX^_bchbckkhjgefghkgegggknmgcekihjkgkjmloqqsqt}xu|yvy}w|~|‚†€€†‚€€‚ƒ„„†‚‡…ƒ€„~~~…€€ƒƒƒ„ˆ‚€‚ƒ…„…„‚…ƒ€€„€…|~‰€|ƒƒ‡€~ƒƒ†ƒ~€€„€ƒ|}€„~}…|‚ƒ‚„ˆ}€ƒ…€€„…‡‹ƒ„ƒƒ„„†‚…ƒ‚~~ƒ‚€‚„‚‚„†ƒƒ~‚€„ƒ{~~|~}{}€|~ƒ~|€|}‡€~~{|x}wxxuzrsqqllppikmimppry„‹’“•“˜žœ›¤¡¡¡£¥¡Ÿ¡£  ¢Ÿ Ÿ¡¤¤Ÿ Ÿ ¢¡Ÿ¡››œ™›šž™™š˜šš——›˜–•š˜™—˜–––•”˜—•™˜Ž““Ÿ¬¿ÇÌÐÔØØÙÛÛÜÛßÛÕγ™~qlelskloqtrtxruysxvzw{{xyy{t{y{xy||~€„ƒ…‡……ŠˆŒ}qaI83::.6?32063//././//0=œœ˜˜Ÿ¡Ÿ œ žžžŸŸ¢›œžœ žšœŸ¢£¤§¦¥¥©©¦£¦¤£¥¡¥¦›žŸž ¡Ÿœš›–ŽŠ€xqjc]YYYV\^b^_cfefknfjgihgceojkgdgijcehhkkolkmtlopsxxw}y{|xxzt{ƒ}‚€ƒ€}xƒ|€‹€~‚ƒ‚~~‚‚ƒ‚ƒ~~‚‚ƒƒ€ƒ}…‚€„‚†„ˆ†…‚†„‚„‚€‚‚ˆ„†ƒ‚‚…†}„„„€€€~ƒ„~ƒ||~~~{‚€€}€€‚€~‚€}……‚€…ƒ†‚‚‰‡‚……€……€„‡‚‡€‚…ƒ~€„‚€€{~€}|z}}€}‚}|€||~|€€€||yxy{xvvsunonolknjjklovuu}……‡Ž•–—˜›žŸ¤¡¥¥£¤ ¡£§£¡›¡ ¡ ¢¡ ž¢ž¡ ¢ œœ™œ›Ÿ›Ÿ›™ž›œ™–™”œœ˜—˜–˜—˜š˜–—–—••”‘–§´ÅÉÏÔÕÙÚÚÜÛÛÜÜØÓËÀ©–tfjhnkoqovv{|vz}ytwzv{€xyyxzwvxw{yw~|}‚„Š‡Œ…„€q^J;L?/0+-0,2(,4,-,6147766››™š—žš£¢ž¡žœŸŸžœœžŸ¡ ¤§¦¨¨¥§¨¤§¥¢££££¢¢¢Ÿ£——‘Œ…}xrg`_XURX[e_^aa`eikingmjjhdhilfhghechjbhhnkqqpoqpsqxw{yy{xvx}w}~}€}‚€|{†„‚‚„„ƒ‚‚„„{…~‚€~€‚ƒƒ‚~€„†ˆ………~ƒ€€€…|€‚‚“„†ƒ†ˆ‚‚~‚}}}y}{~~}{}~}€z€|~~‚‚zƒ|~€~ƒ€†„„€…‚‚„‚ƒ…‚ƒ‚†~€‚‚~‚~{|€€€€‚z}{€}€€‚}~|}|€…}~{~}{y…yutpoklnmjiihnqpxz€~ˆ‘”›ššžŸ¡¢¡¡¢£¡¢¢¨¦£¡ž ¡¡¡Ÿ¢ŸžŸ¢ŸŸŸ ž˜œ—›š˜››™šœœ™šš˜™™˜——˜—˜˜–˜–”—“••““‘“­½ÆËÑÕÕÙÙÜÛÝÞÜÛÖÐǺ¥ƒjedjjlkrwrvyzwzzv~|{|y}}zzxyztv}|~yx}„„‚€…‡ŠŒ†‚o^H9>KJ10(/+.0('..,).01476:™™™œ™žœŸŸ žŸœžœœ£žœ›œ› ¡¥ £¥¦¦¨¦¨©¦¦¤¡¢¢ £ŸŸŸ ¡¡ ¢œ–š•Œ…ztmc\VWVNSTa]`aedhgeidlekghgiiegfdeilgfeihljoollqrqrwzzwxw~vzyz|{{}~~ƒ‚|ƒ|~„ƒ‚„}ƒ}‚€}ƒ€‚‚„ƒƒ„€€‚€}‚€~‰€€„…‚ƒ~‚‚‡„ˆ††€‹Œ‚~…ƒ„…z~z~|€~{}~{‚~€ƒ€|}}}~ƒ}y~€y„~‚…„‚ƒ€……‚‚„ƒ‡‚ƒ†‚‚~~|~}~~€|‡}{€ƒ€}‚€{€‚€ƒƒ€|}{yy|||~wvrmqqlkjhjjmltrww‚‰‹Ž“™œ¢œ¢¡ ¤ ¡¡£¢¢ ŸŸŸ¡œ¥Ÿž žž žŸžžžšŸ˜œšœœ›˜™˜š˜—–›˜˜š—˜˜˜—™”˜—–™’“’‘“’£³ÄÌÎÔÕÙØÚÛÞÝÞÝÛÕβ’ydhjklnorrts|}z{~~y|{x|}vxwxzx|}}w{z~€‡†ˆ‡‡‰~o`R52)0<4.&'%)/**.-.-.74;244096.14;115126;538  œž ›Ÿ ž¡£¦¡£Ÿ¢ ¨£¥¦¦©¦©§©©§¨§¨¥©§££¡ ž¡Ÿ›ŸŸ ž¡¦¢£ž™›‰…~rmc_]WZYXY]ccdgcgiohhgihiiigfiglhgggge_cjhhlkorotruvwuwz{zu{{v{}y||{{{„€‚~€~„€~‚€…||}}y}€„…„ƒƒ‚||€„€†ƒƒ€‚~ƒ€€|†‚‡…„~}„€~~|z|{|z|yyzzyz|{}€z|‚~„zw{xx{|wxzx|}}„{ƒ‡‚ƒ„………†‡„~€€‚‚„‚€€|…€}}€}z}|ƒ~~|~x€{}}€€‚}{~|yxvt{vrwronrrlyphnnpsvzx}†ˆ‰‹‘•–˜”–šžœžœ žžž žœžœŸ ›žž ™œ›˜   œž—ŸžœŸœ›—œ›œœ™Ÿœ›ž˜—™š•›”“”’—Ž‘Ž¢µÁËÐÖ×ÛßÞßÞßßßßÜÑɽ¥…jglcokpqrqtsuw{y|~|wzw|y€……‡Š‚|uaG4.,,(,,&+/2.6;16D4354283322067520.  ž  ¡¢Ÿž¥¢¢¢ §¢¤£¤¦©§¥§¥¥¨¦©©¤©§¨¡¢¢žœŸœŸ¢Ÿš¡Ÿ¡ Ÿ œ˜“‹‡‚„vklaYZVU^X]eadheccfclhdgfggfeehhecheikikhkfnnpotontwxuvvzywwwuz|~y}xw}|~€€}„~†…}~|}|‚{y~…|‚{‚|~‚ƒ‚„ƒ~}{~‚|}„„€ƒ€‚~}‚~‚„€~‚}y}€‚}~z}|€|zzz}}~x}†€|~}~~}zx|}yzxwy}~{vz€ƒ‚€ƒ„…‚ƒ†ƒ‚…~ƒ‚||€~}‚|€~€}€}||~{|z|€„~€}~|~}€~ƒ{y~u~xuyuqvyrpsvqpmgjmnqvyz|„‚Š‹Œ“”™šš›œ› ™œš¡Ÿ žŸ™žžŸœ ŸŸœœœ˜Ÿ›žœš›œ¢Ÿœœœž˜œœœ››˜›œ™œ™š•™–•”˜——˜”““”©¹ÇÌÖÖØÛÛÞÜÝÞßßÞÔÍɱ—zicjiekrrurqqwyyw||}}y‡}‰ˆ†}yi[K<*+*())/-/6549<98853/17130.40765/2,žžŸŸŸž ¤«¬¦Ÿ£¡£¡¦¤¥ª§©¨¦ª¦ª¨¥¦¨§¥¢£¤¡ž¡šŸ žŸ ¡¡¡ ¡ ›•‹†…~xkf^YRTSS\YfZ[dciggihedgbgedjfhffchafikhjjkoklrrpprxuqu||syzqyy{‚{xyz~‚†{‚|‚}|ƒ…||}~z}xz{~}|€€€~~ƒ‚}{€}|€€€ƒ‡…ˆ†ˆ‰†‚ƒ…~ƒ‚€€„€}}€~~€|{}x{{|xv~yƒvy~||}~~{vv{u|{|vyx||{}€€€}‚}ƒƒ„„ƒ††‚„€€€‚„‚}~~}~yy}z|€…‚}}}€}}€~{{{zx~zwvtr}w{sqsooplniplxt|€†ˆŠŒ’””––˜›šššžŸšœœœ ››Ÿ  ››šœž£œœ™šœœŸœœœ›œœž›œš™™žœš••–——˜–‘—’‘’Œ‘ŒŽŽ›®¿ÈÒÕ×ÛÛÜÝÞßààÞÝÔÌÀ¨‰r``hgolpowsvqu~~|y|z€|€‚…ƒ……‚vi[A8,')-+,*.,./31-1236556.;4:322/432,,,ŸŸ ž£ž ¢£ ¢žŸ¢¤¤¤£§¥©©§¨©¥ª¨§£¦¤¤¤£¢¢¢£žŸ¢¢ ž¢¢¢¡£˜˜Š‹ƒ|vpd]TPRXSW[[_^ecichmifhdcgddidfgffhgighddigjonpoussrwvs{yxxwvtxx}}z{}||}{{|‚€}}{}y|}}{‚~€ƒ~ƒƒ}}€‚|‚‚~…„€}‚|€€„‚€}€~}~~~}y{~|{xuz|yux{}~}€z{vzwxxyuxw{ywz|}}}}~‚|~~‚…‡ƒ…‚„~|‚€~€€ƒ€…}}~|~|~~{|}~}€€‚y|~}~~zwyytw{~vxusnoilhhkkqt|†‰ˆŽ’”˜•–—˜ššœ›œŸŸ œ¡žœŸž›œœšœ ššž›œ›Ÿ›ž˜˜šœ™ž¢œœšœ™˜˜™›˜™—––™”›”–’“Ž‹ŽŒ‘£¹ÅÎÒÕØÛÝÞÝÞßßáÞÙÒʹœ}fcbckionopssrwxwuy|~y~…€‡†€vk\J6-+02,()*+(.5254777>:8=6854285.,3//44¤¤ ¢¢ŸžŸ ¢Ÿ¤¡ž¤ §§¨©©©¦¢¤££¥¡ž¤¢¤¦ Ÿ¢ŸŸŸ Ÿž£¡¡¢ž£¢ž›œ™‘ˆˆ~vm`W[WRSSV\cdecfdfeehmoefjfeecfcjigdjjfbehhiprnqpvutuvux{vuyur{wv||}{}||}|{}€€z|zyx}‚z„~ƒ‚ƒˆ‚…~‚‚~|{‚†€‡}€€ƒƒƒ„†~„~€„ƒƒ€|~ƒ€~{~~{„zzzxy|‚xz|yvzzz|zutu|uxxzux{w|z~zz~}|€‚}|y„ƒƒ†‚ƒƒ€~~€z€}‚‚„~}~‚‚€€|}~{|{{€€|}~}z{|zxwsvstsussupoqjmnntww|~ƒ„†‰ŽŽ””’˜’•——›šš™›œœžœ¢  œ›žœœ›œŸ¡™›ž™š›œ››™•™œŸœŸœŸ›Ÿ™ œš ˜š•™—œ””’••‘’”‘”•ŽŽ‹™°ÁÊÏÓ×ÚÜÝÞÞßáàßÝ×ÐůŽubbcqoplmprrvyyqwy}}ƒ€€„„†xl\I4,'-(.1,11-(/;ACLF???@9>3451342-0--..:¤¤¦¢£¡£¢£¤£¡¢¡§¥¤¥§ª¨¦¥¥¤££ ¡¤¥¤§¦ž¡¤œ¡ŸŸ  ¢¡¡ ¢¡¢¥žš™’Ž†zthd`YSOQU\d\[ebjjggidgcdigkfffefddmechfkfjijmtpssvrrxxuyu{zxz|xxyzy~wyy{€~‚{{}~}€~~|€y}z|{w‚€|…€ƒ‚‚|ƒ~€†ƒ|‚~~€„„„‚€‚€ƒ‚…}~‚~€}ƒ~}€„v‚yyy€{{~wvsywzyzy{yy{uwxx{xxv{zw|}}}‚‚‚„…ƒ‚~€{‚}ƒ|z~}ƒ€}€}~xy€~€€€}}z€||€‚}~||~{zxuyrstuwvsnurqstmmors{||‚„Š‹Ž”–•’”˜˜ž˜š˜œ ››š œž™¡žžš ˜›š˜˜›–—š™˜›šžž››™œžš™˜•›˜™˜”–••—”’“‘ŽŒŽ‹“¦¹ÅÎÕÖØÚÝÝÞÝààáÞÚÒÉ¿¡„kdehhrhkponsuswxz{y€…„…yp[K80+&-2,)*.4-)-02375181435101//040,-/,/2££¡ž¡¤Ÿ¡ž ¤¥¡ ¦£¥¨ª«ª¨§¦£¤£Ÿ £¢¤  ¡ ¢¡ £  ¡¡žŸ£¡¢Ÿ¡š—’Š‰ysfd_XTQSXZYdWYlffqifleccdefdffbdkefcibgffchgikoporrv{xyuxxzvw~zx€vwz|xz{w{€‚}{}{€z}y||~}~z||‚€|‚‚€|„€‚‚ƒ~‚„„‚†|€€}€€‚‚}|€€†|€€{‚‚€}~||z€}}~}~yzzzxutvxyuuyvx{yzyvxs{xyyx|€€|‚†„„~‚ƒ€~‚|~ƒ€ƒ}€~{€‚~}{}€}‚}}{ƒ€~z€‡~{‚~}x|zyxwsuptrusnxunommsoptz|‚…†‡‹’Ž‘““’’”˜˜™ž™œœžšœœŸ›ŸŸ›™œœžšœ˜ž™œžš™›˜™˜š˜œ˜šŸž œ››œœ˜™™—˜˜–••–””–’”ŠŒ‹™¯ÁÌÑÕ×ÚÚÝÞÞààáÞÜÔÍÆ®•xdbimkmjpqurqoqtx|z}„ƒ~|qaQ46/*,,-*.)+/4/4:573:3<42.57711-.1.,-,/),  ž¡¢Ÿž œŸ¡¢ Ÿ¥¥©ª¨«¨¥¢¡Ÿ¢¤œ  ¡ŸžŸœž¤¥¡¢ž› ¢¡¢¡Ÿ¡¢¢ š–Ž‹ˆ}|pie]VYQQSZ]Ybdkgfchfdkfhhfifhilackddaiehggjjjoqnpssrzxyyzuwwvz€{|y|€y}{y€{z}‚|ƒ~{}||€|€€ˆ}„}{}~ƒ}|„ƒ|€ƒ„ƒƒ€‚‚ƒ€‚|‡‚‚‚ƒ‚}~}ƒ}}€~‡„}}{€{}{{x}zxxwtwvz{wzxttwwzurtvxwx}|~€}~ƒ€†‚€||~}€x|‚„‚‰ƒ|}}|ƒƒ…|~~€}}€}|~‚€‚}|}|}z{zzxtqyusrswsqxsnqmlnruxx~|ˆ‰…Ž‘“’—••–™™š˜š—œšžžšž ™›œœœ›™›š››™–š™˜š™™š™ššœšžššœ›˜™—–•’”—–‘••‘—‘‘’ŒŒŠŒŒŒ”£µÄËÒ×ÚÛÜÝÞßÞßßàÚÓʺ¢†lchgmhimkqormtryz|„ƒvq^Q=.-+-))*+.+,40.667:<=64461:1341051+.---)1ŸŸ¤ ¢£¥¡£¢Ÿ¢¡£¦§©©ª§¬¥¡¡¡ŸŸžœž žžž™Ÿ ¢Ÿ§ Ÿ Ÿ  ¡ ¡¡¢š•’Ž•€ymb^WUOZWWa_\afcdgidfjgkmjieenjcfljfhcclifilomomqrqs||w{yxuutwy}{x~{€}z{y~x}}ƒ€v{z|z}y‚„€‚„€‚}€€€€}~|~€ƒ€}€€~€~~„€‚}}}„€€|ƒ}€‚~~€†‚€}€{~{~{vz~||zy|rzuvqxxrw|vvtzwytxu}zzz{|~z}€€€‚~ƒ|{€€€|€€„‚‚…|~~ƒƒ‚||€{}{€{€}‚}‚~uwwx~{xuu{urtrtqqoonmnjmmssxz‡Š‹Œ‹”’”’”••—š›š™˜œŸž¡œ™™››š™›š›Ÿ—œšœ›™˜—šœ™˜šœ—– ž—˜›˜——•—“’’’’‘‘’ŽŒ‹‘‹—°½ÈÏÔØÛÝÜÞßÝßàÞßÖÍƳ”xdagjlmljomtrwwzz}‚‰wr_I@,0+(*+*-./000975<9E>>:914642833/.,,,03.)-¢¢¡œ¡¤¤ ¡¡¢¢¤§¨­ªª¯¦£Ÿ¡œœŸœ›œœœ›™œ›œ ¡ ¤ ¡¡žŸž¢¤ ž¢™™”„|uja`]TOWV[^]adfhacmjcegkdejddjoidfgedifeefjnlknorrwutyuxzzxyz|{z}€€{~{{|}}}}~|{||~~~}~|„€~~}|{€€€‚€„€‚…ƒƒ…€€€~~€††~„{€{…‚‚ƒ‚~|}x{}xuw|~y€’€€ŒŠ}y}}vuztustxwwxw}~yuxx{{‡}{~}|zƒ‚‚€€{‚‚‚‚|~‚‚}~|€…„~€}}}~€}|{{y{{||tuyqppstuuqsnkllprqrs{€~…‡‹‹Š‘’“•–—–˜—˜—œš›œ›žžœœ™š˜š——ž—™›—˜—˜œšš›™—™œ˜œš™™˜”š”—•”“Ž‘‘ŽŒ’Ÿ¶ÅÌÑÔÙÙÛÞßÞÞààÞÛÓÌÁ¨‡kbjflkjnprtquxyy‚‚{kaO92,+)(.0.)11133616<;5;95>7:542452-++-..1/+0¡¡Ÿž¡Ÿ¢   £¢¢§¬ª­ª£¢¡›™™œ›šœž›ž› š £¥¤  ŸŸŸ¡ž¡£¢¡¦¡ ˜˜–‡~qja`XSNRT`\^babceddigkfjgcjbfcfkifelefgkhhlrmknouxvuwxxysvzvz|{z|yw{€|}||~‚~‚~y{{}z€{€‚€‰‹~‚~}|}|†††„€~‚‚‚…|€„€}|€‚|}}‚‚„„‚{~~z€€|zz€z|~}|~{}‚{‚”‹«±š¨´¢’š£“Œ”ƒvz|wtwyv{|{|vwzyz{yx|{~yzz‚€}€{€€‚„‚}|~}€€„{‚}}ƒ€‚}}ƒy}€}‚|zztwvptvouvrpoogknlptrtz‚~†‹Š‹“–’—‘•–˜šš—–™™™žœŸ›ššš›˜››š›ššœ˜Ÿ˜š™›ž™œœ˜—œžœ™™™™˜—•”•––“ŒŽ“”Ž‘ŒŠ’Œ™ª»ÈÐÐÖÙÜÝÝßßàßßÝÖÐȲšvedjfillpyqory}xf^Q;/,100*-+,*/2,11562:9;?=:5433076<1/+,,/20.1-¤¤Ÿ¡¤Ÿ¢ Ÿž£¤£¤¨¦§¨¥ ¤œšŸ™˜™™–˜–šš™›ž¥¡¤¦¥¥ ¡¡¤¢¡¡¤Ÿœšš•Œƒ|tig\YWNUS^[YZ__ecjdhfmihmhmijeljkeffehffkhmtoqnvutssx}yvzy{xz}xz|{zz}z{y}‚~~{|~y{~€‚ƒ||€€„€„ƒ~~z€ƒ•‚„‚€†ƒŒ‚y‚}~…€|€‚‰Œ‰y{~‚~|{€~„•ˆŒ‹‡‰„ˆœ’²¸žœ±ºª¢²±¦¦®¸® ¤§›†||rwwvutvywv{zxy€}|}~}}}~z€~~€…‚…€„|€€~y|}|€}}{‚}~€{|~|}{xvtwrpupovxqonqnkjpqvswy€…ˆ‰ŒŒŽ‘•–•“———–š›šœ™žž›—œ™™˜š˜–™™—š˜˜œ™š››™›˜™›™–š˜™••–“’–“”•“Ž”ŽŽŽ—‰‘‘ŽŽŒŒž²ÀÌÎÔÖÜÜÝÞßàààÞÚÔÏÀ¬lbgvijmuuwty}}|siXR@/-+,*200,*+1..0446<:7<8=4788>5*;2/6,-,/.4-,/££Ÿ¥¤£   ¢¥¤£««©«¢  š›–˜•™•–””—˜šœŸ¤¢¢¦£¢¤Ÿ¤¨¤Ÿ¢£Ÿž™“’‚„|kfa[ZQVT]Zccadagghglhelnqkfdgedfelfgidgjflrlooprqsvwyyxxz}u{z{zz|z~}~|}}}‚„~|~z€~„‚€|}}€‚ƒ…~‚}}€|}‚„„„…ˆ†~‚‚€}z}||}…„‡~~~~y„…}‚šœˆ‘“Œ•š˜ž´³œ¢·¯¤§µ±Ÿ¯¿½®±»À¾¯¨§¨zxuqsvqwvquzy|{}z{|}~ƒ}{}€€|€ƒƒƒ„ƒ‚€‚‚€y}~}}}||€{…z~}}||{||xxxyvvtvuquvrponljpglqsuwx„ƒŠ‹‹“Ž”‘‘‘Œ’•”•˜•–™™™›œœœ›œ—™–›˜››—›—˜˜œœš˜š›œ™™––˜•š˜–“˜“”““‘’‘“Ž•Ž’‘ŽŽ‹‘‘ŒŽŒŽ˜¨¹ÆÌÓÖØÛÜÞàÞßÞßÝÚÒ̽ ~om}poopvqs|v}xjYB0-/,.++00/-*.214229678:@?;;88333-0++1+,0.+/00-££  ¢ Ÿ¤ ¢££ª§ª«¬¨¤£Ÿ›š™––“••——“””šž¢¦¢ £¡¤¡ œ¡¥£¤¢¡ž›—™Š‹„‚~mh\_YSRU\Z__\^_gdfglkhkijneeheldhffjfghiklportopqlpwvyz}zwy}{||€|z{}|}||€~€€‚z}~€}}€‚ƒ‚~€€…‚|}~€€‚~€~…}€ƒ‚‡ƒ~~‚‚€€€}€€~ˆ„~…Ž|‰Œ„–šŽ˜ ž§­©š¬¹¯¡³³¨£³À·¨³ÂÁ´¯»Äö¤¢ ¡|{xruvuttvy{y{z||{€y~}~ƒ„ƒƒƒ„ƒ„€~€ƒz~€}„‚}}}ƒ~}y{zwyyyvtqppotorrplmknmpswy||€ŠˆŒ‘Ž‘–’“––”˜˜˜œšžšœž›š›ž˜–™š—™š™›™š›››—›šž˜™•˜–––™˜––“•’Ž“—’’Ž‘’Ž‘Š“ŒŒŒŒŽ‘˜°ÀËÎÑ×ÚÜÝßÞÝàÝÞÛ×ÐƯ•tilifnurr|~zsnbN<,'/(&**,-*)01233:=43<77=:<984341.**,..1.'.-005£££ £ ¢žœž¡¦¨©ª©­ª£ œ›š™“““’“–’—œš¡£¢Ÿ ¤£žŸŸ¡¢¨¢££¡œ›™–‹„€yod_\[TRXW[\aaibcdedfeghfhjckegkgjgfbfeehkjpqtqrpppqxwxwzyuuyw{{€}|}‚}z~{€~|ƒ~~~~||…ƒ…‚‚z}}„‚‚ƒ~{}„ƒ„„€€€€…~ƒy|}{~ƒ}„•‘Ž—š—“œ–‘‘“–™Ÿœ¢²¡”§«³¬­º´¢®¸·°©¼Çº­²½Ãº²¯¹Àû®ž‘zwxswystwsx‚z{}z~}|{€„ƒ„ƒ~‚ƒ‚‚{~zƒ‚|€~}~}|~~||uxxyyvvunsqrorpmlkjnlqrzw}…ƒ†Š‹Ž’“‘‹‘Ž—‘’™—•—™—šœ™š™ššš™“•š™˜™™˜˜•—™››šš›˜––—šš––˜••–“”‘ŽŽ”ŽŒ‰Œ’ŒŽ‹“‘–£¸ÄËÒÖÙÙÚÝÞßàààÞÛÖ˼©†loglpxvx~}vj]L3+&*+-1+,*1--,126278546H3<=6439..06;34/.11+(,.,.2-3¢¢£¡£§«©°¯§«¥ž¡š•—‹…|yswurxƒŒ˜–šž£§¥¥¤¥¨¥¥¤¢ ¥¦¥¤£ŸžŸ——’„€rjcZUMNLMOWeg[dec_a^_ceecbhbbfbcdcccfjjfjjjlmmtqnuryvutwuuy{wwwyw{{z|z|wxwxx~}„}~ƒ~~~€{‚~€}}{~{y„‚‰Ÿ¦Ÿ–˜“’†~~usy{}ˆ|†‡‡…‡‹ˆˆƒŠ„‹ˆ—¡˜‘’•šŽ“•™ª¢’–§¡¡°°¬œ ¬¥©°¬©¤Ÿ¬¹¸¬«¬°¼³«°ºÂž¶±½ÃÆýº»ÀÆÇÃÈþ¾ÇÉDZ™nmmrwvyuvwvywx~{xzxxxz~vz{{|{{wxsrsqwvwsqtorqnnoniiggkhmqlsut}†‰Š‹–‘’””””“‘”‘’““š”‘•”–•™›š—™™––—‘‘•‘ŽŽ˜’“”‘’‘•“’“”‹ŽŽŒŽŽŽ‹ŒŠŒŠ‹‰ˆ‹‘‹–‹ŠˆŠ¡¸ÊÎÓØÜÜÝàããããääâß×»ƒC,,'++'),2+05+1*0-47567027644553,-.50/33.10-/1.:082++(/05  ¥¡ª©ª¬¬¬©¨¢¡œš™–Žˆ€xtpmgpw€‡Šš–›¥¢©¨¨£¦ª¤¥¡¤¥¢ ¦¥¡žŸœ•ŠŽ…‚wj`YTPNRVV_d[^\`_dhjccaeeb_bffbbdedchmfknljkmoppprkxr}pttxqww{wyw{uxywyy~}y|x~z~{{|ƒ~~}|€|||}|~|y|Š®´š˜£›–“‘Ž†|z~}wx}x„†ˆ……†„ˆ…ƒ€‹›Ž™ ˜••—˜•™ —”§¯¤« ©®¨©­Ÿ›«®¹²±®¶·°©¬»»À¿µ´º¿¾Â¾»¼¿ÃÇÉþ½Á¿ÆÊÊʺ¥„ponyyxqszwwwu}yvx}{tzzv|yz|y{x|zysvqtrprpvpqmoijmildfcillptuy€†„ŠŽ“’‘“‘‘’‘Œ”Ž’‘•“““‘”’–’š—š•™š––›•—”ŽŽ“’’‘Ž’‘’““•‘“‹Ž‹Œ‡‹ŽŠŽ‰ŒŽŽ‘Œ‹‹‹Š‹“ªÂÇÏÔÚÜÜÞàäåäçåâàÖ´p/$!*&($()-0.031).4:53230333543.0-.-0221M7425//,768.-.9328¢¢Ÿ¥¬§©ª¬­©¨¡Ÿœ—–‹‡zynjjelu~ˆˆ”—™œ Ÿª©¥¦¤§§¥¢£§£¥¥¥¢ ¡œ˜’Œ€{pa]VYSJKLTZQWU\^\dafnja]dddcbg`eakfifgcjihkooopoqq~svry{wux{{vxyzyzzy}z|€yz{€}~|‚}€|‚}„|v|y€|wˆ‘§¬–—“‘ˆ‰„†~|…z{zwz{u†‰Š‡„|zƒ„‘“Œ…‹~›‘¤—“’˜Ž ­ªž˜¦ ¥´²¥¡¢§±ª­ª»¼·°§¥·Á¿³²¶¼ÀÁ¶²µÀÁýÁ¾À¿ÅÈÈÈÂÄÅÉÆ·Ÿ‚jsttlusoqsqxzy}xyvxzzwzyuxzyzzvvwvsuusuqrppqplpnmkigggplppuu}ƒ‡†ˆ’’””•“‘‘’ŽŽ“””–•“•‘˜—“•”——™šš•—ŒŽŽŽŽ‘“’‘”‘Ž‘ŽŒŽ‹‹ŽŒŒŽ“ŽŠŠ‡‡Ž“±ÂÉÐÔ×ÛÝàâääæçåß×¹p)&$-()*..-)03(-35379;66584==;1,/-/+-15236526,'*246*-+0721¡¡£§ª©«®¬©¥¡žž–•’‡unecefs}‚†•›™Ÿ¡¤¦¦«¦¨¢¬§¦£¢¥¥¥£¥žž˜”‘ˆ„xpdXWSJMORS]ZXU^Y\_`acac_[c`c_ed`ekhbcgfihjrkulnptussvzqq|uuxxyvysxyyyz{}{~}}}{|{}{~}€{{}|€{y|~‡~z‚‡…ƒŒŒŠ‡†„}v€}ƒyyuxxxyy~‰ˆ‹‡…‡ƒ|y€ˆ†‹“†~Œ”š˜Ÿ•‘ ¤¤«¢£¨ £®›Ÿ°°­¦«¯µÀª£³¸¼¾µ±¯½ÀÀ·¨¯½ÅÀÀº³»ÁÅÇÃÂÂÃÃÄÉÎÊÆø¥yrruopppw{vxvxuvw|{yu{yxtytwwwuwuvssspnqpikllnmeiefchiorrxyƒŠˆ‹Ž“•“””’’’’•““•‘“““”•“•˜“–™˜˜›”˜“‘’‘ŒŒŽ‘’’’‘—””‘Ž‘ŒŠŽ‘‘‹Œ‹ŒŽŽŒŽŽŽŒ’ŽŒ‹ŽŒ‰”©ºÇÏÕØÛÞâäåååçâÙÃ…8#(+)++)/)*/01325377553564565..,-*/+319<040,/0++-..-+48993¤¤¦¦¦¬¬°¦ª¦¦žœ—•Ž€zrhg[\hpz„†•”™šŸŸ©©§¥§¥¦¦¢©£¦¨¤£§¤žš–“Š‡€slb[TNJSNTUWUZX^Y]ab]_`ab_ce`b_faggcibghgidijojrpnsqypuuspwxxu€z{rz|xx€x}xxy|}|}}}|}|zx|yz~’²˜y{€|}~‰ˆ€~€{x€~}{|~}{~||ƒˆ…„‚ƒ„€€†€“‹…„‘„Ž•šŠš¡—•£¥ ›¤¤—££— °¥¬­¥§²·¸´µ°±¼ÁÀ´·½½À·®­·¿Áø°º½ÀÄÅÁ»½ÄÇÉÊÊǽÅÆǹ’lilnoopswvutuuxz|xzx|xxx}yzwyuuwttrqnsqoohmjkhilj`cnmkoux€ƒ‡‹ˆ‘“–”–“‘‘’Ž‘”‘‘”•““—”””‘’–™•”•“˜–Ÿ˜–’–ŽŒŒŽ‘‘Ž•ŒŽ‘•”“‘ŒŽ‹Œ‹ŽŽŠŽ‘Ž’‘’Ž‹ŒŽŠŽ—°¿ËÕÚÛÞâãæçäâÚ̦[$()()-,,*-2*'///6445793778561-/+-0--3487310+,-,0.-2.346<:4¦¦¨©®±¬­ªª£¡žœ•”ŽŠzuiiZ\[cox†–™œ¢Ÿ¦©¥¦¨¦£¦¤££ª£ª¥£¨¡Ÿ˜—’„}vja^QQHKNKPRVW[`\c^`_c_[`_hcdbacddbfggkjghjkjnmhlnnvyswwqqyqzw{w{ty}zyx|}{xwzz‚{|{}{z{~{{||z}}‡¯Æoq}|{z‚}€}~zvv}zzwy}y~…}€„‹ƒ†ƒ€€…€‚‰Œ…Š‰Š‡”™“ŽŠšžžœŸ¨ š’“¥­–ž®³¶°¥¦­¸¸½¾¼»º¾¿µ±±·¼¾Àº·À¼ÁÇÀ¹µ½ÀÂÈÉÇÀÄ¿ÃÃÄÌÉ÷ pjnjlnpnqtttvzwrxxtzzwvuvwuvrsuusqplrmnlmpijmngidfjnqqtx†Œˆ”•”““’‘’”“•‘”““”“’’“’—š•š˜”•”ŒŒ‹‘’‹ŽŽŒ”Œ‘‘Ž‘“Ž•‹Œ‡Š‹ŠŠŽ“‘Ž““—‘ŒŽŠŠ‹Ÿ³ÉÏÖÛáãäååáÛÑ·z4"'*($%'+,+32,44/485411/;=4583)..-.,.466380/-+).*/)14687421¤¤©®¯®­¬©© ›–•“ˆƒyme]SQVcpx€ˆŒ”™Ÿ ¦¤¨£©¥¦¨¦¥££¥¥¦¢£¢šš–ŒŒ‚€ul`YOJKJPUWPUVVXZ^`__^`^`bfa^ibcfg`hhgdihjikiqoiksqmusu}rszvxrttwvs{}|{|z}{y|x}~€|~€~y€~{y|zyz˜±“ifm||{t{xxuv{zx}|v‚zzzzw…‹‰‚†‡„†uyƒ‹‚‚‹Š…’Š•—ˆŽ¢“‘¤Ÿ–“ž¨§  ­µ²¢¡®±°¸¶¹·»¾½º²ª¹½¾»´º¼Á¿»·®´ÂÄÃÂÁÁÀÁÅÃÉÇÆÄÂÁ¿°™mhkkmoksutu€ruvvrwuwvwvvuwsxwrstptqurqqphljlejhifilonz‚„‡Œ‘’”–™˜•””’“Ž“‘‘“‘“’“’‘““š—™š—’‘Œˆ‹ŠŒŽ‘˜•ŽŽŽŒŒŠŒŽŽŽŠ‹‹ŒŽ‘‘’’’ŽŽŒ’”¤¸ÎØÚßãääàÚÑ»‹D'&"*+,'))+.+2.127<=57644<5:2-,(+,))02.932/7//+-/).01/731-($§§ª­°®ªª§ ¡¡š—’’‡ui_VQPXhmxƒ„Ž•–ž¢©¦ª¦¦¨¥¤¦§¦¡£¢£¥¥  ›—”‹„|tr_VONJGMQQVWZZ[_]]^\c\ba`a__bbbflaehbhnjhgengjiempnruqvssxzxrrqvxuzy{zy||}y~y€y|€|~}yzzyw}yŒ¾¨m[Wjmxx}vz|q{}ysy}zyzu{zq~}†Œƒ‚Š‡…~}ƒ††‡‹‰ˆ‹Œ†‡ƒ•‘‘–¡•—Š˜Ÿš›¥´º°¥¥¢¬º³®®º»¿¼±±»½¾À¼·°¸Ã¿Á½±­µ¾ÁÇľ¾ÂÅÈÅÈÇÇÂÃÂÀÀÅÄÁº£}nihmhmjqos~rpspwsusu{wwurtwrospptkkmpkokjkicgdbelnpq}‚‰‰‹’”•––•™–•’‘“’“•‘‘‘‘Ž”‘•–——–˜“‘Œ’ŽˆŠŒŽŽ“’‘“’‘Ž‹ŽŒŒŽŽŽŠ“’‹‘‘‘ŒŽ’‘–ªËÕ×ÞáãÞÙÓ¿™V1$,#'--+**)+.6-395;926=684<865--/+/-43772.)/,//.1./856;6-'" ªª³¬°±¬«ª žœ•‘’Š‚~pf]YHOZery…Œ•˜œž¦¤¤¨§§¥©ª¥§Ÿ¥¦¢ ¥£›“Ž‡‰wneZRSJGNKORVW]\a[]]_c__`bb`egacacc`gicdhbeogjjfjktrrqsvprqrqtrqvvw‚|~{x{||y}|y{}{}z~y{{ssz|¡Ï©gb[ns~yx{„yxy~zvs€zxx|wvt}€‚‚ƒ‡wzŠ|€…………†‡‡‘‹€–“…†˜Š’’›¥š™¤±¸­«³¶µ¯«µº¹º·¯©·¼¿Á¸¨¶ÀÄÁ½³·º¿ÂÁ¿Á½½ÃÈÉÈÿÂÃÂÃÄÆĽ¾ÄÃÀ©veeajijomqorrmsprsotvstusutsponpjmlolmlljkhidfhltqyz{‡ŒŒ‹’‘”•–—“”“˜•’‘“”Ž’“Œ’ŒŽ‹•’”•˜–œ’’‹Ž‹ŒŽŒŒ’‘‘‘‘‘‘Œ’ŒŒŒŒ‰“ŽŽŽ‘‘’Œ‘–”’” ¹ÌÓÜßÛ×Ó¿•W3*)+%,++//.(-+420987;0639;74542('+-3336294/**.0*00876:86+'$¨¨¨®«®¦«¤ž›™–‘Œ‡vmZPJKOTdow„‰‘—š¦£¢¦«¥©¦µ£¦¤¥Ÿ¥¤¥¡¢ž™™‘Ž…†~umcVUPHELVRSUZ_^\]d_ad_gab`bcdfh_befhgbdedhekmlmoopqotsrqslqxssvwtty}{wxt}wx|zz|w}y||}||~z|x~}z—±†i`fosuttw|}vy{v{|„‚yytysuz}~„…‡‚y{‰~‡‡‚ˆ{ŠŒ“•‘‹ˆ˜ œŸ«ª¥¤¦²·²¬¥©¸·¸±«®º¹¼»²¶¹·¼Ã¿¶´¹Â½¶º¿ÃÄÆÅÅÃÀÃÈÇÇżÁ¾ÃÇÈÈû¡ƒmdfgjpijgjnmuosunsustrrrqvtppjonqojhmjknleigjhktrv€…†‹–•’——–š˜–”–•“’’““Ž””Œ‰Ž“–™“–‘”‹ŒŽŒŽ‘•””“Ž‘“‹ŽŽ‹Š’ŽŒ‘”’“’”“•”–‘—®ÄÑØÛ×Ï¿œb1,&&*-./),-+/,,152152/6:77648.,-/.-.12725-.,-)*0+-3:5<>:;($ ¬¬¯®­¬¨¡  žš–…{l^SOLJQYcqw€Š•š¢¥£§¥ªª§£¤¥¥¥¢¢¥¥¢ œ˜‰ˆƒ}sk_SWGIFQNUYY\V\[Zb^_ceaead_cabbcecigecheenklkppmqmpuronsuqptusxxxuuwxyxxvx€}€~zz‚|~}|}|}€x{€€smqspsxxv{}vvuw€{€y|p{z~…}~…‚ˆ„‚Š€††‰“‡†…Šƒ†ˆ‰Ž‹Š—˜–—›©¤•œ«²º¬¤³·¶²¨«¸´¸º³²¶¶¸¿¾³³³·»ÅŽºº¼¿Á¿¾Ã½ÁÄÅÊÊÊüÁÇËÉÅÉÉÆȽ©†qfgnljikiikjkprrrptsosrqqslplooplilohjjhiaghnoqsv…‹Ž“–˜›š•˜–˜••’”ŽŽ’‰ŠŠŒŽ‹Ž•——š“•ŒŽŽŽ‘“’”‘””‘‘Ž‹‰‘‘Ž‘“•‹Ž’’‘”“””–˜”•™¥¿ÊÕÒ̸”Z6'++**--,.**)/,2-<3.272436789002-1432874;7/+,21,1//5;<@38+!«««¬¬ª¥£  ˜š‘‰„uveVQLIJRWgrxƒ„Œ’’™ ¥¤¨¦¨©ª¤¥£¦ª¥§¦§£¢›œ”ŒŠŠ„~tlcQUQEDKNQT_V[aX]dbikfillgbhegbib`dfdfimjgllkmgkqqvstxnorrttuuuuvt{uzvwvxw}z|€}€€wx|„||{†‚smmlrumltvw{|ysyszxx|uuxx~€‚„„‡ƒŠ{Š†|…ˆ‰‰‡ƒ‹‡‡‚u…’—“œž¡¢œ¬®ªª©°»¸¨¤©º½·®¦¡¸¿¿º³­®ºÀ¿Â¾¼¹¿ÆÅýº¼ÄÆÈÊËÅÅÁÁÆÄÄÇÈÆÄÉÉÌÌÈìoaedabhlhhmknkjpqqprnstnomqlpmrjjlkknjfgb`iknqp{~‰””––˜–––”——•™”—•‘Œ‹ŒŒ‘Œ‰ŽŠ…ŠŒŒŽ‘’–•–’”’‘ŽŒ‘‘’”“”’”‘ŽŽŽŽ‘ˆ‘“‘“ŽŽ““’‘’’’“’’š—š—˜ ¸ÇÌÁ®‰S1-'//+-00+./,-/627014500656352,,1-:1869@95753,/.1115=??F;1& #$¯¯ª©¬§¦¤¡›••ˆ…vj_RHKKQX]gpu†”™£§§¨ª¦¨¤¤¤¥§£¤¤£¢ ›™–ŠŠ„~tn^QQGIJLQXWXXU\\^_ehjbadal^afhaddcideeajaglklmolmopwwwkmmoquupwuywxvwxxvzy~yxx|}x{z|zy}||{ž‡qlntrsnr{vxwwro}{{yr{}~~}yx}„Ž‡‡‚{‚‰ˆ„Šˆ”‹†‰‚y{Š†€“—Š‡œ¡‘– ¤¯¨›©­µ²ª¢«±½»®¦®±¸Á¹°§¯µ»ÀÅĹ´ÀÅÅļº¹ÃÄÅÉÄÃÁ¿ÃÄÉÉÈÁÁ¿ÀÆÍÍÉÉÈËÆ´‘la_bddehgfmlkorqqvvoqqprnriphmiilhnmkkmiadlgpqz{†‹Œ•–—š—šš™™——œ–••˜‘‘ˆŒ†ŠŠ‰‰†‰…†Š‹‹Œ‘•“””“’’“Œ‘‘Ž‘“’’‹ŽŽ’‘‹ŒŒŒ”‘‘Ž‘’•”“–“‘–”‘‘”š–›š–³½¶£S6.,+-3,*+*/+-3,,20(42102=<21430.-13@5864.5023)+341.24ECM@<.$#7¬¬¬«ª¨£ž¡›•‘‹…~sf[QKLHOX`enw…‘™™¢ ¦¥¦ª¬§§¥¥¦§¢¢¤¡¡¤œš•‘‹Šƒysi_RLPHGNPSWT_\X]_^fecc`cnrgbdc^a`egbdf^baifijopomoprrpr{ussvupr{qtzxuzqvyxy|wz}{{}~}w|{tx{~–|nsroquxtystrnklzxwwuz~{{…}ywŠ…}…~yŠ}Š‡zwƒ„Ž‘ˆŒ““”’–™Œ…š££šŸ¤³°¡Ÿ««³³¯©±´¼¼¾¹¯¯³ÀÃþ¸¸¾¿ÅÈÀº½¿ÄÈÃÂÃÁÃÆÅÇÆÇÁ¼¼ÄÅÈÈÌÌÈÇÆÌÌʵ’sbX]^bc\efgelmiqspnqrrjnllijjlmprpjlhgedekjnpv€ƒ‡Œ‘‘’•˜œ™—š˜˜™•”˜””’‹Œ…‰…†‰„ƒ…ƒ‡ˆŠ’—•’’“‘’‘ŒŒŽ’Ž”—”‘’‘“Ž‘ŠŽ‘ŒŽ’‘’Ž”‘‘—”‘’””—˜“–“™™œ™› ŸŸ—uJ22))-24-)),-.2351036120:771=932*()/3=>836.3+,1,+:6/9?EJHD62, "4b««­ª¨§¢œ–”‹„}xm`STKKHQXbdmx†Œ’—šŸ£¨©ªª©©ª¦©¦¤£¢£¢ž¢œ–“Šƒ{yl^UMLHFHOQW^VZ]d`df_gdg]_faafdb^ag`cef`ehghmkljmllumqnqwtvptuusuyvw}vywyzyyy|xz}}z{~yy|u{Š£ˆvjovpryvvqotlppvrrwsvy}|||‚|u}ˆ‰ys~„‹Š…„„Š{~ˆ‚„’‡„‰–•ƒ„––“‰Œ—£œ‘œ¨¬¤˜¡«µ´¦œ¡µ½½¸¸¯²¹¼ÀÀ¼À½¼ÁÅž¸¹ÀÅÇÅÁºÁÅÅÆÉÆĽ¼ÃÅÈÇÊÈÂÂÈÌÊËÌËËõ¡p]_\_^\^fbdfilktolinopnjhhdlollpnimfhfdghknvx|…‡““•™œ˜™˜šž˜˜š•””’ŽŠˆˆ†…‡‡„~€‚‚‚ˆˆŒ•“™•”–‘ŽŽ’‘‘’’‘–”’‘ŽŽ‘‘Œ’ŽŽŒ‘‘’Ž”’“‘‹”––•””•••š›ž¤˜‡nP43,/02'+-/(/413*14564472561+02.,+(,/6;:722->3..006679@EAF<*&% $4^¯¯«¬§¢¡Ÿž’Œ€yqdYPMMNNOYchtyŠŠ™› ¢¤§«¨§¦¨¦£¥¢¤£¦¤¡žž˜““‡~yn[VHPJHNSRWXWZ]a[\]ca\ceffccjee]fegaccbekhlmjjompmtqsptpwtpspsrtxvw~xxxwy}|yy}}{y{~}|yyyzˆµ´|looqtvprlmqjomrqrvuyvƒ€€‰zp~†‚yty‹‡ƒ‰‹‹†zy‡‰„“~‘‘‚•‹€•žšŽ›¥¥’œ¡©¬ž ¥¨·¹·¬¯¶´º¼¼¹³´ÀÀÃÄ¿¾³½ÃÄÅü¾ÃÉÇÇÆÆÀÀÂÁÄÅÈÆÆÃÄÇÉÅÉÄÂÈÆÉËɘrnmkcZZb_eagheqlllppoomkjjlljejrghgggagejpmr‚‡“””—š˜š—šžž™˜š–“”–•—Š‡‡…ƒ~~€}z€}‚‡†Ž–˜••’’’ŽŽ“–‘”””–“•ŠŒŽŽŠŒ‘ŽŽ”Ž’’‘“’š’‘–”‘˜•”“•–™žœ›•ˆqP;0./1.,'&0).()*135<=D:6133/11,,*'))07569899<1/7514674=DCD80&" &3Vz”ªªª§¢¤œ›’‘†|tl\UNNPKMVU[hww€‰‰‘ž›¤¡¨¨¦«¦§¨§«¤¢¦¥§¥¡¡ž—˜‹€{qgbTMJGKLRSTZeX```ceefdaihfcchfgbehd`ebefddhkklolohsnqrtrspmrpsytv{yxvuyuxt{{~zw|~~|{|z{~—Æ©tprprtrrtoqjhqtrwzwwuv{xƒ€{n}‡|}xz€€x„~†’ŒŒŒ”‹ˆ‡ŽŽƒ†’•†‚ŽŸšŽŽš¡˜•¦® –›«¯¼¹³²¨·º¼¾²­¼¾ÀÁÀ¿¼¹ÀÃÄź½¾ÁÈÉËȾºÄÅÈÇý¿¿ÆÉÅÆÀ¹¶µ»ÁÉÌÑÒ»­ª£šŠiY[^]`igonpmmrljghnmihjfjikhedadc`ilptv|‡‹“˜–”š™š™›šž¡œ›˜”–••“Š…†‚~x€wv{|~‚Ž“–˜“’’Ž‘”“–“š””“Ž“‹‘ŽŽ‘’”Ž“’’’˜•–‘“•”–”•˜–™–ššŸš{VA/.-*)'/*,4)&)+,0137547556/4.,,..(*/0353966/0/-21264@>CCG<30%""/Sp‹ ¬¬¦¥ ¤š˜ŽwmaVQMRXNPRU]kr{€†‰•–˜ ¤¦¦¨ª¦¦©¦§©£¢¡¨   œš•’ˆ€~sf]THMHINSQTWWUae]fef_^a`fad`ebececedggcejephdkiqkkkqrmsvuxnuvuvx~xzvxoxuwr~wy{v{{x{||zvœ«ƒnrtuwnijnginmrnuyvxxrvzxwt~„~z~}|„ƒ€ˆŒ{z„…†„‘ŽŒ’‰„…|Šƒ…Š‘ —“‘—œž¨Ÿ™—ª±´¬¨®µ¸·»º¶µµ¼¿Á¾³³¾¾ÁÄľ¸¼¼ÂÉÆÆ¿ÃÁÃÅÇÇû»¿ÂÅƾ·±µº¹ÁÄÍÑÔ×ÛÙÖÖÐÍÀžr^TX_`cglkjlodqlkfiffjghmlnhhegberoqtt~…‹’’–—š™šœ™› ›™˜˜˜›—”Œ‡ƒ€xzwrwvwz‚ƒ†ˆ“–•—“““Ž“Ž‘‘“—”˜‘”“‘‹ŽŽ‘‘’’’““‘Ž‘‘’“–“•–•™œ™ Ÿ•iG----+,-(50),')0276372529=5740--,+0,6758D632--,320175=CGB8/('$#'/Ko†—§§§¥¥¡ œ–“Œ„~we]PRoPONIPZbfqz‚†Š“™›¡¥£¦¦¦¦©ª©¥¦¤¦¡¢ ¤¡ š™–†€}rh_VOJMJLSPVXXX^_^\ldbbe_b_b_ddbfedfccfbkdfjfmpimpplstpsxvwouqorrzytvzu{z|v{}{zvvz{€ƒ{z}{Žªtosqrrjmnpkhlqsqz}uuxqzw{r{ˆƒ{v~x€‚‹†}€ŠyŠŠ‡ƒ…†{†’”u…Š›’ˆ’•“˜¢ ‹›¦¶µ¨©­µº··²²´¼Âúµ²µ»¾ÀÀ¼¶µ¿ÄÆÀ½ÁÿÈÇÆÅþ¾¾ÄÃÂÀµµ°¼ÆÉÐÒÒ×ØÝÛßâääãâÞË¢kVY[[eflnmjmkofgieakhllggeffge`bhkmtw†ƒˆŽ’—™—œšœž›š˜š•™™•”ŽŠ€€ywurosvrv}€„‰Œ“™“”’“‘““‘’—˜–’‘‘Ž‘Ž‘Œ‘’“‘ŽŽ‘Ž”“‘‘–”‘˜—™™™™žžž–ˆpU6,/(*00(((,)+(,33:/3688861021*),-005<3:;313/502511468AMM@8*&&"#+Gc}• ¨¥¥¢¤žžœ”{m^RNPPUUUPQY\gvx‚‡’š™ž££¨©©¬©©§«¦¦¦¤¡¤¡Ÿžœš‘Šƒztp`ZPFJOPLV`ZUZ[_ahrdcfbciaj_afbidbbieeeelgkekponprnvvrtrrsooquryrwxzxuysxz{{|zzx{uz}y{|}™¤~ooyomklnkholmouvvxursswtj~„zsˆ~vy|u‡‰€yƒˆ~„ƒ…ˆŒ‚Œ‰w…’–ŒŠˆ‘’ŽŸŽ˜œ˜– £©­©œ©¶º¿¿°°»º½Äò©¶¾À»µ³½À¼ÂÉƶµÁÅÆÈǽº¿ÂÂĽ·´¹¹ÀÆÑÒÒÔÔÖØÙÛÛÛàããåãåÝË“]ZYYY]ejgfjlmhefcffhhhijeheja`kjipmw‚‹•••”ž š›šœ››š–™œ•”‹Šƒ{vxjklpsou|~„Š’™–•’‘‘“Ž“‘–”’‘ŽŒ’’‘’Œ’’“ŒŽ‘““’‘“”—”–—˜š˜˜žŸ—ŒwX;32)+/04-'*,9''+.421645453.2,,0+.+20;958876//-08224<99GOJ>7'%),1;Zv‰š£¨§§¢ž›˜—Ž‰‡yrhZQPXUWZTRJXagm|„•”¡¥ª¥¨¨¨ª¬«©¦¦£¤¡Ÿ¢š˜‘‚zth`WPJLJQTSYZXX^efbjb_g`ccfhb\efdbcggddfgffklhirnsoyru{~qortqsnyqsp||ww|xu}~yy{|wy|{}{‚‰vvrqpnkmdgjupiq|w|yvusxqk{‚{}{„zvyƒƒˆz‚…xwƒ‚„Œ‹‡|ŒŒ„~†…ƒŽ‰‹Š–”“Š–’‰ž£ª¢œ¦®®·¶®´´¼ÁÁÁºµ¶µ¾ÀÀ»³²ºÀÃÇƵ¸ÄÍÆľ¹½ÂŽ½²¬µ½ÈÈÏÐÕÖ×ÔÔÖÙÙØØØÜÞâãäæäܽ{VRSSZaaeiiieeagcdcecighehda^cgilmlw}…‰Š’”—•–žš››—ž˜™™—–˜™—‘’‰‰|wsnfafighox{€‡ŒŒŽ••––””’’’“’“’’•“ŽŽ’Ž’‘‘ŠŽŽ’“’•–—•”“——˜Ÿœ‘|[?9.--+++--%&/2-.154354433413,*).)*+608?:1-28/11.1006:AHOVM;3)%%1>Vlƒ— £«¢¢£Ÿ˜—“Žˆ~un`_QMTSUVVXQW^js~…‰‘˜šŸ¤¤¤©¦¥«§§§¨¨¤¤¥£¡£žš•’Œ‹}{rk]XVMKCLMTRSZ\_^_`\b`[cacggbbd^acffjefbffiilllhqonqlpsvwowxout|zwy{xww~y}w‚{}vwwwz‚~|€Œ†|zsmjojnnijpomosutrqswro|{~}}x†yw…ƒ|z~~x‰‡|ˆŽ„„”•x…‡†‚‡š™ŠŠ”‘ ’•Ÿ©¤”­¯·´°¬²¾¿ÄÁ¸±­¼¼¿½¶°´¿½Á¿¿À»¿ÂÄÃÁ¸¶À¿»·¶°·ÀÉÐÓÓÒÓÒÖÚÖÔÓÒÖ×Ö×ÙÛßãâææäÕ£cSMQV]adcihgbehgfdfghcehef_fdjhmrssƒˆ‰“”—œ™™—›š™—™˜–Šˆ€xplg]aZcehry‚ƒˆ‘—š–“”•Ž‘Œ‘”“ŽŽ‘–‘”“Œ‘‹•‘‘’•’˜–—–™ž˜Ž„mH.)-0,,-1)**/55.1-1:>.12<042538.-(*.3497:00-2//.,2136>EKZRI=4+,1CXp…‘—Ÿ¦©žž¤š——’…„yqkYSPRSSTPTVTYcjq~‚†—–›œ¤¢¥¥¨©§¦§§«§¤§£¥£Ÿœ›˜”ŠŠ~xshZWPKKDKPUZW\]^Y^dabagf^\^aiciafhgajfcbhhhjknnqplnpnssrroorqyxzr|‚}z{{wyw|zxzwv{w|~~„Œ~utjmphmmrmnpnxruw|rspowzx{|x|rv~|t†‚€‚wz„ƒˆ‡‡{†‡ƒ}ŠŠ†|Š—¡}Š‘’•–¦¤Ž£©®©ª¬µ»Â¾±¬·¸ºÁƶ«´¹ºÄž¹´¸ÂÄÆƾ¸·»½½¶±¸ÂÃÉÓÒ×ÓØÔÓÒÒ×ÖÖÓÓÕÖ×Ú×ØÜàãâäáÞ½ƒZJSZ[\cadfhekfcchhffddaeg_^[agooqt€„‡‰•”–™›œš™—œœ™˜››šœ™–“Ž†zqea^\\UYbomwƒ†‹Œ“‘–“–’”Ž‘Ž‘‘“”’‘‘“Œ‘“‹“””’•““’“”•’”˜–‘™—ž›“oO6+*23(,9&,,%:+1.31;972264876/./.')05A6<<71-(120++318=DNQQOF=/'1FJHLBAB=?FRgxŠš•–š–žšš–”Ž‰~vi^VQPSWYVU[SXVV\_gpv}‰Ž—›ž¢¤§©§©¬§ª§§§¤§¤¤¡›™”Œ‰|uqie]WSKOQSVTWY^]_c_]cdcfag^be]ejohhiehffajngimnnporpsvussouvsuysuv~swzz}wyzx~{|}~€{x‚„}wnelmmgqqimnmlt}sxyvm|~‚|}tx|{}x|rx€sk‚~‚…{„†‡‚”Ž……ˆ‹”}{ŒŽ…~…—‡„Š’•Ž—¥©–™¦§®©¤ª´ÀÀº±ª¹¼¿¿ÄÄ»½¼¿¾»µ®©®­ª©³½ÄÇÐÓÔÕÓ×ÐÒÑÐÑÎÐÒÑÍÒÑÏÐÐÑÓÖÎÍÎÐÓØÙÖÜáâÞââÙ»wUOQWVW\`[\]fbadbefeca_cccbaikrq‚ŠŠ˜•™ œž™˜—˜˜—žœ™˜—–’Žyi_SG:@>>NZemw…ƒŒ““““‘—Œ••’—‘“’“ŽŽ““ŽŒ”Ž’•’”–œ—˜ššœž—‹tU6+*$)*,())(,+..<84<6798267744..%*-3357;832),.+/.4443?=FORPC@8=K[jw†Œ•–’•–˜•¡••”Š€tneXOQUUVWY`WWTQ\\Yepv€‹’˜š¡ ¤©©©§ª«ª©§§¦¥¦¢§š›–Œ†xsjaZUPLUKQW\X]]X\\[aaebafcaebcfmhgeegdbefgfililjjnqopqqtrrutrsusuvwyxzy}wy{{|y}…z{}‚utiijfmlirkrp{qyuqpsry~ysz{u|yxux}uqoz|ƒ‡„ƒˆ~ˆ•ƒ‰Žƒ‡ˆ‚Š“†‡Œ’‘‚’›§”•¥«ž­¬½Äµ§¥±¼¼¿¶»³»ÂÁø¥Ÿ«©¥©µ¾ÉÍÏÐÛØÒ×ÒÓÏÎÌÑÐÏÐÔÓÐÏÏÏÌÍÐÒÔÔÓËËÎÕ×Û×àâáßáàÒ¨mWJPOVVaZ]c`b_^_bjf^ba]bY`dippr}…‹’—š˜ ššš˜˜œ›šš›—š™—‘’Ž‹„wfaOA599;BV]rpz}…ˆ‹“””””‘‘‘’’”–ŽŽ‘–’‹‘••Ž’‘Ž•‘‘“”˜šž›€^8**$$&()&)'%.)/-425?3B6859753,)&&.246588.0.)58,3;BMI51/*,%(,.-5DA?=FGDKUKKCQZk|”–™˜”Ž‹‚{reYUOVXWX[U[XXSVXU\_jn{Ž••–¡Ÿ¢¦¥¨¥©ª¦£¦§§¦¦¥ Ÿ›—“•‰‚ƒtqj_VTNKJMRXUX\\Yaaca`^f`aeme`gcmfgjdegagbgdlkoqjoniovpwypsuvvttwzxvzxx|{~}{wy{{{…€€wmlspfofgqlopsusvlpmztwyuwqsmq€{lstpqvwsz}|…ˆt†‡Ž…†ˆ‰|€Ž’‡‹‘—†…‹‹––™Ž„‘™™—‹ž£©¤˜¤­°¸¹²ª®¯¸¾À­¥ŸŸ š¥¸ÃÇËËÔ×ÔÔÔÏÎÏÎÐÎÍÏÊÇÏÐÒÏÍÍÏÎÑÉÊÎÏÎÎÐÌÒÕÐÍÌÔÖÑÔØáäßÜÞÙÅ”\JRMOUXVW\b_^^]^]_^a_bg`hnqty†‰Ž“–˜™›˜›šœ›œš˜•–•š—•””‘…„}{mkSI@4.05;GW`lrw€…‰Ž””—˜•’’•‘”’‘Ž’‘“”•‘‹•‘‘‘“––šœœ™€Z=25,'1)'&,.+1.5;=:3590=46822/-0.++5<>;:432,-3030>6:<<>AGCKPIJMXhs‰–™—œ”Ž‰ˆˆˆ†}rc[YSSVWUZYWZZ[WVYUZajpy}‰“˜•›¤¥¥©§«©¥¥§¦¨¥¥§£›–“‰‚€tok`ZPOIIMTX^Z_]^`_aa^]dibghe`jjhghbff`gebfimmopjjkpnrqyrstuntvrzv~~}z{xys|yyvu||‚{thokgjoiipjktoqtqkvy}zxquwrnv}woqsrmxz|vw{}ˆ{r}‹ˆ…‰’Š‚†‘‘‹‰’‘Ž‹ŽŒ’‹˜–š’Œ“‘“–›š¥¨—•¥¬³½½¬­´²²À¿±Ÿž›˜ ­µÄÏÐÏÏÐØ×ÐÏÏËÉÈËÎÐÑÐÆÇÐÐÐÎÎÏÍÏÎËÉÎÐÑÎÊÌÏÒÑÑÕØÔ×ÛÞâáÞÚÝØ°pTNOPTTY[ZYYZfdbd_aa^_b_fhps}†‰Š‘•˜™œžššœš™—™™˜—˜•—•‰‰€|se]Q93)*-4CL[flqz†‰’•”——“‘Ž‘‘‘‘ŽŠŒ‘”Ž‘“’‘‘”““˜‘——œšœ›~fF0*'<=IF;),*+-4;6?756689;1746/-3..,879=35/3*,-0-)7?9;:99.+,255375341668;71/,/-)1468:862+1-0840.8?8?BCKNJKER\dpy†’”“•›š˜…‰–›‚‚|tf^OTX\W[]\ZV^ZRSZVXZ]hq}}„‘™—šž¢¥¦¥¤¨¨«¤§¥¥¨¦¢¡ž ™•‰…}{pcb\PLNGKTXTWZ`a_a``^]cb]bhabbcdgcgc_dahcekjkilkjnnktltutsurtuvxvxy}v}|zvxy|y}z€~tjkopghonqqynqrtqlvxvzxtutuvzvlzxkdgtrs~‚z}ˆ}v‚†ƒŽŽ…ƒ‘•“‰†‹”Œ„†–’—Œ’•’•‰‰‹ˆ“–••ž ¦±·´®©·¶·³¬£§¡—©½ÆÉÌÌÇÉÍÏÎÌÇÌÎÊÊÏÑ×ÓÎÐËÉÍÍÆÌÍÏÌÌÌÍÊÊÉÉÇËÑÐÔÏ×ØÙÕÚÙÙÛáâäæáÝÜÛÁŽYKLNIVRRUXZXZUXYZ[]`^digtw|…‹”–ššœ —›š™˜œ›œ˜˜š˜’˜’”†|xg]N@0-)--:FTbcjsvƒ„Ž‘‘’•—˜–‘“Œ˜’‘Œ’‘‘‹–’”“‘‘’“••—™ŸŽvZ>+33+*1--.--).1/47238045499800+-,/3=8;30///-4/472155<=I?EPKUQXcmyƒŒŽ‘™”––˜”†„Ž— {{xjcXVUUS^\]a[VZ\[X[XTWYdo{€ƒ”“œ¡ ¥¢¥£ª©§ª¤¢£¡££¤¤ ž™—‰…wyoe_]TNHMQVXZ\]`b_adgc^[f^bea``efdZcecdcjfhmihelinuqqtnyttvtutuvzwsztw{zzvzxy}{ƒtmokjmmonsmtoowoplvvvztszv{wvsusvoimuup~~z„ƒ‡vƒ†…€ƒ“‘‡’ŒŠ‘““ŽŠ•–““”‰Š‰‡ŽŽŠ‹—˜Š‘¡ ¬¬¦£§¶®º±¤œ˜—‘–±ÄÉÍÍÏÏÍÉÇÊÎËÅÆÇÍÓÓÔ×ÕÎÑÐÊÈÊÇÆÊÆËÉÈÆÆÉÉËÑÑÖØÚÐÔØÙÓÕØØØÞßßäààÝßÚ¾‚MGKLNOKUTUTZUX_\[Y[abgirv‹Œ–˜š›žšš–›˜——œ˜™™›’‡‡~xj]J61)%,189R`_hkw|Œ‹’”–”•”’“‘Ž‘ŽŽ’“ŒŽ’‘Ž’“‘‘‘”—––  ˜‰dA*(0&*.'3-&*)0*6436474.38430./-/-125:=DB..025:25/13/4B=CHJPQTXdpz…ŽŽ’”’•˜™–‰…Œ–Ÿ£zznbVSQUVSYic[][\[WXSVTVcbpt†‹’’™šœ¡£¥©«§§§¤ª¥¨§ ¡ œ›—‰…zljaWSOLUNQT\^^eacddfbfbf__haa`ghg^`kfcb`gjlmihknknmywmupstsrrytxvxwzy{{|}{z}|ƒyuwqjljjor|rrmmn{rrttyvrtttyrcpvsiopqnx}yv„‰„}v…‡€{ˆŽ‰„‘…ƒ’•Ž“‘š”Ž‘š‡y…•‹†Š“••Œ‘¡¤­§™£²·°«¬  ™Œ‚ ªÁÍÏÏÍÏÐÐÍÉÄÈÉÌËËÌÙØÐÏÑÒÍÊÌÉÈÆÂÄÀÃÉÈËÈÆÐÏÛÖÚØÖÔÐ×ÖÕÏÓÕÕÚÛÛàääÞßãÖ¨`URJJHHQQVOXXW_ZZYW`_giqv‚€†’——˜œšžš™œ™˜˜žœ›—›”’Ž‡€€q`XN0&$,-15DOdafuyˆ‰ˆ‘”’––˜‘‘‘ŠŒŽ“‘’‘•’‘–’–˜šœd?+)*&#)0*,,00117;25:78396552&.)%(-08<7;21),)4//3301:5=7;@JJQ[irzƒ–•š”’‘”‘ˆˆ’š £££kkfUPSS[XW[[ZX][Z[VZWPXT^dow‚†Œ‘’–Ÿž¢£¦¤¤§©¨§§¥¤¤¥¢žšŠ~wrlwYRHGPWV^YY_``eY^bheh\cadcbf_dafkhcfhaejgdfejlnpotmquvzyyorrtuuwywzywzy||~‚…wuxssnkrzokuvqpvkpstuxzty|xqrsuooqrrsy|wv{„|s‹‹|zxˆ‹‚‰Š‹†z„‘–“…”’“”“—”ˆ„€Š‹…€•”‡œž™”›¨­±·¥›‘‰‹ž¬½ËÉÈÎÎËÊÉÊÉÊËÉÈÈÏÓÐÉÇÏÑÍÈÇÊÉÂÃÈÍÌÄÉÎÆÑÓÑÉÌÌÔÑÏÌÉÏÇÊËÌÍÏÍÍÑÕÓÓÖØÙÙÜßÖ¸žz_VPPLJQMMUXT]YSSV_akpu|‚ˆ‰Œ’•—›š˜™››ž˜–›–›•——”Ž‹€~tcXK;/'/@5,*:O\`jjt…„“—•””‘“ŒŽŽŒ‹Ž”’“‘•’“™”š›œ•‡lK96-&#%%+0+,1/1;686??631942,--+&%1159<<3-++285450578@H;=7@FOUcuz€Œ•’•—–‘ŒŒŒ“˜Ÿ¡¤¥cc[UTWWSWX[_][_[]]WVSR[\[ejz~…ŠŒ’—šŸ¢¢©¤¦©¨¦¨§¨£¥£¨£ŸŸ–™Ž‹ˆƒ|nkaYPOKOPLS_]X_baaecdagZhddcac]gh`cbddifjigjjilmjroqptr}zsswssyuwwwyw|x{wu~‚‡|ssztovonzkioqnsojoystztpxoinrqn}zq{€ztt‚y||y…{y‚ƒˆ}ŽŽŠv‡‘‹‹}Ž™‹‘””’‡‹›‰‹‘“‰‹™”‘¥¬©²©›š–•¦¿¾»ÊÎËÉÊÇÉÉÊÌÍËÍÌÌÉÏÏÇÂÅÊÉÆÁ¼ÄÅÄÅÎÓÍÊÓÆÌÓÍÈÇÃÇÆÄÄÄÉÐÍÌÏÏÓÐÓÓÔ×ÖÓÔÖÚÝßÞÙθ™~jULGKJKLMTS[YV\a_km|}‚†‹Ž“”˜œ™š›™›˜œ–›™™™›˜—“–•‘‰‚tdVL;1-*#)9A>;T[]dnt€ˆƒˆ‘““–—•’’‘ŒŽŽ’Œ“”•‘””š™ššš™‹vZ4),,$%)'&'(,.83:;8<<5-4461/,-30)*2;>;791,,-.5557;:;FRdnˆŽ’”•˜•–“‡‡š™ž¢¤¢¥aaWQUWXUXZ\b\`[\Z^[XVYUYggkv€„ˆ“˜š ¡¢¤¤¥ª¦§§©§¤£¡¤ŸŸž˜”Š†ƒ}{oiaZSNLKNMNXYa_`_aadh`jbfdgaacc`dcchgicnhigjiqkgmolttr{v}twstsq{u|y}zw|wyz‰ˆypqrprtyvonnoqlopoootvor{tkp}qyr{xk}rm}zw€Š…{~‰‰„zxŠ‰“…~ˆ‘‹ƒ~…—Ž„–”Œ…‘ŒŠ‘Ž—–™‹˜§«¯¤•Š|z›¯·ÄÇÁÆËÎÉÉÆÀÅÉÍÏÐÑÎÊÄÃËËÉÅÿÂÆÂÁÆÌÆÎÔÐÉÍÄÄËÆÅÂÄÆÇÊÈÊÉÍÒÐÓÑÒÔÓÓÑÕÔÓÖØ×ÛÜßãâÝÍ´’aGDCHJLIWWSWUX_ceow}ƒ„Š•–›ž™››šœ£›˜šš™—š˜“–•‘Šƒ|rdYS73*-(-=;30;O]`hzy|ƒ‰‘“–”““’“ŽŽ‹ŽŠ‘Ž‘’–‘“”™š™›”h=')%))%(('022.=D777656937291-./+2-17?994/0**38924943887:==FFXhxƒŠ‘“•š—–‹‰“šž¢©Ÿ£¥£ZZTSTZTY[YW_]a[ZY`[ZUVSW\kjxz‚‡Ž™”™ž¡ ¢§¦§¦£§£§¡£¤¢ŸŸŸ™–‰†}yqja`SJHKJNLU_W\`_e]b_bbd`cha_da^cccadeahblhlhelllqmlrqvusqrzprpyttvw~{yy~~ˆxxpjslmmrwuuqpmpmsputruwzuvrryx}z|z|vuwyxrz‰Š…x}„‰y|ƒ†Œ’ˆŽ”„„“”‹†ŽŠ‚‹‚z‡‡†Œ›‘‡‹š›©ª œœ‹{„¢»¿¿¼ÈžÂÊËÉÊÄÁÌÐÑÑÑÏÊÆÁÃÊÏËÈ¿¾ÉÍÿÎÇÍÒÐÈÆÁÆÉÃÅÈÏÑËËÎÈÌÏÑÓÓÒÐÔÔÓÔÑÔÔÕ×ÖØÜÛÝâáÞÙÂ_NRNDGLSMTNRXcainv|‰”“”›š˜™–œ›œœ™—™™™œž—‘Šƒ|qdXS;3.-,.*"+03?VYblv{ƒˆŽ•˜—•“‘•Ž’ŒŒŽŒŒ‘“’’”——›™œœ“‡lL8,.-%*%')',1-:29;>7::977750/*+&..12;><50+0,1014:37/77:@EHMQRQVX^ahkr|~†‹Ž“š—˜ž™š›—ž™˜š˜–›œœª™’‹‡„ymfYT>0(*&',+(20>FP]erw}€†ˆŠ“—“•’’“‘ŽŽ‹Ž‘”Š’‘“•–•˜™œ›–‡vY4+%+(%(&)/+++1=724;7D:8822497+,'028B::60-+1:/,:76;267<;?ACHPZm~Šˆ’“’—™™Ž‹”Ÿ¡££¦¥£¢§ZZUUUZYY][[[ZZ[\_YYVTXWZ`dqtƒ“—šŸ ¤¤¦ ¥¤¤¨¥£¦¦ ¤¤ žš•†|yrlb]SPKMIMVZZU[b\`^Zegeabd``dddaceh_fhlpefdgjilmonnoqqsxrvtrvtvtuuy~tuv|x‰‹‚tpjijninntyypnwspnmommostzqrpvtpz{ou|sqzŠ‚ˆ~Ž|x€ƒŒ„„‹Žƒ„ˆ‹ˆ“—‹ŠŽˆ‰Ž„‚‡…‰†Ž–•–‘™ž•Œ}€›¯¾ÇÈÇľ¼¾ÈľÁËÏÉÅÀÄÊÊÇÈÈÆÅÆÃÂÊÎËÆÆÒǹÁÅÅÂÁËÏÏÏÌÎÍÌÌÍÐÎÏÐÍÏÏÌÒÓÐÐÏÓÓÓÓÓÔÖ×Ø×ÚÚÛßàáàÜÅœxUCFHIHORNUV_hntz|ˆŠ”•˜™›œœššž™™—™——ž—›š‘‹ŠƒxrjYOA5=22+)")+54=OWbht}€…‡Š”’••‘“Š‹‹‘ŒŽŒ‘‘”–”•–™–›˜’~a?.%#&')+%(-,.-//5<;9878857735--,..278663-.231./8445?;0;3:9>P]k{†Œ’‘ŽŽ“•—“ŒŒ•ž¤¤¤¤£¤¤¤£YY[QS\Y\`\YbZ^]Z^_\WVXXZ\for}„Œ‘’—žž¢¦¥¦¦¦¦©¨¬§©¨£¢ Ÿœ™–’‰„}~roc_WNJHMOSVW\]_`_afc_cc_^c_bffabddeghgachhegpmmlqpoqvvwuvyuwtxuyv{zwyxz€‚{ulotpfjopnrtrotmpqluqipsqmqsutwtqvy~wq|„‡‹ƒˆ†‡xy‡‰Œ……•”…€‘“‰‚Š™‹…‰‹Š‡ƒ…Š…~€‹‰’„„’“Œ‚ƒ”•…‚‡§´ÀÈÆÆÇÄÄ÷ÂËÅÁ½ÃÇÆÂÂÂÇÇÅÇÃÅÅÆÇÈÎËÄ»ÇÅÂÆÍÎÊÃÅÎÐÒÑÍÏÍÌÍÐÏÍÒÑÐÐÐÎÒÑÑÑÐÕÓÖÎÏÔÖÖÔØÔÔÙÛÛàæÜÅ—aA@DCGIONWY_cks€„‰Š‘–™›œš›™šš›˜•—š˜¢˜š”Œˆ~xmf\PA4-+1*($(*.08FWZjhv€„Š••—’–“’‘‹‹ŒŽ‘‘Ž”˜••–˜››—“‰qH-3(#)%++'+)7/5/5B77935078:60/3.2.7<:@G;6.,.9=145343742688>M[qz…“’Ž‘““Œ’šž¢£¦¤¨¤¤£¢ZZWYW_]_[^]Y][b[VX]XUZ[\bgls€†‰‘”•™ž¤¦¤ª¦¦¦¦ª¥¤¨£¤¢Ÿž›”ŽŠ„~|nlbcWNIFLRQVR[][`[^cd^decifefdfhbfcdgch`dgdhkjknrnnpsuruuuswxtzytsstwxy’‰xwlkrojhdimnvvvrnqxpnpsuwriqqovvrmy|qvv‚‚………yzŽŒ‰Ž‰“”ŒŠˆ‹“–ˆ‚‰“‹~„Ž‚ŠŽŠ||ˆ‰‘u€‡{„’Ÿ»Ã¿ÁÄÅÇÃÇÇÁ¹ÍÊļ¼ºÂÿ¿¿¿ÄÄÆÅËÈÉÆÈÁ¾ÅÉÉÉÏÓÑËÁÄÌÓÓÍÏÑÍÍÍÎÒÎÑÓÎÐËÎÏÑÐÏÓÒÐËÉÓÔÕÔÔÑÐÔÖÓÜäãÙÃ}L=B56?FGLTZYems|„…‹‘———š˜š™›™™™›˜˜™˜œš˜“’Œ‰€vqeZOF3/,(++%&&-)/5:LX^i{yƒ…ŒŽ’“’‘•‹ŒˆŽ‰ŒŒ‹‹‘””””—›—“‚c@..,()-.0*)--5.2294;75/346H4400,3254<23-,**/0142?@74/3333;FUgz„‘–““Œˆ†ŠŒ”›Ÿ¡¥¦¤£¤£§¡£UUVUP^[^_\`^Y\]Y^[VZWW^^_cu}„ˆ““›Ÿœ¤¢¦§§§¡¦£¦¢¢¡£Ÿž˜—‘…€ynh\^ZMLOHKRR]]^a[a_cae]c_hdkihdd`cbebbdldbgghrklomlsoosutwtyyvzwuoossr¼š|rfe^njfbklckpossusvljtoksprtxtlmwsxw}wvx~Š„~|…Š…‡Ž–Ž†Œ’Ž‰…†Ž•‰†”’Ž‚‰‰…„‡Š‡yƒ‹ˆŒ‚‚„ƒ®°³²´·ÄÀÃÉÊÇÆÆÈÁ·¹ÅǼºº½ÅÃÿ¾ÇÄÀ»»ÂÇÇÎÑÎÍÎÍÃÈÑÒÐÍÆÆÏÓÍÍÒÒÎÍËÐËÐÐËËÊÓÐÓÐÖÑÒÑÏÑÓÚ×Ö×ÖØÓÒÙÚ×ÜâÖ§[;96>CKYanv€€ˆ‡”˜™•”–˜–™˜š–—›Ÿœ› —…}qlcRD>83-,)(/0*,&1*%(%(-5COVe†§ÃÃÉÒÚÚÛÙÐꜫ³ÆÅ«•’‰r\6,+''+/-+;453/7608:6721.7489=84/901;846-//775=4172251.&(-Ni›ÀËÉÓÙÞÚÖÕÕÏÉ¿¹ÆËÒÌÁ©“Y@/.-.**,102.)116828489678:@B;:71<9540.60,2/0398<920-./,,+7Lar…“œ——Œ‡‰ŠŠ–›¤¡¡¡¡¡£¡Ÿž¡ ž ž¡ZZac[X[[^ZZ\VWYUWTVVSUSW[fkv‚ƒ‹”–—œŸ¡¥¤¦¦¥¢¤ ¥¡¦ ¤¨¢¤š”“Š€~|mh^XSFPKRRS[]^Y``^^\[abf_hlbcdibeb^bejiixqpjnlkihokqnootrooqrlkjj„ÅÓ¦—sebdpojdhjjmnmsmgptosvmillldp}{usu€~w|†„z‚‡‰€ƒ„ŽŠˆƒ‰Œ‚vŽ‹‰ŠŽ~}tn†€~ytmkr†›Ÿ¤«¹²¹½½Â¶°ºÃ´³´¾¾½½¾¿¿·²´¨¢©¶µºÅ¾¾ÂÃÃÆÉÅÄÁÃËÉÇžÃÌÊËÅÌÎÍÌÈËÆÉÊÍÈÆÍÏËÈÄÅÄÇËËÉÈÌËËÍÐÐÍÌÒÕÓÑÌÊÊÑÕÕÏÐÓÕÖÖÙáâáãâßßÄh35CJ[^km}ƒŠŽ“—˜–”——“›š™œ›˜™™˜˜™›”ŒŽ€wc_UH953()-.-,+.-&"&#$#&2Iq¯ÇÍÓÚáÛØÓÏÍÃÂÆÍÓÙ×ÙÙØÏ°qF/*+,,3**8C7*33=;:65753485:>CB8422;85:3.1.-3626<7710,++.7;L[sˆ——–•“‘Ž‹ˆ‰’›˜Ÿ¡¢£¡£ ¢¡žžŸ œžŸŸ\\`VX^XX\ZWXTV[]TVSTUUTUZbjs€Š•˜žœ¤ž¡¤©¦¡£¦¥¡ ¡¢¡Ÿ¤¡š•“Š€|ypfZRPIJQRPPSW\\^]][_```cca`^_\b`ca_`aehfchggkqkmookppwjpppommlkdlŸÓÏ¿¡|j_aiiekhgekclirvqquroklpoifpyzqn|€y|}}‡†‡ˆŠ‰€‚ƒ‘ŽŠˆ…ˆŠ†Žƒndl}xrpqlw”¤°©ŸµÂÀ¾Á¼¯¯¹´¯¯¿Å¼ÂÁÆŵ¤¦­¬¼Â»½ÁÁÁÀÅÅÆÇÊÄÀÆËÊÄÁÁÊÈÊÄÄËÌËËÌËÇÅÎÌÆÆÆÆÂÅÆÇËÓÒÏÌÆÆÍÍÐÐÐÌÑÔÑÔÏÇÈÌÒÓÑÐÑÒÕ××ÜßâââàÞÓ”C:ANSYkw|‚‰‹’””————›–š˜—›˜˜™ž•—™™—‹‡€{si^RI460/1+-1),+'($%#"'2A|¸ÐÒØááÕÖÐĹ½ÃÍÑÔ×ØÕØÜÝÝÊ”?**(+,.*+*-.*/,4:;316663521538801664861,5.7165<8/.+(%'278NXl~‹™–”’‘‹‰‡Ž—™ŸŸ¢£¤¡¤£Ÿ œŸ ¡›ŸŸ ™ ¡XXX\[^XX_U_XVYV[U_ZWSXXTYdioyŒ™ž›¢£¤¥¦¨¤¦¡¨¤¡¢££¥£ –˜’Œ‡ztmb`THFGMOPOUX\U[X]Z_bXd]]]ab`_^c_affh`^egcehjnjlpmnrwqnqnrnmhelby¾ÙÊ·œuk]dgmejaljinhlqvsxuoqiyvlkpxvny{yur„…„‡‹†…†ˆ‰ˆ†Œ…~~{‚†ˆŒŒŽ‹‡}nqx|~xqqpo~“®«²®¥ª°ÆÇÁÁ½»²­¨¯°¬µ½½Æ¾ª¦«µ»¸·ÅÀ¸¹Â¿ÀÁÄÅÆÉÊľÅÊÅÃÇÇÆÉÃÃÁÅÌÌÍËÉÃÇÌž¼ÅËÍÐÊÈÐÕÒÏÈÅÈËÍÐÏÐÏÏÒÓÑÍÈÐÐÔÒÐÍÒÕÕ××ÛàâÞààÚ®T5?GQ[hq{‡Š‘–˜˜—™ž˜››—››šœž˜˜››“ŒŒ~olgRG:/2.-//-.'(*(&3&'-F…¼ÓÕÜÞÛÕÏÄ»¸ÁÍÐÐÑÕØØÖÙØÚÚÒ¸P"#%(/+1.124*195>A=4:89>.17064/=59779<440053<6E>5.+'%*-->XixŠ‘”™–•‘‹‡’™œœ¡¢§¡Ÿ¡Ÿ¡¡ ¢ žžŸ VVXYXV]]Z[[ZY]\^\b]TTOVQV`kuy‚Œ‹’™š›¡¢¥¦¥¦¤ ¦¤¦¤£¤¡¢Ÿ¡—˜Œˆxsga\PFBCJPOSTX[ZUXX[`^]__^a[_a__a^_dbe_fimhghekgjjoikmlolppjgeadc‹×ØÉ¥’{mf`gnifdgmmnnrlpx|qgoluqwtoiu{ztniz„|‚~‰„ˆ”ŽŒ…~~‚‘‘‡€v|ƒ‹‡Š‡‘Š}xnoy{qrnsqvŠ™ž«®³±±¬¯ÀÉÁºº±¹¬ªª«°²¹ÁǼ­¯°¹¹»ÅöµÁ¾»¼ÅÆÃÄÄÄÇÈĹ»ÈËÅÅÁÂÄÈÆÆÂÆÎÌÉÆÃÀ¿ÀÂÄÍÐÎÑÍÉÊÏÐÐÎÈÃÈÌÌÐÏÎÏÎÑÒÐÑÎÒÒÑÓÑÒÏÓÕÖÖÞäÞààØÃx@=ILYanv‰ˆ’•˜š––——šš›ššœœ——œ•–—ŽˆynkaVI;2*/).()'%%$'!%(.O—ÀÎÙÛÜÕÑÉ·¶¿ÇÎÐÒÕÛßßááááÚÓÔÈp&&*0,-(1//01247774703AAM73,3415646683520057D9465162=7>96:;2333074;5003/:7493750-')*.DWm€Š”™””‘‘Š‹Œ”™Ÿ§Ÿ§£¨¢ ¡ Ÿžœ¡žœŸ›šž Ÿ __WY\ZXVZWZ[Z\ZYXZYVUVUXV_hr}……‹‘—œž¡£¤¥£££¥£¢£¤££§¦¥Ÿ™”†…zth_TQEJENIQNZSUZT^[_^``faab_]`]b_^Zb^ededhlijnkljjhjjltjnoskhfgmyÃÚ̶§Ž}ohd^akfjkirqhotkkmxtqrutuuyswsy€{s|‚{€ƒ„‚{…†‡†‚„Šxsy††ˆˆˆŠ†}y|„ƒxnekip‡ Ÿ«©¤¦®»»½·¦¶¿·°ª¬±²³´´³°°Ÿ¡¬¸¹ºÃÁ½·¶¿¼³²¹ÂÃÁÆÃÀÀÂÄÆÇÀ»ÁÆÇÀÁÄÁÅÈÅƼ¾»ÂÄÉÇÈÉÈÌÌÏÎÐÉÉËÏÏÍÎÊÊÊÎÍÏÐÏÌÌÏÐÒÐÏËÊÏÒÒÏÓÓÖØÙàâãßØ¿sBCNVbjq€†„Ž–“•—™—–˜›™—˜—žœ˜–––•ŒŠwmb\NC:1.++)('""(&)+@x±ÇÒÚßÚÑÄ«±ÀÏÓÐ×Ýàââãàääåçèçæãß¾O"*-).',6/,/;7<=91415=739112.3483820.-:5=.87666<,1'++=LjyŽ“›˜˜–ŽŒŒŽ–™ž © £££¢Ÿ¡Ÿ¢¡ŸŸœžžž¡›œWWY^YU[ZZ_^_W\Z^\]^]WYPT[dnr|††Ž‘•š Ÿ £¥¦§¢§¤¥£££¢¤£ŸŸš•ŽŽ…xyrk]ONLFEIINLOSYZ\[[_^cc`bcc_bcde]`bgfbfe`lghgenkjmjoonooslkohfck’ØØijªœ„ria`hikkfimqoohgstvqqzomt}{prw~zvs…„|{††ˆƒyŒ‹†wnjv…‰‰†…‡{x†‹~vkmkjpŠ¢¬¯¦­ª°³À½¯©¥¨±ºµ¯¬¨­¯¸¿·ž›¢©«¾¾¼¾½½³´¶À¿»µ¼ÂÄÄÄ¿ÁÄÄÃÅÅ¿½ÀÅǾ½ÃÃÀÁÁº´¿ÅÆËÌÊÉÊÈÊÌÊÐÏÉÈÈÈËÏÏÌËÇÆÊÍÍÏÎÎÏÑÎÏÎËÊÉËÌÌÎÑÓÙ×ÝäáßÛÍ ^?BXZmt{ƒ‡’’–••›—––œ™œ˜š—™š™™—““‰ƒyod]SC4-.&*'(3%"$(1MŠ¹ÌÔÝÝÕ͹£§ÄÑÓ×ÚÝÞßâàßàßáâäåêêèäÔ~*)/),2.+,10/499477:6483610...520820,3418;341>62-+*=CKgu‚˜˜”—”’ŒŠŽ’˜Ÿ¢££££¤  Ÿ Ÿ  ž ›ŸŸœœŸWWUYW][Y^]_^^_]b__ZXX[TYZbmsz„†–™¡¢£¨¤©ª¥¥¢§££¦¢¤¡œ›„~tj]XNDBIJLNTRTWW^Z][c`baab`aabaeabecaaah`dgmglfjijknmtqsnnlpjbcl ×Ðí« rfgibledkmrorkclvvtqlquuwruwxy}qq{Šƒ}~ƒŠ†€zxw…†~ser…†ŠŒƒŠ‡|x|…{qjomfvŽš¦¦®°¯¶µº»»¬¢¢££¬´°²²·µ¹¬¡ ª±±³µ¸¼±·¿º»¼»¾Â»º½Æ½Â½¿ÉÿÂÄÅù½Éľ½Â»¶¸¼ÁÆÈÊÍÐÉÉÉÊËÉËÑÐÊÉÉÄÃÇÏÏÌÇÁÇËÌÍÎÏÊÍÍËÍÌÉÈÈËÎÏÐÐÕÙÛàáàÝÙ¾€MIKTjr€ƒˆ‘™›—š™™™ž™™Ÿœ››™™›š–“†wkh^UD03,+$) $$%(2aœ¼ÎÔÛÙÓÆ« °ÊÒÓÙÞÙÝÜÞàßÞÜÝÝßáâåêêåÛ 4(++()-/,210125;666:23.-*/2/9.63/2/,/.;4342.2-0-*+,/)*62,8513038*+&"&97Jg‘™™™›“‘Ž‘šš¡  ¢£ŸŸž ŸŸžŸŸœœ Ÿžšœœš›œ¢œ›___e^c`bcc_eecbe`ec_a^^]\cpp|ƒ’“˜Ÿ ¤¨¨©ª©¦¨§¤¥¦¤¤¨£¢Ÿš”Š…zpkeXTVINPTTSXZ\a]`\bcfedghdg`_cnehagfeggfkkhhjnopnmoqqrqplkefp¶ÙÔÈÇ«†wuhcdgie_lkigjfZ`kuxzxtunw~„}vz~zvtq|ƒ~|xm{„…‚…„–Œ‚†‚~nabi“š–•œ«²¯¨¥—¡¢Ÿ›£¤µº¬œ¡¬«´¾·¶±³¶¯·µ®²¶¼º´¶ÁÀ³¸º·¹°¯ºÀµ²·Áµª¨«½»´¾Ã½´¶ÀÃÀÂÇËÆÃÄÇÃÃÃÀ¿ÅÅÃÃÅÈÄÀÁÈÉÌËÈÇÀ¿·º¶¥¯ÁÉÊÅÆÃÄÌÌÌÉËÌÌËÆÍÎËÍÍËÐÍÌÍÓÕ××ÔØÖÍÀž†„†”•š–—œ–š™››š˜™•‘“…|xfZPDKa”¸ÉÒÜØÏÁ¶°ªª½ËÏÔ×ÜØÖÔÐÓÒÑÒÍÏÊÈÊÊÍÌÍËÍÐÓÔÖÚÜÝáââàÓ†((%))/7763877:8)222*.+-,+)*,-152826310($"!%-GZwŽ—™œ˜••‘–›Ÿ ¡¢¤¢ŸŸžž£Ÿžžœ ¡¢›››œ›–”˜šœŸ›^^e`cca^dcgmcbbbcab\a``^_glq~„‚‘‘—›ž¢©§§¥¦¦ªªª¥¥§¨¨¥¤œ–›“Œ‡zolcWTNJLPMSQZ[`a\\bbdfbaajgbfbfjgqghgdeefgmoklkpmlpqqourpigdcwÎÛËÆÉž”}gn[ba_ddgejhc^ilqu}wqqvyrqtsz~|wigpzz|yw{ƒ†ˆƒ„…~{ƒzm\[p}šŸ£ ”˜Ÿ±µ­ž”›œŸ¨´»­‘¤«®±¬³¾º°³®®·º¼·º©µ³³¸À¿·µµ¼¹²®¸¾·®±´£©±¾Ã½½À¾¹µ¶¸ÁÃÂÃÄÄÂÇÆÈÆÄÄÁÂÄÀÅÈÇýÃËÉÍËÇ¿¸©™¨­ÀÆÊÊÈÉÅÅÇÍÌÉÈÈËÉÉÈÊÊÌÍÌËËÈÌÍÐÖÔÕÕØÙÖ¡‰…“–“—–™™—›šœ˜––•”ŒŒ„zqeYV[w¥ÁÓÝÕÏÊ¿¯´¬¬ÀÌÑÖ×ÕÖÖÒÏÏÒÔÑÏÍÌÉÉÈÊÊËÌÌÐÔÕÖ×ÚÛßãâáßÑ|'0(-22-33346<870/5321.00.*),707>268>0) $!$)AUk†•œš––’‘Ž’›¡Ÿ¢£¢¢   œŸžœŸœžš›žŸžž—™šœ››¡cce`cb]eeeccdc`eaa`^e]X\`eip~„‡Œ‘•œ™¤¤¢¨¤¨¤©¥¥©ªª¬©§©¤ž›–Šysk`XUOJOQQPWX[ba^]edhfbdfhlikcghemhjgafejfmonsqkmootvqttomjdc‚ÏØÊÐÖ’„xrle]\bdabgda^lpnqryulq}snn~…€vofq€}{yx}‚„{Œ‚„}zu}{ƒug\_d{”œ¨¢¢žš ­§ž••’œ°¶®£“Ÿ­¬«­­««°»¸®°­º½¿º±©«°²µ³¾½±®°¶¸´±¹½«™ ©­µ°·»Áÿ¾¶¹µ¶»ÁÀ¾¼ÃÆÇÅÂÅÀÅÃÆÃÃÆÄÊÇÃÂÊËËÍɺ šœµÅÅÉÌÆÊÉÆÉÈËÌÈÅÇÉËÊÈÇÉÊÊÉÇÉÈÍËÌÓÕÖÒÕÚÚÕÁˆ‘——™˜–˜™˜š”˜š””‰‰tq`drºÍ×ÛÕË¿²À¹±²ÄÊÐ×ÙÖÓÓÓÐÏÏÎÍÎÌËËÉÅÈÈËËËÏÐÔÖÙ×ÚÛÞáãßÝÍm',)*112354354F110330.-4.6-17978969;40.# %1Lc–—›˜–”Œ•šŸ¢Ÿ  Ÿ¡ œ›ŸœšŸž›žš™›žœ›ššš™œccacddecdddcgfbda`a`_ba^adjpyƒ‰‹—”š¢¢¤§©§§©ª©§£¨©ª¨¥£Ÿ›”’Žƒ{rj`XONKOPRQ[UW[`^a_d_dbffehbfijfkikdfccddhhjtimlqltolwosqjjggÔÒÐα“wwofe]]c^dhhaennnproqnovri`kx„uqej{~€vw~ƒ|v†{sqz€…|mf_p}˜˜Ÿ¦Ÿ§¦–’Ÿœ‘—¢´²˜’—¢³­¶­ª©ª«ª°¶ºµµ¶¼¿¿²ª®¬¯¶±±¿ºµ­´·µ¶®­£˜¨°·´µ²°¶¿Á¾¸¼½µ²¾Â¾ÀÁÄÅÃÆÄ¿»ÆÈÈÈÅÃÅÇËÃÇËÉÆÄ®˜Ÿ©·ÄÃÃÈÇÊÈÇÉÊÍÌÈÄÈÉÌÊËÊÈÇÇÄÂÇÆÌËÊÍÑÑÔÓÙ×Ùλ—‘•™š›™–˜™˜–”˜”ŒŒ††€wpy’¶ÇÓÝ×ÏȾ¶½¿±¼ÆÎÑÖÕÔÕÒÒÑÐËÊÍÐÌÊÊÉÈÈÉÍÍÊÎÏÐÒÕØÛÚÛÝàáÞÝÊZ-/*'&//20/..4>68B765013/.51312-74184,(#!",:]v„‘œœ™–”’ššž¡¡¡¢Ÿ¡¡Ÿ›ŸŸ¤œ™Ÿ›Ÿœœš™œžžž—˜ž›bbaccdbj`fgddcdjcdj_]]`c\djq~€ˆŒ“ššŸ¡¥¤§©§§¦¨§¤¥«¦«¥¤ž–•}tjb[VLJROTPWTUW`^_\ebdbdbbeafebikkbjeedcdehosknmoopqmsqqrmdfh©ßÓÕȶ¡{utstf`cX\c`dirnquskfjqyj_[g|vtuhiw|}‚€ƒ|…wqmpxy{wibfo‚˜›”›™£¤Ÿ ’‘™œ––£§–“™¨ª´³®ª­©¯­¯«©¿¿º¯ªº¿·®³­§°µ´°¸¼±¶³µ²¨“œ±¶·¼¹¶´³±¹ÀÀ¾½º¹µ»¼½Ä¾¼ÁÃÅÃÁ½ÃÇÌÉÅÅÂÆÍÄÆÊÅ°©š¨²º»»¾ÃÄÆÆÉÊÉÉËÍÉÈÉÌËÊÊÈÈÅÅÅÄÄÂÈÈÌÉÍÏÑÑÔÓÕÓ˪’˜›œ›™™˜—‘–—•‹„ƒ„“¬ÄÑÙÛÚÌÄ·¿¼½¶ÀÈÎÔÖÖÑÒÓÑÐÐÍÉÊÌÎÍÊÇÉÇËÌÌËÎÒÐÐÓÖØÚÚÛÞàáÜߺ?(1-*+,34-21364774882/,**--05<1675543(%%(4Sk~Œ•››˜›—‘Œ–—Ÿ ¤ŸŸ¤žžžœ ¡›œš™š›žœšž›™–š™›˜™šeebccccfddcecfccdja`cc__ebot}„ŒŠ‘”˜¢¤¥§¥©¦¨«¬©§©§§¤¤¨Ÿœ˜‘Ž…{woeYRIJNQMPXZWW^^]ahfebahehedchgdcjgcac[helmlijmmlnpotplof`]i¶ã×ϼ²vlwtgc^\gg^hllhmyqdcpvocbivzvvrv{{ywy|ƒ„‹†|sqxzywtlfksˆš£ž›¡¤”ŒŽ–¥ªžˆ™¥©¯¯±±«­«±³¯²±²»¶²§ªµ¸³¯©©¬·¸±±¿¼¶®«¥•žŸµÀ¿¾¸¸´°³²½ÁÁ½½·ºººÁÄ¿¼»½Ã½º¿ÅÊÉÈÈÇÇÉÉÊõ–•§·¾Ã¾½¿¾ÄÆÄÊËÈÆËÉÈËÌÇËÉÊÇÇÉÆÇÄÄÀÃÆÈÉÉËÎÏÐÏÐÒÒ¾–•ššš•”˜’•˜“—”Ž‰…‹œµÂÏØÛÓÐƸ»ÁÀ±»ÃÈÏÕÖÓÓÒÑÐÐÐËÈÉÍÏËÊÊÆÈËÌÌÈÌÎÒÔÓÖØÖØ×ÜÝààÞÞ®5*/+1.563,/2.6538630.0.).-*/531567973(#&,<_t†——œ™—–—‘“–š¡¤ ¤Ÿ¡¡ œž ›œŸœ›œœœœœ˜›œœšššœš—›ffi`ba_ikibccefcc`cada[cchntz„Ž‹•–™ž £¢§¥¨©©¬¨©¨¥©¨§¢ œš“ŠˆyvqgYOPJIORSWYU^^[cfdilfhfdgdefja_jkeh_e`fedhlhmohqopmpnlihb^i¯ß×ɺž‚Šy{wnje\cffjlhlpki``nnf^dmrwuutyxwxu{{{}‚~}ypr|‚}utmlkr†”™—£©¢™ž››—‘Ž“‹Š’¯®‰‡‘¨ª­±­¬¬­±³±¸¹¬¦¨­´¯ª¨­·¼²­¯°¶¸¬²Á¾®¡™£«­±º¿¾··º´³¹¸·¾¿À»¼»¹ºÁ¿½¿º¿ÁÁ¹ÀÆÉÆËÌÈÊÆÈǶš¤³ºÁÄ¿¿ÁÁÃÆÇÄÈÆÉÇÇÅÉÌÇÈÉÈÆÊÇÇÆÅÆÄÁÅÆÅÉÅÈËÍÏÏÍÖ˨’—˜™œ“›–”™’Ž‹š¸ÅÎÑÙØÐǹµ½Ã·®ºÇÇÏÒÓÓÒÒÑÐÑÍÉÉÊÌËËÉÇÉÉËÌÌËÌÏÏÒÕÔ×××ØÚÜÜâÞßÙ”+'*)/6/;=301/4103056/'*),*,-32/84/4(+-''.@QoŒ—›œ›—“•—˜›¡£¡ŸŸ £¡ŸžžŸžŸ ž˜ž Ÿžœ™›œ˜˜˜š››™œcchbgdfdfbacadbahabcccaccgnv}‚Œ‹•”–˜˜ ¨¤¦¨¦ª«¨¬¨ªª¨ª©«¡™šŒƒ|spcZMPMORNVVZY][^]a`deffageefgcabgeid`gbhhjbggmokjmumlihfc^_pÀÞÒÀ²˜‹~„„vtpbiiaclgioifbeig_Zeuvrxuxzvpmw€|~„€|zvomr|~uyqqijt‚‡’—šª¤›‘””–’”šŒ†‘˜›£¬²­«¨«±®µ²³º§«©¢®®­¨¤®ÀÀ»²¬®¸¶©²´¢ ¦³·µ±¯¸¼»µ½·²··´¯±¸ÃÁ¼¸³°¶ÀÁ¾½¾¾Ã½¿ÉÊÊÌÌÊŽ³©¤¬±´½½¾»ÃÈÇÅÇÈÆÅÅÆÆÅÂÄÉÈÄÇÈÇÇÅÉÅÈÅÆÂÁÂÁÉÄÃÄÈÍÐËÔι’”——šš••–““–­ÁÉÔÝ×Ò˾¸¹Å«³ÁÈÌÒÕÒÒÐÏÏÎÏÌËÈËÊËÉÇÊÌÊÊËËÌËÏÒÑÒÕØØØÙÚÚÞÝÞÜßÖ€/*.*+-640110-.0706:312-1-/%-23763104-*.48Lbz‹•–šœ™—“Ž”–™žœ¥£¡Ÿ žœžšœžŸ››ž›œŸœ™›œšŸ——ššœdd`aihgggdeicdcchf_dbcahinqy„’˜•›ž¥¦¤¦ª©ª±ª«ª©ª¬®©žš–•‹|vmaYNMPKQQUUV[c[b`\cc]`celedhhdf_ghcdbe`dcfelmjikmlnmonkjc^a„ØÚÍÆœ ‡Šxxxndmdcliejhf[ethZYknsnoszvocfmy€}€€†~ujktzwvsuswjwŒ‘ŒŒ—™—œ¢¡“’—›¦£†vzŽ¢¥¤§žœ¦««®¯²·³±¦«°§­¤ž¡­­°®±ÃĽµ­¬²©š¢¯³±¶·²­¬°¼¾»³¶´µµ±©¬¶¼½¶µ­¬³½ÁÁÂÁÂÿÅÊËÊÉŹ£Ÿ°½½¼¿ÀÀ¿»½ÂÅÂÃÆÇÂÄÃÅļÈÇÅÄÆÅÆÈÇÅÇÃÃÆÀ»ÂÅÅÃÂÆËÎÌÑÐÄš—™˜™—”•’ŠŽŸ»ÂÌÕ×ÒÍ´¯ÁÈ»´¼ÇÍÐÔÓÓÒÏÎÎÎÍÉÉÊÊÈÊÈÅÉÍÍÍÍËËÌÌÎÑÓÔÔ×ÔÖØÚÛÝÝßÜÞÏi(*,&*164/9;./22.28.22(-*/+,,15.6.60220/:Jas…ššš—–’”””–Ÿœ¢  ¡ ¢ œ£Ÿ žŸŸŸž›™žœžœ™›ž œ›š›™•››š™aagc_gafdgf`fagcgb_]`f\dklow€‡‰•˜™œ£¦§¦¦¬©ª©­«¬¬¬«ª¦¢›š•…€vlc_PJNMMMSVZ[cZ\]_d_hbcbgkccccgcfebecbcfehckjhlmljikkonbaac‘ØÙÑÄ›••€vjkkimhfngc^fgi`\irg^gsuph[er{ywwx€}{snlv€{srtqtr|•—Œ”Ÿ•šŽŽ•“œ«¦‹€œ¥«¥Ÿ—š¨°®µ¶²¸¦¦¤ª¥¥¯  ŸªººµµÀÀ¼°¨£š™ž²¹¹³°³²±²¨¯¾Á¹´²·³´°²¯¬´¿¼³¬¬³¼ÁÄÇÆÄÁ»ÃÇÃÀ·¦¤¯¾À½ÄŽÁ¿À·¿¾»¿Å½ÂÂÅÄÁ¿ÂÈľÁ¾ÅÅÄÅÆÅĺ¾¿ÄÀ¾¿ÂÆÉÍÑÄ –˜–˜–—“›­¿ÇÏØÑËƺ»·ÁÁ¯³ÀÇÏÔÒÓÐÐÍÏÌËÌÊÆÈÈÉÈËÉËÌÍÍÌÎÊËÍÍÍÐÒÓÖÔÔ×ØÚÚÚÝÞÞÝÈS-)033D675650519108,+5*()('-/25544716577GTj~“™•–“”•’–œ›ž¢¡¡¡¡Ÿ¢ Ÿ›žžŸ Ÿ™žœ›œœœ››˜ššœ–œggefcca^d`dbfbd_fia_ca`hcpru€…Œ—˜˜› ¤¥¥§§©¬¬«®­©ª¬¨©§£¡š’†}tn`]KPLKIMZ]XZcV`bfbhcbccafhc`geihfig`kf_ehcjknjkmmhimgk_YefžÙÖÍ枘†zuhfimofnlbdimaZZoqne`qqie`lv{ywtx|tqrhm|z{|xuvpm€”˜•‘š”–›•“Ž“‘˜¢¢‡y~—  ¦¢£§¤›› ²¼³²¦¬®¤©¨¥£§¬­¤§­À¾°²½¸±Ÿ–”£©³»¸³«©«°±¯«¯º¿·¯«²³´´²¦§·½¶²°®³Â¿ýº¬³´±±«¨°¶»¾»¾¿º¹¼·³¶¸·¿Â¾½ÀÅÅÄÅż¹ÁÂÁ¿¼»ÄÃÁÈÅÂÂÀµ¿ÁÀ½»ºÂÇÈÍɱ•Ž—’˜–•—™¬¿ÄÊÑ×Õ˾´¶ÈǸ²¸ÅÊÔÕÓÒÐÎÍÌÉÉÆÈÊÈÉÈÈÈÇÊËËËÍÏÎÉÊÎÍÍÐÒÔÓÔÕ×ÛÛßÞÞÞÞÞ·B()0/304:3841372/1./+,)%*-52347639=58?@FN`w‡”—š–•“’‘’—™ŸŸ¡¡¡¢¤Ÿ œœŸžœœ¡¢œ¢ žŸšš˜œ™—Ÿ›š˜™š™——cceahbdfadccg_bbfga^e_]ggmmwƒ…‰Ž•š›ž¢¦¤§¨©ª­«­«¬ª¬­¬¬¦£š•Ž…sh`YPQOOLOTW[YcY`]`eg_daadfhffcfdg_^afaecdhfilpjnknjjhjj`_YhµÜÒÊ·°¢‹‡{~{kakpkilkioppcfiiifhnuplcquzzv~}ykostx~}zzyom}“ –‘––”””Š‘”™Ÿ“”„z‚“˜›¡¡¡££¨¡¦¬¤±¶«©­©ª¨¨§¦¨®´µ¥£©¾¸­®²¬–’ž®²µ±±°ª¯°©­²µ¬°µ»·¯¨±¸¾´ª©¨¶¼»µ´º¾¾·´¶­œ ¨­­²´¹¾¾Á¸»°²¬¶·´·½»ÀÀ¾¼ÀÈÆÆÅÆ¿·¹Àÿ¾½ºÀ½ÄÂÀÀ¾¶»º¾»¸·ÁÃÄÉʽ š”š™ª»ÅÆÎÖÍÿÀÂÃÊÁµºÆÅÌÓÔÕÑÎÍÍÌÉÅÇÇÇËÉÊÉÇÊÈËËÍÎÎËÍÉÍÐÊÎÌÍÓÑÓÕÙÝÛÞßÜÞßÛž05002434476:2-76,00*+)'(-43,1350078;CCDIYj€‘“—•””’’‘“›Ÿ™¡¢¢Ÿžž¢œ£ £ž ž œ ›œŸ  Ÿš›š–˜››™—™œ™šggfce`adadcacddffkbda_agfmru‹“›ž¤£¤¦¦©¬¬²¬­¬¨­²­®®«¥ š“‰‡~um_`MONPQWU[]aZ[aa^geaeaddf_bffdded``fadfhiehjngmkmhikeba^ZuÏÝÒʹ­œ—Œ‡z€{magglhchooqlmpmcbkjropivwqpsw…zplrqzƒ€~‚}{vqn{’–š˜–œ”Œ‰–ŒŒ‘¦§‰ty…—›Ÿ›š™¢¤Ÿ«¯©ž–©²®ª§§«© ©£§¶··¥¬¼°£Ÿ™˜ž§®°¹³¯¯®°­¯­®´³²ª«·¸¬©³À·¶®¨®¹À¼³¼¼¿­¦©šœ¬µ²´³¹¾¾¾¹¢²°¶´·¾½¼»¿ÃÇþ¿ÁÇÈÂÂÀ¿·¹¼¾¿¾Â»¾Â¿¿½¿¹´¹¾¼¹¼À¾ÀÂÉÆ·’”Ÿ¬ÅÉËÌÐ˼¿»ÆÊž·¾ÇÈÍÓÕÓÐÏËÎÍÉÆÈÊÊÈÊÊÊÉÊËÉËÌÍÎÍÍÌËÌÍÉÈÉÊÒÒÓÓ×ÚÛÛÝÞÞàÖ4-0.,1071;555348222..'(2.44.3:4399:?:FGVes…“—•–’“’—˜™Ÿž¡¢œ  £œžŸ¢ šŸœž›Ÿžœ™›šš™›—›–—œ›™ddgaccbgjafaacbageded`_eehry}…‹Ž”œžŸ¦¢¦©ªª©ª¯¬­®¬¬´¬¬§©Ÿš”‹ˆ‚rgc]RRHOPQW\ng^X\_baceabeafbbfcdcgb`cgafjddiglhgkfiojjfaY^aƒÒØÕÈߦ¦‹„„skndeke`gjhhonngglsiahqprrnpz{yqklsz}‚~zpji}ˆ”™“——“œ”Š‡‰”••›–x‰Žœ¡¤£›™˜¥««²ž—“–¥­©¤¦©¯¯©¦§²¸¸­Ÿ™§­š”š«²°­¬®µµ°°´³²µ°ª¯¶°¨«´·±­±»»µª®¹Á»·¹¾Â¶¤ž¨´¹º¸¸µ¼¼¶·«£«¶ÀÀ¿¿ÅÀ½¼ÄÈÃÁÀ¾Âž¼¸¶¸¸¿¿Á¿¾¹À¼½º½¹µµ¿¿½º·¾¼¾ÆÊè–¬¸ÉÕÓÑÉ¿µ®ÅÇÁ»ºÄÌÍÎÏÒÑÒÐÍÍÍÍÉÉÈÇÌÉÉËÉÈÈÉËÎÎÍÎÎÍÉÊÌÊÈÈÇÊÎÒÒÔÔØÚÞÝÝÞáßÑ,',183769@64,7<963.33-*//31.,-40/1?@AEJYo€Œ•˜™–˜‘Ž’’––›ž   ¢¢žŸŸžž žœŸž›œžžœ˜™˜›™œ›š šš›™šœddgfefdcceidhfgcfebcagabemquz…Š––¢¢§¤¦¨¬©ª®¨®««­«®¬ª¦¤“‰|spf[RJMRJNTVWb[[Y[]`degfedgcabbdccb\d_ccfbdjffhjjkggheca[Y\“ÓÕÓÉ·ž¶¥‰ŒŠz€wvgeldciohkkhfgnvvddmyrlik|zqom{}€zƒƒ~~skjuŽ‘•™˜˜™“ˆ…„‹˜¢¤ˆtyˆ••“–™¥¡žž­¯Ÿ –™˜©«¨¯®´³­¨£­µ¶¯™”š•¡¨³¸¸°­§¦¯¶±®°²´¯¨§°¶±¨©µ·±«¬¸¾º·»¿Á½¾Â¶©ª®°²¼¼½¼¼Á¾¸»·°°·½ÀÀ¿ÂÆÁ»ÂÇŽ¿¿ÀÀ»¹²³ºº»¼»»¿µ·¾¾¼¸»µ²¼Á»¹º¸»¸ÀÆÇ»¥±ÁÈÔÔÓËÀ³®¾À¹±ÁÉÊÐÎÐÏÎÍÎÌÍËÌËÉÇÈÊÇÆÈÉÊÉËÊÍÍÌÏÏÎÍËÍÊÉÆÆÆËÑÓÒÔÓ×ÚßáÛßàßÐd!%*-1011.745040560,*.+*4+40/3569A9>@EK]k€—–˜–•‘’‘‘”˜šžœ¡¡¡ Ÿž  ŸŸ¡Ÿ›œœŸ›› žš—œš››™š———šž™˜bbcagbejjica^]ceab`afbahfloz‚‹“ššŸ¡£¦©«¯¬­®­®ª¯«­®¬ª¤ “…}unh[TPJGKNOTUT]Z]\b^cbab`ffgade`bbdbcagfbcdkgifigjihjefbWYd¦ÛÛÐÆ´µ§–ƒ€ztjqedjniokle`clnkplqurtsps{xuolx}{…~ysmjw‰™‘”•—•–‘ˆ†ŒŽ’›š{{~“–ž–‘ž££§¡¨§ š¥§¡› ˜ž«°±·²²¶ªŸ °°¯œ’Ÿ¢¬³®±²¶¯¥¦¦­¹µ³²´¬­°­°¯®¤©¹·³«­½ÂÁÁ¿ÅÀ¹±¬°¯³³®°³´¶¾À¾À½À¹µº½¼À¿ÀÂÄ»·ÄÁÀ½»¶¹»¼¹²µ·¹º¼¾º½º±º¾½¶¹¸°³¿½·¸»¾º½Âƽ¿ÆÌÏÑÉƹ¼¾Ä¹¾ÃÇÊÐÑÒÍÌÍÍÎÍËÉÉÊËÊÈËÂÅÅÈÈÇÉÌÎÍÎÎÌÊÍÌÑÇÃÂÃÄÎÔÒÔÓÓÕÝÞÞÛàáÞÃK%$,,)(2-'-127G7?8/23)()40-+-1728B?ENIXlx„‘–™™•“‘“˜›œ  ¡£¢¡¢£Ÿ¢œ ŸžœœŸŸž›žžž›™œ›—–šš™ddaedecghaeaaae_leccb_eghntuƒˆ•Ÿ›ž¡ª¦¬­¬¬¬°¯³®­¯¯«¨«£Ÿ™“‘‡~uqbXRLMPLSOXY]Z]_aaY^ecgdgg``dadbd__deg_^fbaadjflsgkgea^^Zl½Û×ÑÀµ·žŸ”Œ‰wpmndfjsrmhnbdhhlpipqrtu{ytrwsp{wz}…|zukjfvŒ•š”—™–—Ž“ž…ywv‹““—šš•›ª´ª™™“¡ ¢¡ž¡¨¡¢¯¸¹¸´¼·¡ £§ •™¬·±¶±©¬±³°­§¦¥´¹±­¯¬³²¬©©¨¦°¸·°¯²ÂÆź¹±¬±¶·¸·³µ¶¶³±¹Á¼À¼À»»¹º»»ÃÁ¾Á»»ºÁÀÀº°²µ¸µ¶¸¹·¹ºº¶¼»´µ»»±²µ­®±··´¯»¹¹ºÁÆÄÉÎÍǸ¼ÇÃÀÁÈÇÈËÑÔÏÍËÈÌÌÊËÊÊÇÆÉÈÆÇÂÅÉÊÉÊÉÉÎËÌÏËËÎÍÊÃÂÀÇÈÏÑÑÑÑÒÔÛÜÝÞàßÛ©4(,%+0*,471,,29216/5.'.),73;3/;;=BH\hv‰‘™˜—š–‘““–™žžŸ¡¢¡¦¢¢ ž žžœŸ œœœžœŸž›œžœ›››œ™›—œœjjd`ecbdc_X_b_h_eadffgceiknuz€ŠŽ‘›™££¥¨«¯«­®¯²¯­­¬­ª«¨¦ š”…{rs`[SRJGKSOTW[Z`b[]^c_^bebd^ddaa`ecdcab`j_hcgdkmkhieega[Z`vÎáÓÊǬµ¼š“›~}…|o{…tknibhrccknjulpruqqls|z…wyz~€{znfs”‘—›ˆˆ„‹Œž˜Š{x{‰’Ž”•“˜œž’’££š–”–œ£ž¦¤¨°³ªž¥«®³­ª¡–¥¥§¤²¼µ¶ª©¥¨²°³´ª¨¤­³±®¯²¯®¥¬¨¦¥©´¸»³®­°·¸¶µµµ¶²µ·¼½²°²²³¹½½¿Å¼·¸½¿¿¾½¿º¶±±·¼·¬§¯²°º»¼¹¹´®¸·¶°¸º±©©¤¥¨±³³ºÄÂÍÍÈó©«»ÇÉÃÂÃÃÊÏÒÓÓÒÑÌËÅÂÅÉÉÉÈÈÈÈÈÅÆÇÇÃÇÊÊËÉÏÌÉÍÊÍÎÎŽ·¼¾ÅËÌÏÓÑÑÔÔÞÜÛÝÙÙËi)(&$2+..50.,454/.,.*0'>10078>73:.6:PNiuˆ”œ™˜”’–œŸ ž£¡ Ÿž  Ÿ  Ÿž›ŸœœŸŸœ¡œšžœž›Ÿš™œ››œ˜›™šjjg`_b`eadceaabaaaaac`cejeqq|~ˆ“››¡¡©¬­¬¬¯®°°­¬¬«°­¬¨§Ÿ™–‹†uocYQJGMKNLW[\WZ_bc]ffd_^dd_ed^bcdebc__h`feaeempkgjefka]X^{ÕÚÔÍ»³Ã¸¡”“‚Šƒxx†ƒxslpokmghnkkhor{nhcjrzyttzz€zztip’”””“™–†ˆŽ¨ˆz…ˆ“œ–”“˜˜¨š€…— š“’™«§¬­«°­³§¥ž ¨« –˜¦³²¬£¥±³¯ª©©«¬°±²³§§§£´¹®°¬®°±©¦«®ªªº´­¬®±¹À¼¹´´¯±±¹º¯©²·µ¸º·¼Á¾»¼¶º¿Á»¹¸µ´±¬²´±ª©­²¸¸¹º¸¼®«µ³¬²³­¥¢§££«»ÀÇÑÌþµ®¥©¹ÃÆÈÁÅÆÌÑÒÔÔÑÑÐÎȽ¿ÆÇÈÈÇÈÈÊÈÆÄÆÅÄÉÌÉÈÉÎÍËËÍÌÑ˺·°´¹ÃÇÊÎÏÒÑÓÔ×ÚÚØØÚ¶B)% &,/0)+1.2-13716-').-,,4:756+4(/-**&**./-1-4421:A:2&+/7,2358=841*)6Hay†”Ÿž˜•”“—™œž¡  œ ¡žŸ¡¡Ÿ Ÿ ¥¡ Ÿ¢  Ÿ ž¡¢œŸŸžž™Ÿ  œš__ccgeac\c]`aa\fe_gc]_^fcfqszƒŒ‘™›Ÿ£¦©«¬««­¯¬®««ª­­ª¦¤£š“‡~ysa\VLLMPSVY\Y]^^[^`aecdbehd```fecca`cc]ccagjigihkkgjd`_W_™àÛÒʲÀ¹ ›¨¢…ƒ”‘‹|‚†‚zijsdelihllekutlfq€ƒ€se`efnyŠ”ŽˆŽŽ“˜ŠˆŒ†“œžzkqv‚‘•’”’›š›—œœ”‘Š‡‡—“™ «œ˜ ¬±¯žž•“”œ¦³¯±·µ±¯«¥¦¨¤ž£³³°¯§¬²­¶µ³¬¦¤¥›£¬­±²¨ ž¢¬­­±®³·¶§¢ª°°±²°·¼»¸¹¶«²»¼¿¼¼½¼¸³°®°­°´´³µ¶¼¶«¥±¸§¢·´²³®©›£¡™œ²ÂÊÏÐľµ«¯¼¾ººÃÄÅÆËÐÎÏÏÊÌÌËÊÌÇÇÆÅÅÃÇÆÈÆÈÈÈÈÂÆÉÆÉÌÈÊÎÌÊËÊÎÎÊÏʸ®£Ÿ¥¡¨³ºÅÍÆÀÀÅÍÔÕÓÕÓ•*.-%)/,,-/1921,/61.53+..2-00205410->Rm€•œ™˜•‘‘Œ”–Ÿ ¢  Ÿ¤¡¢£¤ŸŸ›¡Ÿ¢¢¡›£ Ÿœœ œŸžž›ž¢¡ž›Ÿœ¢™__fech^b`adbcbbee_ibbb_adgrt{~‰‘˜£ ¦§§ª¯®¯®¬°¬«¯¬²¬©«¢—”Ž‰}vrd[VSROQTU`]\^^^_[d]ffgefdaf_`ebegaagecebbihigejiicecb^Z^”ÚÛÒÁ·½´ª·¥—“ŽŒ–Ž€~€vipninohdccdutrlow~slfbedqˆ—™“„ˆ“‘‰“Ž…•’‘Žsn|„‡‘”—–›—œ™™˜ŠŠˆ—˜œ–‰‘§£œ–©¬Ž•ž¨ª¦°ª«­­±§¦¬¬¥§§Ÿ¡§´¶±­­¬ª°²±ª  •™›¦²³°§¦¦¦¦±³°¤ª«££¨®¶·±±±»¼½º»±¯°¸»¼º¹¹³´¶°°³³³·³²¶¿¶ºª¤¹««²²®©¦˜ ¦»ÊÐÎÉ¿´²¯¼ÃÃÀÂÃÂÅÈÌÌÏÌÌËÊÉÈÈÊÅÇÆÆÆÆÇÇÉÉËÈÇÈÅÉÈÈÉÆÉÉÊÍÍÍÌÍÏËÌͽ­© ž¢ŸŸ¦¯¼É­µ»¼ÊÑÒÎÔÅ](&)*4*1-,4.171-02/1++-1//.0+1038:2>Idv‚‘˜š›–’”““–œœ  ¡Ÿ£¤¢¤¡¢Ÿ¢¡Ÿžž¡¢Ÿ¢Ÿœ›žž¡™ŸŸž››ŸššœžŸœ›Ÿšœš ›cc`aaaade_dj`a`ba^f_^cbbjhmtƒ‰”–ž¢¥¡¬¬¬¬¬­°¯­¯­¬­­®¦£žœ•Œˆ‚tlbUXNQLNQXZZa_abb_bdbchef`ge``c`fccc`cdaecdfbkcagghdcbYZY…ÙØ˴Ķ¥²®©“°«‰…š‡…ŠzuortnqnaSUimqhgmw~xvrijfgr†Ž—’Š†ˆŽ‘‡ž†psvu”–——’”‘š¡™‘••ŒŒššœ¨£‹‰¦¥˜•–™‘¢­²¯¯­«¨¦¦§¤¬©©¨¦§£Ÿž¤¨µ²­©§¢©¨¢¦££¤¡œ¥®¬¨¯«©¬¢­¦›  ª²¨ª®³³²±³»½»¼µ·®³µ¸¸´±±°´°®©¯·º¶¹»¶¶´²ž°± ž²«¦¢œ¢µÄÍÑÑ¿¶·°¹Ã»ÅÃÃÈÉÈÎÉÌÌÉËÇÈÃÆÂÆÃÃÅÆÆÆÆÇÊÉÈÈÆÇÆÇËÊÊÊÆÊËÍÌÐÎÐËÊÏÇ´§§Ÿ œ› ¥´¿»Ÿ«´ÀÉÌÍÒÓ¢>(-*(<2767..61855:/-,*&+2-.-+/3:;IBEXr’—˜™™’•“‘•–œŸ™¤¡£ ¢¡¢Ÿœ¡ž¡ ¡¦  ››ž£Ÿœž¡¡œ™žœž  ¡žššš›ž›``c`c]`e]b\\__bb]cbb^b_afhou|…Œ”˜šœ¢¥ª­«­®²ª¬­­®¨¨«¬¬¨¦š–Ž†€vn_WQPNMMRUYXa\`ac[abdbdkdec]_fdccdaace`cgebffigghfcgfdXZ]˜ÞØÆĸ¬¬± –©™‚Ž”Œ„‘Š~qzvtobWS]rllaixywxuxng_s€‘‘Œ|…‰‡ˆŽ“¡™rhmxx˜””–˜˜–””•—˜†••‘˜™¡Ÿ›˜‘‹…ŽŸ¦£—‡ˆ•£ «³°²¯¨¤¦£¤§«®©§«©©¬¤žžª«²¬§žž¥©ª§¢§£›œ©­¯±®¥›ž¢¡ª®®³«¬«¨°³­­¶º¸»¼·¶¬®´±´°°¯°°¬¤§­¹µ´²³³¯³žš®¤—©¢¨ž¥­´ÉÐËĽ²¨µÁÃÁ¾ÀÂÁÍÏÎÌÊÆÊÉÈÇÄ»¿ÁÀ¿ÃÃÇÆÄÂÅÈÆÆÈÈÉÄÆÊËÉÌÈÊÍËËÏÎÏÈËл¯ ¡›žœž¦°¾º“Œ”©³¿ÄÇÏÔÏs-,'+,1@9//7/37@202+1))//40)()-3CLQOTiy‰‘–—˜’““Ž–˜œžŸž¡Ÿ¡¢¡¡¡  Ÿ¡ž›¢¢ œž¡ Ÿ›ŸŸžžŸžŸ¡ŸžŸœ››Ÿ šœ^^b^\`ega]`c_a^e`c\^\bfcgeiw~„ˆ‘˜œž¢¨ªª¬©¬«©¬±¬©ª«­®§§£›“‘‡„vkfZQUKOMTRYYb_^`_]bdcea_`acc_cd`ebfacabcjfdbfgfjdhhbf^`\^šÝÙɬõŸ‘©Ÿ—‰Ž‘†‹…ˆ~}ypi[Xaia_gds|wtouse`x†Œ“‹€€ˆ‹…˜Ÿ“uooq‹—–’–œ—–Ž”ƒ–ž˜ –•‹ŽŒŽ—ž¤”Š‹ž¦©¥«²²®««£¤¥¥¤¦«ª¨©­¦ª¤¡Ÿ¥¬®¬£Ÿ¢¥§®¨ ¥«©¢««¨©Ž“š¡£¬¬­°«®¬­°°²©°µº¼¹¹¸®°®²²³´¯®°®¬£¤¯±µºµ®­¬§•¥£” ¡ª¸ÁÆÏÁ¹´¶¶º¾»ÁÃÄÆÉÍÒÎÌÆÉÅÅËÇÅÁ¾ºÀ¾ÃÂÃÅÁÂÈÈÇÆÅÉÈÄÆÈÉÊÉÆÈÍÌÉÏÎÏÍÉÑÆ©¥›–™¢©±½¸Š•¦¶»ÅÃÎÕ¹?.3-#'<8E-3/3/820.1(3))017-,2/2:@FOOgt†•—•˜”””˜ŸšŸ ¡¡¡Ÿ£¢Ÿ™™Ÿ¢¡ Ÿ ž¢ Ÿžž˜ žžŸœœžœŸŸ¤œ  œšž›œ ›eece`a^j[^c_d`a^^`d``eh`bdkv~…“œž£¥§ª®««ª®«­ª¬­¦­§§£¥¢™“ƒ‚umaYYNQOOLPZU]_aaeahiidf_^edddaceccdabeaddffghcilc_edc^ZT\—ßÕƲÀÄ°™¥§Ÿ˜¢¡’ˆšŒ‰‚†Ž†{xhfdem`WPapspnqpqhkt‰‰†‡ŠŠŠ‹Š…‡Œ™‘nrw}‡‹‹—”—šš“ŽŒ‹•‘‘— ¡–‚‰•˜•™”‘’™›“¦ª¬ªª©­©§­¥£¢¤¬¬ª¨²«ª« šœ¢§®´¢ Ÿ£§¨§§¨­ª¡¡¥™”œš¢¦¦¥ª©²±°°¬°¤®«¦­º»»´³²¯ª©²²°­¯¯§¬¦§¢¬¸¹·±¬¥«”–¦—¨µÀÈÈż²©°À¿ÃÀ¿ÃÃÄÍÏÏÌÊÊÆÆÅÃÅÃÁ¾¿Â½¾ÂÀÆÄÆÇÈÉÈÇÉËÌÉÆÇËÉÉÉÉÏÎÊÏÏÐÊÍѳ£ ›™ž©­²¼¾“~ƒ›¨¸ºÁÆÑÒ‘/&&/'')/=42J<513,.++*-2/27+,0.:=LUV`q}‘•™•˜”‘’—›Ÿ Ÿ  ¡ ¢¡ž ›ŸŸŸ  ¡Ÿ¢ ž¡›£žœ¢Ÿ˜¡žŸ œž›žŸ›ž›™žžŸaa]db]a\\_a\[]a`ad_]beafahpv…Ž•™›Ÿ ¤¨ª«­©©¬©©ª©¬§ª¬©¤¤™—‡uldXWKLNNLUY[^`\[d`_bm`edcc_bccbcaeac^badcdeibddjiad`d_XV`¦ÞϹº¾¸´®¤²µ§‰˜ˆ„Ž~xpkhdia]T^ispjoqj_dwŒ‘Ž†††Œ‹ƒ†‰†…’›nvvqy†ˆˆŠŽ“™›—’”’†ƒ“—˜–›‘œŠ’¡œ ›™—Ž†ˆž¬£•—¢§«¦¡¦¤§«¯§¨¦¡¨©©¨¥¬­¥£ š›š¡¸°§ž ¥¦©¬¬­¡žŒ™Ÿ §¥Ÿ¥¬¥¤¬¨³°©³¯Ÿ¦³¦£±¹¹º´­°¯¥¦ª¯«¯°®¤ª®¨ ¯¶±­¬¡¡œ™ªºÂÏɹ¶­°´½µµ¿ÅÇÇÎÌÌÎËËÈÉËÇŽº¾ÃÁÅ¿¾¾ÁÁÆÇÆÆÇÉÉÉÉÈÌÈÊÈÉÎÉÇÊÌÐÏÎÌÐÎÍÑǤšž˜›¥«´º¾˜||‹–¡®·ºÇÌØÈX%%(%&))*400I@;6-,*')3-263/,/328BJP[l|ˆ—™—’–“•Ž”šŸ¢Ÿ£Ÿ¤¡ ¡ŸŸ¡¡œ¢ žœŸŸ¡œŸ ŸŸœœšœ› ž›Ÿ¡›  œ—›œœbbb^[[`]__Xa\^aZX_b^\_bbceoyˆŠ’•–ž¢¢¬©¨ª¬ª­«®­¨ªª«¨©¦¤ š”‘…~wjg[YMKMRNQSX^[^_d_c`daafbdba_j`]beccb`b``ffgiffhf`da`]UXe«ÛÊù©­°­–’­¬’’zŽ›‡}vmclgd[]_qghjjlk\ZuŒ“’ŽŠŽˆ‚‹‰ˆŽŒŒzcw~{„“Œ‹Š’›™’†‡“Šˆœž™z˜””—¢¢œ•‘„†‘¢©®§ššŸ¦¡œš¥®ª­²¢¢Ÿª¬¥¥¦¦¤¡¡¡Ÿ”š­®²ª¡££¥©¦› ¨ªª¬¨©¯®©§¦¨³¬³¯£Ÿ°¬¦©®¹¸µ³¯­ª©¨©¬°­¬ £®«§ªµ­©¦Ÿ˜¡”¨·ÃÇÊdz¤±´¿ÀºµÀÃÄÍÒÒÎÌËÈÈÈÆÆù·½ÁÂÃÿüÂÄÄÅÅÆÊÉÉÈËÇÈÈÉÉÉÌÈÇÊÌÏÎÏÍÐÌÐб˜“š¢¥¤°¹º–}€„¡©¯²¸ÅÑÛ¸=&*&)&,)+418G860..&++./7515-,,5??FTaqƒ–•™œ”—•“‘“–Ÿž Ÿ£¡¡¢Ÿ¥¢Ÿ™Ÿ¡žžž¡ Ÿ¡¢¡™žšœœš›œ›¤Ÿ  › œ™›¡š ]]dh`Y__a`_bb``a`a_``h_`ejsy„‘”›Ÿ¡£¨¨¨ª®¬««­©®¬­®ªª¨¤¡–”‹umb^QINPNMSV^^]`^d`_adhdhdefb^]`bcc_fdf_bechhdfkb_ac__ZYVbµáËȾ¤¶¹ª•¨¢¡Ž‡™žƒ‘—†zikkgbdlknlgrlg^an‹“Ž‹Šˆ|ƒƒŒ”–vjvstv‚‘—Š‘“’•—ƒ†‘—Ž‰Œ‡ Œw’œ™šŸŸœ†Š‘—«§¨¦ ••˜˜¢š¦­±µª¢¢¡¨¢ ž¡¥§Ÿ¤¢›ž¡ª°«¦Ÿ–™–‘§¬¡¢ ¤Ÿ¦©¥§¨«¬¦¥³±©¨§¡¨¯ª¬¤®¶°®¯§®ª¨¨¦¶°­¤Ÿ£²¤Ÿ«§¦¢–«¯¾ÇÍ¿°«¢§¸¼¶»ÃÈÅÉÐÑÏÍÍËËÉÇÂÁÀÁÀÀÂÃÃÂÀÀÁ¿ÄÄÄÈÅÇÉÊËÉÉÈÇÆËÉËÈÈÉÌÌÏÏÐÐÎÍÐÁŸ™˜¢¤ª¯µ»–~…‰Žš¨®³³¶ÇÕÖ›.$$')'&*.2253/705.),10;1/23,.0&%.&+*0)205.146F*'+.+.365/-,65DGFap€‹–Ÿ™–•”’’‘–œ›Ÿ¡ž¢¢Ÿ¢§Ÿ ž™ž›œ›šœœž šž¡œ ž¡œ›œ™ Ÿ œœ›ž—š›œœ^^^bc^]`_^^_Zf^^\Z[`\^addgnuƒ‡™œ¡¢¦¥©¬«ªª®­§ª¬¬¬©«ª«©žš“ŠylcaXSMMUSU\]Y]]^`hbc]c_c^c_e^adadfdaadegh`cgecfed`_]]ZTS}ÏÕÁ¿Á½³±º¹¡›”™’¤”y”‡ƒ|svtoochggd_a~‹Š”‘Ž‹‹Œˆ…‚……‹‡Œƒlj{‚x•“•Š†•™™…†Š‘Œ”‘‹v€‡’‘”ž–’Ž˜‘ƒ†• Ÿ¢¢¦›˜ššžš£¢––™©žŸœŸœ•š£¢ §¦¥Ÿ§¦ªª©›”‹‘––¡¨¬´§Ÿ¢¦ª­­©©¤Ÿ¥ª±¦¤²­Ÿ¨­¤¢©§¡œ£¡­®©§¢œœ®¦¤˜ž›Ÿ¬±ÀÉõ­«¯»¼«¶ÃÃÃÈÍÎÊÊÈÇÅÄÅ¿À¿Ä¼¼¿ÁÂÁÃÅÄÃÅÆÅÇÅÈÆÈÊÊÊÍËÌÇÊÉËÌËÌÊÎÊÐÐÒÒÑÒÏͤœ——ž¨µ°œ‹–¤©©ª¨—˜©ÀÑÚד/').1,4,10//84/+=A**+/272/550265=-88.2;HUm€‘—œ—ž“–”‘”š›¡›ž¡œŸ›ž ›žœ› œžœ›œœ››Ÿ¡žžžŸœ›œœ›žžœ›¡œŸžœ›œžœš™^^]^b]cbgea]^]b^bba_ecgcflux~‡Œ”—› ¡£©§§¬ª®«­­­±¬®¯««¥¡£›™—€|rccUKJLQKSUUZ]a^_\]^fa`_ab\_]]```gefddbbb\^bcg]c`][]WSPVšÙÒÉÄÏ˸¯¾È®œ±³§“© ’‚‚‘›•Œ•vlkkcZXjˆ‘Š†zzƒ‡Š~ˆŠ}ov€x{Œ““‡†‰‘–…‡“–ˆy}xyˆ‰‡–š—™”ˆŒ}Š”—ž¥¡Ÿš™˜ž •”Ÿ™‘œ›ž¡¢¢–‹Ž‹‡}{u}qiYY]n•ªªŸ›¥¨¥¤¥  ¢¤¤ž¥¥¢œš¡¤¥«¥¡›š£ª › ££¤ ¥¢›œ¥«¢›Œ™¢œ›—’’¥¹Â¾ÅÀ´¤¢³°ºÀ½»ËÌÎËÆÄÀ½¼½»µº¹»º½À¾ÀÂÁÿÞÃÅÇÅÇÇÇÉËËËÌËËÎÍÉÎÌÉÊËËÏÌÍÎÒÐÑÓÓÔÕÇ™“™¦°¦ŒŒ›¤§›‡mglqx–¨ÀÑÜßÃQ%$%)*,2,197834>6Har‡–˜™—•”’‘”˜Ÿ› ž Ÿ¡Ÿ œ Ÿœš›žš››› ŸœžžŸœœœžššŸŸœžœœžŸ›šœ›__`ab^cbc`e_a^_^bbbbhhllmmzx…Œ—›¡ ¤©««­±¯¬©¬¯¬¬­ªª¨§£¤–•‰‡€k][RKILINMSU]^c\b\a[`dbaac_b[^faeccdaahbcb`bb`eb_]__TPOSØÎÊÏͽ±Âκœ©¶®™®Ÿ…–˜’’€x‚mc[UdyŠŒŠ…‰{z€ƒ‰ƒqhuzx‡“•ŒŠˆ‰Ž‘ˆŠŠ‹Ž“yx€…‡ˆŽ’¢™’—Œzu‚––™¢¨¥ “™ž‘ˆ™—ˆ“”’—”’{„‹tkaJFŽ¨¦£œœŸ¦¡žžž Ÿ¤¡¦¤ ¤¡Ÿ ¦£¦¢¡–œ£Ÿ š™¤¨Ÿž¡¢˜¤§‘Œžš“—ª»ÃÌ¿´±®­¬­¶ÄÆÅ»ÁÉÌÊÊÄ»¾¼¼¼¼¾¼¾º½½¾ÄÅÁÃÂÂÂÄÁÆÇÈÆÇÆÇÌËÉËÉËÉËÊËÌÍËÈËÍÍÌÍÐÒÏÐÒÐÔЫ“š¥¬ŸŽžxoeU`lv—°ÆÖßÛª6"')#%-.166<>1.29/2/.9IB5922.16??Xj‘—š–“”’”‘”›¡Ÿ¡¡¢ŸŸ› žž›œ› ™žš™›žžœœ›š›žž››šž›œœšœŸœž——œ™œ›™bb`cb`dee`c``^_`bdgcdgkhhrszƒ…‰”˜ ££¦ª«¬®««¬°­ªªª¬«ª§¥¢œ““Œˆwm]\RQKHHLXVZ[[\`de_a`ffc___[^^eadaa\^a`eaeceddab_a\WUPNX¢ßÑÓθ·ÅÌá°±«•©¦¡Œ¥™‹‹©–’€„†qbZ]s‚ƒ{…Šˆ‡‹€y|ƒŠŽƒfoƒw„–“Ž‹…‰ŒŒ‰‡ˆŒ‹{vy…‹‹‹‘Ÿ ˆ‰„‰‘—œ™¡œ£ž”ŒŒtmfkinruw€ƒœž™‘€y”“ŒšŠ{kX;}¢¢¤¢¡¢¤¤ ž˜“œ ¡§ ¤©ž¢£££§Ÿ˜—œ˜£¥–Ž£© š§¡•”¦–Œ‘œ•š²¼ÁÊÅ­žª«­¯ÀüÆÊÃÄÃÈÈÅÁ»À¿¿½¿¿À¾¼ÀÁÂÂÃÁÆÅÅÃÅÂÈÅÅÆÊËËÈÊÉÉÍÎËÍÊÌÍÎËÊÍÎÎÌÐÏÕÒÒÑÒÒÀ”š¥¬’›Ÿx_^hd_^o€¥»ÖÜÞÒy)* !%'..6/4,104/00-.0<><525AG8;@Da|†˜˜œ˜”••”™œ›Ÿ    £ ¡ žœ£ž›™›œš››ŸœŸš› œžœœšœœ›œœž››™˜›šš›™ff_cbb^``_d_dd_adabdflkimnry‰‹‘•™ ¡¤¨©ª©­®®ª¬¬«ª©­¬©«¦£™ˆxnb[UOIIHSMSWY[cYfdbb_`acb`^Z\\cbc`d_ac^bbbhieejb``\VTTOUÞÙÔ½Êʾ©«À³—•½¬”˜©ª›“¤’Žƒ}gaegw„€„‚†|~‡Žzhiwt‚—”’ˆ‰‹‰Œ‹‹ƒno~‹Šˆˆ…ŠŽ’}zŽ––’”™œ˜•”‰qb\dljoih[Z][iqv„™™‡rw‘£ŒŽ”–Ž{iNo ¢¡££¢¡£¨¦£žž‡…‰žžŸ¥£¦££–“’••‡bz«¨ Ÿ¦”‹˜”ƒ™¤²ÂÅÀ¸²¬¢°¯¹ÂýÁÈËÇÄÃÇÆ¿¼¹¼¿¿ÁÁ¿½¿ÁÁÀÃÄÄÇÅÇÆÇÅÉÆÆÈÇÉÍÉÆÌÍÌÍÊÍÌÌÌËÊÊËÎÍÎÏÑÔÓÔÓÐÉ£›¤¨›–™|fRQRW]]f‘ž¯ËÚÝÞ»D&!! #%,,--,07*.5-0--47<8337454=LTm‚‰™™–’’”“˜–š ¢žŸœ ¢Ÿžœ  šŸœ›š›ž›™››ž›š™šŸœœžœ›šŸŸœœœœ•—š™™˜—cc]bedbc\_cdedeb`ecdkjhhkmtz~ˆŒ’“šŸ¡¡ª®®«¬«­¯°­­¬­©®«ª«£š•€xk]\SKEIKQRUT[YZZc`ed_]a__^__`df_`b_efdbb_bcbccc_^a]ZTMLP’ÚÙÇÂÒÓů¼Ã»ž¢¥µ ¤ª Š¢Ÿœ‰£™ˆpcupqy‚|}x‡}„ƒƒ‘‘chz~y{‚’‘ŽŽ‡‹‰Š•…s{|zˆ…ˆ–Œ‰†ŠŒ€€—œ™—•”’“–Š|lTdxy~„}umlnaU^^el‡`s‡•‘ž¢£™Œ~g\n†€ƒ£¡šž©©¤’‰ŽŽ‹‰‰‰”¨¢žš¨¥•‘xkdS8?{‘››šžŽŠ›“‘ª·ÁÉÀ­ª©ªª¼ÀÄÄÆÆÉÊÈÆÄÆÇÃÁ¾¾½¾¾ÂÁÃÀÄÁýÂÄÃÄÆÇÅÆÈÅÌÉÇÆÉËÉÌÊÍÍÍÍÍÉÌÌÍÌËËÎÐÍÏÐÓÔÓÖÒ̯¢§¤™“šŠeWQRQUeddoˆŸ±ÈÕÝÞؘ)"""#%$.,/2264,)(002729:52.191<7I_w‚‘š˜•’’‘–š—ž¡¢Ÿ¢  ¢ŸžŸ ¡ œšœœ™œ›žš›žœŸŸšŸœœš›˜™š–››žšŸžœš™›šš™™aaef`bef_cddc^ccbbecfhjkjpus~†‹”•šŸ ¦©¨ª§¬­¬¬¬ª®­®­­©¨«¤œœ•Œ…|ndZWRHEIINXZY^Zbcgad_aaea``e_da^gb^_bba`cceae^a\b]_^XQPQ’ÛÐÌÑÒ÷Æ²ªŸ˜ ¢š…”ªž‹£œ…{xwyw~€x|‚{z…‡Š†€{^j€|t“Š‹Œ’‹€‡„Ž‹†~vyŠ{„‡Š‹’™ˆzƒˆ‹—›ž—™”Œ‰v\[^w–‡ŠŒ€vuvwnagYNcpdV€‹™§¤¨¤£œŽ~qfca`hp|ˆŠŠ•¢­¡œ™•“vlj™ ’š¢¢•v€~wV58N‚Ÿ— •„Š˜¡®»ÃƱ¦¤°¥¤»ÄÂÉÏËÉÌÊÅÁÀÂÆÄÁÀÂÁ½Á¿ÂÃÀ¾ÃÄÂÃÄÆÄËÉÅÆÆÈÈÉÉÈÈËÊËÉÏÌËËÊÊÍÍËÌËËÌÐÏÐÒÓÔÕÖÒ´£« ”™‹vWOJVS\Xblq}›²ÃÑÙÛÝÃ[&'$'%%).-54+/13+---4:177403227=@Ph’š™™—’”‘“—›Ÿ ž ¡žŸ¡£ Ÿžœœžž ž™žœœŸœŸ˜œž˜ŸšœŸ›žš™›ššœ›˜—›ž›—ddeacbbc__`ecc`chcagejjhkquy‡‹Š•“›Ÿž¥ª«­«¬¯®«­­«°¬«­­©¦£ Œ„yqcZOOEDHOPZZY[Zab]eaad`e`gbh`d_cfffdad^bdhcfeb`_a__\TNMT•ÞÒ×Ô´ÁÓÉ­©°± –«¬Ÿˆšœ—¨•Ž€„nr{}vp}zx‚€z‚‰Žbllw~‚ˆ‘ŠŠ‡‰…†…’pmq~‰ƒ„€‡Š‰Ž¡’…}z‡”–‘”–™šš“ˆx\Xn€ƒ––ŽŠ…‰xxywrrmSKLPN€™£ª¨¦¥¥¥›Ž€~squrl`[ap†¦©¡ž¤¦§¤†‚hhƒŒwr˜¤˜ep…lH.3Y“œ›Š‡ ¸ÄǶ°ªž¤§§³ÂÁ½ÊÐÌÉÆÆÄ¿¿ÀÂÃÂÃÁÃÁÃÿ¾¾ÁÂÄÃÀÄÄÈÉÇÇÉÉÉÈÉÉËÆÍÍËÌÍÎËÊÍÍËËÌÊÎÌÌÍÑÒÒÕÔÖÓº¥¥¥ •z_NKPWWb[`hrzŒ§¾ÑÖÝÛÔ/" &")''0,7-/72-,4,01436>>=1789@M^sŠ›“•‘˜’‘”™š  ¤¢œž¡›œ›Ÿ›ž¢šŸœžšžš›œžžœšž›š››™™››˜ž™™ž™›™œš™š—–™›™—ccbbaabgceba^aecha^bdddjlpu|„‰•–™Ÿ¢¥ª®­«¬¯®¯±­«­«©¯©¨§¤œšŽŒƒ{oe[PKDLOOVSTVXY]^babhaa]aee]d]d`fbdcgfbfccdcdaebd\XXTMOP‹ÙÛÙÈ·ÊÒË´·Â¼¯Ÿ«¬œ‘­—ˆ‡¥£Œ‡…ˆwvqw€vvzoy€}}‰‡†reyvvv“Ž‰ˆ…ˆ‹ˆ„|tn~†‚†‡‡‡ŒŠ’ƒyƒŒ–˜–“‘”™™kgw†Š‰“‹|„~|yximiog]SM9T€˜¬«¦¨§©¤š„y‚ƒwor|v~sidXiy”˜’¬š‹ngh\CQbZ?@p~q`3#/{¥›”•¢²ÅÅ´™¤¢£«¶¾½¹¼ÄÇÄÇÉÆÀÂÁÁÄÃÃÂÁÂÅÂÆÁ½¿ÃÃÃÅÃÆÆÉÆÇÉÊÈÇÉÉËÈÈÎËÉÍÎÎËËËÊËËÊËÊÍÌÎÐÑÖÔÓ̽ªž–“mVLTYW[Zjaanwˆ›µÇÔÙÚݯB(!'&/=*-.1/-/32-++(/776=794/-59JVh{Œ”——“““”•‘—› ¤¡¦Ÿ¡žŸ¡ ¢œ¡ œžš›ššŸŸœž›ž™œ›››œ›žœ˜™™š™™œš˜šš™œ™š—•™›˜”ccda`acccgeb_cbbhdacciejtow{„‰‘•œ¤¤©©¬­­ª­±°¯­­¬®®«¬§¡Ÿ›—‹„xqc[PMEEOKRQST]Zab__h_]_ccecfd_cfff_`hce`agfdcbe]`YZVVNQQ€ÖÜÌÄÌÒÆ»²ÉƵ¢²¹¤Š˜žš†¥ž”Žœ‘ˆyxps}ytspt{{ˆƒikm{xu€ŠˆŒ‰ˆ‡ƒ‹wpu}w†~ƒƒ…†ˆŠ‹Š†€€~Ž”‹””•”‘”Œzr~Ž”ŠŒŽ„yqpojlh]^YWY[bK:F~¦¬¤ £¡q€Œ…†Œ…€„tiTFBES]ohbrgVaa_WX317AF14T^F+"-Y’–œ±¼Ç¾©š¡› µ¶¾Æ¿ÀÀÅÃÅÇÅÁ¾ÂÂÂÆÅÃÅÃÃÁÃÄ¿ÀÀÀÂÁÄÅÅÆÉÉÈÉÅÊÇÈËÊÈÆÉÊÊÎÏÏÌÈËÍËÎÍËÍÍÍÏÑÕÕÏÁ¬£Ÿ“ƒiXYPMT[cW\__fz‡Ÿ³ÁËÕÙÚËi)-+#$*.0/04.-/7.**+*,5363/4-0026Fdw†–—™›••Ž’•˜¢ž£Ÿ¡¥Ÿ¡¡ žŸž¡Ÿ   Ÿž›™›žšœ›ž›šœ›œœžž™›˜œ—››œš›–š›šš˜™œž›˜ccdbgabab`fl]cdklffighhjqs|ˆ‹‹“™š›Ÿ¦¦­«²®ª¯¬°°©®ª««¬§£¦¡—‘‹„tnbWTKHJJPNTVW]b\[\_^`cc_kefid^_filccfbccabfbdcgcb^XYVRRU}ÜÕÂÑ×ʶÀÊ˼¯·¶³”ž¤“‚xš£‰¡²•omqgi|utry„†‚r_ft~|€ˆ‹Šˆ…Š†‰†‹‡†lrz„ƒƒ€€…Š…††‡{€Œ“’Š‹‘”š•Š†wsŒ”•‹‰rgdefkbRJE>;?ID2@y””£¦¨¢—ƒxŠ†|……{{una`[TQXv`QEHRRQYCHCP?=F7:E5,)2--/+'&'+*IŽ¹ÉÈ°–”“ž¦°¹»ÂÈÊÍÇÄÂÆÆÃÁþÀ¿ÂÃÅÅÄÇÀ¿ÀÁÿ¾ÀÁÅÄÅÄÆÈÉÇÉÉÊÈÅÈÊÉÇÈÈÌÎÎÌËÊÌÏÎÍÐÎÎÌÎÒÍƲŸ“€k\\XTPWUXVZ_Xbnr“¯¿ÃËÓÖ×¹P((*$,(0-26.30,17*,0200:4?21*),32Lcv†–•™–””’ŽŒ’šŸŸ¡¡¢Ÿ ¢žŸŸŸŸŸž ž¤ œœœš˜œž››™š››šœžšœ›™œ›–™šœ›™œ™š™œ˜š™ffgccdfdgbfb`gaedbjimhjjiyw}…Ž”››Ÿ¡¦¬­¬­¯®¯­´®®®­­±©ª¨£ž–“Š…}of[SJKFKOPVQR^b^[_eb^_bbaeccg``ggd``c\d_bcbhbcc_]b_][VSLoÃÛÚÑ¿¾Íι±ËÊ¿ªª¬¡‚|…{q“¨™…vimjjotq}€w~ƒwo]`tzxw†‰†‰…‰‰‰‘Œwr~‚}†~‚†ˆ‰„Ž†{z}‰Ž•”†‡‰Œ‡vdx€†“—‹qh\bdhnebXW_imbTIXZ`}|•™Ž„‡‹‡…~oME?JCHE>9Mbz€d8:BZ@A835167,)-.)*.'&$#+Rw®ÄÀ®—‘šŸ«½ÂÂÃÇÇÇÉÄÃÂÈÄÃÀÁÂÁÃÄÅÅÆÄÁÁÁ½Á¼ÁÄÃÃÂÄÇÇÇÇÈÉÉÆËÈÆÇÉÈÆÇÎÍÒÎÏËÏÒÎÑÏÌÐËÌÇ­•ˆ~le\Y[ZXUWXXZ^Y^Zcu‰›«¼¾ÄÏØÚЃ,,(,&(.1*/2121--3',6;74559-,,*(17Ln~“•’“‹’–£¡Ÿ  ¢¢¡¢Ÿ Ÿ Ÿ œ¡ žœŸ¢›Ÿ›œœ—˜š˜›œšžœ›š›˜š™š™—›œœ—š›˜›˜cc_bblhgeebacc`bgcehkmmrmtt}„’”š›Ÿ¡¦«¬®¬¬­«­­ª­®¯¬­©«¥¦–—Ž†zsfTSQOBKLRTPU_a^]`__d_eb`lg`c]ahfjb`acddabeebfd_db`_XVRNc°ß×ÄÂÑ̾·ÌÙÅ°º®£—|l‚™“Š|vjenqmqtt{}l\ajwxx‚“‹ƒˆ……‡ŠŠŽxw€€‡‚„~ˆˆ‹ˆ‰…wt‰“Œ‘“ŽŽ‡yjf{†‹ŠŠ‰‰~qX`rvwxdY]quwzng`h^g…hpu{€‹Œ}gYWNLH<36?:DZVH,,0($%#%)GH(%3c^m‘·¾²˜†•¤ºÇÇËÊËËÉÇÄÅÄÁ¾ÁÄ¿¼ÁÁÀÀÂÂÀÃÂÆÅ¿¿¼ÂÂÁÁÃÄÁÄÆÅÇÈÆÆÉÉÇÅÈÊþÄËÓÍÌÌÍÎÑÑÐÍɹ”ƒnaY[VWV[^]YX^TX[VcfoqwŸ´µºÂÆÍÕÕ´Y-&1.0%*+2/66-945.-0+).1;65.++7&-8L^|‹’“•’“’”•¢Ÿ¨£Ÿ   ¢¥¢ŸžŸ£Ÿ¡ž žœžž Ÿ  œ›™™—š˜™š™œ›œš™››œ›šœ—™˜œ›š›š›__fddeihlfcc`c`beidehlonntv|‰‹“˜¡£¬«§«°®¬«­©­±ª­®¯«©¦£Ÿœ”Ž†~vdUPGHJLQQTXW^]\\c[_acc__a\bbacgej`cfcabe_ihhecda`[bZWQNY‡ÍÓÕѽË×˹Èξž§¡‰uvqx{t{Šrvxsrwlqrx‚j`qysr{ˆŠ‹Š‡ƒ‰ˆ…ˆ†Švnqz‚‚„„……‹„ƒ‚ƒ‡}~ƒŽ‹’ŽŒŽŒŠ‚tatx|†Œ…~wehw…ŠiaikŽŽwxtU@SSJe`OK_t}p\PSHUU00FBHm†mB097:9.+8dw:0*-%7, %;h‘¯À±“ss‚™ºÄÄ»¸À¾¿À¿ÂÂÂÆÅÄÁ½¿ÁÁ¿¾»ºÂÁ¿¾¼ÃÃÄÄÂÁÁÿ¿ÀÁÃÂÃÆÄÄÆÆËÉÉÌËËÊÈÊÐÎÒÎÍÉ­tg]WZ[cZY^[ZWWVYe`ecrjlx‚™¨¯µ¿ÆÌÆËÆ7),*'(+*/2/464022-,+06**88379=791-+03C[r„•™•’Ž‹Œ“—››¡£¤£¡£Ÿ¢£¢¡žœŸ¢¤œŸ£¡ž£Ÿ  œ ŸšŸ›ž›œ›™šš››œ›—š™—š›˜›š—šŸ›™™œggeiagjhggbgb``]`felhjkmtrtƒ†ˆŽ‘•¥¨ª©¬®¯«¬«¯±¯¬­ª­¥¨¨¢ œ‘Š…}ka^OJKKMSQLTY_\d\a]acfgg`beb`^hcfhad_`_fcdbbc_d`^]\\^WSOOVšÔÛÔÈÁÎÕ˸ÈÛÄ£¥™•€ykvŽ¡£˜†† ‰q|{qqk]o{p}‡Š‹ˆ‰‡‡‹ˆwq{~€{…€‡…ƒ†||z{†ŽŒŠŠŽ…usnaoƒƒ‡†„…„zlctwunahbRD::A82=98<799:J]mf\|‘hOimXLfzgE[v|>78OD<@Jg~6&"$*$+0=wŸº¶£Štkœ¹ÅÆÄĽ»¸¶¹ºÀ¿ÃÃÃÄ¿ÁÁ¿Ã¿¾¾¾¿º¾¾ÀÆÀ¾À»À¾¿¿À¿ÃÂÄÅÃÇÇÅÃÊÊÆÇÉËÏËÌËÁ a]]\_^b]\Z\ZVR]Z\cks{ƒ‰– «±·ÂÇÈÇÍÑŸ5&*+**.3+-.0416/4,-/011',.-328<770.-38Qk€Ž—–””–™› £¤¦££¥£¢Ÿ¤¤¡œž¡žŸ¢¡ž¡œœ¡œ ¢žžžŸœœŸš›œš››ž˜—ššš™˜››™˜›™—š›™˜—œiijkjgkgigedbcdbbcbmijmmotv€†…Ž“•˜¥§©ªª®ª¬©«­¯°©­«¬®ª£¥œ•‡na[UPJLPKMTSV]^`\_\Zccedbcb`dbccbmc`a^bfddcdb]^^`[bc`]TRSRxÔßɺÊÔϾÃÕÓ¹¬¦ƒy„{˜•Ž‘‰xŠ—}~rjefhmxs€…ƒ…‚„‹ŽŠ‚vmr|{}‹ƒ‚ƒ†„‚„|zy„ˆŠŒŒ‰„ƒwbc|}„ƒ‹€~}f`ntc_PMNLFGONF@269@@B:@DWml[z“mSdaO7Llf[Cv‰vf3FIOU:-3px9%!$!"$,GWv¨Â¹ž‚qnw›´¿ÃÆÃÁ»¾º¹¼¶º½ÂÂÁÀÁ½¾»¿Â¼¶¹»¾ÄÁû½Â¿º¿ÂÂÂÂÂÁÃÇÂÂÄÂÈÄÅÆÉÄÄÆÉËÊź¤}yoZ^]\^]\ZZ\XX\[[guxƒŠ˜¤°´¾ÁÃÃÏÓ´U,$))2/*,,,.66/578.+010+/1231;B9:;75485?[`Q\^[KK^caO1&-y{(%"! %@Y‚ªÁ±š}ts}š¶¼ÁÆĽ»´°´µ¶´½ÁÀÁÀ¿¿½¾¿ÀÁ¼µ¶¼¼¿¿¼¿À¾ÀººÂÅÂÁ¾ÄÄÄÄÅÅÅÅÇÄÉÆÇÄÆÈÈĹ‹h~…‚~daa^f`VXXW[^afn|ˆ”™ ¦£¨®²¶¼¾ÁÈкc.*02101.5113544033/.-))*.2:=?>A@M4-/14JizŠ•—•’”Š‹–¥ž¥¦¤¦¡§¥¢¢¢£¢¦¤£¢ŸŸ¢žœ Ÿ¢œ›œžžžžœœš› œžŸœ™š™šžœ˜›™™—›–—kkikkpfeghc_fbe_ddegckilln|€…‘–˜œ¤§¨¬©±¬«¯«ªª¬­°¬©¬ª¤£™”Œ„zndXYJEHGLUQVfY\]aab^_db^cb]`d`fjfedcb^`fdjea^_aeebfb`_]SKO^±ÔÕÖËÀ¾ÏͺÁ̺–’’‰„ˆ‚“‘‰¡’‹…„wb^fquowƒ‘…‚‡‚ˆŽƒˆƒ†tq{€~~}€‚…Žƒ~x}|u†’ŠƒŠ†ƒ†~jH‚…‡‰„~€xcaPLV?:7;313564,:J`€…^jf`K1-)2//ZqvB8NZldY=6;#).~G+(#3[Œ²¹œ‹}xyŒ®À½¹ÁÀ·´±°·²²»¾»¾À¼½¼½¾À½¿µ¹¾½¾º¼¼½¾¾¾¾ÄÂÀÀÅÁÁÂÃÃÄÆÆÅÅÅÅÉÌÈüŸnigb^s…„}nc^`gaemv†Ž“Ÿ¦££¢¥ªª¬±²±»ÅÊÍ®T20('*2.2,8.4:>;53:=.*/)./,,-5=CH<4<:2<Qiz^;*&,##I}@U/#:hŽ°½ ˆ|{†•¬ÅŽ¾Â¿½·´³´µµ¼¼¼¼¹¿½¹»¾¼¿¹¾¸»¼¼¸¹»¿¾¾ÀÁ»½½¿ÀÂÃÂÃÅÁÃÈÉÈÈÆÆÆɽª„YKblnbxŒ„€onq{y}Š“›¢ ¦©§¥¢¥¢£¨«±´¶ÂÎϨR--(+--,0.-.7/852178;0140+')-0499ShfO4373*)-6:D6,%&4904ctd?PVC.,,2:Fl†ƒg[JMZi@%&$0J, -5‰H0c²­“yt…ŠŸ¸¾ÂÆÇžµ·µ¹´°±µ¹¶¹¸¸·¸µ³³¯´µ´µ±´º·¸··½¼½¿ÀÂÀ¾¼¿ÃÃÅÁÅÅÆÇÇÆÀ \\D./:izup``xk`hŠŠ‹™¤¥¨ ¦§¥§¨§¨¥¦ª¥«®±«¼ÂÈÏÒ¼v8.(+,%*),-413718=7.27<71-0.,151236412(/>12Ph——”‘‘”•Ÿ¤¦¥£¥¦¢¥¥£¤¦¦¦¥¢¢£ ¤¤£ž¥¡¡£š¡œœž›ž¢žŸœœ Ÿœœœ š››šœžšœ˜œ›—˜˜›š›–˜™™”kkkojihhjhleil_feaageejmktr‚†Ž“”›Ÿ£§§«°«¯­¨§¬«««¯­ªª¬ª¥˜“Žˆ~rm[ZTEFMLRYXX[_W[`]ad\[_^dedbeehdbfbebcgchdac_hfeadedd^\^TSRY¬ÝÞмÆÐÓ¾³ÍÏŪ¦ª ¤µ†—«”h]glz~…ƒˆŽˆˆ……Š‹j`crx}y}z…‡xyzz€|xwu€Œ…}upbZNSu€‹Œ‹oZVX?4GSB@RbUD96AA1-..=EF1+#,4:/Gv}zM3LI220.8Jnth[^hfX'"$0bR GŽM_Œž´ž‘€v€ª»³ºÄÇÈÁ½´··²®²··²¼ºº¸¶µµ±¶²·²°³´¸´µºµ¸¼º½ÂÂÀþ¾ÃÃÂÃÇÄÁÁÁ³zA7Pa>3Ab~vdeqyib‚••¥§¨£¥¦¦¨¤ª¦¥ª¦§«¯·ºÀÇÍÑ»q.)%'('%,/246/55289=78<790)-*.-).4;89>62-948Xp„”™“’“Ž“Ž‘•ž¥¥£©¤¦¥¤£¢¤¨§¥§£Ÿ¥££¡ ¤¤£Ÿžžžžž ¡ŸŸœ›žœœ›œœœœ›šœšœš™—š——™š™—–jjikngjghlkeidbhdifibegjipyƒˆŒ“—šœ£¢¨§­®¬­«¬­«¬¬«®ª¬¬£¡ž™“…|riZ[KFHQKSYTY^\\^`Yb^]e^ea_f^`_fa_e^_c\aefc`edgdfeeccjc]Y\RNUŠÉàÉÊÓÓŶÈÑ𜥳³Ÿ°®ˆ›œn_fu}‚ˆŒ†‰ˆ…‡ƒxfqxvz{~€€xxu~ƒ~|ws{‹ŽˆŽ„xndQKXxy†€vZU@:=@OWVSMAA=A77:.0>ON/&#$(.7Hflt];;=7,2418c{qNM\zwp\3"&)`wI!]˜r­«–‰zy|Žª¼Á´ÀÅÆÇ¿¼²¶±«°´·¼´¹²»»±µ·²´³±´µ²°«µ±»½»¼¿Àº¿¼»»ÀÃÃÃÃÂÂÁÀ¾¢Z02>Xg\?AW†Ž€tftywdw‹–¥¢¦Ÿ¤¨ª©¨ªªª©¯­¶¶ºÀÄÏÐÂ}-'((%**-0,0020790297245631-,..02118304,4/55Jewˆ‘•’’™¡¤¨¡¤§¦©¥¥¤¡¢ª¨¥¤¢¢¤¤¡¢§¤ ¥¤ ž ŸŸ¢ŸŸ¢¢ž›šœœŸž›™ššœœšœ—™™šœ–›š™–˜lljmjikhffhheddhaiajgcegkmsz€‡Œ’”— £¤¦«¬««©±¬¯¬­«­¨««©¨ŸŸš—ˆ…wiZWMGJJJQYYZ__\_`^b^fb\ac`aaadeh__^_]_d`bfeacfidjlkgfae][XQUh¦ÕÓÚÓȾÈÕƳ¬¡¢¯º¬ž¨¢ƒƒgbfo…~zy}…ŠŒˆ€|km{‚€}|…}~ƒyvwy{}xsxŠŒˆŠŒ‰‚{kkWUPdolP;:B@BEKVIDO>99<;39=QP7.(*''46_eOmF+0;7E94>exdJ?^x~teC*+,Vƒv" 1zž±²‹{wuyŽ¤½ÈÄ¿ÂÁÆÄÀ»¸¶²µ´²µ´·»³³·´¹·¶¯²²´¶²¨«±··½½¿¿º»À½»»ÀÃÀÄÃþÀ»—E-#*G_ro[=Gx•yijw~ej€‹šž¡œ¨«©¬­©©¯±¯±¼»ÂÃÇͼ‚;&%+9(,/3/1406554;565017335-++.8,437:02:4<6>Xj†‡’’”’Ž‘˜ ¨¥¦¦¤¥§¦¦£¥¤¨ª§¥¥¤£¡¢¡¡¥¡¢ ¤¡¢ ž  žœŸœœ›šœœ›¡›¡ššœ™šš•™™—™™™•ggihgkikhihhhddegceedclbempt€”›  §ª©«®®©ª«ª«¨ª««®­ª«£ŸŽŒtd]QHAKBOQST]V[X^[^^`_a_]]\_]_eiic`^b`_\d^aa^gjijklkgcgda^_WYWwºàÚÌÃÏÙ̹¶ª¤§«»¼¡ž¬€ibYat}†‚}xw}‹‡…yvf`{|‚~zˆ‚txzqp{}zv}{„‹ˆ‹‹‰‡ƒoih_ro[ONHRNJIGC@JU^SPM?>?702=\cJ,'$&'+<=eHas=.6;69<6MbJBSow^SE,&2L}…Q!)GŸ±®‰znwz«¼ÆÇÅÃþÂÀ¿¾¶´µ³°µµ´¹µ¯³¹³µ³±­±­´±¯®°°¶µ¾Â»ºÀÃÃÀ»Â¼¿ÃÆÁÁº©€X70..9_lrgL<`…“ˆpi{…to€Š”š“˜™©¦­ªª®¬®³µ²»ÂÈÍ¿™a9-%&(*)*/.104533255843:4>6,/,.-+4*654232..73Hapƒ‰’‘‘Œ‰’› ¡¨£¨§§¦¥ª¦¦¤¤¤¤¨¦§¤§¥£¢£ £¢¡ ¡ ž œŸœ¡ Ÿ›Ÿž¡žžšžš›š›šžšœ—›™Ÿ–™››–™jjkjjhihmhhfdcdbjddcclfjilqz€‚Š”–š¢¤¨ª«ª­¬¬ª®¯©«¬®­¬®¬©¤›‘‘Œ€ukYUNGCGGOQSX]ZZ][^ac_^\cabf_a`dbbe^aacbebc_bcddffmgekff`c[UYT_¦ÜÝÍÕÛμľ«›®´¶´›®šlYXgŒ€„†„yz‚‰}tick~„zƒ‚z{zxzxsyzsxƒ‰…‰“‰‹ˆoV=7J]]GEDP[WTEDMbhQG>E?>-*39]xb-+&$&'(HNn'&M‚}*.p¥ŸŸtt‘¬¿ÁÄÇÆÄ¿¼¿¿¼»¸¸µ·¯µµ´·±´·µµµ°®®­®±¯´·±«¯¶»¼½½ÀÂÁÁ¿¾¾¾Ä¶¶ŸqVMGF927HjlrlRFc‹’‚jtŠzoj|‘š™˜©©©«©¯­±·µ¹ÁÉɸ~;2**5#%'**,.046864446;;;=4830451-,.23307/1399B>+$(-TrkA))((,*/RXm5^E*)&/-7;Idh;1'.d¤‘l" *H’®’q{ywƒ™²¾ÁÄÆÇÃÂÀ¿Á½¼½»º¶·µº¶¶´´µµ¶´®°³¯«¬°¶²º®±°¶¼¾ÀÁ¾ÁÀÁÁ¿¾º½·±¦˜qZRHP\V>ESgotf_PtŽŽ{m}}ctŽ›˜˜š¤§£¨«®ª­¶½ÅÎ̬f4&*-'% $*0-,.324458@<64EC65A51/51,003717:4212AEWl|ˆŽŠ‹‰Œ„„‘š ¥§¥¥§£¥££©¦¦¨¤¦¢¥¢¢¤¢¢£¥§£¢¡¢¡¥ ž¤ž Ÿž œžž Ÿš›Ÿ¡žšœ››ž›™™™˜–š”š˜š™›uuknionemjkknhcdabbcdcfebnsv‚~ŠŽ”™ §¥ª«¬ªª©«¬­¯±®«¬¬¯©¥¡ š”Ž‰wg\NNKDILOWUT]__d``^\haa`c^ba``_Z^bcjd_badibbgekdhfgmhhdegb\XUW_˜ÍáÖËÌÕж¦Ÿ§°¨¹¾¦kdm{Œ‰„ˆ}xunkqzx~„€‚€{yzyvy~s|‡Š€yvmj\fdi[UNG??CVHJFAAaZNHD==>5.*,2<`s6*%%-&+3T`a0e8+//4>PK>?B2.-7Wi\*(%6|žŠ9#*Fj–‘z_nx†š¶ÆžÃÇÄÂÀ¿½¾¼¿¾¹¸²·¹µ²´··¹¸¹±¬°®ª¨«µµ´µ±´®¹»»Á½À¼¿½»½»¶»¹³³¥‘w]LI\h_Q>GiegecK’„oowlgƒ”˜™“¢§§§¯°¯µ½ÊÐƘ^3()*)/6)(,-.2411//24;7>98E520.+5*-),)034722/2ABLXpŠ‰……†‰†‰“›¥¥£¦¬ª¨©§¥££§§¦§££ ¡¤¥¥¤¢ ¢£¡£¢¡¡¡ŸŸ£ž› œž¡›œ›žœž›šœ›š™—šš———•š—ggmmnmphtjomijgc`bccedfbdjtv€€‹Ž”›Ÿ£¥¨§­ª­¯ªª®®¯¬®¯¬­¨¤¡œ—”ˆ}ucWWMKKFMPSRTY\Z]`\]^beedg_accbaa^a^i\a]dccd`gfffkilniffebbb^UTVl­ÝÎÌÙØÊ¿¿¶¨­«´¸¿°“tg€‚†…‚ƒ…|}xkkuv‚†‡‰ƒ~„}y}€{yw}|‰ˆŠyfhhijvukioZXTSTMC<>BVcZI;A//4-,)-@_q…k*""%+**9Qbf0^/-+>;:85;35-/'=dtN'##A„“m%A[e‡}utag†£¸ÀÇÆÃÂÅÂÀ¿¹»ºº¶²¶µ³±­¶¹º¸¸¶¶¯¬¥§©°´»¶µ±µ°ºº¼¾»º¿¿¸½·±ºÀ¿¼®¨†fQKJXnlRLY_\_aX[‹Ž|ruwhd{Œœ˜˜¡¤¬®³¶»ÃÈοŽJ4*++6)1&,'--./36314.:965@6904*,/7.*,/+5262915CECRgw†‰ˆƒ†…ƒ—Ÿ§¨§§¦¥©§¢¥§¤ ¤¦Ÿ£¤¢ ¤¢££¥¢£¢¥¢¢¡ ž £¢¡¢Ÿ¡  £¡¡ ¡ŸŸ  Ÿžž› ›šœ›š››™˜—•–™—kkjihlmpjjiekchedabba^\cainw€€Š–› ¨§«­®­­¬¬¬®©¯±««­ª¦¥¡œ–”‰|ufVQJJIKOUUYOUW[[]]^`_^cbbccf^_aacfbbb`_^cebeggljhhkiflniffdc[YSWÂÍÞÚÑÈ»½Äº±¬·»º©•kxš~||ƒ‡„…‚~urnpz{~„€…‚}~yv~zpsŠŽ‡ˆzww|w|ywrrdfieY\UB:@FQ[ZO<5/+)&'#/DAXn„i-**$*0.3Wd^2g/).8<902;;6502=mwB-",K€ˆZCp|ŠRcqbo£¾Ä½ÅÆÄÀÁ¿À¾º¹º¸¸¶¶·±¯±²¶¶¸±¹µ¯«¦¥©¬°¶·³°´»³¸½¹¼ºº¼¶°³¶²Áž²¬”x_TLEJpucJSdaYeYp‚{u}lf~‰•—™¡©µ´»ÃÅÊ÷ƒ@+,(*+.+*/%+11458;6722:67:?5812--()01/,/9;7>239HGDYtyˆˆƒ‚„‚€„‘›¡§§¨¨¥¥¨££§¢£££¥¢£¥¢¢¢¡¢£¢¤£¤£¤¡£¡¡ ¥ £œž£¢Ÿ¡œŸžœ¡››žœœ›š™˜œšš–›–’––nnmjljfnhdjgifffcedd\c_ccfns{‡‰”™ž¡§¦§§¯®®«­²®­¬¬­ª­§¬£ž›“ˆwiYQIFIHMOTUWU[[\]ZXecb_caa`c_a`dddc`_^`beg`gidihgjlihihhef`]_[TTc“ÒàÑÏɽÁÆȹ¶»¹¯‘i]‡ ‰uu|ƒ…„€€tvt{|…†Œƒ}ztztmp‹…ˆƒ~}ƒzuyu^_dcZNK?JFXb^^U>;,-'&)(,ECgrƒN*&/*00)0WL[opC*%5pŠ}enŽŒ|BXorƒ²Ä¹¿ÃÃÁ¿ÁÀÂÀ¿·¶··µ³³±²²´´²µ»³¸±­ª««¬¯µ·¸¹´º´·¸»ºº·º²µ±¹½½Ã¿Ã¿½·­Ÿ„o]\PD]YIAQXS_Za`hQE631.2,*$.8Rxlr6"$(+2\b+;5;:679?BIau‚‡Š†€€w{…Œ›¡©§©¬¦¦©©¢¤£££¤£££¤¢¢§¥¦£¦¦ ¡¢£¢¤¢¢ŸŸž  ¡¡  Ÿ   ¡ž¡Ÿœ£žžššœšž™™š™œ–•›—–™lljllmkmdiigefddbbhc`b__\giny†Š‹• £¨«ª­ª¬«¯¬­ª«®°¯¯¯«ª¢—˜Ž‡€xeYYLKGGFOOTRU]V^b]\g`baae`c_cdaa``^badfbadffjjhejknkqponjlifd][XYRtµßÐÈÇÇÂýÂÆÁ™mv¥ˆ†zqvpvzrolnx‡‚‚†„v{zuomovx€ƒyzxunpkedZ\QH>GOKGS[XNZdcdZ@C96:96*'11okTVc‹Žzl˜¸­Ÿ¨¼º¹¹´µ±·¸»»µ¹µ´¯¨¬¯°°®³°­¯°´­³®¯´­¯«¯°´²µ´±±¶»¿ÀÀÁÁÄÂÁÄÅÂÅËÌËÇÅÁº¨™ŒqcXWXO;?fZSUSG@ƒŒ††„ŠŒ™ž¥‚mR6)+,,&*.+)032320/1994:2877:7=9:<90,**+/1.225246++2>@MZm~†„‚|}€~ˆ” ¦§¨©ª¢¦©¤©£§¥¡§¢¦¡£¤©§¤£¥¢ ¢ ¡ž ££¢£££¢¡¡£Ÿ Ÿ  ¡ žŸž¡žž žŸœšŸš˜››™––˜——mmmnpkmlghhhfififeacba]]^^js|‚‡’“šŸ¢¡ª«®®®®¬­©¬³¯­¯«­ªª¤œš™‰tiaRMAFKGQVUTUZ]X[Z\c^_\db_a\``]_bdbceb^dbebgihfnjllkprpnokklhf`]YU[ÕßàÖÉÃÆÄÂÉÁš—Ž}yzzxtvrockux|…‚zwnllrkqŠŠˆ|€€sx„…|qhVD@@FM?><57==686894/-'*41052;10627==IQdy‡…ˆ…||~‚Œ™¢§©«§£¦§¨¦¦¦¤¢¥¦¦¢£¡¢¤¡¥¤¤£¡¢¢ £¢¤¤  ¢Ÿ¡¡œ¡££¤¢¡¡žž › žœžŸœœ›ž™™™š›–”–˜llkjllfjhklgeedhc``bb\\^\cjmw‚ŠŒ•šœŸ §¥«¬­¬¯¬­«®¯¯¯¯®«§©žœ”‘†wm[UNFEHIMPQLSX\ZX`b]`c_c]a__d__]a^bbgebbddehfhhnlhommtmpjkcjbcd__VZ†ÏÙÜßÐÈÎÆÈÅÀ¤°||u~€xwgeips{€}„„~rrlks|ƒˆ‰‡~yy]\|…†tkXOHATG<:5;GH@BY[bZIJE86/0-1-:AEAF@_`BXNC1+*/6.1..../1151/0,(%$+:V+HF<897:8@XaOTPDC=E2/654?DOB4?_f]X_K225..-000.15173.1)12&*)3OFQilSSY8LgkuyŠ•¤«µ·²®«³³¶²·³¯ª©±ª¨¤ª´±¬¬¯¬­µ±´±¬²ª°°°¬£¨ªº¿ÄÅÇÈÅÀÃÂÄÂÀÄÅÅÅÃÇÆÆÈÈÅÀ¸«š‡tfb]JJH8)>nZ]TQ6_„„‚†‘›š“‹~riT82)$(,,)(,+0-57;78485:==?886;530.5/.*%)014923200>BCObx„‹‰ƒ…zwv‚Œ’š¡¦¥§¦¤¥¨¨¥¦¦¤¤¦§¬¢¢¤¤¤££¤¥¨¥ £¢ ¤ £¡£ ¡¡  ¤ £¢  ŸŸž¡ŸžŸšžž›œ›š˜œž•™™˜›—jjjlhijilhekjddfdfdea][ZUbhnt}…”•—ž£«¨©ª¬¬«¬ª¬¬¯°­¬¬®§¦¡›˜‹…‚vm]PLDFKOTJPTT]`^_\bafdfbcgffcf````aadb^cdiefgjjghmnttololpkohhd`VVZÓÜÖÔÙÖÇËÄÉ¿µ›†v{}zykknz{y~ywyqju„|‹‹‚~„€vc[xvtlccUCOG@>;68>..6=WdESEDHMRA7>53:GU;'4fkofXJ('(-/4/2/30/-5<3+-/,-**?^YgxfVV^@\†¡Ÿ¥¦­±®´±°µ·¸º´·±¨©¬®¤¦©­°¬®±´°³µ°°©«±°±®«¥¡®»¿¾¼ÁÆÈÉÁÇÃÅÅÃÇÇÇÈÇÅÃÊÊÈÃÀº¯›Œyd^fV?<=,%=iV\NCAr†ƒ„ˆ—–Ÿ™’‚uhJ431*')('(/0.38=>98656;GZn„Š„ƒ{v…•™ ¢¦¦¨¥©¦¨¥¤¦§¦£¦¢ §¥¤£¥¡¤¢§¢¦¥¦£¤¡¡£ ¢¢ Ÿ ¡ž£¤£ žŸ  š›Ÿ›ž œš—™™–šžš˜•lljgnigjjghkfefb`fd`b\[XWddn}}ŠŒ‘—œŸ£§ªª®¬ªª®©ª¯±­¬±¯®«§ž—‘‡„viZNMECIMPMOTUY]ZXZ\cdbb`de[bbde`gfaecb_cbeibhjjcgnspsqrommkmmlb`[[V€ÓÜÛÒÖÚÎÏÆ»£…wqvv}w|wurxu}€zztqtqtx„Ž†ˆ†„€~|vo\[|qjYUSIJQML=>;20)*8:HMHNCAEEUQG>;'6LQ8&6q[yx_X2(,+/:/,-00610:/)*,)'),A_l„kXUYaOr§¡ƒ¶°®©±·±°³µ·»¼¼·²«­­¥£¦«¬¯¬³³¯²´³°©§ ¯³¬­ª¢¨±¼½ÁÃÃÂÅÉÇÀÄÆÇÄÄÈÆÄÂÆÆÇÈÄÉȽµ°Ÿ„j\bNQ?80(0WjbJOMg‰‹…™”œ——‚v`;.-.&,(&(+,-/-1:8978658<79I;A:41-/3--*+*&..812.575HIbtx†ˆˆ~z}‹“š ¢¥¡¥©¤¦¤¦¥£¨§©¤¢¥Ÿ£¢¥¡¤¤£¡¥¡¦  £Ÿ¢¢¡¢¤œŸ¡£¢¡ž£¡žž¡¤ Ÿž  Ÿ¢œŸ Ÿš—™—™˜—nnnhljgkeekigib_db`d`ZY\\dhn|~†‹— ª¬«±¯«¬¯­¯¯¯¯¯±¯®¬¤ š˜ŽŒ„wj^NJGENKPPXUY]`YX``a\`db^e`bfc_bc`ce]^_^cdgfeimgjlqpsnqqnrmiiefa`ZY|ÒÙÜ×ÓÜÔÓÍû†rnjtyz|rqy|€|~zuhfluz}‰Š‰Š‡†‰Šƒ~wjfXOgb]NF;DWZOB34./-.+15=JUQFUDHU`L=8%8KO?(,^Y{€l^5)-/2-12240,*13+/!',&5967;;:9;3:B897224E./(-(*02931-0/:KWm|†ŒŽ‡‚|w~Œ—¢Ÿ¡¢ ¥¥¤¤£¥¥¢£¤¦¡¡¢¤¢ ¤¡£¦¢¥Ÿ£¡£¢§¥¢ ¤¡£ ¢¡££¢ Ÿžž ¡¡Ÿ  ¦žŸŸžšŸœœ™—––•–—jjdjfghlkinilfabdbc_]\XY\\iru„’–œŸ¡¦¬««­®­®®²®±«­®¬°«žž—‘Œwm^QNHGAOORXW]^\[]ccbddcbbfdbicgbdacedb`c^addhfjjptmqpqovpmkhkggc]XY|ÏÚÙÚÑ×Ø×̼¥viejv|€}ttysv|{uqggfxˆ†ŠŒˆˆ„}ym^VCJSD312IfYIA.34**0+/43FaK;EDXU[YE)-7HP6"/;Zv…|oK*+,0.3:1+))),-(*#$$'6\inzkOO_o‰‚}±—…³·´·±¶²¶»¶»½»¸´´¯©§¡¢£¥§¦¦¥«±¶¶°¬«£š¥§©§¯¹½½ÁÄÃÆÀÅÊÍËÇÇÃÄÃÃÄÆÅÉÎËÅÅÈÃÁÀº®¨ž„ye_QI<7.0+2N_UKTGpŠ…‚“™”˜‡qQ54,.-+/,.00/1/335<75E268:<<:4;=1-2.+0+*-05836++1.8Sat…‰Œ‰‚…‚~}‰Ž– ¤¢ ¤¤¥¥§¥£¤¡¤¤¤¥¦¤¡¡  ¡  ¤¥¥£Ÿ£§¥£¡¢¢Ÿ¢£¢ž¡¡Ÿ¡ Ÿ£ ŸžŸœŸ  žœ ž™››™–—–—–kklghdmlnjlpdhfeg_ed`[_[X]em}‘˜›££¨§§ª«¬¯­­°°¯­­¯®­«¡¢›˜’Š}uk[ROHIKIJYWT_`\^]dcde`cgdficcbcbhafbdjcdcffihigljonttvvrqqnohhob^X[ËÙ×ÛÕÏØÛʯŠtebovz|vtxxyz}z}nidqs€Š‡„ŠŒ‚„ˆvuv{v]C55=9.+8N_J64+-31)1/239JbYJ>EGRTa;+/6HVA'(.Gvu~b9**-/.014+/,.#""$&)7_v|lu\N[w“£‹z±˜“¹µ³¶´¸¶¸º¼»½»¶µ³ª¥¥¡ ¡ ¦¤¦«¬³¹´¯¬§™œ£ž¥®µ¹º½½ÂÄÄÇÄÇÈÌÊÆÊÇÈÅ¿ÃÈÇÆÌÉËÈÌÅÄƾ·¨ž†th\SSC/020,6MSOHI]‘†‰–™žƒ`G-:5-.602.40,/14436<>>9<?>640+/'32(0-7311(-48:Yjx…ˆ‚|}…Œ•›œ™Ÿ¡œ¢¦£¦¨¥§¤¥§¤§£§¤¦¡ £¡¢¡ ¤¦¤ ¢¤¤£ ¥£¦  ¢Ÿ  Ÿ  ¡Ÿ¡ž›ŸžŸž›ž¡ œœ››œœ›š›™”iiolhhjjgjhiigl``ec`aWY[X\cht‚…‘‘”œž£¦«¬ª«¬®®«­­«°®®ª­©¢œ™”‰}pm]RMHJLFMPVO`[a^\d]bcabb`]ha`aeah_de``dcfgbhkmfhlprttssuqrlrljlb`[[zÀÞØØØÐÒÛѪxcdakqxxoqrwx}{}vnjpw~…‚‹†…„„„w{zx€vR.'+1;4+X_XB:AUW`M+'/@WP%*,:\h}†\F?6/.*1)*&)#""$(&/_~“zfi`\w•µ®†w¦ž§¼¶´´µ¶µº¼Á¾¿¾¹´±©¢¤›œ¢¤¥¨«¬°µ¶³±¦¢› ¥¬®¶¶µ»¹ºÁÅÃÄÀÂÇÉÈÆÈÇÅÉÆÇÅÉÇÈÎÎÌÍÈÉÇÁ¸® ˆvkZVUA4).,)*DXTQAQ‡šˆ‹¦—œ‰Y917;46-,*0,+31/:9:4:86<:=BF<:C963-40-,(/6.4//,+16:C[kŠ‹Žˆ‰yˆ‘—™›™–•œŸ ¥£¤¥§£¢¤§¨¦¥£¡£¥¢¡ŸŸŸ¢¢¤ž£¥£¡¡££¢ ¡¢¢ž  £¡ œ žŸŸŸŸœž¡ žœœ™œ›™™šš—•”ggjkfhimfpkfnceaaa`d`[]ZWZbtx~…Ž’š›¡¢¥¨®ª¬¬±¬­­­­­ª¬¬©§¥£œ—‹ƒwo`UMMDLOLRUVYZc_`^]dbeghd_hideacbafb`hfb^dekojlgnmootqoorrpqllkcb^]o·ßÛÕÛÖÑÙÆŒpehgipvssnsqtzusrppv€|xƒŒƒwr~wxr]4-&)/<3CXGA300+-1-128/14F\PS;?KNYK=,.:bS%#*71Srˆ‡kh^_]H5%#&*$!%$%!2[ƒš”uZSfv–´¶¥‰x•¬»¼¶°µ»º¼ÀÂÁÁ½¶³§©¥¥¡¡¡¦¥ª¯¬´·¶²­§¤¡¦«­¬±¸·¸»½ÀÅÃÁ¾ÃÇËËÇÉÇÈÈÆËÈÌËÌÏÌÉÍÊÍÈú°£“€l^TSG2,)/(%6YQL<+4.*--,,..720.0//5?Qgv…ŽŒŒ‡ƒ‹“˜˜š•“—–›š£§£¤§¥¥¤¨¦¦¥¥¤¤¤¡ ¤¤¡¡¡¢¡¡ ¥¤¤¤¤¡¤¢¢¢¡ ¡¢œžŸžŸŸ  œž›Ÿ˜ššž™š–œ–•kkkiknhnfjcffcfeeedbaa^[\cjly€ˆŠ˜š¢©©«ª­¬ª¯¯®°®¬ª®¯­§¤ —ŽŽ~ugbVRJCLKMQSPX_e][cd_caec`dfehhgf`bd_bacjhmfflfjlonlnnpqtqqpmmnngd^_d¨ÝÝÖÛÛÒήymggkigipspuurwnggqz€„…{{|ne„}uns{‚xhW0,&+6?[]6-/,+5***+.01+7CLTPN;?HVUE8(8gS$#-9+;b‘‡cVQdocY3%!*"$"(.P†Ÿ¢f]c|žµ«¡¤Žz{†°¾º®¯´µÀÁ¿¿Á¿µ®ª¦¢¥¢Ÿœ¡Ÿ¦ª­µ¹¶²°¢ž ¤§­­­°»»»¼ÀÁÇÃÀÃÃÅÉÌÈÉÇÉÈÌËËÌÍÌÏÏÎÎÍÍÉȾ´«™ˆme\[I3'$01,1PTLAErš™“ž£¨xJ30../4,)+,3-4102317926:B>9??;47./7-0.(/)216.51:78HXq†‰ˆ‚…’–™›–š•”—˜™žž¤¡¥¨©¥¥¦¥§¤§¥¡¤£¢Ÿ¡ £¡¡ ¤¢¤£¢¨¡¡  ¢ ›Ÿ ž ž œ¡ž ŸœŸŸŸžšš—œ–™šœ”–ddljkngiig`ggcceffed\c[\[cir{~†‰‘šž¥¨¥¯±®¯ª«©°±¬¬®¯®«¨¤žœ™’‹xfcOHHIFSSSSV[][[\a_a]gbfgddebikeb_fbcbcdghghhjhlnlnsmtvwvnplpnlj^gbcÎßÛÕÚØË™ljjhjkhijpwuqwxtnu|ƒ„„~„kWx|rprryonuiG-'+->W_V,-)/&+/64-+20-148JVOE:?IKE@1EbX+-<<,2QŽ…X1>@KC>.)&$##!)V‚š ˆqlhxŸ¸µ §¢˜€{Ž »º±´¦·¼Ã¼¼¾¸µ­ª¬¢¤£Ÿ¡žŸ§±´¶¼±°Ÿ˜œ¤¨¨§¯°´º¹»½¾ÀÄÄÁÁÆÉËÈÉÊÉÊÉËËÌËËÓÑÒÒÏÑÑÎËÁ¹¯¤‰shWYK=.&*./.BIUK>e’š”›­£š}M--/31*+/1-1+3371565:1@:=8@?EG:4/+,,1/3-/1=1*--16?N_vƒ‹‰†…‡“—›š›––˜–—›–˜™›Ÿžœ¡Ÿ¢¦§¥¢¤ §¢¦£¤¦¡ Ÿ  ¡£¢¢£Ÿ¢¦¡¢¡ £¡Ÿ¡ ŸŸ¡œœœ¡ŸŸž Ÿ¢ šœœ™›–˜›˜”—fffddjchijiceeiadgdgd`\YZaenvƒ†’—š £§§ª¯¬¬®ª¬¬°®¯®­­©¨§žž ”‰znjUQJFCOMOVRV[aZa\feda`f_adfagaegccffdfdejfjgggkmjjporxwxqpoopmkic_^wºÜÞÖÚÛÊŠkhpoqnsiiqupmmuot†‡‚y~€‚tWesrpqofVWPV?/.23Q^`M2+*)'-273/1;325.38STHHEBEAC:@aV+.>@7-)'+./6BLI?W‡›œŸ¬¦—vM1+2//+)170,.4448:@5;6868;BC?6/3/,.(,()-.72.,..79DOp~‹Ž‹‰…ƒ”œž™›š˜••–“œ’”•œŸšœœ¢œ¢¡žž Ÿ¡¡¢¢ Ÿ¢¡¢ Ÿ ¤¡¤£ ¦£¡¤œ  ¡žžžžŸž ›Ÿžžœ›œ›ššš˜˜•–hhigihkgmgijhfhgccef`e`[\cjow€…Ž‘—Ÿ¥¥§ª¬®ª«­°©®¯±¬¯¯¬©¦¡˜›“Ž„wlaQQCCGNPQPW[[_^[[ac_hac__dacfjdediddfdfcfihghdijp~|jotusprotqqpjea^k§ÝÞØÛØ»qnnosqqtnnvsjlbn~Œ|xw{€nXWc[`NLA9ACBD54..Uab>-*'-)-4;..8>31/613@QLJA=D9AMFYP)+K;5-YˆŠ^')&$.(##!&As¤¬ˆqgt‡Ÿ¶¿­¦¤¦¥£†€›§¤¬¬¢°À¿¶­¬½®§­ª©ª¡§ ¨£®°·µž™Ÿ¦¥ª²­¯´»´¹½ÁÄÂÄÌÈÆÆÇÉÊÉËÊÇÉÉÌËËÏÏÒÑÒÑÓÕÕÑÍɸ§–la\QF1&#&./0?EMF=v–œœ²®œM//216..0CE78?85894567;=BC:?A:503+0/,1222:7/(,+46M`u”‡ˆ}~‹’šœ¢œ™•›™—™—–‘“™›—™˜šš œ¡£ŸŸ¡žŸ£¡¢¢¡¡  £Ÿ¨ ¤¥¥¥Ÿž¡¡Ÿ ¢¡ ¡œœ¡› œžžœ™œ™š˜––™™–cccmhelgkdjhigebb_ba`^[[ZXcmv…†Ž”–š ¤£¨§¬©­°««­²±®«­¯¯­¨ š“ŽŠ‡zsaYQMIPQKPQTU_`]`bafhhckebhlhbhdcffhefdiefiffacgoŒ§{lqurwnpvrnpmgdb`h“ÑàÞÜÖ¶yrtkqu{xutqmoeaiz†Š‚}€zwlchPA@;HWORIKM\\ZC9.7ThZ2-)*-&-@C7.A:2,.4+0:@<430-/0010567768,*-16Qiy‰’‘Œ†„~Ž•˜¡¤Ÿž—™—“š˜—•™””–›˜˜›˜› ¡ž¢žŸ¢¢ ¢Ÿ £¡£  £ Ÿ¤££ ŸŸ    ¤¡žŸž¡žœ›ž›ž› š˜š——š˜–“ddfnmifcogjmeggcebcbd^b[^`dmvˆ’“˜¢¢¥©«ª°¯­®¬­®®²®­¬¯®¦¡—ŽŠ„wleXUHFKMONTUW[VX^bb_hjceifekjejkecdi`cedafbcfijmŒ¹™rnmsvsvmqqlokkmebg~´äáÞÖ¦turjtuxttrgedg‹…„‚ƒ‡|_L[ZPRB964DZ`c;Cj7,/4P7)-*'$!# !$4k› xkj}›µµ¬«¥¥¦¦§£”„§±­£Ÿ±ºÁ¾½¸·±§§§¨ª««ª«­®¬§œ“•¢ ¢©ª­¯°®¶º¼»·ÃÄÁÃÄÉÆÄÇÊÈÈÈÉÈÊËÌÎÎÒÐÏÐÒÕÐÐÓÔÎÊÄ¿±¥ŠzkbXK71.-*'+*7FR?BŠ™›¥ª¦†e:3@?62+3:600;7789879;;?D
784.*,*04276?6/).,-:Qq€‘ŽŠ…„ƒ‡šŸ¡£ž—œ—›––—“•˜—•”–˜•˜–—ššš—Ÿ¢¡ ¡ ¡£¡Ÿ£Ÿ  Ÿ  £££ŸŸž¡œž¡Ÿ›žŸœœ›œžš™œž›™šš—•˜hhkgfhehhgedgcfcicad_^_\X`ihu‡‹‘–Ÿ¢¢¦ª­ª­­¬¯ª®²°®®­­®ª©žœ™‘Švo`XOIGQHMOVQZ]Z]\_cbfhgbjgfgicjlchcbehacdebbgfp°£xmosnxttqptpsopnglio›ÜåÝÖ¤smuqrvxx}smcaru†…z~y…Œ†sjzkg`KGQSC/.3?7.*,,G?23;525176D.+.;>@9227Ncng\z?7-3;€‰G%$($#(#)+b‘¥•tr{ µ¹¥®­¨©¡¨¨ª–‡Ž©¶±©¨¯¹¼Àƹ¸¯§ª«©ª¬©«®ª¯¡–“•œ£¦¥©§®¬²°º½¿¹º¾ÃÂÂÄÆÃÅÄÉÈÉÊÉÉÈÍÌÑÐÑÑÑÑÑÓÑÔÖÔÑÌÃÁµ¤”~oaQM:;2,&'(+07LF.x™—¡®©†lA3339.)/,15337;9<=9;D9=CC=<843.-//,2.094451**,/E_tŠ‡†‚‰‰“¤¢£žœœœ”–™š•••–—–”•–˜””’–”–š˜–›™œž¢›ž¢Ÿ¡žœŸ ¢¢ ¡¡¡¢ ž¡ŸœŸ¡¡ž˜žœ›˜œŸ˜™ž˜ž™œ™š˜•jjikhkjlciggicgcdce_``][\bcrw€ˆŽ’”›Ÿ¢¥¨«¬®­­¯±¯¯¬­¯¯«¬­ªŸœ—‹ƒwnfZSGLNFROVYY`]b]cgcegdgjjfjighibhebbedeebddflƒ§Žxqrnxyspstpqvutupnpep„¼äßÖ«ynurruyuyytdi~y~yƒ€}}…Ž‹ƒztooicWZD3.-/2+2&/58imA'*)/.ALG8,6=0-372B57).6A<8742?`rix~P@*56h‰X) & $"$6]‘©”„{w}•¶¹©¨¶³®ª¦£°£”‹©µ­¬¯®¹¾Ã¿º¶¬§¬«§«­¨§«¥ •“”—¥¦©«¨­­³·¹¾¿¾¿ºÃÃÅÇÊÆÆÅÆÊÍËËÊÉÊËÑÑÐÒÕÓÓÓÔÔÖÒÏÊÄ姙„scRN<40)"#'*36KR1hœœž¬¦‰sJ701908@B+)-8486*+.:H;-983FIfloyYL;;-^˜jA% %.Yƒ¡–…|s{“´½©ª°¸¹®®©¨«®™Š§¨§¦¶º½¿¿Ä¿³«¥©¬§§©§¢¥™‘–›œŸ¦¦¨§©­¯·¸ºÁ¾ÀÀÁÅÃÄÊÈÉÉÄÊËÊËÉÉÍËÐÑÒÑÓÑÒÒÖÔÓÑÏÎÊȽ«™†sgVQF7.&!#*.1KY=;0.4-+/-1042655)*05=Zj‰“ˆ€” ¦¥¢ž Ÿœœ›™š—™˜ž–—š–•—”™–‘™ –•˜˜––˜˜—˜™žž¡Ÿœ¡  ¢  ¡Ÿ¢Ÿ žŸŸŸž›œžœ™ž››šš˜™™—”™–”’kkglkkgdggg_echaaabca[]ZYaiov‡—™££§ª¬¨¯°®¯¯ª¯¬®²«±¯©¥˜‹„leYULHLTSWXX\[]c_ghfheihdglddefebfdcbcacgjekmlwmrnrvrvxwtttvprvuvrnjfp}ÁâáÉqwvrqngmrw}‚‚}uvr~†ˆ}„}jhgdT>@95864C-)&'.(+Wn>'+.*8@?/57D4,/48=7121.D<1.1h¤Œo6# )R…—›€yr{Ž¯À·¦¬¸µº°²°³³±¡¤¦¦ª±·ÀÇÅʾ°¨¦­­«¤¢£¤•’›œ¡ ¢¦ª««ª¨¬´¸»½ÀÁÁÁÃÁÃÆÅÇÈÊÄÊÌÌÌËËÌÉÑÍÑÑÒÔÒÓÒÓÔÑÑÏËƽ¯ŸtdUWG;-($#"(&2AZF@“«¢¤¬cZ98324C86<;2478<99?=>C>CBB8>42-4+1//44660/+.38Q`v†Œ‘Šˆ……‘—œ¥¨¨¨¥ž£œšš˜š––—–™—•—˜”‘•“—–—•”—–––“’–—™˜˜›œžž¡ ¡¡¢žžŸž›žš›œ™š››™›š™••”—˜–”•ffjhjfigfed`ddccddb^ZZ[\jeggu|ƒŠ•™›¤§©«ª¬¯¯­°¯°­¯°­±®­¥ œ”Ž‚pr`[QNORWUSTV[cebcegcecchddddefghdcdjaeefjhgijmtwqtrrvssuxruzyuvttttnqijt¤ÛãÏ™v{vurrjirƒ€}{yƒ‰zy‡‡ƒ~tkfbd_I.2103@O?+'%,))1MnI,368>3.-5=G0-373:B117;H=5&$.GiYNd4,&"))(1;TP9„°§©ª|bZA:6:*+,59;1<55B@5@><;B?DD:91-+-12-021581+*'.8Rr‚‘ŽˆƒƒŠ‘˜ž¥¢¤¢¥£¢¦ž¡žšš•˜˜•—–˜”“’•”‘™•–š”•“Ž’‘’—“–‘•”œ›¡›Ÿ ›ŸŸœ›œ›¡›š›œš—š›š›——š•—˜™“˜kkjlhklkffbae_ij^beZ_^^]`_cks}€ˆ‘”—Ÿ¤¨§©¬¯¯¯¯®¯®¯­°®°«­¦¡œ•‹„zmaYUNROT[YYZ]]\a\cfaeffgei`edfgjahejdblcelkemppwururmqvvxuwxutxsvwttsnnnŠÆâÒžwxtotmj{‰w{}€…‹|…‚xha^faM9<;01AS\/%')#-(/EhW3GKN5+,/:B11109856329HK:9&',8j[5.("&(*(2G`7f®¤ªªƒcnN,/2.-348>6;4;9==>86=EE;?666.+-3530778;8.*-4Kezˆ‘’ŽŠ‡†Š”›¤¤¤¥¢¥£¥¢¤¤ŸŸžžœšœ™—˜•˜™™–”š•˜—•••““‘““””“”“’“–š›š™›œž›œœ™™™˜˜˜›œ™šš™˜››”™˜——–•”hhhkhhieffbcfde`a`\]]\^VX]fmtŒ”œ£¨¨«®ª­¯±°°±°®­ª®®¨«žš˜‘~ulcWQJNNQSY_b]`c_[`bbdfdgeaifjfhjbfcidiegijffnlv†}moqpnx||uwxvywvxxurrrpq|œÖت€vyrncvƒˆ‡yz…†Š‚wxƒw]Y]VA/614:S]\M++(++)*+3ZlM?>=4/?AHK1/*29G21,0=R?88/(,8ha.JQLH/'"$.n‘i.#6iŠ¢Šxzr{–º«¦¦¬­¬³¿Â¼ºº´¹¯‰˜‡‹ª¦­´¼ÅÉÀ²¬§¢¡Ÿ¡ª¢œ–™›¡ œ£¦©ª«®ª®¬°«²½»¸¿ÁÄÀÃÀÇÈÃÇÈÆÇÌÊËÉËÌÌÏÍÎÎÐÓÒÒÕÔÓÔÔÕÓÑÌüª˜…xjZNI8.*+)+//+;W:P¤©©«]tQ/-41045578<87:6:>;9=;1//(()*38VCH˜ª©±ž[q>.(14756;55::@8:74<78>B::3183/,.,2:8660)/,/:St…’‘ŽŠ†„‹” ¥§©§¦¡£¤¢¢¢ ¡ ž ŸœŸŸ›Ÿšššš›™š—™˜˜“•–‘’““‘‘Ž‘•’‘’•–•™——›—›œšœ—™™—™™—™™›š›˜—•˜˜–•“ddmghgj`dkdhgaka^a\]X_XXXYam|}…‹˜œ ¤¥ª©¬®®¯­°¬±¯¯®®®¨ª¥¡ž””Œˆuh`XKKLNORW_[]]_]a^cccelffdhegfiidjhmdgkbiiiomimu|nov|uuzwztvyywvzwywtovyw}ž¹—x~yrioƒ‹ƒ„…†~„„ŠŠ„n^]C3-1A9)&CPdg3,)&67()+,3HhK6%2.>WN54-<6/;*0*6YK2=N/171.B-4NS?## $3s†Z1VŸ”}owz·©¢¥¥«®³³º¾º¹»»º®’šv¬«¸À¾¸ª«¡™œ¢¥š˜›˜¡¡ £¢¨ª®­¬®­³®³°°²µ·»½ÃÂÃÂÂÄÅÇÊÄÃÍÌÌÉËÍÌÊÎÎÐÓÒÔÒÒ×ÔÖÖÖÖÓÑÊÁ°~e`XMD7,-/()$-1T]>~¨¨¯£^n<3.70&/686<5@>CA:;8<=?=3:776.31/-55432-'*(2Fau‡Œ”‡‡„–Ÿ¤¦§¤¤¡¡¥¡¤£ ¡ŸŸ›¡¡¤££¡žšœœœ˜ššžš››˜—•’’‘’‘•‘˜‘‘“”‘Ž•”‘’“‘–”˜˜”›™Ÿ——›–•—›™™š—™š———––ggegigbgcffeccd_ccc^Z^^VX[inx€ˆŠ“™—¡Ÿ©«¬­­®²¯¯¬±°­­­®¨ª¥ ˜“‚ujdTKIKLKXW\^Yabb\hhbgcgebjgjfjmicefhhfihfhhlnintuwnuqrwuz{{uxwzzy~{yyuy~‰š‹qszwn|‡†Š‰‡’‡€€{|~uaTH2-7KD3'(-?nF2*)1E3'0,&)4Ia;.);UXJ9.+/819*,*<_A+E]3-7'+.=6Oe?$! ,O}g_r›¡‡toz„«¯£¤¢¦¦ª´µ½»º¶¿»¸± ˜t}©°¼ÃÀ¶¯¦¢¡™—›–›š›™› ¤¡£¥©ª­ª©¬¯±±´°·µ·µ½ÁÁÃÂÅÃÃÇÇËÄÆÇÈÉËÊËËÉÎÍÏÒÔÒÔÒÖÕÔÔÔÖÓÓÍIJ£’‚m\`WM>3/),+''1GcCj¡©®¤iYB3D<2,;63;99::A;A=;==>;;7-02643/39763,+(.5E[s}ˆ“‹‹†Š—¢¡¢¨¤¡£¤¢£¥¤¤¤Ÿ¢Ÿž£¦¦¥ž £ ¢Ÿ œžžœ˜šœ˜œ™™Œ“Œ’•“•–“Ž“ŽŽ’•””—˜™—™™—•–ššš›žš™˜™——•—ddfjbicdcggdaec\be]d_^[ZY`dls~ŠŠ“”œ¨¤©­­¬«¯®­®®²¯°®®­«¢¡œš”vj]TUQKLORZWY^``_]`cheeghdidfdjhmeeifcfegejmmklppstwtqpqpskqjsonopjefy}…Œ„qn‚Œqmupz~€„‹ŽŒ†|€z}l`YN90.EY8,!&'Ev@8*'JT21<*%%(4RH>9ZbS=2&()297,))@f;';Z142%&2E4OzS! # 1bgŽŽ¡ˆ}jtˆ£²¥ ¤¡œ¢¢¥¯³À¼º¹»¸»¹¯¤Š„«°¹Ã¸®¨¦Ÿœžœ›˜ž žžž£ ¢¦¥¬ª®¯«¬¬°¯¯´´³·¶¼½¿ÂÃÅÄÆÆÆÊÊÆÇÆÇÊÉÊËÌÌÏÍÏÑÑÐÒÓÔÓÖ×ÔÒÔÎĸª”†uecXP=2+-)()(1HePi¤¬®«nXH1C8,).8=?9:Mcib?67()09<.+,-Rd-&-J<>9)12-.cŒa)!(>lŽ—„|qn†§¼­ž£ Ÿ¢¡¦¬¯»¼º»¼»»»²®«µ¼¸§©§¦¡žš›œ ¥¦£ž£¡¦¡¨¨°«°­­°°®´µ¶²¶¸¹¾½¿ÁÄÃÆÇÄÇÂÄÇÃÄÅËÈÊÉÊÎËÌÏÐÏÑÒÒÓÖÖÓÑÎÊÇÀ¬›Šsd\YQ@4*%%*),18]IX–ª®ªƒYV-9@@B@;930*+3/2482923-),3:Sr{„‹Ž…ˆ‡†•š¡¤£§¦£¡¡¢¡Ÿ ŸžžŸ ¢¢¥¢£¤¡¤§£¤£ ŸŸ›š˜š’–’‘““’“•”Ž‘Œ‘Ž’’““•”›˜œš•˜—––˜•–”˜ffekfcjifdcjde__a^_g_^[[T_ehyz„“•˜œ¦ª¬¬¬¯¯¯®°°°±¯±¯®¬«¥£œ“‰ƒwkeWOKLHOTWUTV^__bhcdcgfcgihiiheglidefcglgkljklnrqtywvzxwvstsvrqqnqwuz‰‹qY[Uay{w`p‡ƒ{€‚‚€|x{xmfWF,+=bZ,'&"&P}R@/@O+$37=/2-.7BkheG6;*%"+;7.&)7Yd*%*GQX9@C/';=CF@<;?832.242025539.,)41CYv‚‡ŽŒ‰‡……ˆ˜ž¤§¢£¥£¢¢Ÿ¡£ ¡£Ÿ¡Ÿ¢¢¡§¥¢§££¦¢¥¥¢  ™›œ–—™””’–•‘˜’“’”Ž“ŽŒŒ‘‘’Ž‘’˜˜›™••“—–—˜˜–™ggfngdfhbdf^fe^ac``ie^W[Y\egvˆŽ“œ¡¦¨«ª¨«®±°°­¯³¯²¬¬­«© œ“Š~sh`XTOHLQRW\TY`]^bddddghe`dlahihfgbhiifikfjjklnmmprwxwyvyywtv}uxxz|w}~“xLLarŽ’ŠŽgr€}|„€z†ˆ~xvs€{ohU;/3]nM'&"#'VZ??64$(=,:?;;3GmqB9F64%'.,<7)('7kM'*,?]]:;;(*]u>(,(% )+Ix‡uc\fyš»°¡ ¤£¥¢œžž£¦¯¼¾Â¼·´¼·¸²ª®¹µ¬©¦¦§›˜š¡¤¨¢¤¦¤¤¡¦£©§§¬«´²­°°°²°²´®®±¶¼½¿¿ÂÄÄÈÂÅÃÁÁÅÂÉÈÉÈÌÊÉÌÌÌÐÒÔÐÑÔÔÔÖÒÓÎÎÆ´¢ˆuc`[U@4+&***(.5QJOx¬«±‘a[66A29:=I;=?>;<;:EDB@9<982.082//575/3,+,3Khz‡ŒŒ‹‡‚ƒŠ“™ ¤¤¡¥££¡¢¢¤Ÿ£¥¢£ŸŸ¢ ¡¤¥¤§¦§§¢§¨¦¢¡¡ œ ›˜––••“”•“”–‘Ž’ŒŽŽ’Ž’ŽŽŽ‘’–“—–˜——“™•—˜—›eegggfgghbcbac]aaaa_aZZVY\cit~†Œ•—Ÿ¡£¥ªª®¨­®±®°°±­¯¯®¬«© “’ŒsmeWOJHKOMRVZ[Yb^cdbgfggeaggfcfhjijfhheihglhkqqnqjqvrsuy{yztyyvvxyuvw…¥Žaow‡œ¨º¶}nzt}…|€†ƒ|qpz„ujV9/4BYzL+$ %,L…]QE')*47#4GKDNhxWIOH51'(/(8=1%+Dr3*(+?^r>6)+A}:)$-4.!">vŒiVYr¹¸Ÿ §§¥¨ª¥Ÿ¡©¯¾¾¾½ºµÀº·­¯²¸¯®²¨ž••˜  ¡££§¥¥§£§©§©««®¯´±±¯±²²±°°´²¸¸»¸¿Á¾ÄÅÄÇÁÂÃÃÅÈÈÈÇÉÉËÍÌËÐÑÏÒÓÕÒÔÐÒÒÒÌƱ¤‘~haUN;2'&''.+48TOHw¬²°”lY78K36;AJ=5:C?;9C<=@A?6-023A4363583-3*+7@Rky‰ŽŠ‡€}ƒ““›¢£¡ž¤¦£Ÿ¨¢¢¢œ¡žŸŸ£¡¢¤¥¨£¦§¦¢¥¦§££œ¡žœ›™™’”•—“–‘•’‘Ž‘‘Ž‘“‹Ž’ŽŽ‘“Ž““”‘””˜™š˜ddfmcad^gaeae`a`\]a_]_]XY\dhwˆ‘‘™œŸ¦¨«­­««°­°¯­±¯±°³­­£Ÿ˜‹ƒumdRTOGNPOSVX^_^^bffbg_adhakggjhdddghighegglllqnqsqswtqxvsxvxyywyrwvw†§¯‡‚‡Š½Á•uutxw€…†yss~m[;-/:@Zx@"&$,N‡`d5&!%7%(/8HSfnVPVC>1,,--1>83-+Go/'(&8du=)%,\f*+082&$.dŽšs_Yi”´¹¬ ©¦°«®©¥Ÿ¡ž§°½¿¾ºº¹¿¼·²¶²°´¬¢Œ|…‹“—–žŸ¢¡£¤§¤¦¯©¨®°®±±²±³¶·¯µ²¯¶¶···ºº¾¾ÄÂÂÄÂÀÅÄÁÈÅÇÆÆÉÍËÊÊÍÏÌÒÑÔÔÔÏÏÏÍËƶ¤”~i_RG<10'%'+-(5DD;y¦²³”uOGAH6?=QHDB03:;A@;5010440@37@881.*4>A::8>:8@F:E>68122/3;//7396/,*-3@Shv€ŒŠ†‡„‹–˜žŸ¡£¥¢¡£ ¡¡Ÿ¢¡ŸŸ¡ž£ŸŸ¥¥£¥£§¦¦¥¤¢£¡Ÿ œ¢ž ž›››—–˜“—–‘’’”“’‘“Œ‰ŽŠŒŽ“iihencchdbcfaaade]a_]]]_U^dhr}Š‰–ž¦¥¬«¬®­¯¯­­±®²®®­­©¨£Ÿ”’Œ€ui]VSJFSSRWYRYX^```adgdilfgidgfhheedgeidjmikipppotovwztuywuxuxut}—©¶™‰Ÿ83>CCNYbv†|}‚‚€ypm}q^4.2M^GwW"#)'/<2>C-(,(%*(-123:3/WG$$&,Tel<##JmAEP;'!*E}—t[e}ªÆ¹¤¨§«³³·«¦šœ–¦²¸ÀÀÀ¾Æ¿¾¿»¶¸£mNJRfunyy†‰Ž“‘”˜˜ž¤«ª®®ª±´°´¶´°´®®±°±²¯µ·¶¸½½ÄÄÆÆÁÄÁ½¾ÃÅÅÇÇÊÊÇÈÉËÎÑÐÐÒÑÏÌÎÈŽ³ž’ybG=7302*(+(.%-HY,^ž²²›†_CCB86>A:DK@>@=ECOS>?7:/1,741648>90,114EWr~ŠŠŽŠŠ…‹“¢£¥¢Ÿ¢žŸ ¢¡£Ÿ¢ žŸ¡¡ ¡££¤¥¤¢¢¥¤¤£¦ žš›Ÿœ›››œ—”˜–š•’–“‘’•”‘‘’‘’ŽŒŒ‹ŽŒ‹‰ŽŒŽ“ggdagcfef``cdddadbede]`YYY_js~‚‹“›¡¤¥¨©¯¯°±±¯±°±°±±­¬¨§ —‘‹ƒwkcWQPDKSQYW[aaZ``cghihifd`f`Xgedehc_ebghhnjknkusvsvuvxyuvxxvvuz–Íͽ¥œŠF$&%&&'+>n‚‡ˆ‚}ƒymirp^TE/>?bFZm?%#$,4Pur+##&=239?94///3@2(1)*+4,.5351,G7*))0eUl9)2[[72.)#;yŒ x_dr—ƺ©«¦§°¹¹·«£š›–›¤³½ÃÁÀÂÅÀ¾»¹°‰OEGUY]ejnhty}~}„‡‰”˜ž¦¦¬±¯µ´´·µµ´®³³¯¯²¯´·¸·½»ÃÂÃÃÀ¿À¾ÄÄÂÃÄÈÄÉÊÉÉËËÏÎÍÐÐÌÍȹ®¤˜„oRA<702+&%&"%,/A_.P ¹µŸ‡^@85>@C8739==:;IIGFH=52540332015421/3+1H]s‚Š‹‰†„€€†‘—Ÿ¡Ÿ¤¡ ¡ž ž ž ›ž¥œ¡žŸœž¢ Ÿ  ¢¤ž£©¡¡¥¡Ÿ›œš›žœ™››ž›—˜˜–˜””’—–’•–•–›’’‹ŽŽ‘Š’ŒŒŠ‹ŠŠ‹Š‹bbgeebgafefcccgeeca``\`[[^cfuˆ‰“˜š¢¤¨¦ª¯¯°°±¯°°±±±±­«¬ª¡ž–“‹€zkaXXHJRNUXYUZZY[``fefjhgjihkegdfjgbdagjefldgjlsnroxyrwvwwwuxvwƒ¯äÊosV8%!"%&*%IŒŠ—¥«™|{piesiN905@YfAk_("(,(:_j &+A,,.8439*45:0+/*,5:7.2895.JF/+,8`Il>02_B*% #+m‹™‚c]lµÁ¬¥¬®³²¿À»­š™œ­¸½ÀÃÄÆÅÀÀ¿ªxUUWXaa`fc[`hddVfnsz|†œ£¦­¯³³¶¶µ±²³°°¯µ­ª¯µ¹¶º»ÂÂÀÀÀ¼¿¿¿Ã¿¿ÃÁÅÇÉÊÌÈÌÎÐÎÎÎËÆdz®¤…odL?;6-+&'(('**/Eb9>›»µž‰xR353;GMB15B89B>FDE;9.5/3/11275696/*14;Scv„Ž‰†„~„—¡¤¤¡¢ŸžŸ œžžž¢¡ŸŸžœœœœžšžŸŸ £Ÿ¡£££¥£¤¡Ÿ›™šž—š›ž™›˜˜˜™—”•“’•—””—•’ŠŠ‘Œ‘ŒŽ‰Š‡ˆˆ‰‡ccgdeddedhheiacdheeab]\\^[cgv~ƒ‰‘—›Ÿ¤¦©ª°°®³¯´³±¯°±®¬¬­¤ ›˜’‹yl^WQJMINYSYRX\\c^ad_ahegifggggh`gicjeiiggkjnmmmquwxxutwzzw{yyx¶ß·l]455,''-'+8a˜®ÔÖ¼{vjUPkWF214<\EXƒI)(1+,Ha~ˆq""((6.'00/8784?J93)0/69-+'/HFOZR2==4W3iN&/\4'' *L„¦ƒl\dˆ°¿®©ª¬¯µ¸¾Â»©—š˜žž¶º¾¾ÂÄÂÁÂÁžvfhnvxywulf`ge[SMWU]ekr}…’˜Ÿ§®°¹µµ°­±³²±¯¯­ª³µ¸¹½¿ÁÁÁ¿Â¼º¼¿¼ÀÂÆÃÆÉÊÈÊËÎÎÎÍÌÉÁ¸µ¨˜‘s`_G=9514+(&'('&1C]85}º¹£{Z:;-<:9@@L>B565./-4407:17441++3BUjy…‰Ž‡ˆ€Ž™œ¢¤¤£ ¢ŸŸ œ¡žŸ› žœœžž¡ Ÿœ›  ¢£¢Ÿž ¤¢¡£›š™™™›žžœ›šššœ›™š™˜š˜˜”•˜•–’ŒŽŒŠ‰ŒŒ‹Œˆ‡†‰ccfbfeddidegjdcadddc^^_[WZ`er}ƒŽ’—š  §¨¬¬¬­²°´¯±®²²±²°ª¨¡š’Žti_SPJNPPOYYVYaea]cgfgdheieciehmljggfhhhe`gkiijnsystuyuy{{x|xy}†²Ñ®‡d364/-&(2u—Ÿn[`{ª¹®¦­¬´²¸ÀÂĵ¥šœ˜Ÿ¨¶¼»½ÂÃÂÁº™yvz‚‰ŒŽ‰yunkd[P??DGIKYjozž¥¨°³°¯±³´³´°¬¬¬¯²´ººÁÄÂÀÁ¿½¸¼¼¾¾ÁÂÂÅÈÊÈÉÈÍÍÌÆü®¦›‹zoh^TB>98/+')&(+),1?=;838;15,:8405<<411,2/F`kˆ‰ˆ†„“˜›¢©¦£ ŸžŸ¡ŸœžžŸžšžžœžžž ŸŸ ¢ ¢ ¡žœ›•ž˜š—š›—››˜œ››–ššš——–™“––˜”’‘Œ‘Œ‹‹Œ‰†…ƒ…„…ddiidhgbhfgbhdaecc`fa^^[U[]mt„‘”™ž¢¨§¬¯®°²³¯­²²´¯±²®ª¨¥œœ–Œ…vl^SSKGJOUTVS\^a^^_^eepfbgcbcchhegdfjgfbfiijmgpnsvrsowvvr~z{€€‹¢´œšoJI;=-&')0V~Œ¬¡ˆƒ†vlVA=VRC==6W][‚H+(.%4W[\Vo)!!('&*=D83((,(+*/1;E9-y¬¼©’Œa5<.869H?HC<;F@>;;847=42,-109=67561-7L]uŠŽ‹‰ˆ‚€‹’¢£¥£¦¡œŸžžžœŸ¡œ šœšœ›œšŸššŸ›¢œŸ¢ œœš˜šš›ž—šœšœ›•˜—œœœšŸ™›œ™•›š”ŽŽ‘Ž’Š‹ŠŽ‰ƒ†…†…kkelfkhfih`dcdgjedf\b\^^V_`ht~„” ¨§¬¬®¯«¯°²®¯²±°±­­­©Ÿ”‘‚{mcWMILLTPX]Y[Yc]^__fcngdlegbbeb_fehebgfddefjoomppruovvuzwz}€Šˆ†‹•˜¥^F61-%'-0P{ˆ’n\`m_@?I`W>68B[OlT.0.6-Gb_V;."%(''3M?B:+=S*3JT4)6>*(#,) ()4PfY=ia%3]:->"('*P…¢rdsš¿½¦žª°²¸»ÁÆij¦›”œ¥¨²»½ÀÅý±ˆvyƒ‹‘‘˜™™˜’¢›–•zm`]RFMCA?9FOYg– ©¯«ª­«¨«ª«°¯¯¶¹¼º¿¿¿¾¿¾½¹½Áþ¿¾ÃÄ¿¾»³«š‘rjXOTBKUUY^XVVVG6/.1,,+009B;.u®·¥“‰u@>484;O=CPEABGA=75+-613/1--39:82161:Nk‚‹Žˆ‡ƒ}‚„•¤¢ ¢¥¡   Ÿžšœœ ›¡Ÿž›™››™›œšž¡žŸ¡¢ž ™›œœœ™›››™š™š—ž™™œœ™šžœžšš˜˜œ’•‘’‘‘Ž‰‰Ž‡‚……‡…‚hhfifdfdhjgihbcbieec`_^^Y[_gn|ƒŠ“˜•™£§ª¯¬¯®­±¯®±°±²´°¯©© –‘‡~i]SQNTURSRXW^V\bcceahljehfgecacae]efclecffnomliporturysvu~ˆ’ŽŠ‡‡¦’HA80,$&)&R€€‡hZX\bI=KZR85B`_QZ50**'E`]h@0~„? &$/3EaLF<7=cF?[\C'5;))(+'%)#-3O_fvT&-[Y.*$9uš§ˆnh·Ã¬§ª­´´¾ÂÆÇ¿¬£––¡©³¼¾ÄÅÇÁ«|txz†‰Ž—™š•Ž{–Ÿ£ š‹…~~saaVSHHD??AO[yˆ•¡§«§«¤§««­¯´°¹¸¼Å¼¾»Á»º¼ÁÃÅÁ¾¼Á¿¹±§œˆnaXXVNXPUTmnuohjkaT?3.5*,&'-1HA/y´¶£‘†vF>>434UB?DA=DC==641,72074/485C877/87.*,39[]a<80$$$)()'*01YS`…R%+I\' 2bŽ§–‚q‚¨Ã·¡¨¬±³¸»ÇÆÄ»§–š™¨«º¿ÁÅÇÀžon{‚‚ƒ…‰’“Ž’Šuz¥£ ›Š~[hZ^UTOKNHNN`v‡–¦ª©¦¨§«ª­¬°¬µµ¹Á¾½ÀÁ¿º»Á½Â¾Àº·¼´¨šŒvbTXSa_Wlfrf{‰xnqe_U=:76)+'(*.CF1k«µ¥•„sW;7385GS9<=<=EC=7;3,/30250:8989:925A[qƒ‹‰Š‚}ƒŒ—š£ ¢¦¥Ÿ£Ÿ¢Ÿž œ›šŸš™œœœ›šŸš›šžœ¡ œšœž™˜ž—™™™›˜™œœœš›œœ™š™š—™š••”’“Ž‘ŽŽ‰‡††„„…ccfcifhefmkmfihhfc`ce^SVZW_js~Š”–—œž¥§¬²°­«¯¯°¯²²°²±³®ª¡™“ŠƒypgXNNMPTTY\[^c```ceukggebgddedfdaZ^caabenbheeijjhmqqrpr‡‘šŸš”Œ¨]K:_trC*&G„†™u_O8VY?2<34GPici;4747NzlS0$1T†}8(%,)4L@7+'&0(8WffL5*#",-,*1('*35ClnA+1/" !J{žŽ{r£¿¹¨¨©«²¸½ÁÆÅ¿µ©š¡œ±µ¾ÄÇǽ•loqx~}{|Š‡†„ŠƒsO{››‰q„‰v[lejd^W]ZQZ\bowž¥¤££§ª¢¥©®¯ºº¹¼ÁÁÁÁÁ¾º¼ºÀ·¸´´·­˜o[VZ_gtlhryzmˆ‹zqbcb[K@6:8**)0)3EC)d¢·£’€s\813.6AJ29B<>I?E349/.B64=4144<567>=Jgx†ŒŠ‚…‚‡‘˜Ÿž  ¡¡¢žŸ¢£¡››œžŸœš˜œ™š™œœ¡žžœ¡Ÿ¡›Ÿ›—™›œ”–œ›œ˜›œŸ›˜™šœ™ššš™˜–—™–˜“”‘‰ŒŠ„ƒ†††‚cchceheikmdkfkcbebc`aXZWST^jr|€’”š›¤§¬«°¯®²¬®°­±¯³´¶µ®©Ÿ›œ“Œ…zrbXQKHHUSXZ\[f^^bgiiegccegdcddfchcdfhahccdeiglomenmkqpz–šœ›™–”’‹°¸‰yVl¥hPGg„}|”vW;YR7/+29HSmxeGA?DKY{d8#%&?qD0/)*DRq}…ŠŒ†ƒ~}ŠŒ™¡Ÿ  Ÿ¢ Ÿœ›žœœœšŸ›žš™š›™›™šžš™›žž¢ œžššœž™š™›š˜˜™›™—™›œœžž›žž œ—™‘–˜—›–•”‰‹‡‰ˆˆ†…ƒccdighfikjdmfhedffa\^ZU\XZagtƒ’”œžŸ¦¯­¯¯°±¯±®±®±¯±³­¬¨¥ œ“‘‰yp_\PKLLNTTSX[Y]fbahdfidbhhffaihcea`kfecdgkfkhniimnkkts•—™žš–™™•±Â³¬‹Œ¬ ˆxyƒziu‚ƒn<7;>(2:FLRZ{q=FCMHPesb-#"#7[kW,,1*0[W4.)%#$0Mglb4(+%(&+42.-&,*%(-;U&!,a”¡shkŒ¹Á°¤¬§²»½ÂÄËÈù±¨¨¦²º¼Ä̲uUd`hlke^_bffimkW>/Eo‘„|SDepIgn{|k_utomqpfmyŠ“›Ÿšž££¢£¨«²¸ÀÄÃÄÆÂÁ¾»½ÀÀ½·¬¤š‹|zzzonvp_FWKEZ_U\MKMQJC>AM9*)'--:BL-dœº®‘€nc_.-/17^;>D?A?:;23,-/577758740.25=H^x„ŠŽ‰†€€€‡”Ÿ  ¢  Ÿœ›žšŸž›šœ›œœ ™žœ›ž™œ›¡š›žž ž  œš›››š›š˜›—›™—›•–š›šœ Ÿœœ š˜›–”–˜•™™—–‘‘‘Œ‰ŠˆŒ‰†€__ebdcgmhkfmbee_dba^^[UWRZ_gs}€’™š¢¦¬¯¯°²¯­¯°°±°­°°¬¬¥£Ÿš•Ž‹xicUOPJMN\UTVX\e^\adceibffccc`aiabbhid^aceidbejghipqy…‡‰’–ž›™–•–“¨¼´·¬¥®§›Ž‡fVRU\H:,dxa%"#"1TRn10--_`lW4%0++,.-4*.++*.''D?">¢ji|°Æµ¤ª¨­±»ÁÅÈÈÊÀµ³©®­·½ÆÊ­dTU_b`dgd`JKICRIQ;6/8Qi^K0.CE@Toy€We€wzusttwz€†“™œ¢ Ÿ§®°¼¾ÃÁÂÆÆÅ¿½¿½¿¾·©žŠˆ~ˆxZQXI76799AG?AC?ELFBDIA..*%'.6IL-\œ·±“tpgW0106;T<=CAC<85/4.4.4.8036;60+*4?Wl}ˆˆ‹‰‚~ƒ’™š  œ¡œŸŸŸŸ™šžœ›ž›žœš›˜™™›™›œœžžšš›™˜œ˜š™›˜–š™˜˜›š›œš™›œœ›š——˜’“‘’–•””“’Ž“Š‰ˆˆ‡‡iijfjebmdfdedccdjb]]^]TXPX^ct‚‹—™ £¦«­±²°´±¯²±±°³°²¯¨¦¢£›––†niUMHIJMMSWXU\`_gccdcdfiicedaddgedaa]__c`ddhbihow‚ˆ™”••›œŸ›™–›¥œ•Š˜¬­™{O3C80/,.0;V\9JLP]r{a1,@IYWKhtP*"""5]@h@')-6Y]+'&&$).0C\v`:*),/2-(/-.3)0&$#(=!"'nŸweo¢¿¹¨ªª°®¶¿ÄËÌËǼ¹µ¬±·¿Æͦ^OQO^WMEFWT@@C>9;962,25<78/+/008S{daxˆ|yz{|wz„‰Œ–šŸ¡šŸ£­°¹Áÿ½ÄÃÄÂÂÁ¾À»´¢™Š‰„gnaG;9732414498<5363243310/.467:58777dyŽ‘Š‰ˆ‚‚†–›¡ žŸ¡Ÿž›¡Ÿ›™œ››˜—˜›–š ›™¡˜›œœ›ššœšžœž™š››˜™žš—™™™˜–•š››˜˜™™™™›—™˜–•‘”Ž’‘ŽŒ‰ˆ‰‰‡†‡ccigeb^bahdd`^`]^^b\]YVRQSPbn{ƒ‡Ž•›Ÿ¥©©¨¬³®°³°±³²³±¯®±©£ —”Ž‰yncYYPJGJUTUTZY^WWea^eijdh`eafc_cf``dc\_\]ZZ_ew– ¢Èξ}†Ž““•–™™›™›•}kRF;PlfE(&$$)?eti[NPYk‰]XdPFLlPIa||U'&.'0_>)7V:/2Ys.&)'$'%% 05pyqr`@&&$'+/34* &*&Z­vg{šÁ榬°­¶´¹ÄÈËÃÁº¼¾¹ÂÆ¢XF@?K;67952544:3/24.0./,37?TG73.(.''0(7Xoƒˆ‰€ƒ{~ƒ‚Œ‹’””œŸ¥«´»¿ÂÇÌÆËÊËʼ²ž€[N;8<17:719>:10042377:@657@?32.40,-$,1FE/F”§µŸƒof^GGJ12J>@<@A54/,0/142-:98285++',Jg‚’‹‡…‡‡•œ¢¢¡¢¡œžŸž ˜™žšš›š–—š—ž•– š›™˜˜—›š˜œ˜œ›šœšœ™™˜—œ—˜œ˜š˜›š˜›–—œ™˜™›•˜˜“”•–”‘“’’’’ŽŠŠŠŒ‰„]]abbc_^]e__`^\_]^Z[SPRNMUYcmtƒ‡–››¥£«ª®¯²¯°´²°´°²°±­«¥Ÿ–‘’ŠzodSMFEFOIQWUXSZUZc\^_ifdg`e_`c]_dbaa_c]\VY]b|¡²¦ÆÕˤxˆ––‘—™š›–™”‹„uiO30KTJ5'$#"(@ZvtgNC=ec3AfUNNfEOmuO#!/*6X=#*?U=-^‚8,,*(&$$)%*AiyyrgH($)&'-/%)'"!#E€¡•dd¹Æ¯§¤¬±°¸¸ÂÅÍÊÃÂÀ½¿¿½Å§^JAACC952/05535735-,*/./0OBbwo\F9.*'.)&.34GV[K>;2/048A;9<9;650--.*%,,3FD.E•¨·¢„ab^J@=?6SF;;=:41///34427.12>51.)+5SmƒŽŽ‹ˆ„…‡’™Ÿ ¡ žŸ›œ›™——™™›—šš›—œš™œ—ž¢™™›žšš›Ÿžœ™›š™—››–›™šœš•——™™•–”œ˜›–•™™•”‘’’‘Ž’‹ŠŽ‹Š‹‰‡‹‹‡‰ˆ‡]]\]ba]X\^\a^Z[]^[_UYSPLLNT]ms‡•—œ¤«ª®­±¯¯­¯°¯¯±°¯°®¨¦Ÿœ™“‹{rbUNFLHKNSTWZXX[\`\`__bgc`]^aa`_aea__YVXWSUn®ÎÁ¯ÐÑňy‹ŽŽ–•œžž’Šˆ‰‹tW73FOnzpmfR;+''-)""&!!3j“¦q_~¬É½§©ª«¯³¹¹ÄÉÍÊÂľ¾ÃÁŦYCKI>;B3004/00/7/30.,./,28FZŠ¢–ŽhN8*))+&*.Cdu„ˆ„~€‚ˆŠ‹Š’–”™Ÿ¢¬µ¼¾ÅÊÎÍÌÑÐʽŸe86:3/27629?3V|j[C1,+-323:89;2/.544+(,04NL,B”¢º¬’`ZXG2A5E^€¢ÁÀ¯•wb;*'&'*,3Qn‡~}€~‡ˆ…ŽŒ“•˜™¡£§¯¹¿ËËÒÔÑÓÏŧpA123-.*1;:Qq\K–ˆs_@.')+0686:77.)042.*$//P@-B“ ·¨’`SfLB@;>TP=><:302-032413063022,26Lj~‹“Šˆˆ•™š  ¤žœŸžžž›ž›œššš™—˜—š›–˜šš˜™š˜—™™œœœšœ™—š™ššš›ššœ›š˜–—•™›–—““——˜˜—“”“’ŒŠ…ˆŠ‡Š‹ˆŒ†‚Œ†„ˆ__baab^]^[``[[ZYZ\YUOVZKKOQ\is€”š¢ª¬°¯°°²¯±²°¯³±°±­«¤¢›–Ž„{pdXRIILLQUVZZ]\[``d`bbafcb`cfb]dc^`^ZXWXXUW‡ÍƳ½Î¶Œz€‰‘•–•™™‡e\‡ƒoPMV7-%"1/,*Y€sa5'.7mvD%$*@Uirc]d}yI:/-',*?<),0-.0G€e*/-11.+2/+-02;;-3?PZU2*'"!!2r˜œk_y±È°¤¨¬³µ¯µ¸¶ÊÎÉÇÁÅÅÅįiLPWULD<2*)*35=MC+/><-'$(XWAVy®ÊÌ¿°£šaE++;LJ?Om{‚|yvy€Š†Œ‹’‘”™ž¥¦ªºÂÊÏÖ×ÓÕ̵zQ621,+1,,78[”€E¡¤—‡kP6++*+4768:5/30/2.%&,.PA+7‹¢·©“_YcXE?@>XC<=E<51-,414579500/.,+0@]q“Š‰†ˆ‘˜œ¡ ŸŸœŸœœ›Ÿ™š˜™œœœ—›™™“˜™˜š—™š˜›š™ž˜”™˜›˜šš›™™—™™œ—œ›šœ™˜˜˜–””•—™˜––’‘Ž‘ŒŽ‹Š‰Œˆ…„„‰‡„„ˆ†ˆ†``eii]]^c]_b]]aZ[XYRQPQMHIS\kx‚‡Œ˜™¥©­¯®µ®­±´±²¯²´´±®­¦žœ’”‹yqbSHJMINRXYZ\[bebfaadf^_d^df``cdc]]\\\ZWYVWïÅʼn~„ˆ‘’™–™™šƒ^m‰ŒiB?G4$&,833PucN=&&3_rM1%#+,H^|xc]Zvp7/+*)G/.0''8.',>z}?+5+,(*+)30/1./++-@HA8:%&'!%R¡~`lœÆ½¤­¯±·²±·¹ÃÎËÊÇÁÈÅË·kQRXUND815,*,3ARZQ2hlTKd{|xzwy€‡‚‡‹‹–‘š £ª³¼ÇÐÒØ×ÖÓÁ\C225<40+-=9M‰L–°Ÿ’{^C8-)-0113831.22/.&'5?PI-6‹¤²¨ŒeeVl@>H:_B=?;86-.//0+6=4<2.00/1:Jax‰‘‘ŠŒ…’šžŸœ¡ žšž œŸœ•—œœ™š™˜˜œ™šš—˜ž›œ™˜˜š›™—š™™š›™›™œš›™”•˜˜™—––•’•’™•”–˜—‘‘ŒŽŽŒ‰ˆ‰…‰‰‡…ˆ‰„‰€…ƒƒ„‚bbcb_f\`c_a`[^^[ZWUSQSQJHLQ^px…‡‹•š £©®°­µ´²¯®¯²°´¯´³µ²ªŸ™™Œ‚{k_ZMILNQVXT`aa`c]^dcde`]ea\aafaf`a^^[\ZVXRI^ À´¾Æµ§“ˆ‰’“—–“–––g‚˜š†H-LQ+,&&CHUm\>.0&7MfG@/'#)2RVƒwWZR‚q545/+.,,%$(5+,,4fI1=5)')(../,:22*+*4:4*)/IK9;t˜Žg\ŒÂÉ´¤¯¶³¹¹¸·ÀÌÏËÇÉÉÄɽzP[^VQD8853*.48F\gZ29^]L0)+EpM8BÌÌÆÆÆÁ¬bFD]ƒnT[tzutqsˆ‚„‰‹‰Œ™œ§¬¶¿ÇÓÚÛÙÖÌžoVE82AC?6-(<,)*,*-,*0:.*&()++%'#%%.Ji„rVl“¼¿¨¡™•™¨­³¾ÃÊÊËÆÁÆÇÇ“ibgtni\TRNB;.+-EJ]uycC:TbVV[SH9B~ÅÑÎÐÒÍÎȶ•lLFl~j\`ppmpvyz}…Šˆ•œ¡¥±¹ÁÈÔØ×Ó˨|ZUga==^dYKCWiUK:W¢°¦tN>;-+*'+-/1/2)-1*'+-44/-3347<854.-.0-6RhŒ‹ŒŠ…‚‹•—™›šœŸœ›žŸ–˜˜˜–œ™–™™––——–˜šœ˜›šž™˜˜™›™œ•—–—›˜––“”Ž’–“–Ž”’•’‘‘‘‘‡Ž‹‰ˆ€„€†€€‚Š‹‘“›£ ii`dcc``b`ceh_\\\\XUQPNJCGNVgx€„•š £§©¯²°±±¯±´¶´³¶°²±±¬¢Ÿ–ˆ‡{rd\UNITSWR[[ab]aefilkd`fkkl]gkhlirzkUGHA:1++@š¬qn‰–­ÁÕÍÓÆ´­šk9*(*)-1#$'/0>^bSE8730=CR>J8=DV98>HUƒˆvaW™u@.'3+04//6@.,(,(:RtM*,405,-++540*0,'(+'.(%,@}ŠgQf‰¦¡—£¨«»¹ÁÆÅÈÇÅÄÂÇØlcprz~}tuymd`J2+3D\ir}qY>96=:AMk ÆÐÎÐÏÑÊÈÀ°žƒraf}}tforw|uq{‚†‰ŠŽ“›¢©±¼ÌÕÖÛÙÖ¿†hil€†vQAUgd`bREGo¡³­¥š‡mRE=.56(.,/-(/.(-(',5Re1-5j°§¹›„W?[WLHVN86572.?:0511><53,1-/15Yl‚’Šˆ‡ˆ—™žžŸ›ž›˜š—™™˜—‘—ž›•—™š—–––™š˜”—›˜˜–˜—š›•šœœ˜—–•™–”“™““”—”Ž‘“Œˆ‰‰‡‹‡†…ƒ|€ƒ„‡’”šŸ£§¬eedc_dbbcfa`_`ZV[^V\SMMIEJUYis‡•š›¢¨«°±´±³°±µ¶µ·³¶²±­ª¡¢–‘‹}yqg^WQPMSUZ][aiedefjihiiggfmdcglftkN928:2-41Gˆ«†Š³Ã¾¹ËßîâÓ»y@A*,*/)))&)14Ta]?88ED<8=GUNWPXŒvhXQt‘}H6&(-:0029<5(.*.4EO=*)1:2-,(--68(''$!%*025?n•|SV~¯¹Ÿ˜©°³´¼¾ÃÇÉÊÄÅÅÅÄ mhquvv‚„‚|‚|ulVA//Icqpuxq_R?BKXž¼ÊËÊÊÎÌÆü£”Š„xjt~zpps|}xv{z†„‹Š”›¥«¯ÁÏ×ÛÝØϵcor”oZMKYXVKLsž´¶±§›‚jPA512.,0313(..++++-4P_:4:hª©¹›‡\>V]YR\O;;886.0.7533?:51-,,+0YaTL@WMJhvx1Ot¥ƒi\GK3-.%.9,'$')14,1-0<@:6.,02D;/4+#'%",);n‘“_`|¬Î¿ž£¦®´º»ÅÈÊÈÆÄ¿¼`bwy{{€~ˆ“Œ‚|tkciSKq}‡Š’•Ÿ¨­°»»ÁÄÁ¹¯§ª›’Ž‡|uv‚€†~}xwy{€‚‚…€„Ž”š§­»ÃÐÝßàÕÊ¥~tf`\lwŽŽ‰ŠŽ˜¡§®´®¤ž|f\M5.4B@>885:810262336[W988\¥½°‹oSU]TeF>>35-.)/,-,1/758/+(0/CYu„ŠŒ‰Š†€’›œ ››˜šœŸ™—š•šš™–™™“•™›š˜šš™¢¢›–›™›–˜™›š—›š™˜–—”––•™““’”‘‘’”Ž’ŽŽˆ‹‰†ŽŒ‹‰‰…ˆˆ†„„ˆ˜›Ÿ¢¢¥¬°¯°±¶¶º»¿hhghggd`dcc`bcYY]Z[T]PLKIAPXiw‚†Ž™˜¤¥©¬²´´³´¶²´··µµ³¶¯ª¥ ’‰ŠqfaYVSXUY\]`eicfmnloqjnnrfzŸT.1,+.2;Fa‡œ¡ •Ÿ°ÄÀ¥ÍÍ´“S82-0-3Td@.3:Jg{…ˆ„h^m2$!+ #1Mn(7Y[ONHN^Pc‹†x7T§utpKA3FR$2+($%+%,/4210182.901/*8/'&-"!#,R„ŸmVl›Â˯£§¬¶¹¼¾ÈÉÊÆÄž”b\lx{|{†~}„““‘‡ˆpmrilxrot……—›—ž©§¬²²ª±´»½± ›—”ˆˆ‰„ƒ~ywysx€ƒ€y‚”—©¶ÁÏÛßÝÖȨš“|vyuŒ˜““™˜œ ž—‹†€q^L9,0>JC>98;840/1J7289[U005X› ¼µ’pULWXlB5DAG/.+/:-+24;5:;1+6BLbv‡Ž‘ŠŒ‡†’—¡Ÿ œ›™œžž™–—–š——–˜•——šœ™¥¨¨–™šš•™™šž››——•š™––––”“•”’“‘ŽŒŽ‘’‹ˆˆ‹Š‹†…‰ˆƒ}‡‘™¡¤©«­³µµ¶¶·¹½½¿kkggccgbbikc`][\[WURTPMJHHOZet€ƒŽ•™ž¦©«­²±³³´´·µµ·µµ´´³«£¢“‰{pi]URPPV\`ab_fikkjpqmoppkm©>%.$*7?Nc€™œ’– š¤ŸšÄ³‰M/4/)*$1Hq_P_kt„…lSIH^U+$'$()5]y-4aYQJONN]^•{Re‚©pos@8:`I+/.0*#)*/,6-./00+*+2,:-9($%$%#""9wœ‡_a·Ê¹¦§ª±¶º¾ÃÊËÉ¿Š^_huw‚|‚Š‡‚…’Ž†xv}~~lmk|o`z…ˆ’–‘“§ Ÿ¢¤¯¬¬«®­Ÿ”Œƒ~€|t{‚{~€ƒƒ†’•«·ÀÐÛßáÕɳ­®¥Ÿ …ˆ‘–Ž…Ž™›ˆub[NA2/8TSKF;75>94)1H764:UL-.4S•œ¸¶[MNXfI6DB3,2220/)(2;=91.6:{Xly‡Š…ˆ…‰•žž››œš™˜”™›š”–“–”•›˜•˜šœ§± –˜—™“œœ™œ–™™š™–˜˜“•””–”‹ŠŒ‘Œˆ‰…†‹Œ…‹‡ˆ………Ž—  ¦¬¬±±´¶·¸»¹·½»¾¿hhhjfjhelmfa__YY[XWQPPRQCHL[h|‰•žŸ£¨ª«©±²´±µ´µ²¶¹´¸²´­¤¤›“Ž‰€qf]VSWUYZ[`ebgijfqppmuqqnlš@**'2Lbo~Ÿ¯šœŒŽ~†”¤º¼tC32<:7,.8Gq€njh[WE5;Bei4("%%*2=`z'5ZbZH6DFVeq”{he¡mNpEFl_6&--,&*-.+0/+-.1/003293.+1$&"# *^‰œoYgœÀ¢¤¨¯°»½ÂÈÎÆÅÆ–``invx…ƒ†‹„‡‰‰’‘’’‰†„ˆŠƒzmhw}dYv‚„ij€seŸ£¨§³¯¯¨žˆ}w}x~|‚ƒ„‡‚Š–œ§´»ÎÚáãÙÍ´©¬§¤Ÿ–”“—‘ƒ|{q‚up~X?B>=?@C?CXYUE78794/-07456CSQ502T—™´¹“‚^UETcS@9<-.2/707/3;32;QMT4,6O‘šµºŸoZ:YbM=2;433561'/6>A2..64EepŽŠ…ˆ„Š–¡›žŸ¡ž™™›™›š—™›š–š›˜™—–š”•—˜™•–—™–šš“–”˜–—˜˜—••™˜—’’•’‘ŽŽ‰ˆ…††„ˆ…‹…„ˆ‹–œ¢£©­±²·¸º¸¸À½½¾¿¼¼º»½»¾gghigkjd_bhc[YYVTVWVSRKJEHFTft€…”›¥¦«®¯´µ³±µ¶µ·µµ»¼´³®¦¥–‡€ukeWLOWTU\\aegkmimpqrsnmonpŒƒaouxŠ‰r|„“—’‚sOAJYTQZYI981'),/-%'KO4+7N‘˜«À©{bL\p‚„Š“•¢¡¦««­®±º¶´·´´··¸¸¸°®§£ž˜ŽŠ‚yh\QRUOS\\_]abfkhmmpmohmkolmx‘œž®¨–vtwoaH@?LIF56Nu€weKXa`haXXj<9@SjgT9=?7)%./NW;8AW\XmeuMCJGAgiRI/,+$#586?VS4/2Nq‚x}yvqJJln@@_ˆH&+10,,,-/-',1(+)067-32100&'(-G‚ž„iek‡´­±´¶»»ÃÃÊÏÍÁ?ET`fqporx‡†‡ƒŽŒ–”—œœœ›Ÿ¤¡¡¢¤ž¦¡¡£ŸšŸ›¢¢žŸ¦¤«ª£¦±¬®¥¢¬¬ ¢ª¤¤•Œ……ˆŠŽˆˆ‚‚~„€}Œ˜ ¨´¿ÑÙßàÖÆÀ»ºµ¯ ™žœ—–—Š‚‡‚…‚ztwqvurrj^UI>I94$-670@;?VL4,4?‰Ÿ¤º°j=BW]./91<-*&(11;,-.)00Lf|‡‰†„„‰Œ“šœœœžšž›Ÿš—–™™š˜——–˜™š–˜˜˜“–”–š”•”••”“™•“˜’•’••–”‘“ŽŒŽŠ‰†…‚†ƒ’œ¥­±¶½ÀÁÃÄÅÄÃÀÁÁ¿ÀÀ¿¿À¾½¼¾¼½¿¿½¾ff^`\[Y]\`TYUTQMPSTQIFF@=>AJXk|…‹–˜œ¤¦©¯²°²¶³·²·µ·µ¶¶¸²¬¦§“‘„€tgZZPKOR\]]adbgoippnlljrklmnuuƒ…„plhrolL?=JGP]o`B00<2++1=VRF@88*373:@<SS,/5192/(,2464+,,*6Pk|ˆ†‡…‡ƒ†’•Ÿœš™šž—™™™˜›™—š˜˜“˜—•”˜š––•™™••’–——–•’‘“‘‘•’’–“’–ŽŒ‘Žˆ‰…ƒƒ…„ƒŽ ¦¬²¶¼ÀÃÄÄÆÄÅÃÂÁ¾Á½À¿¿¿¼¼¼»¾¼½¼¾Àcc]`^Y[XW[YTPRPPRSNKFF=?=;BN\l}„Œ“–˜¤¦©¬¯³±´¶¸²¹¸¸¶¹·µ¶®¨¤œ—’‰wga\OMUVU\[_e^hgkisnpqorlkr„tzxpmltsgODYbx}yw]M93833*4/<]ZQE^wwng€dI45Ejw[G($#&/5-3NShqRB7*2gŒ”|SB;CgSz¦£Z-/)-.3300341&++,(,15165245*.,P‚£genŽ¹£±¶¼»½ÀÂÈÌ̤@?GQ\_lptx{|ƒ}†‰ŒŽ•–˜˜˜Ÿ ž¨©§£¥¢ª¬¬²«©¨£¦ª¤§¨®±°®¬¥©¦¦¦§§¦¡¦›Ÿ•ˆ‰‹Ž’Š†‡…„†‚„ˆ˜Ÿ§¸ÂÍÖÙÞÙϽ¶µ²­©£Ÿš™–˜”Š‡„ƒ€|z{xzsokgfZC=;96+5/29C<XuƒŠ‡…„†ƒ‰•›ŸŸœ™Ÿ›Ÿ™šœš—•–˜——”—”–˜˜šš˜›–™’”‘‘“–•›•—“—’“‘•’••Ž‹Œ‘’ŒŽŒˆ‡……ƒƒ„›¨®µ¹¼¿ÂÄÅÆÄÄÄÅÀÀ¿½¿¿½¼½½½¾¿¾¿»¾¾¿aa^_^]X[^XUVWTOTUPQPEBD===IUZgy†‰’ššŸ¨§©®¯²²±µ¶´¸¸³¶·¶°­¨ ¢–ŠuiaWOMRSX]cad`fhfjnoilnpsmquyzo`ns‚yoeq…”‘’…w\?889201/7Om`MPh‚t_uj_?AGlnR/&$&'02.9ObriUP=;HMOm‚mT<\is¦«r;236342141376.+0,(/2/53-.11'':o–›tli‚¬¾ ³¸¿À¾ÄÃÇÌ°L9CKW_dppv|zyŒ‹‹Š““–˜—žŸŸ§ª©¡£¢ª¬®´¬«©£¦¥¨¦©¬®®­¬¨¨ª¦¨¬¨ª£¢ ™”ŽŠˆŠ…ƒ‡‚ƒ„…€‰˜¥µÅÊÓÜßÚÏƹ´´´±«¡¤™˜•˜“ŽŽ‰‡Šƒ|}yy|rqkdTEA;<4)/24<;6=PI-#*:wž¦¶´¦“n@9EM(#263,5.07751+,-4Des…ŒŒ†ˆ…†Œ•œŸ¡›£›š›š›šš™””˜•š•™˜—–•™–—–™•™“–’•”›––˜–•‘’’’Œ“ŒŒŽ‰‹ˆŠ‡†ˆ‡‚ˆŽ¦¯´¸½ÀÃÅÆÅÉÅÅÃÃÁ¿¿À¿Á½¼»»¼»¼»½¾À¿¾[[Z\V^WZUSTVQVPLQINLGDA;<;EKXn{†‰™—¡¦ª¬­´°·±³²²¶·¶·´µ®°§£ž”’ˆ‚wl^VOOOQU[W[`agdkimpnmnoptsu|sglv‹§«‘’ž¢™“z_PD9=::A@<:QvdNGr€i{p[YTMg†u_A#"%(,*3+9/,--63..,-(01,417,+2,)R‹¥~igpŒÀ²«µ¼¾½ÂÆÉÉ»Y67EQRakpqoy~z„‚‚Š‹‹’—š¡›ŸŸ¢©©¤¥¥ª­©±­­¬«­«¬­«ª¬­¨©¨©©°°­¨¬ œšš•”ˆŽŽ–‰‹‰€ƒ‚z†z~‡Ž˜¥¯ÄËÑÚßÜÑƼ¸µ±¯¨§ ›š˜•‰„ˆ‡ƒ‚…~|z{zrpnd\JA/84(-8?A1??RC2,*:| ¨°·¥u97JJ*%1A910*,431.01/=Umz‹ŒŠ‡„„†˜™£Ÿ›žš•œ›–™˜š•™—•š™˜—–˜–•—˜—–“˜–˜’–”–”“’’’–‘“‘Œ“‘Ž‡Œ‹ˆˆ„‡†ƒƒ‚œ¥ª³»½ÀÂÄÅÅÇÄÇÆÆÁÁÀÀ¿À¿¼½½»º½¿À¾¾¾ÀÁXX]\\[W[TTVVURTNTINHB?;;;=BPXiv‡‘˜ž¤¥­­°²¯´²³²µµ·³´·²°­©¢™ˆoe]ZRPNPV]]__aeafjfkmmorruˆ‡‚…•›¤®¦¥–‹ŒvdMIG=?>CFFB9?`zWGRnyu{X\p_hys]K+(%))%)2-14:D[muTbllbXZN\• Ÿ˜vEDkc_RQUMB'%(434)&/+*)/--.+)(-Bwœ˜najv¤¾§±¼¿»½ÆÌÍÁz64=GKVgmrpux|{ƒ€„‡Œ”˜œ–›Ÿ ¥¤¨¨¬§­­¬°­®­°²²­¯¬ª¬­¨¤­±±²®²¬§¢››˜•“ŠŽ”‹ˆ„‡‚‡|€zƒ‹œ£±¾ÈÓÝàßÒÊ¿·°°­®«£›””Œˆˆ‹ˆ„ƒ~}y|vtlk]NG8<6325;71F:Y@)#&5yŸ¢¬³¦•wF4G<)%+B3+*,2891+-.+;[p‚Œˆ‡…††“žŸœž›šš˜šœšœ™™›ž›š••™šœ—•˜™˜š™—”—‘’“•’““““’Ž‘‹ŠŠŠ‡‰‡†‚€ŠŽ—¢­·¸¾¿ÂÇÈÆÄÆÇÅÄÅÃÁ¿Â¾¿¿¼¾½½¼¿Â¾¿½¿Á¿^^^]kd]YX\UVVTWOMLNLKBC>;:AO[gx…Š’˜Ÿ¤¦««®±°²´³´¶µ¸¶´·´±®¨ ž™‰~ph^PQOOWZZ]Zbaa]ddlnpuƒˆŽ’  ˜¢¢¨«ž¥ŽzcRKLNXSA6789=CF>3IejTH[iyqSSbyr€vcE)(%)*'!+823.+5KTjeouz}pk_VhŠ‡i@2_}vfSVYS/'.26-,10+050+*,)'(-T“¢}fgpˆ»´®¹¼Â¿ÂËÎÈ403?LS__oruyxz{ƒƒ„ˆŠ‹’—™•š  ¢§¨¨®§§±¬´°­¨±¶¶±±°¯¬«¥©®²®²«®ª¨£ š˜––ŽŽ‘Œ‹†~‡‡|€€„–œ¬½Æ××ßÜÓÌÀ¸¬­­¬­©ž™•—’ŒŠˆ‹…‡……}‚~{|vwrj[G99;0,18A75I;U70+'/t ž±®žœyJ2A4""(C=-#09585/01*Eev„ŽŒ‰…ƒ†‰š ŸžŸ›š›››š•š™˜–˜›š˜š–•–•˜š—š––˜™•“”’”›–’““’‘”•Ž‘‘ŽŽ‹Šˆˆ‹Žˆ††‡‡ˆ…ˆ›¤©²¸¾¿ÂÆÆÈÅÅÆÈÈÅÁÁÁÁþ¿¿½¾½¾¿¿À¿¾ÀÂÂÃZZ\]gdVXTRVQSSSLJKIEFA?;99DMbl{…‹’—Ÿ §©®¯®²²´²³²¶¶·¶³¸±­£Ÿ™Œ‰„tk^TONOUY\[[^cbfggks„”¡£¡™’–Ž™¢…M>?BFF:QmeVLVwrOQbu€ycV?/,*3),')(.*)/0>TPCFnu||vjM;51.2_†ˆ‚rca_J0-354/:--,00-+0)))&1ož”pfov¦À«´½¼ÄÂÉÐ̨=*(6AKTZfqutuz}~€~†ŠŒ’”˜˜•žž¢Ÿ¤§®¬­©­¯¶µ®¨ª«²²±¯¶³±°°­®¯±°°©ª¤£Ÿš“‘••”‘“ŒŒ………†‡}ƒ‚…‹“ž¨»È×ÙßÝÔ͸­­©§¤¦¢ŸŸ—•Šˆ…ƒ†‚‚}‚zuuniWF:8=4-3@I6:E>V:+3+,g¤´«¤ŒQ/D?/.*;9,(-393+.//4Siz‹ˆ‡‹‚…’ššž Ÿšš›œ—–™šžš—•˜›–˜–•——”–••›˜—••Ž‘‘—Ž•’‘‘——‘’ˆ‹ŠˆŒˆ‰„Žƒ„†ˆ–¤©³¸½¿ÀÂÅÆÆÄÃÄÄÃÂÃÂÃÀÀÀÀ¾À¿½¾¾¿À¿ÀÀÁÁÃWWVXZXWUWSPULMSOMNKHJ??;56@Mat{~‰’“œ£¡¬«®²²°²µ¶´¶¶³¶´´³®¤¢”Ž‰€uh[PJNONRTYY[ahkhuƒ–ž™‰‡‘Ž€zŠ€~pC05.655/-.../-.0.-./10+,6S‰ª€srt}µµ³¼ÀÃÃÆÏϽX)$.4DMW_iowuwy|}~†‚ƒ‰”“—˜—˜šž¡¢£§©«®­«®³²´°¬ª´³°±±²±°­®²¯²¯­ª©§¤›œ”“””˜•Ž’Š†‚ˆ†„„ƒ‚…‰‘ž§ºÊÓ×ßÙÒÏĸ¯¨¦¥¢¡¡ž™˜“‘‹ˆ‡††€‚„‚}w}qh_K9?<0+<;B>5CCU8,+)/_”§´§—¦Žc9C6(**42,2689+0),/6XoŽˆŽˆˆ‡—™ ž¢ œŸ›ž™˜œššš›—–•—”™—™–œ•’•”›˜••”•’’’‘’”“‘‘‘’Œ“’Ž‹Šˆ†‡„…‚ƒ„‡Ž¢¥®¸ºÀÀÂÄÅÅÄÃÄÅÆÇÃÃÂÃÁ¿ÀÀ¿º¾¿ÁÃÃÂÄÂÅÆÅYYTSY_XTQPLNQ^MLMOHGIC?9;;CO\ky‚”–œ£¨¬¬¯°­´¯µ±³³²··¹´µ¬§£Ÿ˜”‹rfZVLOJTQVYZ]ggu‚‰Œˆ„€yu{}ƒ‚|~u`TG862B\[OL>B?A=9I=4?HVdXFS]vwcoŒ†~u:5506661*/13.5,(0-24F^WA6??SjM/$$(12Ea‘ŒtgF78)./2.-+,-/*/3))*0:l”—ssxu¼¨¶ÁÁÃÃÍÒÉ|-!(-8GU`blow|{z~€€‡ŠˆŽ””‘“——¥¥§§ª®­¬°±³°µ¯°´²·´®®¯´³°³²²­ª¨¦¡¡š™š’’””ŠŠ…‡…ƒ‚‚{‰ ¦»ËÑ×ÝÛÕÐÇ·±«§£¥£¢¢—˜”‘ˆŠ†‡†„~ƒ‚~€x{ztiZF9@A1-/B<64OBW;4++1]–¢­¥”¥šk2:2+*.,6))2303**,+DZuƒˆŒŒ‹‡ƒ‹”™ž  œž›žœ™œ˜œŸ™˜˜–œ™—™—–™––›”–•”“–›•‘“’‘‘•”ŽŽ““’‹Œ‹…‡‹„‚ƒ„ˆŒœ¨±·º¼ÂÁÂÃÄÄÅÄÃÄÄÅÂÃÃÅÁÁÁÀ¿À¿¾ÂÀÀÃÂÇÄÊÉÉTTUXSZWQPOROOUOMJGGDCH?<69?M]kz”—›¢¦ª¬®³´±±µ³¯´¶¹¸´´­©¦¡š™…udYWORPRW\\^biky„ƒxtuqjv€{u‚€s\_WLEKOJNZK:<=A96?:HQSnVKZky‚Œ“•œ¤¨«°°²¯±³³²³¶»µ±¸¯°°§¤•‡~tl_ZOINSWVW``dlkwnmopsru€ƒ„ygifj]i`_VUTZ[]?:BD5/:=CLbop=7JQr}|‘vNH+A^@-&'"$/_blŒ}kZf_70+#)+/,'&230&!*,DXl{ƒŠ‘›¢¥©­¯±±´±³²´µµ³³´±±¬§¢–”’‰}ogaXJKPR[\\^aiinfelmopqp|€ƒx\Z]NH[bYUYh_JQ=HO747BIUapsY6:)0>445:G_M6-*'.L†¢¬¥|’¨’S(/#&,*0K6571.1.+8Xn‚Š“ŽŒ†‡˜¡ ¡¢¢Ÿ˜››˜—™™šœ›–˜˜•——“˜’˜’–––’“’‘’•””“•”Ž”•š“‘‘Žˆ‡…‡‰€€„‚’ž§³´¹¾ÂÄÀÂÁÁÂÂÂÂÁÂÁÃÅÂÁÁÂÄÁÁÀ¿ÃÆÆÅÈÊÉÈÉËËËTTQMPRRMOMMGKMPHHMJEDBK88>EGYkz‡—› ¦©©¯²±¯²´³·µ³´¶µ°°«§ —’‘‰†wg^WMOMZY[`]dcbnifonlnwt|„}nN][HHRUK^fcM@Z]PM429;;7=F]jy„ˆ’•˜£¦¨ª­¯¯´³³²±µ°¯´´²°®¥Ÿš—–„€oh\XNKTOWT[bda`jjnolrorut}~jPQXTZPJfwq\B_fYD<;GXmuz]<18'%$','#"&2%"")[‰”voos„ÀÇ»½Æ½½Ãά:/+-5.26@OYelrquu{{‚ƒ~‚‰…ˆ†„‹‘“•—˜¢§©¥¨«¬°²´¶³°¯´·³­¯®©¯°¯«­©¢£ž››—–‘“’”Œ‘ˆˆ††~|‚„……‰—§®ºÒÖÚÜÛØÍ·°©¥¤¦¡¢›™˜–‘ŽŽŠ……‰€ƒ€~zqh`E=;71(19845:HaK2*)',HŒ¦ª£…˜¥˜a,-#+;)3<>33/-,*/JbyƒŒ‹Š‡‹—™¡¡¢ ›™œž—œ•œ˜šš™˜œ˜›––’”–“—•’˜”’‘””•Ž‘•–’‘’“‹‹‹‹Š‰…ƒ†zƒ“Ÿ¨²»»ÂÅÆÅÆÄÂÁÁÀÂÁÁÃÄÅÄÂÃÂÂÂÄÂÆÇÉÇÉÊÊÌÌËÍÎÊÌSSTRLKGSHJKJKHHFI@AG@?=965CLXg}„Š’–ž¢¢«®¬®²°¯µ°¯´®°±±¯®«£¥™‰„ui^RKIMQVYYY_jjheimmlqrsqurd@@Zwgh|‚|^HG_€j`JGJ\lwkO;/+5;UPg›‚]YmkB>M:C;+*,,4>336371.3123-,H).-'1@[<(""1KYeq„mm•¦“wX-%# #"%$#""!%9rš‹srpt›Æ¹»¿ÄÃÅÌÂj20*-:-743-4211=75,:A/00JD)%":A`fq{gZ°šzE*"+/)"!")&"$*S…Ÿxstw{¶Å¸½ÄÅÉÐÌ—2)))5C,0<=KU_entyvxyƒ‚Œ„„…‰‰‘Ž•–˜™œ’››š¢§£§©ª²¯³¯±¯±¸±®®©«°®¥¦¥¤ž›Ÿ’’ŒŽ‰‹Œ‘‹Š‰‰„|v„€ƒˆ–Ÿ¨ºÃÐÛßÞÙÓ»ª§£ª¤œž™˜˜‘•Ž‰Š‡„ƒ‚‚wzqeSD>:4)'=12//3E]K.,)%+@y­´¯‘ˆžž|;+)"$#1CC@-1835=Yu†‰Œ†Š¯£Æ¥¡¡›šœššžš›šžš—šš••”—•••“””’“‘‘Ž‘ŽŠ’“Š‘‹‡ƒ†‚„ˆ“ ®³¿¼ÁÄÃÄÃÃÃÁÂÂÁÀÁÁÁÀÃÃÃÄÃÅÇÈÊÈÉÌÍÎÎËÍÎÊËÍÍÍIINKLMGLILLPKKGGECEEB>:77/4>LXG1'&(%9s¢¯¦˜Œš–W7=#!&47?:/6215Lf~‰‰ˆŠ‡ƒŽ”ž£¡¦¡šœ›˜œ—›˜š˜š–˜šœ—”–”—•’’“”“’“Ž’‘‘’ŒŒ‹‡††‚€ˆ˜¥°µ½¿ÂÂÂÄÄÄÁÀÂÁÀ¾¿¿ÀÃÁÃÄÃÄÈÉÊÊÌÎÌÍÎÍÌÏÍÌÌÊÊËÊJJLPRNMKLLPMNRHFJGIC;@<652:GXhw‘›Ÿ£¬¬¯±°¬°©ª­®®­±³±©¦¤œ•–‘‰ƒtlYOPDOTP[t…‚d_dbjlgkgnzƒˆ•˜•ŒtTH/@JXp†€jQAVƒˆX<467VI>7Lr‚tX„€E(3A:B<@53I94-27+,)+*3'&/LIU2(.3=9---=`ovˆƒhOO‰y“²˜n2!."&++('0`•mdpy…ÃÊÅÈËÎÑÔ§/"%%(/9H7689AO]G*!$"$1lž©§œ…˜“d4C$1(.;4<,-(*<\w‚‹‹Š‰‡£Ÿ¢¤¡ž›š›™——˜™˜™™•–—•”––•—–’“’“’‘Ž•–’ŒŽŽ‡Š‡„††…‘š©±º¾ÂÂÄÂÂÃÀ¾ÀÀþÁÁÃÂÃÃÅÆÅÇÉÉËËÍÑÐÑÏÏÍÏÌÉÊÌÌÉÍOOLKGGKGGJLJOIEGBCCB>>5374=HXkx’“›¢¥©¬±±¯®®«®°²±²±°©¨¢š”’ŠviUUFHJMP\yŠh_a`iigr{Š› ¥žaD:;61FSnŽ”zW?]}Ž`9.,.5`uHHW68:rŠSl’Y=87874<:0@C1*).'(3+*:(&&?GDAGF>92*597:LaP/(%%&3g˜¤¥š–‹h=7 #-8?5871,,=^zƒŒ‰Œˆ‰™›£Ÿ ¢¡œ›šœž›š›œ™šš“š“—–”˜’•“’”’““““’“ŽŒ“‰‘‘Š‹ˆ‹‡‚‚€‹š¤®¸¼ÀÃÅÂÃÂÂÃÂÀÁÃÂÁÁÁÁÁÅÃÇÆÉÉÌÎÌÐÐÒÑÐÐÌÍÌÉÉËÉÊËTTNQHOLKLLQIHKJMEA@B;92410@I]lwŒŽ”ž¤¦¦«°¬«­¬ª«¯²³°µ²°¤£ ™—vn^PKMMKL_}‡t]Z^]ijw¤©©™‘ˆnE*.7:5QkœœvIQ||[183/+;tnIMV75V–‰ƒŒ…\Z’p2546:7R>8C7,+%.&'*%)0(**ASMLCGM:.8HN[\yœ¢˜‰a=5St›­˜i& $# &[Œ”|nkt¶ÎÆÍÏÍÍÉ‹1"''$+&DU8/59LVZefoqsv~xƒ…€ƒ………†‡‹‹“•˜˜˜˜  ¤œ £¨¤­±©ª§¬¨®°«ª¬¬¥§ ¥¦Ÿž˜™”‘Š…†††„ˆ†‚…€€{zx{|‚‚ƒƒŒ›¦®¹ËÖÝÝÝÛе££¥ ›–”““ŠŒ„…†„‚zwbPB70)(-776D95?KWX0%&$,,b‘¡¦›}–“ŠoL5)$/88951.'0Nh|‡ŒŠ‰‹ˆ‹–¤¤ž£ ¡ œ™ž›ž˜˜š™šš™œ™˜”–•”–“‘‘–‘“‘’‹‰ŒŽˆ…„ƒ‚ƒ…¡«¶¼ÁÂÃÆÁÃÿÀ¿ÁÂÂÀÁÁÄÄÈÇÊÊÎÌÍÐÑÑÐÒÏÏÏÎËÈÊÈÇÇËPPJGLNHRPQMJIGFCFD@GA:7103@J_ix€‰•š¡££ª®­²­«®®¬°¸²±²°¨¨¢¢˜”Ž†seYKJGOEQ\€{`a]dt‡›¤¢”…wxeA',91@o|Šš…b`yyH>2<<-4Q{dDi[2:`˜Œu~‰`D{†K33<63;>.,&&)'(%*0,1>Q[\PMUO2-HbWPc‰¤¨© uH3Cb~“`&$$;œunp~ ÆÇÊÌÍÎÌ¥?&###!!+AW<74F:=ALVY-&)(/2^‹¢¬›{žš‹uP. ,:742,-(@Wl€Œ’ŒŒ‰…Œ™£¢  ¢ Ÿšœ™›™™—™——–”™“–•˜““•“–“‘”ŽŽŽ‘‘ŒŒ‹ŠŽ‘ŠŠˆŽŒˆ€‚Žœ¥±¹¼ÀÁÄÃÄÂÁ¿ÀÀÁ¾ÀÀ¿ÃÅÉÉÉÍÌÎÎÏÐÓÑÒÒÏÎÏËÌÈÈËÊÊËSSLPMNNLOPOLMPLEA>E>:83/0,:MVex‚Š“›ž¤¨«¬­¯¬¬¬¬«¬¯°²­±¬§¥’Ž‹wcXNJIIHMVs”Žo\ex‘¤¤˜oq|‡€X1*76=`~€‹ƒSRzyH917cp]N’jALxydsrAn—b8B<576329>83;70)"'*%%$)6,:Co‚{fVC;30NWf{ƒ¼··µ”^)3=\…vF$#7p ‹m~vu‘¾ÃÊÊÌÏÃd(!#%&!'.KUD5:DJQVhikpo{~}}ƒ…‰‹‹‡ˆ’˜‘–—™š–›¡£¢šžž¢¤«ª«ª¨§©¨ª¦¨¦  ¥¡ž›•˜‘Œ‹Š†…€ƒ†‡…‚}~€|xz{|{}€ˆ– ¨³¿ÅÓàãáÙÊŸ˜Ÿš›˜™••’’‹„†ƒƒ~zofZF:,(+-11-7C>DNCNX/)!"3I‚œ¦¦‘Œ§‰T) *80(,,,2IexŒ‰‹ˆˆ™ž ž Ÿ œš™˜˜™šš™ššœ–™—–˜“˜”•“””“‘’•”“’‘“’’’ŠŒŒŽŒ‹…ˆˆƒ…Ž§±¼¾ÂÂÄÅÂÀÂÁ¿ÀÂÁÂÁÂÁÄÄÇÉËÍÍÏÎÎÐÑÒÑÑÑÑÒÍÎÍÌÊËËÊÌÎOOOLLOKIIQIGJJGEGA=?;:82,.5@Ug}Š’—¡¢©©©ª²­­­«­¨°°¯²­¬«¤ ž”Œ‰~ubYRGEGJLL]l“œ††‹wnsn|…ztW<:GOz•wqiCNk[Qgd|A26Tk\KMy‚L:W‡uucv–†X[ŠJ88).:85790(%#))%(=H48>]roO>8:AFfv{xv´½¹¶™h,&2LsM& !%Pƒ•yoyvx¥ÇÈÎÏÎΉ1%&%'!#)')I\H56761,)3AZey‚ƒŒ”œ¡¤©®¬®¬­°®«®®¯±±³®®©¥¢——Œ€rfYPIKRIIQX]n…Šƒuneikkr|tudG7C=n„lqQAiaZJKaV5?H`b[QqhK:c…nfly¡•\D]‰I&-)*99A7;/-&),*%(08/D;@TkjO9;MqenuzgO‹½½¸žy<#.=N5# /k†sptv¿ÍËÎÌΣ8%$&)%&'"$%MfN:BGEKWaglqqy~€z~€€ƒ‚‡ˆ‰‰ŠŽŽ”“‘˜›—–™šž¢žœ ŸŸŸ¢¦¨¢¦¤¥¢ ¤¥¢¦Ÿžš““ŒŽ……„„€„}„‚||{y{y|}‚†Œ’ «´ÄÔàåâÛÒ¯”¡ –š™—•’–Šˆ…ˆƒ‚~ytkcUC.,*0742.?A?=NDRT-'"&4Lq™§§š€¦’^+"$77,)4.59Xr‹Œ‹†Œ—›£¡ žŸ šŸš˜““œ—™š˜›—”š•—”——›—˜—“’”•–—’““‹”‘‹‹ŠŠŒˆ‡Š‰‚†…›¨²¸ºÃÃÆÄÂÃÁÂÂÀÂÂÃÁÁÃÃÃÆÊÌÏÑÑÑÏÏÏÐÐÑÎÏÒÐÏÏÍÑÍÌÍÍÎÏQQVPWNKFOKEEKGLICCC5722/0/0JILQ3'"!"1Ln—§ª˜¥Žˆm,&#/0'*(.;<_q‹Œ‹Œ‰Š“ž¡žŸ›Ÿ›šœ™”™œ˜”™™š˜™˜™›•——–––”–•••—–“Ž’‘”ŠŠ†‰ƒ„…ƒŒ”¦°·»¾ÃÅÄÃÄÀÃÀÀ¿ÂÃÂÁÂÄÇÅËÊÍÑÑÑÑÑÎÎÐÐÏÍÎÐÏÐÏÏÍÏÍÍÐÎÎOOPNTNMMLNFIJGKCDEA73443*+.DPgw€„‘—›¡¢£«©­°°°¯±±°±±²¯®¯©¥¢—”‡~reVQIKPMPPSZ[]_dkv|{‡Š‰ˆƒˆ{XG48Hnhg]Iah^Xi^:8OlcSIFvT]_D^|\Op–šj:5vn%$&*0-.0:31+1.-*9223e^gLK[JG[z£‹punZB;=ZOBD.*$):2!#0!,(\‰Šuxxy’¿ÌÎÊ¿Å/""'+)"(''(0VdZA7HESW\`fquww}€€€‡„„„††Š‡Œ†’–™“—•˜”–š›œœ˜ž£¢ ¥¤¤ ¤¤£¤¡ž›””’Žˆ…}|z{|{‚ƒŒ…}{}~yuz~ƒ…‡’™Ÿ§±¸ÑàæåÞÒ¼•œœš˜•—˜”ŽŠŠŠˆ„€‚}mdVF0'+)0-52BEBIEGHFK67#! 2F\Œ¤¥›„ ‘‰r57--.(&-,LDc|‰ŽŒ‰Šˆ“ž ¢ž¡™žœž˜›™•›˜—˜—˜˜”—œœ •¥——“”‘”•““””•—’•“’ŽŽ‰ŠŠŠ‡‡‚€†ž«³»ÂÃÇÅÄÄÄÂÀ¿¿ÃÃÁÁÄÄÊËÍÎÑÐÑÒÒÑÐÍÍÏÐÍÏÎÏÏÏÐÏÏÐÌÎÎÍTTQQPJJMMJNHOINCB>?<9503.$1EWes~†•›¡¤¨¨°©¯°±°¯®­¯±²µ¯®ª£ Ÿ™’Œvf^UMKIKSSU\\]gl|‚kku…„€zuX?:>H_VSMWdl`_fB9Y`bUJ@Kz…FFN>\qSFhˆ“£l?2b‚6$'///4++,51/930//*1SgH?EOGRc…vacYC2DY_G;2*%1,7/!.OKm‡vr€{~žÉÊÊ« £<("%'+'&,%%,Yj]=BGMRYXejmutv{~}€€………Œ‡‚…Š‰”’—–“™–——˜–”›šžŸ¢   ¢¥¥ž£¥¢Ÿ›˜’•ŽŽŠƒ|wry}‚††‹‡ƒ~{|z|{~„‡‡“˜¢©±³ÎàæåßÓÁ‘˜—˜—˜–™›’Œˆˆ†„€~~ngQ5)')+/,3,-:CADRACEF.(#"/EY‡£œˆœ–D,)/+'#$/ENh€Ž‘ŠˆŒ—›¢ž ›žœœš––›—˜•—˜–˜”–™—›—™˜•”–‘”“’•–”‘–“‘’Ž‘‘ŒŽŒ‰…‚‡„…Œ—¡¬µ¾ÁÆÅÄÄÃÃÂÿÀÄÃÂÂÄÇÈÊÌÎÑÑÒÑÑÑÐÏÎÌÎÌÎÍÏÐÏÎÏÏÏÐÏÐÐÎPPOOPMOSRMQPRJJM@>@873.5)'.>Nax„Ž“œ ¤©ª­°°­¯°¯°´±²¶²´±«ª¤›’‹~vnZOHEIKMQX_aiu„xkhmrz{|wg9:LVc\Z=Detse\@=Sh]MCC;d’o:/2AgtW=fˆ’¢rF5FŠS'(&1A.&/*I><0,%(#*,:b4.SOO`y¨wcQHBGo‡sO:/(##0/+#(Qeg~…jnrr¹Éæ‚—}4$##)%"*%)*\l\A8GHOV]ghlsuuy}€„‚ƒ‚‡…ˆ†‡Œ‹‘““•š›™˜˜—™š–šž¢£Ÿ¢¦ž¢¤¤£¡œ˜˜–‘Ž…|yurv|„…ƒ‡†„ƒ‚„y{{††Ž–¤¬³·ËÞææàÔÆ–“Ž‘—–˜•“Žˆ†…€~~yqsdJ1,,(.-57.0;DCOSBIB9.""$3;T…ž©›˜ Œ€_75)'#(#-JYt†”ŽŽ—¤£¡ŸžŸ›œ›™›˜œ™–—˜—˜–“”‘“•–—••™š”—–’“”•“–‘–“’–‹ŒˆŽˆ……„ƒ’›¨µ¿ÀÄÆÆÆÃÂÂÂÃÁÄÂÀÁÁÆÆËÌÌÏÑÒÐÐÐÐÏÏÍÌÊÌÎÏÏÍÎÐÏÐÎÍÐÐÐÐRRNLMNOOOMQIKNEIA:;6650+*$2„“­ŸŸ–•‹_3<7%""'/Xq~Œ—Œ”‰”œ  šž™šš˜™–›™˜”‘™–“™›–••”˜™š—•–™˜•”š’‘•“–“•‘”¢‘”’‰ŠŽ…†‚€…„‹œ¦°¹ÁÁÅÈÄÅ¿ÃÃÃÁÁÄÇÈËËÍÏÐÐÏÐÏÏÍÎÍÌËÌÌÌÌÎÏÏÏÏÑÐÏÎÍÎÏVVUUQTPPPQPMKJG@A??965/.+'.@Pfy†Ž–› ¥§«¬¬­®°°°°¯²³±³²²¬¨¤œ™“‹~zeXOKBJS_q‡‹ŠƒijcknkkquwngOCJ=?\^HRxt‚nBP]]JARI/8x]M2&7TnŒb>I”šU20PˆF+219HL64.+&79$ #58AOh¡“Ÿi@5@PYgqe?3*/)'!'$&1' !*x©¡¦¤™–’€uw‚¡«½±‘e1$$$(&2'#'(%,]qcYCEJL\Zimotx{€x}‚€…ƒˆ‡‰Œ‹’“•——–™•˜¡›ŸœŸŸŸŸŸ¢ŸžŸ¡žš•’’‹Œ~xhpv}††Ž‰ŒŒŽŠ‚|y|~‚‹“¬³½ÈÔÞâÜÔ¿‘Ž“–•’“ŠŒˆ†€‚z|zr[?.$))&&0-308?<@JHIM;/9*""3)7v”­£ –‘’‡kA22#"'$.[u~Ž’““‘‰’¢  œž›¢˜—˜•™–™•’™••”•––˜“”””•“˜”’‘””•‘’‘‘‘ŽŽˆŠ†ˆ‚‚…†‘¡¦³¼ÂÃÄÆÅÅÅÃÁÃÃÂÿÃÄÆÉÌÎÏÏÑÏÏÑÏÍÐÍÍÍËÎÏÌÎÑÏÐÐÏÎÏÐÏÏÍÎTTXVUOPOQIKMKIHKIG?A=;,1)(4DTiw~…‘“š¤¦§°±¯°°¯¯±¯±´±³³³®©© ›—ˆtkZTMV`nŠ„te`iikhsvxusq]DOFH;[ZTnyuwULZOD=HCR0F‚ƒQK.,2Mt‹cH@f‘š•`25;f.2?JGD1/(-:I=#%))0:G@kRO<+)5.5.%)804r’¦¥Ÿ—“–~oP3+##&4T‚ˆ“‘“•Œš¡ ŸœŸ››ž˜–˜›™—•––“–•–˜•˜–•–”–‘“’’š””“•—”–‘‘’Ž‘Ž‘‡ˆ‹‰„~†™¤¬¸¿ÂÆÆÄÂÄÃÄÁÄÀÂÃÂÆÇÉÉÌÏÍÐÏÎÎÐÏÏÐÍÍÌÌËÌËÏÏÏÏÑÏÏÏÑÐÐÍÏXXVSSMMWPJKQKHHADBB@?>-,++:MXiu„–š¡§§«¬®«­®­¬®±¯±³µµ¯®°¢œœ‡wqb[Ymyog_^bdeglquxzwjXEL=‹ŒB1-9?7+0+2;PC* !(*6J78//,((*2?i‚rpG-'$$'".* b¨ª¨¦¯©¬§±µµ¸½­ŒwO7)$&&',)11/&'2Xi[V>:GUZ`entsv}|ƒ}„€ƒ€…†ƒ‹Ž‰—˜–™“—•——”›œœ š—œ¡ŸŸžžœ›š›–‘’‹”€tlt|}‡Š‡†‡†„†‰„‹„~wwvz…‘” ¬ºÄÊÎÔÒ˧“”‘”‘‘’ŒˆŠ€€~~xoYD1)**,))69325@=HR=FP=-20)&4(*g¥¤¨ “xrP2.+%%%>]‘“”“Ž”ž¡žŸœž›ššš™š˜™šš—”™—˜˜––”–š˜•”–˜••‘•–˜“”–“‘Ž”“ŠŠ‹‹†Š…€ƒ„¡ª±ºÀÃÇÃÂÄÂÃÃÀÀÀ¿ÂÃÉÉËÍÊÍÎÎÍÏÏÑÎÎÎÎÍÏÍÍÌÍÏÏÏÑÒÐÏÒÑÐÐÐÎZZQOSMP\RMSRGHMIBDA<>?;1-,:KXe{†•—Ÿ¤ª¨­¬¯¬¯®«¬®­´¯²²°¬§£˜šˆ€}nbei`gd\]Z]_^aedekox}v{dWSJ25J]cibhzkjXLAK/%3Ql…ZS=B.*6a~mRIUvŸ­„C75~¦_1).4,.0.3:_H% '++:LA?9+(%*3CKqbOG3))''&&,) !%Œ®¥§§´´©°°´¹´¶´™{L-)& """0-+&()%4`od\FMLU\]fmtoyz}€|}…}ƒƒ‚ˆ†ŒŠ‘’••–—•š˜•—•—™œœŸ˜žžž Ÿ ›ž—–”ŠŠ„qlq‰‡……ƒwpu~€‚„~zzyy„•§±ÁÈÍÌͺ™’—’——’“‹‰‹„‚|yvhI1,*(,,--05236;:HG:=L=(06*#1*,WŠ¢©©¡Œ‹„vV)$/"!)Be”–‘ŽŒ•  ¡ž›˜———™——””•š•—›˜—•š™˜—™”––’’‘”—•““•—’Ž’ŒŒŽ‰„„…‚…”£­µ¼¾ÂÆÆÅÄÂÂÀÂÀÃÃÅÅÉÉÌËËÍÎÍÌÍÎÏÎÍÍÏÐÏÏÍÏÐÑÎÏÐÓÑÏÎÏÏÎÎÍWW[PPOTLQONKMPNED?BB;98631;O\jw„ŽŽ–™¡§¨¨©¬­ª«®¬°°¯³³´²±ª¦£™—ŒymihZSKOPXR[Z__fbdimvu}\]PHB?MWe__nweRLD@"$8X’˜naQ=R5.3W‚n^WVs µš\@7m£s8*21-3M<93\M' $'3,8?J=3+/3T‰sD(&$'+%+,*% 7¢´¬¯­¿³³¸½¹³¯§¡[<5'%!""&)-//%')%.^nX[GPLV]bejwsyw}|z}‚€~‚„‡ŠŒ‹Š‘•›”’š”—šœ•˜™™Ÿœžœžœž™Ÿœ–’”ŠŠ‡€tx‡„…„ŠxV:89IYfrsw~y{y~ƒƒŸ°¼ÄÉÌ¿¥š”–“‘“’”‰‹…€~~{r]:3(,&//--7;83>CAML7@N<0040$*(&X›«§ ‹‹{`1(3(,/Um‹‘•’—ž¡ žœš˜š›š—œ—””“”——––——–˜™––”•Ž“““š’“‘‘‘‹’Š‹Ž‰Š‡ƒ}ˆ™¦®¶¾ÁÃÆÄÅÄÄÁÃÅÂÃÃÅÉÈÍÎÍÍÎÏÍËÏÍÍÍÎÍÏÑÏÎÏÏÑÑÒÐÑÐÒÑÎÑÏÐÏÍMMSPQNNSSIQHHMJFDBC;DA9:/5@Tbo}ƒ‹’–˜ž¤¦ªª«­²¯®±­°±°´³±±°«¥œ–Œƒ}qiaRDOLOTV^Z`bjihkkotrj]MNTK@UeYQfz’}cVPO5&$6g¥‡]X;@^>+9Ryl]cXl”¬©k4.Q~;).116HMB=O=%##(!!)/;OB05g°ª~4#%"&+*.,,&%"!X­±­³ºÄ´·½¼¾·®¢t0)*#!&&%%&,8.*.++-Wjb_KIQ`^`bkpquyxzz{€‚€‚‚†Š‰ˆˆ‹ŠŽš––“™™–›œ˜•šœššœ ŸžŸŸž Ÿ¡˜“”‘Š‚wy„†ˆƒeA212@MY`Zcquz~y{ŽŸ¨¹¿ÈÇ­Ÿž–•–”˜•“’‹…‚€{vjK1+(.2.-(09654987=CWgu†Ž–˜š £¥¨«®¬­¬¬¯¯¯°³²¶³­©¨¦Ÿ–‘ŠqeYJKINNW]][]aggjgpnqokO' 1;}pR?3MoB-IGvn\cYs‡Ÿ¯{A5I“…>$+7':CeY3G<.$##%!#'-0H_MBc±¤v=).**-+12+" "/¤¦ª±´Å·¾¿Á¾¼®e4#!((*%%&+*424/,''.ZmpiGOU\bdfintsy|y€}}ƒ‚€…‡‡ˆ‹Œ‹“““Ž”“™—––•˜—””˜œŸ žŸ›žœžœŸ¢––˜•”‹…{uz„ƒ„iWF;GQa]\WUY]rvv|~‰•¡´¼Æ½ª¡¥¡”•’“ŠŽŒ‹‡‡|w`9-1/0,.+.-94/4;CFK@@IR932045*&$>{”­­ž|}˜~`6#(@1BdzŽ””””ŽŽ”›žœœœ™™š•›•˜—“˜—–••“˜–’˜—–——–“–’–“”‘’‘’’’“Ž‹ŠŠ…„…‡‡”œ©¶¼¿ÂÇÆÄÆÄÅÄÃÅÆÄÆÉÊÍÍÍÎÍÏÏÎÌÎÎÏÐÑÐÏÒÒÑÑÐÑÑÒÑÓÑÓÓÒÏÐÎÎÍNNUJPIPMLQJOQNIJGAD>@GF=<@LYhx}‹’•™žž¦¨¨®­±°¯­¯±¬°°²³¯°­ª§Ÿ–‘‹„|oaTLHDNSQTZ[b`cbgipmookTIb`N=]^^Tn~{fYNH+#'/g”hA5GFS:6ET>1/-8<%$!;u—ª¬Ÿƒ}›„^=*'7HJp‘”•‘“‘š¢›Ÿœ››š—š•™–”–—˜•–•“—””—š˜—––“’•“•‘‘‘’•‘“Œ‘ŒŠ†ˆ†„†•¢­¹½ÁÄÄÄÅÄÃÃÆÃÅÄÇÆËÍÎÐÎÎÏÎÐÍÏÍÏÑÐÓÑÏÒÓÔÒÒÒÑÒÑÑÓÒÑÏÏÍÏÍÔOOURQNNNNMPOMNJGAEKHEE?BBER[my‹“˜››¥¤©¨©®¯¯ª¬­¬¯³°µ²²±°«¦¢™ŽŒ„{lYWNKMSUT`\ZaegfolonstmNJfdIA_\URNOmZHPHW‰qmA4HjnS20KtxddXyyv¥›g=D‹ _! ,##-217Xdv_11(*(# "(1YgT6,)4??83-$-.,;Fi‰“™¡­­±¶¾À¹®)%&'$*/+,4.,./2(1,10`nmdMNPcefluwquv}}x~€ƒ‚ƒ……Šˆ†ŠŽ‘“Œ•—•—•–—šœ™šœš›Ÿž œž¢›—˜‘””{tx}ƒ€|~ƒ}wongbmyxz~†›±»µ±«¦¢œ˜””ŒŽ‘…€‚„sb@0/1178+(-*B23<9FHU<9CMF0-.7A()"2e”¥«žŽ}˜ŒkH0")NWt†””“•—“”“Ÿž›¡›™š™˜˜–“—•—”˜””—•–•˜–•’‘““•““’‘’“‘ŽŒ“‹‹ŠŽ‘Š…†„„›£®·ÀÃÃÆÄÃÄÄÅÆÀÅÆÇÇÌÏÎÐÏÏÐÏÏÑÐÐÎÎÑÐÍÑÒÒÖÒÒÑÒÔÒÑÒÒÏÏÐÍÏÎÐNNWPOMNPOMOOKFFIJEDFHCDGBDS`o}ƒŒ•˜œ¡¦¨©­­­®«ª±²±±µ±³µ°­§£š’†yl]VKHFPTY\a`gaeiknoxyyqSW`UB=cZROBPbP;=1-'F‚ŒvbUM;VacP=2=x€nbRpusœ¨xFOp¥k"!'*2)/m’š{C0,(%!$ "+W‰zU2)& 2B31N=;USL^dpp{‹”–”™Ÿ¨¤®ž_7'& #(.8<,1/+*+1&//*1ctshRJP^flhtoquw€~{{|€‚‚ˆˆŠ‰Š‹Ž•“’”“••“‘‡––“–š—–œ˜›žœ¡Ÿžš žšœ•””•’‰‚~{z~|€‚„‡„††…„~wwvtpxv~ˆš¬¾¼³®¨¤Ÿš›—˜’‘Œˆ‰ˆ„„‡vmZ403-0831+*0@75@9JMUB@IMC2+,78+%#-^¦¯Ÿ’z‘[S+&.Od{Ž’‘•“Ž”— Ÿžžœœšš™œ–’™™—™™”——˜••™–•”›•’–—“–’“–“‘“‘‘‘‰‡†Ž‰€…‘Ÿ©±¸ÀÁÅÄÆÃÅÄÃÅÂÈÉÈÉÌÐÑÏÎÍÑÑÐÐÏÏÐÐÐÎÐÓÑÒÔÒÑÒÑÑÒÑÑÐÏÏÏÎÎÐÐNNQOJHRPNHJEJHLGDBABCJCMLKVfp}„Ž‘˜š £¥¦¨«ª¨­¬®­­®®°²¶¶´®©£ž•„zodWOIKPOT]V]bddhenz~rqeXbS:9>U]WV>NVE4+#+Kq‰ujND]HYWRJC5Du„iKFe{q€ªYX{•2!',76'0o™§ŒLP5$&#$2p|mM,/#"J[DMei^em`o~mmz„„z‡›µ´·c1'##$&*;RKKFE,,--'3;4,Wqyh]SQ\aikpwvtv~~~{~ˆ…€††‡†Œ‡”’‘‘˜’””‘•”“˜œš“—˜œžŸ£˜›žžš—”–˜““†††‚}zz€‚‚‡„††‚|twvz€‰‘©´º¿»´¬¨¢ œœ””—Œ‹‰ˆ„††xi?/,/4.94,/3-=3;98N^NA9PRD2-,;1('$+OŽ¦¯ŸŽ{‘”eY;''Pp”•••‘”› žžžœ˜™šœ™–”’–•˜•”•””–”–•–š›–—“”‘Ž““”‘ŽŒ“ŒŠˆ†ƒ„Š“žª¶½ÀÂÅÃÄÄÃÅÄÆÄÇÉÉËÌÐÐÒÐÎÐÎÏÑÎÎÏÎÐÒÐÑÔÔÔÒÑÑÏÒÓÏÕÐÏÐÏÏÐÐÑOOTRTLRMQHKNONLGA@?FGKGJNRZfu’˜› £¤¥¨¨««©¦««¬¯¯¯·µµµ¯ª¦Ÿ–’…{m^TLGGRSW[]^c]cekvzyuwgZQ.55>UaXVBLFB1%$7h‡ziH?>\UUDOGX=>j|`XTc„qc¡oc~…†O# *=6*/rµšwq/&Wy^F^O(#(Jb`diuosv‡—”ajtklos„»ÏÏ-)%,#)*2:CNZ451*'0#*+/5c}uccORYipqoquxxz}z‚„‚†…‡‹Œ†Œ’‘‘Ž”““”“•š”–ž˜š— œŸžŸŸžŸœ˜—‘•”•‰Žˆ}€€‚€…‡ˆvyŽœ­¶¾ÀÀ¾¼·²¨¦¡šš›–’’‘ŠŠ†‡€„xvU6,/-+20*2-/1;37<JE@6--<-+.",I‡£±¢Œ|ŒŒbb7+(Sy‚“”‘—œ Ÿžšžœ™™–š™—›––š––”••˜•—”––“‘””“—“”‘”‘Ž‹ŒŽŒ‰……„„ˆ…™£®¸¿ÂÄÄÅÃÃÂÄÅÄÅÊÊÌÌÍÏÑÐÐÎÎÎÐÐÐÎÎÐÐÐÑÐÓÑÓÔÒÑÒÑÑÏÐÏÌÐÏÌÐÑÓJJOORNSKKGTNTLJMEC@EHLLKSRYhz}‹Ž•š›¥¢£©ª¨ª«©©ª«­±±°±´´°®©¥œ–Ž„xp`ROLIMTVZ^[b``eiuwpsvlaD+)'2NaXZHM<<0%4\y_H20@Hc]CGQjCHnoaVVw„jT…§zb…ƒŒc1#$,>.*0i’¥ª }79xa56UF03EZ]lmhw~‘­¬rdufclrƒ¢Ó×ÀR%&*'$&)-18=A4010/1'%)&.gvy^dKU[gjstsuvt{y}~}€‚|ƒ†‰†‰‰‡‰Ž“Ž‘‘’“”—˜“”›™™ššžš–™žžŸ¢œ˜œ™š—œ•’”“Œ†ƒ‹‚ƒ…‡–„†‘ «¼ÅÇÃÀ½¹®ª¥£”—–“’‘ŽŒ…‡†~xl>4/1//41+.,24>7:?;SXMOKSDG:61B*1+"%?…ž«§xƒUc=/0W}‹“‘“”“‘™ žžšŸšš˜™”™™–˜››•”””—’“’–“”–›”””““•Ž‘Ž“‘‘Ž‘ŽŠŒˆ‰…ˆ‚}Š˜£®ºÀÂÅÄÂÅÇÄÆÅÅÇÊÌÌÌÏÐÑÑÍÎÏÎÐÑÍÍÏÐÐÑÐÓÑÑÐÒÒÑÑØÏÐÐÏÍÐÑÐÑÒÓQQQQNHHNIGMQOMKJCGFICGHMTU]lx‹‘•›š ¥¢©©¦ª©ª¨¨­­®±°°²µ²²¬£š”Š„xl^VSKHRRWW[[d^_ekotrr{tG)-$+PVQMEE=9-.Y…ƒc@9/2>GTV>=\yP[~sd]czzfJgœŠe†ˆy6)$&28,0W€œ“ƒ9)!#)Xb6(;;JSSdcbfnt›¦¶´Š`dj^eu}ŽÀÔËw0)*).+/*223-FA446132)*-1dwyWfNW[`nmsszyy|}|~z„~}ƒŠ‰…ˆ‹‘•‘’•””•–Ÿš™œœ™››ž Ÿ›¡œžšœžš˜–“–‘Š†‡…ˆ—˜¦¤–“”­ÁÆÇÄÿµ´¬©¢™——––ŽŽ‹‡†ƒvV1210.)0403*03<;>/5MJbkdprmowŒ™°±ºž[cp_jw}Š«ÏÔ¡:2.-48652:9>@>:839451/118`w^gQT\emmruxyyy{}|}{x}‚†‚‚†…†ŽŠŒŠ“ŽŽŽ‘‘•Ž”˜š›ššœšŸžž¢›žžœ›› ––˜–––•ŠŠ‹‘¤²¶¥š–£°½ÈÅÂÿ¹´­¤žœ˜–•ŽŒŠ…„ƒ†€tI62503*//+216+8A?8B]bD>P\M<70>L)/.&"6p‘¦¬–m†T`J:Jdƒ““’’’œ ›š—š–™›šš—–›–™›˜””–—–••“““˜–’“‘’‘’‘”•‘’”‘‘‹†„‰‚„‡›ªµ»¿ÃÃÄÅÂÃÂÄÄÆÉËÍÍÏÐÒÏÐÏÐÐÏÍÎÍÎÑÏÐÐÒÑÒÓÒÑÑÑÒÒÑÐÏÒÒÒÒÒÒÒÔRRSVPPPSSPRTPNMIGFHCAAFMT^ck{€‹—˜žž¡£¤«¨¦©¨ª­­¬±°°²³²³µ°®¥ š˜Šˆ€pbVNJOPRTW\Z\_bfigpx…•š‡Q7*,0IWSG>OHJFx“pXD85,.>GMML?R[\kqcgsl}nWBP–škp“…qH.)/@46Kj‡{dI-;%/DG4#!+6W|~vpy‡ Ÿ¯¾²eXojct‡‰¤ÂкK/.0004411-543A686622/,,04\ss_iUTdaiqpvw{}€z€|„‚„‹‹‰‹‰‘Ž“”‘“˜™›—ž™œžž¡¤Ÿœž›š˜š™™–“‘–‘‘””™¥³º¿±¡˜¤±¼ÈÉÁ½·±¬¢ž–““‘Ž‰…„‚}x`;14451/1.*+-14BI;7?c^J;GYD9A6AB-6)("1h‘¡³˜o‹†Q^T?\kƒ““‘‘”‘–Ÿ œžž˜š™›œ”•—›—™“‘•‘–”˜”•’™—‘–’”•“‘“”’ŽŠ‹ŽŒ…„‡‚‡„˜£©³¼ÀÃÅÃÃÂÄÄÅÈÆÈÌÍÍÐÏÑÏÑÑÐÏÎÌÍÏÍÐÏÓÑÑÏÑÓÒÑÒÓÓÒÒÓÒÐÓÒÐÓÖÔÔRRNMKGFLQSSKNDHKEHB;>@FMWbcn{€Š•’œœ ¢£¦§©ª«ª©¬®±°µ²µµ¶°®®¦ š”Š‰}lcUPJNLUW]b`baakhnv‡Ÿ“rV?15:Lc\MFSPan“~\=<5255AJJVNEFM\gohZrn~viJJ k]‚–YK>@?MLGljopD8C7738:4=?864,.2'-,2Zop]nVV`djptvx{x}‚z€€~‚€„ƒ„ˆ‹‰ŠŽŠŒ“‘‘“—–›——™™™ššœ›Ÿœ œš–”š˜™—–”–—’’‘‘•ž¡¬ºÂÅ»¨¡§µ¼ËÇÁÂÀÀ¸²¨¢ž™’““‰‡‡Š‚uB120453/615/344DH=5E_]IAFXE??9F?5<,(#/XŒ ´š|ŽŠQY\Dgt‹’“’‘”’Ÿœ›Ÿ››œ™–š•—”“˜——™•”“”••––“–™““–‘““’–•“‘‘ŽŒŠ‹†„„…‰š¡­¶¾ÂÃÇÃÄÂÅÄÄÈÊÌËÏÒÏÏÒÏÏÏÍÐÍÎÍÎÏÎÏÑÑÐÏÑÑÑÑÑÓÒÒÑÒÔÑÐÓÕÓÑÒÔNNRMDGHOMINQKJIIFDC9<CBLABB<::/9::\rtgpb]ckkorx{€}‚…„ƒƒ†…ˆˆŠŠ‘Š‹ŠŒŒ‹ŽŒ•™™šššœ™™›˜˜›ŸžœŸ››˜——š˜•—•’”“‘ŽŽ•˜Ÿ£±¿ÉÈÀ°¥¬²¾ÈÆÄÀÅÅÀ°¨ š‘“’”ˆˆ‹Š„{\7/0102023///.49SG;5R`V@;FLH::>A73:,..0N…Ÿ®œ‚ŒY\dMp{‹‘™‘Œ–“•žž£›™™Ÿ›™›ž™”——˜’•™—–””–—–“–˜‘–“‘“”‘’—‘““’”’‘‘ŒŠ‹‹‹‹…‚†Œ—£°·¾ÃÃÄÃÂÂÅÆÈÉËÍÎÐÓÐÏÑÐÏÎÎÎÍÍÎÎÍÏÐÑÒÑÐÑÑÑÐÑÓÓÒÒÒÖÔÑÓÖÒÓÓÔLLLJEFHKJKGJNKKJEA?;==BISUes€‡Š•—› ¡££©¨¨ªª®¬¬«¬¯±³³³µ°¯©¨ž›“Ž‚|maXNNMLRXWY\^b_aj‚‘›ŽrlfV@2;=LX@Bbuƒ~rb479,-1/08KFBKLG2.>B+%$4J{¦«‰ŒŸ¤ ¬§¯¼°ˆS\jYZbeŠÃÇ‘7,1&,2(41.13.-171A=<;.2/,+(&JponffTallqqpvzy‚z}~}~y~ƒ„…‚…Œ‰‰‘‰Ž‹ˆŠŒŽŒ‘”–—™˜——›š–”˜™œ›œ›——”’š˜•“’”””‘”—–œ©¶ÆÍÊÁ·©©³ÁÉÇÅÃÅÅ¿®§£š—•‘—’‰‰Š‰~uB6.6213-,0+-0.28LD;8R[TH;?WipaVOKSJ+$$7G3(/@T•¶ª’‘¦¦®µ´À¼¬_XbZX_av Èª?($$)41-,,154028<=L@=C:32,00-KwinaiQ^aisrst}z|‚}€€ƒ‚„‚ˆ…‹‰‰ŠŒŒŠ‹Œ‘Œ’”˜š——™——š”—œ––—™˜™”””“•˜•’”“——˜šž¤«¸ÊÎÍÇ»±«±ÄÌËÉÅƺ«¨¡™˜“Š”‹‰ˆ…‡ˆxg5.*2142-110+0-1?EC79XYUFUOXH<@XH5GC;/3/"(#,;s’¨¢~bJknuƒ“”‘•“˜Ÿž››š››š—š™–“—“—”•’”“Ž“™—•–“’”Œ’”Ž“’Œ’•’•‘ŽŽŽŒŒ‹‡‡ƒ…‚‘Ÿ§³½ÀÃÃÄÄÃÅÇÈÌÌÐÑÐÐÐÏÐÑÍÎÍÎÏÏÏÑÐÏÎÑÑÐÏÎÐÑÒÒÓÔÓÔÏÓÒÓÓÒÔÒÒÔÕHHLKFHJLKFCIJJD?=AD>B@ELT[ds}…ŒŽ›š¢§¤¦¥«¬©ª©ª­±¯¯´µ³´¶¯¬¨ ›”‹Šzoc\HCMKMSVR\Z_i„——rkp|x`>6DB8RTgy†|M%++-[d5/ND><1-6/'&*Fleh\wX[ceopqrvy}{~€‚„‚‚€ˆ‡‹ˆ‰‰ŽˆŽŒˆŒ’ŒŽ“”‘–””™—•““™˜™˜™ š™““’–——”–™–š™¥¥°ÂÒÏÎÌÁµ¬°¿ÍÌÊž¹®©¡™’”Ž‰Š…}h7.../-.02/4--*06AHB9JPZQHB@PC9BE9511*,$/>p¢£}w‹fNo{w†’’”“—› š˜™—˜žš›—––™”–‘•–•–’“—”•––”—““’Ž‘—‹’–ŠŒŒˆ‡ˆ}…„‘ž©¶½ÂÄÃÆÄÄÄÈÊËÐÏÑÔÓÏÐÐÐÑÎÎÐÑÑÐÐÐÏÐÒÑÎÐÎÒÏÑÒÕÓÓÔÓÒÑÑÔÐÒÔÓÓÔIIFIHIGCGGC@CDECB=F=CBGNOXbq}ƒŒ‘–˜œŸ££¤¨«©«ª®¬¯®¬¯±³³´²°©¤¢™–Šƒyp_TOFHNMU_UWWfx’togw„ve;CCIB;7]SA>EMFHARyq;2LXt†€o‚||‰e7j™S/8,(,?K24DWfmejt~—¢¦¯¸ÃÀ±e][VYZ_ršÂ•:*&*-84/6D82.353,4=8JA=B-.40,)*Acdg_{YQ^ivnmwwx}~‚€‡ƒ‚„ƒ‹‡†‰‹ŒŒ‹ˆ‰‹’ŠŠŽ‹ŽŽ–”“••”••—’’—œœ“”—–”‘–”•››™›š¤«°ÄÔÓÎÍű§®·ÇÌÍÃÀ¿¼¯¥œ”’“Œ‹†Œ‰„~N/.7-1.,8/-72/,3>HMPKU_px|ˆŽ•››Ÿ£¥¦§©«­¬ª¬¯°¯®­³³±µ±¬¦£—”ƒzo`VJHDPPRRR]]xŠ“qplk{†v_4=B@Womp|~h6)0:;5(,)$*7604877+2;02/A5DLMB67/.0+'Biad`zdJ\bimuuu||~z‚„~€…††Š‹ˆ‰‹‹ˆŒŠ‹‡ˆ‹‹Ž‘‘“••’‘’’–˜™‘•””’’“——˜–š›› ¡§ª®ÄÏÑÍÌÀ­ª±ºÉÎËÍÄ»½²¥œŒ‘ŽŠ‰Ž„ƒp>4-.+2.0210.+5843>A>GKPQQMDKJ8/E96?23*+()?pŠ­Œt’hIt„ƒ‰Ž’•“šœš˜šŸžšš˜•™˜œ˜œ••••–œ””“”“””””’“‘”“’‘’”“‘’ŽŠŽŠ†‡‚ƒ„†–¢®·¿ÁÅÃÄÆÇÈÊÎÍÒÎÑÒÐÌÒÏÏÐÎÐÏÑÑÐÑÏÏÏÒÏÏÐÎÑÒÒÔÕÔÒÓÓÓÑÒÓÓÕÔÓÓÔMMJDFJ@HFDHFDCCEA<>>BCNNQS]pw}„•˜Ÿ£¥¦©«©§ª­«®®³°°±¶²³´«¥ œ”“„{sbTHEENSWUY]nˆ›fgfn†€wX4ELGFF=jffZqeS\bgjsov‚}|ƒƒ{ƒ}‚~ƒ…ˆ‰‰ˆˆ‡ŒŽ’‹ŽŒŒˆ‰Š‹ŽŠŠŽŠ’Ž’’’’“‘•“Ž’’•™”“–›—››ž ¬±ÄÏËÑϾ±±¸ÉÓÓÐÌÉÀ¾´¤™Ž‰‘‹Œ‹‹‚M5)-./.,:8321--2C7?<;CHPLNFBID99C9;:,0*'''7n€­p’uEq„Œ‹Ž“’œ›œ¢šœ™ –›Ÿ–•™š—“••”––’•“”••”—“‘‘•‘‘“”‘‘‘Ž‘‘‹Ž‰‹†‚ƒ„ƒ…™£®¹¾ÃÆÄÅÄÇÊÌÍÎÒÑÑÑÐÐÏÐÐÐÏÏÑÑÓÑÏÑÎÎÐÑÐÐÑÕÒÓÔÖÔÓÕÔÔÒÒÓÓÓÔÔÔÔCCFADB?KBHGFCHEA=?A=GHDJN[^h|€ˆ’”œž¢¥¨¨«¬¬¬°­®°°°±¹¶³³±¯¦¦š•ƒ~mbSEEGMJSQXk–ˆlkhfo|uV4LVZJFOxhbE-76<08FF?;EPFDGFT_^c:.0>Ru””wq|“;')1Gh|„‹~qmitƒ‹§¦¨¸ÅÁ©VZrVXcfv§¾r*&($&(7MQA410/(+80724:GHHGA0.2&,(5eg_]o_LQ[agxptyyy}…{‚‚‚‰ƒ‡…ŒŠŒŒ‰‹Š‰ˆˆˆ‹Œ‘Ž‹Ž‘‘‘‘”’Œ’•Ž‘’Ž‘‘“•›™›ž¤¥³¶ÀÊÍÕÑËÄÂÅÍÔÊÁÁÀ¿¿µ¨•Ž‰ŠŠ‹‰Š‹ˆ{=,)/+.4-9D424,.074=@FLJQLVCALLABB?G900,&'&/k{œ«uŽ}Kt‚ˆˆŽŽ“—’•›œœ—š˜œšœ—˜˜—š“”‘‘“‘““”’”–—““””š“”’’’‘”‘’Ž‹‹Ž‰ˆŒ‰„„}‹—£¯·¾ÄÄÅÆÈËËÏÎÑÑÑÑÐÒÐÏÏÏÐÏÒÑÒÑÏÒÏÎÏÍÐÐÐÒÔÔÔÔÔÔÔÕÔÕÓÓÔÓÔÖÔÓÔJJA<;??F?EAHEIJBCC@?EFCGOT\i{ƒ‡•œœž¤§§¨§®©¯®­­²±²³·¶´³®®¨£™•…}shQJGHJORU`~’‹madgep„wkT;JXD49T|hVD*7<54IQB9?>SE<@QaNJ\KNB;GIMSQUq^?-3;X‚›†nzŽœ†['%#2Vl‚‡‘££”Œˆ~Š¤··¶ÂÄ´iZlfZckxŽ¾›9(1+,&*@UcF7:34+,?/3+54BBSQH12),*(8`Zb^od\ZZdgwpqwy}ƒ…‚‚……ˆ‰ŠŒˆ‰‡ŒŠ‹‹ˆŠ‰‡‹‰ŽŽ‘ŒŒŽ“ŠŒŠ‰Œ“‘ŽŒ”–›™Ÿ¡¢¡¥§©®³¹½¼ÊÔÐ˾º¯°®­¸¶¶¦‰†„‡ˆ‰Žˆ{X>/*0(,.56K41//2973>EEHKSOREAJLEKF;G>0-$$'&*^{š®›x†~N}„†’“Œ˜œœ˜›š›˜—™”™”———”‘”•‘•–š“–”’”““•“Œ“”•‘‘‹ŠŠˆ‡‚…}€‡–§±º¾ÂÇÄÈÊËÌÌÐÐÑ×ÔÏÑÐÐÍÎÐÐÑÑÓÑÒÐÑÐÑÐÑÑÓÒÓÓÓ×ÓÕÕÔÔÓÓÕÏÓÖÓÔÓÕGGBB>@?DIFSV^hvˆ“™›œ  ¨¨«®¬­¯ª¯±°­¶µ²µµ²°­© ™–‹ƒ|neSEGJFLNXt˜o^`ddip{wkJ9GC5'4kxhX:27C2?MHB>9<\J?TQkgJ^]SRHKKRNHL\qT883K`wysw‡”Œk3*+*(Cbxˆ†š¢·½´®—«¿È¿ÂÄ·wP^qW\ltŠ¶´E-0.(&**B_kL2030'*:5765ADDVOM/*,.**;[jWWfgTN\^aorsyv}|}ƒ‚€‚‚‚ƒˆ‘‡†Š‰‰ŒŽ‹ˆ†Š‡Š‰‹’Œˆ„ˆŒŠ’ŒŒŠŒ‘“Ž‘‘™šŸ™œ›–––  ž£­¹À´©¥ œ™ž¤«¬‹}~€…†‹‰„z>0.+0/+2569//01/826EF>HIUPZHBGXRCA;JE//$(&%)T›§¡u}„]}ˆ‹’”˜˜š œœš›™š››•–›˜—›•“”‘”••™˜™””””˜–”’Œ‘’“’“‘Ž’‹‹‹ŠŽ‰‹€‚ƒƒ‹™¦°¸»ÃÆÆÈÊÊÍÍÑÒÓÓÓÐÒÐÐÐÐÐÓÑÑÐÐÓÑÒÐÏÐÓÓÑÑÓÑÕÙÖÕÕ×ÔÓÔÑÕÓÕÔÒÑÔFF=;;?>GC<87ME@?AbvVS`_UVMPPPF@HmtSA;:BUXWm„‹ƒ^+'Ssbel„¤°ÆÊŽ¿ÏʿƳW_m[R]r€ªÅu*((-%&**@_qR5+-3**;5586>>GHGD4.5,'+9TgOXib[HV_dlqsz}|{„ƒ„~†„ƒ…ˆ„‰‡ŠŒ‹Ž†Š‰ˆŒŽ‹‹‡‡ˆ‡‚‚‚…‡‰‰Ž’‹‘’“•’““‘Ž‰ˆŒ†‰‰”‘’˜Ÿ¢œ™™“‘•šš‘~u{~‡ŽŒ‹ƒY012+3105:3612435:3>@JE;?TLZHDFQPCA;FH7-&&%%.B~œ£ sw†c~‰–‘‘“‘–žœš™™˜˜˜›––š“—•””•‘‘“”—™““’•˜••‘’“•’‘ŒŒŒŠ‹‡‡ˆ„}Œœ¤®¾ÀÂÅÆÊÌÌÍÐÑÓÓÒÑÏÒÏÐÍÏÑÑÒÒÒÒÒÑÒÏÐÑÒÒÓÔÒÓÔÕÓÔÖÖÓÕÕÒÓÕÓÕÔÓÕFF=><;9CA=EB@FCDFC:9?AMOIRYn}€Š’—œž¥¤¥¨©¬¬­¬­°¬°­±´·¶¶²±¬©¡œ–~yn`OPEEIP[v“ˆl_[\acitŽ‡mE5/*(0Wl^j<01B8:?DC8937@FC@_`Sahg_VUXJPDB[wmK429J`[fƒ‚}ˆ~U4*:p†g]o„£±ÅÊÏÎÌÒÈÄ»ŒT\igZ[d|™Ç‘/%&(&*-'7KbI,+,5,'48585DJQFHL7//-*,=`pOXd]THTX^jqps{{~€„‚„ƒ€€„ƒ…ˆ…‡‡ˆ‹‡Ž‹ŠŒ‹‰‹Ž‹ƒ…€~~‚ƒ„…ƒ‰Žˆ‡‹ŒŠˆ‹Š‡‚†‡‡€†‚|‹Š‰–›’Ž‹‡ˆ‡ˆŒ‚qfhvƒ‰Ž‹ˆx:0-3*.2+131/804618.9GKD>FUGXLIPZBA>7>DHBH@@:<;BHKOU[hz„‘š›¢§¤§«©«¯®ª°±¯°²´µ·¶°³²ªªŸš–…zn^TIGBPSlŽo[ZY^gjr‚‘ˆeC34.)2^S2jkM45H>AABC3;;4999;AQOC96217?Ii„}eadidjcPPPI@>H]{oWHbpXQ\wyaUWt‰”¯«vv‹§¾½ÅÖÍÏÊÁ©eVjugZak„°Æ|-)/0+-4/-&%=QN0&*12/.12<>D4GBJSF,+,*/2VzERWkNMJYaclowuxy‚†‚‰…{}ƒ|„‚ƒ……„‡ŠŠŒ“‘Œ’”‡u^FGOYemorzy|}xywu{upsnqrokkjqoopt~|}Šƒ‰rXMCW^ainidls€‰’”ŽŠ|D-.1-+/.576-1/2-3:19>II3=GU=O?ISR@H439EC3.!'()7f“  l•|ƒŽ•Ž‘‘˜•‘™šœœ›œšœ”–œ˜˜™•›˜•–“˜”“›’”–•’‘–”•–“”ŽŽ’’‘Ž’’Œ‘‘Œˆˆ…€„‘ªµ¾¿ÇÊÌÎÎÑÑÔÔÓÓÒÔÑÐÒÐÓÒÒÑÏÎÏÐÔÏÒÑÑÓÓÔÔÓÔÔÔÕÔÖÕÖÕÕÓÖÓÓÓÕÕÙÕ9997:@>12=6Mn{gnl\gif[LMN?>MXzxcy{O:Gas`J:_‰˜š}sŠª·ÁºÅÐÑÑÀ´zM`olb]d¥Ê®<$'012292&$,6JN=0),5,*2.:9A1DBLOK,*''-6Tp>KXlWMESYfkpvvyx€‚…†ƒ~~~ƒ‚‚€ˆ‰ˆŠ‹‹‹ŒŽ’Ž‘‘‚r\WTVMIHMU\ahhkkkjqosga_]_Z[TQX[\dgpvvx}ztc]ZT[bcntpps}Œ‹‘“‹‰a5*60-%1.5=3.531.6<6:FKN7HOS>LEQTRG@-/?UG<1$),+6b‰šœ‚w’…‚’’‘“•••“œš™¤¡š—˜—–™šš——–’–—“’–’‘““—•‘‘“‘“—•“’“Ž“’‘’‹Œ‡ˆ„‚€|…’¤­·¾ÃÆÊÍÌÐÒÒÓÓÔÓÔÓÑÐÒÐÐÐÐÏÏÏÏÒÑÑÐÒÓÔÔÓÓÔÓÒÓÒÕØ×ÕÕÔÔÕÕÖ×Õ×ÔÕ;;6=675A?BBFBD?>@@A@>KOOQabr|ƒ•™›£¤¨«­¯¯²²´±²³¶±´³µ´±­¬¦ ›“ˆtn]VLCY‚ž‰l]PVT]g}—“ž‹wZ<54@YVD.$)1/6@NM4CLU16H8;95Hu‘‡ljfYgosfW^UC:@M]{„…}IF>]LAA@So{zxwz®ÀÈÇÐÕÕÎÀ¤WWhrZbev”Å»`&&(0,021.,*.3>IG0'*+1,558:?7B?LRN/%&*(2Rm>QRcXKIQ^fkiwxyy‚‚‚{„{}ƒ‚„ƒ‡‡‰ŠŠ‘Œ””“‚uldndbYZSRWTRV]Z]dblpjhgf`c`WYYa_fopswuu{tlonhdlt‚~x|ŠŠ“‘‹w@-+-0-1.2472,**/4;22@KB=1;SW@PHOQO=:,+:XN@1'.1,5Y„Ÿ¢ˆ~‘‘„‘˜•“•””•‘¡žœœ¤œ›˜œ•š˜™—™˜˜˜–•–“””˜–’•‘‘’™•‘’ŽŽ‘Œ“’ŽŒŠ†„ƒ€zˆ’±·»ÄÈÊÍÐÒÓ×ÓÓÒÓÒÒÒÒÒÐÐÐÑÒÎÏÑÑÒÓÒÑÐÓÔÕÔÔÔÔÕÔÖÖ××ÚÖÕÔÖ×ÓÔÕÔÔ::76595<<:@?E>@@@GQPT[dq{‚Ž’—œŸ£¤ª­±¯®²²¶±²±²°³¶µ´´°­¥Ÿ™“‰ƒwp_QLU|žŒt^XQTZZtŒ–žŠ…tX@.7QO<@/0(+9>LNY6DOH64X?<87CuŽrŠo`dZ^hdfpjbXMQMXh™zA76NF.9D[u„‚ƒ†‹¿ÔÙÙÔÓȹ„M]iVX_w”¶Å„2-1,,73.2+)*+09ID4-68-0558:@55>JPS9*+/(4UgBRSbYSMS]Yeiszy~~}ƒ€}|~}ƒ€…„ˆ‡‰†‰‰Ž‹—“‘“‘…y{x}|tnkb^_^a`jkhqqssnpqnlpjlklpmkpsz~ƒ€‚ƒ‚}xx‚„ƒ€ƒ’‘‘‹‡T4*.2,+-123;.+-+,/814GJA96=WMHP?JSRD;,27OP>2$&1*2Q|š¡|Œ™Š‘™”‘”—•“’žžœšš˜˜™˜š•—™––’–˜••‘—•–•‘””–••–““‘”’‘‘‘Š‰‰‰…ƒ†•¤­¸ÁÇÊÌÐÐÓÓÕÔÕÓÓÓÒÒÓÒÏÐÑÐÑÎÒÑÓÕÕÒÒÑÔÔÑÔÓÕÕÕÕÕÖÔ×ØÕÕÕÕÓÖÕÕÔÔ33:96>:;?==BEGB?A>@CAJYYWZfoz†Ž–•šž¥¥©«®¯¯¬³¯¯±¯³µ¶´·¶´ª©¡ š…xqYUZu ˜qbVNSR\e„Œ“‰{oT=/>T:8?82&+C<<9:;GXG47YU?=<=|˜€ncddcc^Yhvmjc\U^m}‡wVJFBR8ISo‚Ž‘††„|°ÚáàÕμšl]j_Ucu•ºÇŸ<,)0+20.40,2()15C><-+0*4=6:8++3/2Rp9QWVVIMN[`efpqvyx|y„zyz~€~€ƒƒ‚‚Œˆ††‡…‹“–‘””’Šƒ€}~|stolnnruruz~||~€‚~}{€~‚‡‹”“•›ž›ˆ†‚‡ŠŠŠ‹‘’‰u80-//4.207;4/./123<:9GH878D[HLILKSUI918>]a?/*,/+4Qy—£yŒ¢ˆ˜•Ž–’–—“žššœ˜ž—•˜™˜˜•š•˜–—šœ•“”‘“”’’”–”•–‘‘’”’’‘’“Š‘Œ‡†‹…‚ƒ{„‰˜¦²¾ÁÇÎÎÐÒÓÓÓÒÓÓÑÑÑÔÒÐÏÒÔÓÑÐÒÒÓÒÔÒÒÒÔÓÓÔÕÔÕÕÕÕÖÖÖÖÕÕÔÓÕÔÓÖÔÔ666:78;;;@:;B>B><=9BDJ\[_Ujv|†Ž“™š¡¡§©«¯³¯¯³®°²³°µ¶¶±µ²®©¢›”Šti\d}››{\QMOV[_r‡”zz{g]E6IG;AE7*,:8/8;.5@VE8;Jf:92:„¥“ŒlLOc_d]aXebkoia_eT\Slf<=cHfh€–™‘ƒ†{‘ÑãßÔÁ¥|Yio[_s¡Ç·U(*/1:3472/-,%*;9B;>.)013=9@8A@2;EJPB,,(,4MgBJQYVLOPVbbeqsuxx~{zz{|~~€~…‡…†‹‰‰Š’‘•““““ŒŒŠ‡€€€}|€{xx{xz}€‡ƒ‰…‚…Œ”‘‘˜™š™Ÿ©¨´°³¶­£’Š†‚‡Ž“’”ŽŒ}L2,*.2-01-8<-.1.2/3<=>N?3:9F`JEKRISUNE02;Ma=212.)0Mk•£™|‡£›—””——•œ›œ™™—”™–›™—’—˜–˜™™•‘”’”’‘Ž‘•“’””“’Ž““‘Ž–‹‹Žˆ…ƒ{|Œ™¥±»ÄÈËÎÑÔÓÖÔÔÕÓÔÒÐÓÐÓÒÒÑÒÐÐÑÖÓÎÔÓÓÐÓÖÖÔÔÕÕÖÕÕÖÔÔÕÔÔÓÓÓÓÓÔÓÓ8859==@>?;=<;IIOWS_^gs‡Œ’—š§¥¦«±°±®°´±°³·¹µ¶¸µ±¬©¥œ•Ž€vok‚¥œ€ePMPQUWmŒ˜{vvud]K?EB6KQ<.89-#4/.1@aM74FbB81?‰°•‡oO9TUafifmbb_UXaV>;@iyT:d]zz„›œ•‰†‡€u|²ÝÚ̬‘_]nfeo¯¶½}91-30796555-1''4B8<82+-03<@<@:B6:>TdK1*-2:M]J>VTNSLHMX`akssvuqvvvyw‚z€{|„€ƒ‡‡‹‹‘‘–“‘‘‘˜•Œ„„…€}~~‚~|xwz€~€‰ˆˆ–™ž«¶¹¼±¾Á´¹ÊÆÅËÊIJ£Ž‡‡‡†Ž”˜ŽŒˆƒxC.++),/152356,)**(739146.38@KfKCJNLSK8607EGZL4&)2+2Odœ¦ŸƒŒŸ’Ž˜˜•––•˜šœœœŸœœ›•–›™›™•š–›˜›——–”••›“••“”š–““’““–”“‘’“ŽŽˆ„„†…‚{Œ˜¥¶¾ÈËÏÕÔÓÕÖÒÔÓÒÒÓÒÒÒÒÒÑÓÓÒÐÒÓÔÔÓÓÓÕÓ×ÔÔÕ×Õ×ÕÔÔÕÔÔÓÕÓÒÓÒÒÔÐÐ5587;78A9?@DD:A?A4;?IMST]\bpz„Š“–›¡ ¤®¯¯¯±´³¯°·±µµ¶´³³®¥¨ š˜‰}{‰“–…dJIHLSSUcŽ›ufgtkfd?@@2@p~A><.&&2)'3QgQ=8:^h4-F¶”…mF<4IQ\llwul[U\^K=>7N_pcmƒ|„›”Ž‡tw‚¬ÑÊ™m[jrj•®¾¼ªV..796:753626'+1-/-6>0<6+,.26;5=B6?CDNH:..18GWD8VPSPCBHSW`gnpquot|vx|z|y~{~€ƒ†‹ŠŠ”‘’’””‘‰‰…ƒ‚|~€~w‚ƒ~vxz~}…†“œ Ÿ¦³­´³£¦¯¹±º»µ¯•‰ƒ‹Ž—š–‹‰†[5,0/.*../6257/**),85<9>0436ENlM=NNORJ>95BL9@:;>@@75=ETW[[bcmx~‹’œšŸ¢¨¨©¯°°¯³²«±µ¶²·´±®®©¦£¥œ‚‚‡‘|\KGGILMT[l‚—khhlbhUAJJ6OŒƒFC-''.3%*BfcEF;9Ql?.B—±›nO1,BQWYZlyyk]\bHETTX[]`m|‚Š’•™ž¤Ÿ§¨®²®±µ´±±¶²³´µ¶²°¯©§«±¦Ÿ”ˆ‘}cIEACGLQUj‰žlhnjaXDALV?f˜wP8')%-,(2Rhc8OF5AnPQL]_F@<@H:A\U114/62R^’¦Ÿ•‘—ŸŸš“’–—’™œœœ›œžœœ¡›˜™—˜——•˜˜˜™—”•–—˜œ”•”’’•Ž•“‘‘’‰ˆ„ˆ‚}~y~Œ¬¸ÄÍÏÕÓØ×ÖÖÖÕÓÓÔÒÒÓÒÕÖÓÖÓÕÖÕÕÖÕÔÔÔÕÖ×Ö×ÔÖÓÔÔÒÑÐÒÎÐÓÎÌÍÎÏÍÏÍ::824:3;994>;6?:766=FPQY^^`ix‹’—šœ Ÿ©©­«¯²´±²³·´¶´¶·¸²°®§§¬µ´š‹yiRA>@EEPPZtŽ¢ˆoifjmmO8=@TF{•bG=344/0)-Sj`:GcJ3i`?b¨ªˆp{„W57KUZW@@W}ƒrYjuS`Mgdck‹š—“„™‰wn{°ÖÔ¾\_u~Š­”Ê»—y64-51/.-15587<82.-,23595=674012:JD;9;>D@I;10.7ITX;NUTI9CHN[^chnkopvqsrvqyxx{~~|ƒ„‚~„‡ƒŠŒŽŽ‹‘’”“ŽŒŒ‰………†~~z{zy~ƒ‚„}~Œ‹‘Ž—˜–““‘Ž”‰‡ˆŽŽ”“˜™Š‰ƒi=/)02/0---3=0/413//56+8D4...9CQmF=HGaUGD?DI=8T^:-1-63K`“¤™—™Ÿ›’–—”–›™žœ›œ›š›—š—œ˜š›—›˜˜š˜•–™–”•—“˜•–“•’’‘•’‘’’‘“ŒŠˆ‰ƒ~z~‹ª¼ÈÎÓÕÖ××××ÕÕÖÔÕÓÓÓÐÒÓÖÖÔÕÖÖÕÕÕÖÖ×Ø×××ÖÔÓÒÑÒÑÐÑÏÎÍÏÎÌÍÌÍÍÍÎ<<72968;<;3;<;78:67@CNUYXZZhr‰—š¢¢¥§©«¯¯³´±³²²µ´¶³µ¶³­­¦¥ £‹€p_PBADGLOYnŠ •lfcfptcF3787PŒ‘Y6,+07+0+8XnS2BjX9a]C}´toi‹r>;OQ]eA3J`jx•Ntk}tn`¤ Ÿ‰rl„²ÍÌŸ]n~…­©°Ö±”Q5:6::8:5;97@9969.2-287532-774441:D787BHGM;2.4:IRVAUWOC;DFHNZ`inioqnprrsswuwx€{z~€‚„‹ˆŒŠ‹“‘”Ž‹‹„‡…†€€}z~x{~‚~ƒ~†}„‰Š‹Ž‰‘““Ž‰Œˆ†‚‰•–““–•‹††{b=+2/000+-/:?.1.33-.>2.:E717-9EUfB>JEaSJOEE@;8_^2-9../Fk’¥Ÿ“š¡ŽŸœ“•š•šššžšœš›˜”™›–œ›–™š•›•œ˜š””š–’–”—™”•’’’“•‘’’“‘Œ‘Œ†ƒƒ…{y{Ž «¿ÉÐÕ×ØØ××ÖÕÔÕÓÔÔÑÓÔÒÖÖ×ØÖÖÖÖÖÖ×ÖÖØ×Ø×ÖÔÒÑÒÒÐÏÏÍÍÍÍÌËËËÍËÎÍ44.13:8777;9<896798AJSQX_j\esˆŽ”›œŸ¡¥¨¨°±´²³±³³¶µ³·¹µµ®¨©ššŒƒzh]JFJELMPb†šŸhadlttgJ7A21c–Œ]2'$.52+:DgoI/9Y[KW\HŒ²mlV‡XJN_msN=:ST}‚vxT†…ˆ}{Qnšž¬¤ˆ—†qm¯¾ÅŽf€ˆ¡¬¬Ì»‘g402:7-55414=557@49.45:534014745775AD>9GF@F<55.5AQV>DVDL=?AMOQ\efjinllnssvt{xy€|{z„‚‡†…‰†Šˆ‰…‹‹‹‘ˆ…‹„……ƒƒ€{|~|zy~~~}ˆ‡„‡‰‘‹Œˆ„ƒ€‡‰“–•“‘”Š‡~cN2'+/1-5203=:356?5/5;409A87./:FVeD;MHbXENCF=:<[b9+7852BqŽ¥Ÿ¡“– Ž›•–š”Ÿ˜™šŸš˜››Ÿ—˜™šœ™™›ššš•›–š“˜“•–—•’–—’“’“‘‘Ž‘’ŒŒ‰‘ŒŒˆ„†„~z}}Œ¯ÀÈÎÒ×Ø××ØÕÕÖÕÔ×ÔÔÓÕÕÕÒ×××××ÖÖ×ØÕÖ×ÖÖÕÓÑÏÏÏÎÎÌÌÎÌËÌÌÌËÎËÍÌÍ004/33727695:696756:ERX[Z[Yfqˆ“–™Ÿ ¢¨­°³±´³²µ´µ²²³·µ²®¬¦£˜‹~skXLKBDIKQp ƒobgeq}pXH051>ož‹Q-+446.,0RniF-8;ZPXWRœ³rhCq“y[Zfy{]E?>:X…ˆnaŠ„}‚fa{˜²¬}Žtq€¨Äȇ•¨±›ÑÇY>7598966627<>>77L:644695:930<=?<==7@BA6?EKKJ?=41@DV@@YOPF=FQNNXacgehhinsoxp{zu|y}}„„‚ƒ„…ˆ‡ŠŒŠ‹ŒŠŽŽŽŠ‡…†ƒ„†‚‚‚{~{zwvx{|€„‡‹Œƒ€}}{‡•™––“Ž–Œˆƒ]KN4&'2.,*1/-:2'-8@0.;726?9;21,Vi@/4,3+:e‰¦£ –£ š•—›•›—žœ›šššš›š—˜šŸœ˜›——–—–˜•˜˜˜•““••—”’”Ž‰ŠŠŒˆˆƒƒ†{zs|Œ¡±ÂÇÐÖØØÚÚØ×ÖÖÓÓÕÔÕÕÓÖÓÕÖØ×ÚØÙØÖ×ÖÔÕÓÔÒÓÏÏÍÎÌÎÍÍËÎÊÌÎÌÏÊÍÍÎÎAA33-03167??8:<4584@HR__WSUhq}ƒ’–›ž¡£¨«±±³µ³±±´³²¶³·´³±¬ª –”Žxk[RFDCAG[‚œ—necdfsyfJ<5;6Kw¡ŒK&%13.#"8_o]D750TSXTU©¶…b9YŒnlq{wdEKAB7b‚……‹wkp…fK† ’n•uwŒ®ÌÊ–ž Â‘È×°e>975786:358;7<72-7;?7745/5>=>D76?GD;7=FCC::25;COE:YURC7GIJHTWbfllijhlpspwuuuwyz~‚ƒ€‚ˆ‰„‡†‹†Ž’ŽŒ‹ŒŠ…‡……‡ƒ‡…ƒztuwsuwyvw}|xwu{rz€‡—œ–›”‘ŽŽŒ‹o:UB6-),.+'(+04.*1997;:22579:1/0?Q`YFIU@\T?RF?68EP_>00//5=i‰ž¦œ‹šž‘œ›”–˜—ž—œœ˜˜›˜˜˜˜™š™›—œ›šš˜–™››˜™—•–”˜•”•”—‘‘’”ŽŽ‹‰‹‡ˆƒ‚yvu}Žœ²ÄËÑØØÚØÛØÖÖÖÕÔÕÔÕÕÕÖÖÖ×ÚÙÚØ×Ù××ÓÓÓÔÑÐÏÎÏÍÎÍÍÍÍÎÍÌÍÏÎÎÎÐÐÏÐ9933456203<485:2<77?OX]]XWVbq|„Š’’˜Ÿ ª­¯±µµ²´´²²°µµµ³´®¨¦š•ˆ‚wlWSCAAFKa‡§„i^`jhonX?12=8Kr†G+&233*%=g[E81-)6O_Xt·¸‹ŠW8Kk‘}bo{†fC>DK2D`Žšˆ}_Xys5x‘„iŽ“x{’¶ÒÁ§³ž©ÜÂv:4247//359;8642748/+..(35;0040,8=<?D75058>RM9LRJ=:@AGGTSYdfmlhffnmnpxuvzvz{€€‚‡…ƒ‡Œ‰‡‹‹‘‹‹Œ‹ˆ†‡„…‚‚€ƒ~~}}uutuswwotstww|…Š” —–•‘”ˆ|E6Y=),1-(&+.110,07<6:E8.581349.,=Xm[DFSEc^GOD@@C=UX?06454;fŒžªž‘–¢•—””’œ›˜œ›š›™™œœ˜š™–—˜™œ–›™š››š˜•••••”—š•‘’Œ“Ž‘ŽŒ‹‹ˆ…„}zztx…œ°ÃÈÒØÛÛÚÙØ××ÕÕÕÔÖÕÓÕ×××ØÙÙÚÙÙÙÕØÕÓÒÔÒÐÌÍÌÍÍÎÍÌÏÍÐÐÐÐÐÏÐÒÒÏÒ22012859078.33//358EQZ`]ZUXao|‚Œ–•›¡©ª®³²³²°³±´··´·¹±¯«  œ”ŒƒvnZPC?>EKeˆ¤}e[dmnkfE2*5>=Xq•uA/./5/.'Hd^@;72)-?Pa†»®‰”gC=ZŽttw€oGLLT8Ly‹……zk`uf:nŠ{VzŽu{£ÃÏ®‡š³œËÈŒ=0/.112,0500536:<7A:8,*)2973673F5:7:DJ72D<;>8A?83535?LI=IYR@9;GKNPQU]biihiinjjjtvwvv~{~„‚ƒ„†„ŠŠŽŒ’‘Œˆ‰„‡‡ˆ…„…€‚†……€~yxuvzu}}~~ˆ•™œš›˜Œ‰Œˆ‡a19V;++--3(/.,.714843LC74?7386A).:Jt[>HMC^fKHGB=@?N[C.=H778538B[|‹[E.,0),&4OcY@B>33+0=d˜»–}œ{\9W‚˜}r€pUZX]Tk‚pw‚‰€~ebXNm…|Rfˆmu¥ÊÑœƒ¶›ÎÇŠC4,3519<;835/779886>80+2,687/)206027:8<6496;=69@=6:/56DD7COUBA3HEOSNU[Z[`ecfogliqrsuzx~}€€ƒ‡‚…‡‹‰‹ˆŠŠ†Œ‰‡‡Œ„ˆ†……‰‚…†…ˆ„‰‡€†…ƒŠŒŒ”‘™”™•–š“‡‹Œ’ŽˆA.@B:>CEB;165BB6AOSG>7>GUVNX[]Yceiglnloqryw{|}€ƒ…‰ˆ†ˆˆŒŽ‡Œ‹†Œ‹‹‡†††Œˆˆ‹‰‚„‡ˆŽŒ‘‘’—Ž•”—•šš™–ž•‹‹‘Œ†]-/?P6-0-++,3/+.>81:45@E64511+1;)-6Iq[EMKF]`JCH==>9M_Q/2/521\‡©¦£š’¥œ™”“’šš—˜™™šœ™—™˜˜œš™˜œ˜—œœœššš–˜˜•–—“”’–“‘ŒŒŽ‰‹„}|{ux†°ÂÎÕ×ÚÛÜÚÚÛ×ÖÖØ×Õ×ØÚÖÖÕ×ØÙ×Ö×ÕÕÓÓÐÐÓÏÐÒÐÑÒÐÑÏÑÒÑÓÒÔÓÓÓÔÓÓÓÔ>>3/652514205403.5@Tfbibi_gmv}ƒ‡Ž“—œ££«®±²¯´²²²±²³µ·µ²°¬§¤š”‚~oZVG=C@Jb…–yeWacWXUMI:;CDJrf6;252+#*7Q`S74CE6/1A~¢¹†‹w‘rLH‰œ‡…zkiav†€\PTQ~uŠrG71**+'13-4:43=678=71488037,+:Os^GSPJ^YHHGBBBDNWO42396.Y…¢©žœ’¢œ—“ ›˜˜œšŸœ››š™—›˜š›šš˜›™•›•™—˜–—˜–‘•”—“”—’”•‘‹‹‹‹ˆ……€~|xzsu‚µÆÍÙÙÚÛÜÚÚÚÙÕÕÖ×ÕÙÙÙ×ÖÖØØÙÕÒÔÔÒÑÐÒÒÐÏÑÒÓÓÔÓÒÐÓÔÑÒÒÓÒÓÔÓÔÑÓÑ5542/271/1300110+3GWdilheahnr†‡ˆ’—›¡£¬­­®±³®´®²±²¶±´´««¦£¢—‡yn^OG@JDKZxŽƒm\daY`YJB;GPJMdW-77--.'*5VbJ47AI59CBi¼‡‰^v‹uRk¡š„gmf~‚lBGWV|ƒu“zA78^…}frŒ|‚­ÖÜͶÖÂ~P8,))-.4:70150,.0>95/;912&23B3//327212048:<>9<7<;B;?8/,65>?9CBK>:4;DJGFNTZ\Xajgglmqotsw}{€y‚„‰‡‡„‹Ž‡‡ˆ†ŒŠ‹‰Š‹ŠŠˆŽ”™˜—˜š¡Ÿ¡¦¡¢Ÿœœžžœ˜•“‘ŽŒˆX1,3TD42"(++04./3661C979>@2257+4=+1;RtaELCB_XTLMBFFBPUM940;8(R‰£¬§¢–¡¡—Ž˜œ™›žš›žœ™š•—œš˜™šœ˜”™•š—™š˜š““—––‘“—•’•‘‘ŒŽ‘‰Žƒ„„|~|svvž¸ÄÎÔ×ÛÛÚÛÚÙØØØ×ØÕ×Ù×ÖÖÖÕÖÚÔÔÔÓÔÑÒÑÑÑÒÔÖÔÓÔÔÔÓÒÓÓÒÒÒÒÓÒÒÓÑÑÑ4407371201//.)-/27NZfigiedgj|}ƒ‰Œ‘˜™¢¦¬°¬±²°±°²²²±³¸³²®©¥ œ•Œ…~q`UJ>BHFVpriqbZ_VGADWZNDdC5?:..)))>ZZL/1>F=8,3N”³‚z]av†jZ‘¢ˆ{motsqZHMcZ]pv‘ƒVPHj„qIv‚uŠÂÚàÈËЛI862.1/5446-2002657>::@89-&.0892/68;2-0733=>;;6;>:D?@:,-27:59GFD564*)&)*@X\G+.2D>823GŠ¥lmuctfxx\uš’‚jpyif_NOXTVa„zƒ`cct†i3gƒbv¥ÏÚÏÑ¡R513.13555;==260,549;;9=61.*03?82567=4031.-2;;864@9?H:64002;?=<;JH832CCG<4--*(,-EcaF3)0=@>77AŠ§hdhVrxqqai…™„upylce[WPILV‹~sp€…g/61698/,.0.17=99588DC;71107:BB;;AF623=INC=K:;:7-IŒ©¯¤ —¥¢‘‰››——¡ž š™šœž›™–œœš—–—™›”—–––™š˜™“‘”“˜—–”‘•‡ŽŽ‹Œ‹Š‰€‚~{yvpvˆ§¾ÇÒØÛÛÚ×ÙÚÛØØÖÕÔÕÕÕÕÓÔÒÔÕÔÕÖÔÔÔÔÓÖÔÔÕÕÔÖÓÒÓÑÎÏÏÐÐÎÏÐÍÐÏÏÌÎÍ--112.-5:38/13306GMT]hnlecldHIOEX]__`V;5>4.)'(/Id[A++.40,,211087987::E<7301/9=?6A9E720:GOE937BFOYY\^begjllss|‚‡ƒ‚††‡ŠˆŠŒŒ’ŒŒ‘•’“™›ŸžšžœžŸ¥¨§ª©ª­§¬©¥ ¤¤¨£ŸŸ˜–—–™’q.&*)>M4-)0)-4,/1<7;@;<>=;10;AG>.-33/E\qeEPRNiTYM@EDLK[M3MB?7<.RŠ§¬¡£—¤£“™˜™¢ŸŸŸ–œœœ™šœ˜™™˜˜›˜™–˜›™•–—’•—˜“™–”’Ž‘‹‹Ž‹„ŠŠ‚~yzwqzŠªÀÎÓØÚÛÛÚÜÛÚÙÖ×ÖÙÓÔÔÕÔÓÒÓÕÕÕÖØÕÕÖÕÕÔÔÔÕÓÒÒÓÒÐÒÑÎÑÏÍÐÐÏÎÎÒÌËÌ--.2.1035/0001:46AP[gmkji`gqx„ƒ…ŒŽ—™œ¡£©®²¯¯®®±°±±±¯´²³®§£¢š•‹‚wjaULBCLNVYank[cl^JEGKMHL[_V@4A:12'#-Bd[E20647?GJOx¡[gnZL]hr|nxyŠw~‚vpk\LJMv˜~aeˆ…”l.Dn^s…š»Ã[/.?C1.+,.1/05405.1/5HH@476,++/69;4-150;22-33231:972946;@85815?=8<<<;75BGNL:438>FUKRUabb^hmmptv{‚††‡ƒˆ……Š‰ŠŒ’‹“••“Ÿ¤£¡œœŸ ¡§ª®±ª¨¡¨©°¥§¥££¢••’š—’‹`31,-LP11)0..14+4=5=E925AA./8FD'1-/98J_xiFNOJlQWI@GCLLSE1PO?343M‹¡¬ ¡˜¥ †‘––š ¡šŸœš—œž•˜™™–––”––•–’—šš˜—˜›–œš••–’“”Ž‹ŒŒŒ…‰ˆ†‡‚}xstz’²ÄÏÖÚÞÞÜÚÜÛØ×ÖÖÔÔÔÔÒÓÓÓÒÔÕÕ×ÖØ××ÕÖÕÓÓÔÓÔÏÐÐÐÒÒÐÐÏÎÏÐÐÍÐÎÏÌÍÌ00//,.,102-/5.1.3AVZeqljheaju‡…‹”™§¥©°¯®±¯­²°®¶¯³´µ³¬ª¨Ÿž—‹‚yn]PIB@ETTZgtj_ioU77DR>7J`r]8.A755&&.@dT@-'0:7?LPOn›WmnG6ACF]{„{n…‡|xwukVHRu¢‰c`€¡m.;`[}|†Ä¾U26[A1,254855:1.88077`A>;;7/(%178=32/03?531.05302;5;?7<;A33;42C=:6CA@7.7FOL@5.47:DEMVZa^_dgkpru}~€|„€†ƒ†„‹ŒŠŒ’•‘“‘˜—–ž¡¤¨¦§¤£¤¢¢¥¦©§£¦¡¢ªª¥¨¦£¦ž–›–‘„@(++2RD-0/1:640-5:4=@4-05K7/9.067Mb}kONKJqJVO@QONMSA3IY>17,>ˆ©­§žšž¡‘•—˜£š¢›œ™š™›’—œ—š˜˜–“–“”˜••”–—™™™”‘•’“‘””‹Ž’ŠŽŒ‹‡Š‹‚…~€~{tsu€š¸ÊÐ×ÛÝÞÜÚÜÙØÕÒÕÓÔÔÓÔÓÕÖÕÖ×Õ×Ö×Ö×ÕÔÔÒÔÐÒÎÏÍÍÍÍÎÎÍÏÎÌÏÏÌÍÍÍÉÇÈ//.-1923-.-.,35,6DUUW\`__`foz}„ˆ‰Œ•››£ª©¯³²°°°¯¬°°°³µ´±²«§£›“Ž…p_TIGEHQTZac`eVKI<5-03@ZUD,36?7-;Q[™VbeF92873JUl…‹‰Œˆjp€‚‚xiddš”}w|˜ƒn^MHy]BVQ:@kF233853A:3201767/9A=<=:=,.,18>:0385.2>73.2.6245;:4C;7787896;;;6:C@B6538?>I842*15?8+02576D[ziROSMsMMMARXIRVF/JW<8@*Aƒ¬±ª¢›£¤Ž•’œž ›Ÿžžš›–™—”–˜—˜˜›”™•™–•–•—™”˜“•˜””•“ŽŒŒŒ‹‰Œ‹‹ƒ‰„{†{uvsœºÉÒÙÛÝÞÝÛÚ×ØÔÔÔÒÒÒÓÓÓÔÕÕÕ×××ÖÖ×ØÕÓÓÒÑÐÏÎËÎÑÏÍÍËÌËÎËÌÊÊËÉÇþ00.256960*+.2917AAQQY]`_`bcoy‰‡ˆ‘“š›¤¨ª¬±­¯¯®®±µ°¯³´³³¬¨¡£Ÿ–ƒxq\OEAAHNQYjctvX6876;981N‚sW2/;0>8110..)<0:C433;?;85@F<905JCHEB/11-+55=>EQSUW]kmqxzz{|~‚€†‡†‹‰ˆŠ•‘’—–˜–—›§¥¤¡¥¨¦¨¬¬ªª¥¦¨«©«ª©¥œ‘’’—Š„pR,%+2E@15629;:654689:;BL84217817249.;?MhuhGJPMoDMFAQWOFMK7FXG4<,E‰­®£¢œŸ§‘Ž’——™š–›Ÿœšœ˜—–“•–—š˜—˜——™”–““˜™““––—“•‘ŽŠŽŒˆˆˆˆŒˆˆ‡†ƒ||wtux‡¥ÀÍÓÙàÞÞàÚÙ×ÖÔÓÒÒÕÓÔÔÕÕÖ×Ø×ØÙÖÕÕÔÕÑÐÏÐÎÌÎÍÏÏÊÌÊÉÇÇÅÅÃÀ½º´³¨ŸŽ33-/6455201/11.,26CLUZa`chrv„†‡‰‘–ž£§ª®®¯¯®®°°±²²²³³­²«¨Ÿž–Œ…{nZOG<@BMNX]rxO;21483<-1Z}^dI039948@LEPK;30-*))07?@FQO[cjouquvtv}~}…„„‚‹ŠŽ“’”“—“—”šœŸ¤¤©¦©¬¬±¨«¨¥¥¨¨¦¦¡¤›’‘“–Œ‚nR-(+/?9338<=7:7965:78=@RA1.884089050=EI:1JHBC2//84.)(Kˆ˜„x‹tM9.NSKQf\azYc|x{Š•—‡†‰or…ŽŒ™¥ƒQBGV\T]O?564<35068;7967123;8>DCFM@23,*-7E>//24:55393/0/7330.27<;68<=C:49<=<8454./3=7?NPWYbdfckpry|~|„„‚†‹Š‰‘“’“’˜–›œš¥§¦¨¤¨«­¥¡¤£¥§¥žŸ™š’“‘Š}nX-,04B9549;<6:9<889:16FN<859A0/2:9975EUdqgPXWLfISKNO[RUWN?O`I<8.Fƒ°«Ÿž™ œŽŽŒ‹Œ’’’•”“•“—˜”—™“•—•”——–““•‘’–—“•””“Œ‘‹‹‰ŒŒ‹‰‰‰ˆ‡„€}yxuv{’²ÆÐÔÚÝÜÞÝÚÙ×ÕÒÒÒÓÖÕÖÔÕÓÕÕÖ××ÖÔÖÔÓÒÑÑÎÍÏÎÎÍÍÌËÊÇÿ¶³¯¦˜‚scR=;80.-,--./.-&,+05579CKY_`fhot‚Š”—™ž£¨§°®­¬ª°¯±¯²µ³³°²­¬¤¦œ–‘ƒ{lYND?C@DLc|rSA898,-5CIHhRBWF509B:@C@GCFB3*)852'-?‚¢†wŠ~[=8D]NJRW\xm]n\l…š•š™zyry‹–Ÿµ¢]FMknkyZ93307023262162863989=BCHQA78018:I?7/35>3:9<;3352787525:;;>?NIIL\V]X[`kpvpt{vs€€ƒ……‹‘‹‘””–œ˜—˜œ¨¤¨¦§ª¨£¡ŸŸŸ £›Ÿ¡˜“ŽŒŠ|jU/,*4@;=@:6<=59<59@;6@TI9:4;H37<35-1<>TbogJXURbNZLJQaQVTJ?S\G?;1Pˆ¬ªž›™ž›’Š‡ƒ‚‰ˆŒ‘Œ‘‘‘’”›“–’˜˜•––“˜“•”–”••˜‘•‘‘‘ŽŒŠˆ‰‰Œˆ„‹‡‡‡~}zwst€ž¸ÅÏ×ÚÝÞÛÛÙØØÕÔÔÒÕÕÕÕÓÒÔÖÓÖÖÖÖÓÓÓÓÑÎÐÎÏÎÍÎËÊÇÆÄ¿º´§¡”‚s`LB9310--,6//12630,*+47119=LU_acikpz‚€ŒŒ–šœŸ¥¦ª¬¯­­®®«°²¯°±°³°­­¨¥š’‚xiZQD67AIev‚bWFXe2-++CP`lL=LN>29AF;>AU>9E2)+86;$!0y¤‰xŠƒW@8@QMGEAVkyhq[]e…™…rp{zŒ—›£¥vszˆwqoB220.026<445338116788EBNN8/11.3?K>482631:48940337/*/2,8368=:;866=?A:D?9499ASJHIF==5<-4+48:=:AEFGEDAFMTZ^^fpsxqy{yƒ…ƒ‡Œ“˜–™—œŸ¢¦¦¤¤§¢Ÿ—››š››ž–“Œ‰ˆ‡vaA+,./9926896373;8871:6K@4347:46/385@=@UarfOWULbM[JNU`R\ZI8M\H<<.W°¬ššŸœ›†‡€€ƒ„‡‹Š“Œ‹Ž’”‘Ž”——”•—“œš‘———”•“’””•’’’ŽŒŠŒ‹ˆŒ‡†‹‡„~{uvuw†¥»ÉÑÖÙÞÝÞÚ×ÙÖÕÒÓÔÓÕÓÕÕÖÔÕÔÕÔÕÓÓÔÐÐÐÐÎÎÎÎËÈÅÃÁ½¹³©£€kVA3310.++)),)04.1-.++,(*3,3479KB<894),6-8,.-~¥Žƒ’Œ`I@@ZXMDAP\zsx}eU[x”vSn{‡†ŠŸ ’”……˜Ž€‹e?.)+)+,//142994335BDJFNQ3+'*(5?S;3..//16:<70...51++0466488>=;>9@HEABBA4<>>MIGNMG==:>D<9@@=8B9:>=1YŽ°¯•š¥•’ˆ€}xwx}‚„…ƒˆ‡ŠŒ”’•’•—““–•—”š•”“”””“‘ŽŽŒ’‰Š‡ƒƒ‰‡‚{xwqu|¯ÀËÓ×ÜÝÝÛÚØ×ÖÕÑÓÕÕÖÑÔÓÓÓÓÓÔÔÐÒÑÑÏÏÑÏÏÌËÈÅÁ¾»µ±¦›ˆfJ:4,+++..++//0,--10,/*-/*5*)2?@BT^__\Zdtzƒ‰‹”–ŸŸŸ¥¬¬«®¬­¬¬¯­°°±¶´±®¦¢Ÿš’‹peYC9AJl‘®È^es w0-*)1FQUG<:?A:@@EDHNR^\Z``bg]fmrxytw‚‚……†Š“”Ž’––”œž¢¦¡¡¡—––’˜™‘’‹‡†‚‚Ši\@9348556;787592?75::68M>37:7.-44./8A?>S\qmQTWTbSXMVJYPX^GAEKRCM4UŽ²°”œ£”“‡|qpwxyzƒ‡}„ˆ„†Š‡‰ŽŠŒ“•’‘“’•’˜–”’“•’’•’’‹ŠŽ‰†……„‰yz{wusvy•³ÃÍÒÖÜÝÜÚ×ÕÕÓÔÓÒÔÔÕÒÓÓÓÓÓÔÑÒÓÓÑÒÏÐÏËÉÉÇž¸±¨ ™‡s_K<4+)$'))***-00-,/>300),,1()'*.1?FLXc`X[dl{€†‰’˜ž£¦¬­°°®­«­¯®¯­²²µ²­© Ÿ™‡zraTE=Lvœ»Ô¡[f[‰¦f2'+./?SNZA45Wlqilpƒ”–£š‹ƒŠyz–­ œ¦pG<574634352332166CRTDTR713,--?L<21.74..3:76,1/185+.4492:<>=>>989>;;@A5.66FIW^`\`fdbkmnrsyuxyuwxyyƒ†ƒz}ŠŒ‹Šš›™— ž¢Ÿ¥©¨¦¤¢££ §¤œ–Œ…‰†‰‰~k`A2/0639;8B8?C3:7A;8-7;PJ9::;04>82-6D7AO^sgMW^Z`VUHTOQRYWK;LIS=G5Y³°’ŸŸ“†{q~rnspqt}ƒƒ…‹……‡‚‡ŠˆŽ“Œ“’’˜•—Œ’Ž“ŒŽŒ‹Šˆ†Š‡‡…ƒ€€}{vsut µÆÏÓÙÝÛÚÚØÔÔÓÒÒÓÔÑÔÒÒÔÑÒÐÑÐÒÐÒÐÑÍÎÌÈÄÂÁ¼¶®¡™‡u_I@7-.5/#'&/.1/3//./10,0())),**&'/3@IKW]]W^^hu~…ŽŽ—›¡¤¦¨®­°²«©«±­®°³°­¬¯§Ÿ›‡ym\TIVy¤ÊÕŸRMKGƒ™c5-(&':K_XC216FD879@?8<<;966@GKQSQGDKJRV\nmkkmmty}~ˆ†††’ˆ†ˆ…Š†‡Œ††’“•–¤¤›œ¢¢Ÿ £ž£¦¨¨¨©©±­°­ªª¢ž£¡¤¥ •ƒpJ@>;7577>N’ŸF2++&*3KaRB@9;AE@9EI932985+*/*2+).]’{‡u‚ hJHTPJ;89H^yzgDC]tš—‚YHg‘‘Ÿœ†}`5DMSn›¨¢‚d@)(+%-/(.55+.1?528;655::57;=A675501985/7J9:S\lmRSPWjVTLKM[V\ZH=FIFKF:d™µ©‹¡†€sf{vlhmqsqtxu|zu|x{~‚ƒ…ƒ‚ƒ‰‡‡‡Š•’–’’•ŽŠŠ‰ˆ‡Š††€~{zvruv®ÂËÔ××ÚÚÙÔÓÑÑÒÐÓÐÐÐÔÑÒÐÐÐÐÐÏÍÏÎÐÌÊÇý¹²±£šˆp^H90,$))+**'110<;<>22;>7349/-*(+&(-,)4?DINVPLMWhy€†‹š™Ÿ¡¦­ª°­¯®­¬®««­®¯±±°¥¤œ“ƒvndl‡­ÒÛœIYXB?]²‹K@7A2'0F]ZKF?BBC:CO724:@E4*17.43)9h‘zwyp˜y`JLYO=93>GUe[KRoŠ¤š€aJU|˜¤‰vF@>5?t£´ ¥“rD+(),1-/-1327>KHOWF1-&&.3JP323-1.-/64858-11001-,2532397:<975@B894321114JEGRZWRXfkknoxvz}ƒ€ƒƒ‚…‡…‘Ž‹‹Š‡ŒŠˆŠŠ‹Œ——˜™›Ÿ˜›–™––œœ¡ž¢¦ ¤©¬­·¶»½ÁÄÆÁ¶¯œ‹qZD@7947727=75634<7=>245*'383/3I=;NXqmRSPWcQYMQSUR^bMJJQHG=Dež²œ¤™seyvsiimpmmqqzysywyzqw{{z|{‚„‡„ŒŠ‰ŽŒ’ŒŽŒŠˆˆŽ‡„~~{{wxnr{“³ÁÌÔ×ÙÙÚØÑÑÐÑÑÔÑÐÏÑÖÑÑÏÏÎÏÏÏÏÎÌÍÊÇÿ»°¬¨›ŒwbP:/-+1.,):%++2=FEBE99467:;5./0)++(*+)3=DFKROLJRbu‡Š”™¡§««¯®®­®®®®ª®«®°®¬¨¢›Š…vtq‘±ÙÕ—MDvfJ79<3ZV:305/75/>l‚ˆy‚qbˆ”[HF?+),;Pw~en‘›™qkUQ_q~˜˜xiƒ‚]J;AV©¬³¯ž—u?,0/2.4.74:DDOVR@76)2*;V_2.014527139:92..0.212603159989=5239E;59-05..AFJRQU`fjprw}‚ƒ€~…{y€‚„…ƒ†‡†…Š„ˆˆˆŽŽŽ“••˜”•™›˜›–•™–“–“•”–˜˜Ÿ¡¨ª®´³¹ÁÁÁÅÇÇÈÆÆÈÄ·¡ˆjK=:3:6:45.63974.3/(*.1,4/4S@OXirRLTUWNdGTMGOZ]IJMPAHH@o¢±—™ ’~zsizn{yofqnrtomvrorqsssuxpsvuttv{{{‚~~„ƒ…ˆˆˆ‰‡‰Š……Œ†„„~€}zutpt~œµÇÏÓÕØÙ×ÕÑÍÏÐÏÏÐÐÒÓÐÑÐÑÑÐÏÏËÌÌËÈÉÁÁ¹²¬¢”†s\E701'$&)).2:3/.3-@GR843.25:,012587-/0431+/244656:>A@:;;@81846936>JQUQW\`qtvxz€€‚ƒ}‚~|~€€„…†‡†„ˆ‰…‡‹ŒŽ‘•”’–’”–“–’‘“‘‘‘–••—¤¡ ©ª¯²µ¼ÀÃÃÆÃÈÈÊÈÊÍÍÆ¿¦ŒvVJ>@;58;676=:6/2-41=5;7>TPSZgrWHQQXUcOURMQ_]JPRTHM>Eoª­’™™~zzutz‚yrqtroowuqsoptpornmpqsttvvyy{€€~€ƒ~…ˆ‚‡„‚…†„„„„€|{ywsvt£¼ÊÑÓÖÖÖÔÑÎÎÏÎÎÐÎÌÑÑÑÑÑÑÑÑÑÎÉÍÊÅÃÄ¿¾·±©ŸzaJ@1,.*+/-35=>EMURUQOI@@?FIBA:953522.&*'-7;@JJFAKKYjv|ƒ‹Ž•› £¨«ª¬¯­ªª«ª®©¯®®©©¦ Ÿ–‘’ »Í®kG6@PVJ20W›w5(%')%!'9T\YIDE8=?E>/88:Cv]@=<,:51>AD987825>6025BKMULSNJIKKCH>>C=<7;5675-2/17CDCBC@CL]dp~‰Ž•›¢¥¨ª®¬¨«¬­¤«¬¯ª®°«©£¡ ˜œ¬ËÉ£jNC=R]J?5C…©o2)..-((,4KfXM8326II3889:@njO>;59706IDKi€ŠtXa€ŽuTSTVUap†‘Ÿ„VMCHhnVS\e{‰‰mGIFc`Rs˜™wwy²P.-/716?>DCKXN<93*--8FW@?4.8<60-1,66:?21.29455743/189@<:79634315<1+03&0,2;=AZVWdqYJYO^OUGLOIU_TMEDUUN;Iµ§“˜”‡€s|z‹‚ƒ†xw}yztttsomrpinkihljljknhmiimrpsrsuqytz{}ux|{{x|utxtrns¢¹ÈÍÒÔÔÓÐÍÏÎËÌÎÑÐÑÏÔÑÐÑÒÑÐÑÎËÆÄ¿½¸³°¦žŽ€fU7/*)'/-5<;;BLPOUYYZMRT__RQGEKA=>28586/1/4CE=H?9@:GR\lw~…Ž”œ ¥§¯«««©§¨««­«¬®¯­©©¤ ›µÏÌ vUF@8MHI7Af§¤U3(%)($"$4H[XN>,+5E=.5596CxlUIA>L@87>59Gq„†~eRZƒ„x{xz~xšœ¦’]IROOUwoXa[j€’€WB>^‘uv¡wvWX¦¬‚I<,,266<:@JSE3+'***:L\>5/.3:42324,49<42/58663.49416<<;:9;9;;5499/34EHRY\diuow||z~}{}y{|}ƒ„…„‡‡Š‡Œ‹‰‹‹ŒŽŽ“”‘‘“‰‹Œ‘‘Ž’–˜— ¥«¬«±±º»¾ÃÂÅÅÇÉÇÅÊÉÈÌÊËÊËÌÊòœz^?411*05+&*2**'336>QYK_w[FLLXPTJJRER^SPGBOZK7J†¶£•—“…z‚€‹…„ƒ†‹…z~{x{tqrrginlgikmdkkgjifmkrqpwwsrptntrsxvtsxxoolmps{¤»ÈÍÏÕÒÑÏËÎÍÎËÎÏÏÒÑÒÓÐÏÑÒÒÑÍÍÅľ¹µ¯¥–…q`I5&+&,.07?=?AHIMRWUNXP[\oocgXWJBGB?6641.154BD@B;5:=AKVis~ƒ”™£¥¨«­©ª­ªª¬«©©¨°°®«©ª«°Â¿š{fXF>AALX?`¨6'!'$*-&"+1GWOJ/+9>;-0408HkqjQ:;EC<>>)*0Nˆ„sZYjtov‰‰ŽŽ–žl@BSc]L[sl`adt{xcPKd”˜”·Ÿ…}S5y·ªq=)+*0:64AIWH;.2+3.7TU=62/:81,2,0.6;6755-03.4/73/*/6>>?9<9@=73=9-57FKUV\^iwurzz|v{€€~{}}{}}„„„ŠƒŒ‹Šˆ‰ŠŽŠŠŽŽŠŒŽ‰ŠŽ‘‘˜˜˜¡¤­««´´¸»¿ÁÅÅÅÅÉÊÆÊÊÇÈÊËÈÌËÌÌÎË·šxbA0.12-*&$&($*5:CU[IXuZGQM]LWKNVDV\QRDCEFD6MŠ¶¡•”–ƒ~~†ƒ„…ŒŠˆ‚|~}wxwyzusuqlihjlifgbag^gjjikothliiinnpkopjmoomgggk£¹ÄÎÏÔÑÒÎÎÈÎÌÌÐÐÐÐÒÑÒÑÐÐÑÏÑÐÌÈÁ»·°«”|dQA58/+*+1:99<@FLPSUWWSQSYYyytqcc]RQLI?A984487@<48<6/2;AJ\mvˆ‘™ž£¨©«©ª«­§ª­©¬ªª±²±¸¿º²«˜sgVNBGB`bU‰—„V1+$0.1('(--;LUT@0GT+%--6.;YlfU=IJ?8MQ,"$F8;:@4479<124>OIYWbmvyzzzry~€}}{~}}|~|„ŒŠŠ…‡…‡‹‡‹ŒŽŽ‡ŒŒŒ‹’”™›¢¥¨¬¬µ¹º¼¾¿ÄÅÃÇÉÇÇÇÉÇÊÌËËÊÈÌÍÏÑÐÉ´˜yW92/)'$(%$$*61AQNKRsaDJOZMVHQPAQ\MI@JK@I5SŠµ•˜”“„}…ƒ‰‹‡„„…Œ‘ˆ‚‚‚€}~wv~ttorojijhibfcefhbdZadlfnedefeiiehmkqid``e_a‚ µÀÉÎÑÑÑÍÎÌÉËÏÏÐÐÍÐÐÏÑÐÑÒÑÑÎÌÄÀ¶²¨™yaF3/-+0027>C=@AEDJTRRQQRUVU[~yrohYWPOMJ?;857079DO\gs~Š•œ ¥¨ª«¬¬­­ª«ªª­­¬±¹½ÉÁ´˜‚vh[KDHU{]¨^>/)(*#)')+/-56513061/-1.38::?<=6><=>A99:./29NQT[^jov}yt|{z}{~}}€y…ƒ‹ˆŒ†ˆ‰†‡‹ŠŽŒŒ‘ŒŠŒŽ‹Œ‹‹ŽŽ•“™™Ÿ¢ªª¬­´¸¾¾¿ÁÁÄÁÆÇÄÅÈÊÉÉÉÍËÊÉËÌÍÌÑÑÑÉ´“jH2)&&*$#$(20BOI]Ul_AGOXOYPMPDPUFIAOC9P1[‹³š˜Œ“‰~‰‹Œˆ†‹‰Š…ƒ†~ƒ‚~{ytuzsqlkbhifecddga``bfca_e]cdadnnlnoc]ZXTYw—¬ÀÉÐÑÑÏËÎÌËÎÎÏÑÏÐÍÓÐÏÎÑÎÍÌÊÊÅ»²©˜„`E4.,3327=;EBFCCILIVWUPQTWWYY€€€ƒ€zqj`YVVQAE:=@GE@:584/3:BLVip}ˆ—¡ª«©ª«®¬­¬®««­­¶½Ã¼©£ŸšŠ‚xm[OBOour·¬`@.*$%'))'&&-/*-AXbaqM #1199MulbUMKBQkC%%!(8Lƒ„ƒ{xhVJLTbKQ|Œx9Aeqa`cZcgfc|puosplps_–«ˆRBWJQNKk–d3/4:51?L[@5/-'$,:P_:1-.821--52/16=788:2410.-1<8866>=7:EI@74<92035GMQ\\klpstuz~~yy~}x|~€|‚ƒ„‡‰…‹…Š‡†‰‰‰ŽŒ‰Ž“ŒŠ‹‹Œ’””’šŸ£©¯°µ¸»»¿À¾ÁÁÂÃÃÄÄÊÊËÉÈËÊÌÉÊÊÎËÎÑÑÔÑÄ©‰]71+%%&&%13HJJ\RlfCOKYJUJLLBRUIIEHJAQ1]‘¯•••“‰‚’ŽŒŒ‰‰‰‹ŽŠ‰„ˆˆ…„„~„y}ywzonqkiojjbecabaa^c`^cY]`d^hnkrnfd\VNMYk­ÀÉÏÑÑÎÎÎÌËÎÏÑÒÒÑÐÏÐÐÎÏÍÊÉÇÄÀ¶§œ‰iL-'-+/5A>ABGEDGKNPOVTSSQXUSST……„„ƒ}xlb\VWOGBC?NK;?8905/7BFVgr~‰’—¢§©¬¬¨©¬¯¬«­©¬¶´´´±¥¡Ÿ—‹…yj[QQa‰hÍ¢<3.%'.&(((&*0)*)3M_wwG!&*29DwxjUIOLbrA%"#$*9Qu“„†weYk]@Z|Ži@3VyggditlTZ†}msnpw‚k†¤¢~ZiD5S_P“žW37648DFSB310,'*8RO55-+54/0.1/),487=62343..2049::6>=>?LJA87862127>FQ_bggstrwzx|{z{zx~€}€ƒ€}‡Š„‡…‹‰‡‹‰ŠŽ‹‰Šˆ‰Š”––˜š ££§©¬²¹·º¿¾¾¿¿ÁÿÁÃÄÇÆÇÊÈËÌÎÌÊÌÐËÐÏÔÔÓÏ¿™oJ,+)!$%75NGHWRh`FHJVGOGHK9<99:1:5225369738>ECHMC=6?=246:AKTefikotnntry{y~~€…†~„‚ˆ‰‡†‰‹ˆ‹ŽŒ‹ŠŽ‹Œ†Š‹•””—œ¡›£¨©­­±¶¶»¾¾½Á½½½¾¾ÀÄÈÃÅÆÉÈÊÊËÉÊÌÎÎÐÑÓÕÒÑƬˆT3,'$$49KF8WWffDAIQFSIDJAJRAHLQE8H6f–¥ ”Š‡ˆš‘“ŠŒŽ‘ˆˆ††‡ƒ‡…†„‚„}|{|{wsqppmnehbbd\^``YZZZ`cpv{tyqi_SLGRd­ÃÊÏÐÎÎÎÌËÏÏÒÓÔÒÏÏÎÐÏÍÍÉÁ¿·²ª›…rTB3-.8@EKONOPJGMNISSTYUS\S[Z[YWŠŠ…„Œ†…‚~ywk_]UQQRSMID=;/624?LXgn|‡’š ¢§§©«¨©©©¯­«ª©­¯¬¨ª§¤š“†zn^^l eaÀÂ^(,3)'(/).*,+((5>=HG~tB& $#$2:KƒŒtGINavc7-7+'(4IQXUMk†ycc•ŽEDPA=R~kpnylLR‡žxv‚‡ˆxlilš›g5//Z„dœ¡W3/7:GHN43+.($(=cW?83.7<<216..-5>83:OG23220424/:5::=;AFLC8A:9518>OPY_cmonpvvtzyy€|~|„‚~x„‰‹…Ž‹Œ‘ŒŒŒ‹Œ‰Œ‘““Š’“––œœž£¦­­¯²¶¶º»¼¼¿¾½½¾ÁÀÄÂÄÄÁÊÇËÈËËÎÊËÎÑÒÒÒÒÔÔ̺‘c:."%*,=<0A\ecA?JKLQBINEMTKGFK>:C:r £™•‰ƒ‰•““”Ž‘Œ’‰‹†Šˆˆ‰‰ˆ…††‰†{€{x~yrurtnjnhg\fc\VYV`_jvyzwvqfYOLLc°ÁÌÏÒÐÎÏÎÎÑÒÔÔÓÐÐÐÏÐÐÏËƺ±ª£‘ƒ`P;.-31@FHMOVPJPMRSSUUXYZ[YQQYXTUŒŒˆŠŒ‡‡…„‚zxng`ZURTSOFG82/*/@HTho}‡‘š££§§§«©¬¦¬«ªª¬¬¯«®¬©¦¢–tozp¡UlÀž;..'&,+(.,'**-%@ic\Xvi@'!#*AqŠcCIUneD.2:/#+DcY]A9FWumjyš„aMBBTVG>]‚zrvpubVn“¢‡u~ƒˆ{_eq~¡–b3)4Oen£…C299EK?37,.(,.9_ID11388663:/1.1596:FE43735+254626>>;FLSL:89:417DTQXcejwvwrrttzx}z€|ƒ€|z{„‡…‰Œ‰Ž‘‹‰†Œ†ŠŽ…ˆ‹‹’’“—››œ §®­¯±¶¶¸¹»¿¿½À½¼¼ÂÀÄÄÁÃÁÇÇÉÉÊÊÌÌÍÐÐÏÐÒÑÒÕÔÐßsB1.1.::49]c_G@LMNPHEQI[TJ@HL?4F=t¨ ›”Š‡„—‘’‘Ž““‘Ž‹†Œˆ†‰†‰†‹†‰ƒ„€€xzyz~upprihgllf]ZVYhjir‚ƒ~}sjjUIFQi—±ÄÊÐÒÐÒÎÐÎÑÓÖÕÕÓÒÑÐÐÎÌÊ°¨š‰yY@//*26>EKOQRKPOTNRRVWY_Wb]YURSWQV‡‡ƒ†ŒŒˆ‡ƒ„{woscb^`[SOF>/,+1@KUeqyˆ˜ž£¤©ª§¬«©©ª¬­­¬««®­§£Ÿ›•‹}y‡’~³Ž`t›t.0,+)0)(&$')!$,5j}{u|mXD.-+3KpˆvH=HZYJ=@6--*53--,+/=ZOH:23;4382723251=77@KD5374943:>=4BA8?MQQE<94957:QO`[finttsxwwz{~~zz‚„‡‰‹‹ŠŒ”‹Œ†‹Šˆ…Œ“’‘““•—›žŸ¤¥©­±¯±µ¸¶¼¿¿¼¼¿¼¾¾ÁÄÂÄÃÁÈÅÉÊÈÌÎËÎÎÍÐÐÐÒÑÓÓÖÔÈ«zI-,58009WfaG>NGGPCBRFPSCDEF56F;{ª˜”‰ŠŽ“›œ”’‘“’‘‹ŒŒ‡Œ‰Œ‹‰‡‹…‡„ƒ|‚|{y{yx{sunoopsgdfZbcltx€‡‚}qnbSNEVu›¸ÅÊÑÑÒÒÒÏÑÒÓÖÖÔÓÒÒÑÏÏÍÉ¿¬š†lV<0',)3=MPPUWTLOJOOXYY[[_[^]\SUNRW[ˆˆŒ‹Œ‹Ž‡†}tqja_bYSPKHCQDFPY0'-:_xuO<:87673235>@=>D97JOOH746=82=XR[cdqqustxvutx‚~{|~z„‚‡†ˆŒŒ‘‘ŽŠ†‡ˆ‹‹†Œ’’‘˜šž¢¢¦¨¨«­®³µ¶»½º»»¼»¾¾¾¾ÀÂÃÁÃÇÆÈÌÊÊËÌÍÎÐÏÐÎÒÒÔÕÔÔʱ€L0.7/+.N\XA=FDEFEBHWC),=g}]?9;>IfŽzbH`O>:60<55:.53/081999B99>85431.2„«’™”†ŒŽ–˜“™‘””‘”•“‘‘ŽŠ‹‹Œˆ‡‰‰‡‰„…€ƒƒ‚}xwwvyuquqmkeeemwx‚†Š}wohXSUjŽ©¿ËÐÐÒÒÔÑÕÔÑÓÕÕÔÑÒÐÎÍÎɲ˜ZD0+6.2=KT^ZXWNOOTLOSY]a]cfa`__STSTX[‚‚€ŠŒ‘•š”“Œ…|spj`ZRJD51)-6EVcv}Œ˜£¤«§­­®¬­«¬««­¬®°®­§¢ –‹„—ÂÇÌžFt`pVD991''()*()/,&+'0=BD-.2@Jz‘VM:9EE7<;>Ofc_LLazs~~‡“†ˆ•ƒ—n3*&7‹¯œa.+B\^¯–B/?;81.(/*/.5^KDB10@646773+-1.4A=@<=:984222.;9JJTI@Q?E,/6Fˆ¨•“‡…•–‘•–““‘•’Š‘Œ‘’Š‰ˆ‹Š‰„…Š‡…€ƒ~€{}zzyuvyn~kginru€„‡‰wkdXV^z˜±ÅÍÐÕÕÓÓÔÒÕÔÔÒÕÔÓÐÐËÌÉƹ£wT:,**;:OZ\[^Z\WUQRNQ[a_d`ecba]ZTOSP[^~~‚ŒŒŒ“–™–•Ž„zvpdZQGCH<'(-7IUZMN@=:DFK<8=DOVjpylL.,'*;c‹€;89;;MF9:;@ZegYW\alr}†ƒ„‰…{Œœ”£‡K$!&k§²™N+5UP˜¶\62588/--())6XO@:24632:=7935>52>?F=A3/2945569N5?C??UV^cI>211*7WSWZpsqsqvy€„~~|~rnv{~‡ˆ‹‹‹Š†‡ŠŠŽŽŽŠŒ‰†‡†ˆŠ‹‡Ž‘”–œœ  ¢¢¦¨©¨ª­®³³³¶·¸¹º¹¼¼»¸À½¿ÃÅÆÆÇÃÄÉÉÊÎÏÏÐÎÐÓÓÔÓÕÖÔ××ѹˆT1)6APTB2>9B77@LGPC?K;D).5L¨•”„„š••’˜”‘’’”‘ŽŒ‘Œ‹‡†‰……†††…€„{|~xwwzwutnkmqz~„„voi_Zcˆ¤ºÇÌÑÔÒÕÖÖÕÖÔÓÕÖÖÑÒËÊÊÈ¿² gG0%+17FP[[^ZWSWZVQQS\aagdoe`\[Y\ZSW]`||……Š‘‘“™›—“•“†ƒztkcVGB;6*&6IUfp|†“¢¥©­°¬®¯¯«®®«¬­°²¯ª¥¦ ™ŽŒÄ×Þ¬cZdGY;;?A82/,-1)/)&*03APQ9 %%3FNC>B@C:=38AV>B>?LejgSV]Xdqs†„„Œ‚ƒ£—„¤Ÿg1#%<Š±½…;5`Wb¸€686/1-'1+/-9UP;:46<5161;26533.<8D?A7,252915;R@L;@GRY^`YB9-221MVJ_ostsrvxzƒƒtqqtx„…‰ŠŠŒ‰‹ˆ…†‹ŠŒˆ‰Ž†ŠŠ‰ŽŠŽ““–š™™ž ¤Ÿ ¥¦¨©¬­±°³µ´´µº¹¸½¹»¾½¼ÀÀÃÄÃÅÄÆËÊËÍÐÐÎÌÑÑÐÒÔÖÕØØ×Ò¹†M55FNXCAE@D?@JPPUJLK?I.7:V”­’™—‡‰–’˜“—•‘”’—’—‘’’ŽŒ‹ŽŠ†ˆ…Š‹Š†‚„ƒz{{zxzspptu|ƒ„‚†vqnfbnª½ÈÌÒÔÔÕÓÔÕÕÕÖÕÔÖÒÎËÉÿ¸¬“|W;,%-6GNU[^WYYUTRXSU]bhfhefi`\YY\SV_efƒ‚†‘—™———•’ˆ„|wi^UH@7.+7KTbn|†“š ¤¦®®­¯®¯¬®®¯®°±±°­§¤—•˜ÇÖÙ–qx€iV-2,762145@637:/;@@IM7-,-8LYLGBB:<5400=?BFIC@;@:4#$%=bˆŸs@/0F?@XIED=BLgshVXR\gp„ŽŠ„yˆœ€Œ¥}J((,^¥À´c>qUL¥ŸG/2.)*+0,*15VHD34396/74985/477<>EBD37315749;S;EC9OO^cgfM63,-+CLNSpvqxtww~~~zqprx€†ƒ‰ˆŠ’Œ‰‰‰ŠŠ‹Ž‰‹‹‹’’””˜–›š   ¤£§¦ª¦¬ª¯²²¯´²²¸µ¶¶»¹½¾½Á¾ÃÁÁÁÂÅÇÉÊËÊÍÍÎÑÒÑÑÕÕÓÔÖ×ÖØѵvD-9AP?0;4<58IPTREJDEG(38]ž©“”“„ˆ•””–š•‘“‘Ž•“ŒŽŒ‹ŒŠŠ‡‡Žˆˆ†ƒ‚‚„}}„‡wwuvrtx|~}€„{tpehz™±ÁËÏÒÔÓÔÒÔÕÔ×ÕÓÕÓÑÌËÇú³¤‘pQ9/,2?KUZ\U^bZ^ZYQWV_`akljib_^XY]YT^e^z|€ˆŽ”™˜™™˜–“ˆ…††}qbWMA6)*9ASbq‡™ £§¬®±²°­­¯¬®°¬´¯«®¦ ¢—–ÏÛчy‘‹¡_%$)8&+14:=;<655D=ALF?4-+9X`QC>89?:@AB468;14,/>22/),:V‰ŽrP3)8:DRQMIJADUomZ[PU\iŒ’ˆ€ŒšŠ]“‡sG58I›£È˜XyU>ƒ¸k8:58/24517;XIC8>7<6;<<=959;;<@?ECI86738399@[HG@9KUbhieY@72.-?TN[rztzwvv~yysgoy…Šƒ„‡…Š‰‹ŠŠ‰‰Š‹ŽŠ‹ŠŒ‰‹Ž‘“””–™šœ¡£¤¢Ÿ£©«§¨¬§¬°¯°²´¸±²µ¸»¿¼½½½ÀÁÁÂÃÃÈÆÍÊÊÌÏÏÑÐÒÒÔÕÔÒÕ×ÙÙØϳp;87HA/14>75@DPF;MJNG)08a¤§”‡‰“–“’””™“’“‘’Œ‰‘“ŽŽŽŽ‹ŒŽ‹‹‹‰Œ‰Œˆ‡Šƒ„„€„€€€}xyztxw}|„…‚~pon…Ÿ¶ÄËÑÕÓÓÕÔÕÕÔÕÓ×ÖÕÐÎÊý´§šƒgH5509FVZY[W]\_b\[XUXdijunjih^_]VUSW_`_yyu~~„’”–˜™™–•‰ˆ†ym[YF2-,>IQ^n~‰–›¡¦¨¯²³°­­¬®­¬®°±±«ª¦¥Ÿ—•Ž•ÇÜÇu\tŽÆi$%"'#%0188<<<;9AI?OKG7/':RH@<833:CC@D@6=-++/20>C7/.8Npkph=)-8GRJLTIPKN`ygeeSUgv…’Œ„Š|‹‰_u‡…n]TE‰‡²¯t`B9[¸Œ@3.,,-1643=bKE;=9F5>6=<859478<?5;B^IIC@NZdhig\@885,?RP`w{uƒ{vsvytltx‡‰ˆ…ˆ†‰ˆ‰ŒŽŽŽŠ‰‡Œ‰ŽŠ”˜•˜™œœŸ¡¡Ÿ¢¥§©¦©©£ª±«®±²¶²²²µ·º¼¼»º¿Á¿ÁÃÃÆÈÇËÌÊÎÏÎÐÐÐÓÒÔÓÖÚ×ÙÙÖϯf9,?C.3/;.6HFJ@>HNO<)1;i«£‡‹Œ“•›–‘“’’•“‘ŽŒ‘’’ŠŽˆˆ†‰ˆ‹†‹‡‚‚‚‚|yvyxuvzz‚†~ƒzupp‰¨¼ÉÎÓÓÓÔÕÔÖÕÔÕÖÔÕÔÐÌÅÀº¯ Ž|^A218DO\a_\[[___[[YZfkols€nje`c]TQT]`a`ggkp{ƒˆŒ”›˜™“‘•’ˆ€pePB4*/6HXep}†“˜ž¤¬°±¯±±­²®°¯­¯µ±®¬¨¢ œ”ŒŽ®Ð¿gNMÅO$)$-).-,4361,41AMGGABA41567;4,14GU]IFA972$+++-?L5,,44GRgu[5/3;GD?HGUIIKovf`VO]vˆƒ‰…€~di‚Šuncyz|—Œ\02@©¯W.0220-3,2:^G?B=8G467162-./35<BIVLAE[zrg\USw‡‹‚ˆphŠŒaOk}_Py¬€2.5ŒÅv6.+-),(',?bE?9@:889/00.48BFCC?K\ivvgdP6*0+6QLWpzv~trqlm{€ƒ€ƒ€‰†ˆŒŽŠŒˆ‰“Š‹‹ˆ’ˆˆŽ’Œ‰Ž‹–“•—›˜›Ÿ¡¡Ÿž£¤¥£§¦§­°¯°®¯±±¯¸µ³·º¶·¸»½ÂÂÆÄÄÇÊÊËÉÍÎÍÐÒÐÑÕÓÓÖÖ××ÙØÛØÉ‘G1:0*'-32?LB<ILcvteWQr‹—Š€…ŒˆsŠ‘l;i}P8dðU.4qÓ¡7$(&$-(%-<-&0Aƒ¯Ÿ‹Ž‰‘‘”–”–•‘”‘“–’‘Ž’’ŽŒ‹‘‰ŒŠŠ‹ˆŠƒ„ˆŠƒ„†…‚~y}~}|ƒ‡ŠŠ‡‡€€{|†¨¾ÈÎÓÕÖÖÓÔÔ××ÕÕÔÔÓÑÍÊ¿¶¡—ƒoYJB@LNVac`ZYX\[[]_cdjpnjonnjd_^^YTZ`bghh<&&0IŒ®›‰‡‹‡–”•’•“”’‘‘‘Ž“‘ŽŒ‘Œ‹‹Š‰‹†…‡ƒ†‰‚~„…}~}}€……ˆŽˆ‡~}|Œ¯¿ÉËÕ×Ø×ÔÔÕ×Õ×ÔÕÓÒÏÌÉÀ²œŒ{bTFGEM[_cc]T[]_b_adcejmtpomjdeb[_X__bbggh338O`iv|†‡’£§£¥¤¡™“‰ƒwgU5*&5BS]m‹“Ÿ§ª±³´²¯²¯¯±±±²´³®¯«£™ Ž¿Åz}‚MT?,)*(*(3++++6,..;_N3/0;<5851,,/)0J`olZ4,OSF.'(+'3RvS1'0*1S]LTZeC18BONLKIGUC[th^Xywysuowt•Ž}Ž¤§|‹j@,;f®Z;UÐÎf,(%&+%*.7YB=@6:D678693-265:5>AD;5<<65.+/7II>?ETiozxsiaI3/+1PTVbshsgu€~…Š†„~„‡ˆŠˆ‰Š‹†Ž‰Š‹Š‹‹ŒŽ‘‘•–™˜™˜œ¡¥ž¢ £¢¥¥¥§«®¯ª­°²µµ³¯¶¹¾¹º¼¿¿½ÁÄÅÆÂÆÊÌÌÌÌÏÐÑÓÑÔÕÖÖ××ÙÜÞÝÛЛT60-,03G[X_J@L?Cni_Z}}hcokm}‘Œx ©¯š‹‚_0$*6¾BQÆÑq'!#%'%$'0X<D77>8433'-2BJ;5MXou|vqkcK6-).JNVdl`unz|€†‡ƒ„‚ƒ†‡†‡ŠŒŽŽŽŒŒŠˆŒŠŒ‹Ž‘‹ŽŽ”‘–˜•••—˜œŸ ž¢ ¥¢¦§§¨«®¬®²¬²±´²±µ¶½¹º»¿¿¼ÂÃÃÆÆÆÉÉËÍÊÌÎÏÒÒÑÒÖÖ×ÛÙÚÜÞÜØÁ€J,(*040<6/.5@@%*5`š¤“‰ˆŽ’Š”“‘“˜‘’’”‘Œ‘ŽŽŒ‘Š‹‰Š‹ŒŠˆ‡Š‹†……†||€ƒz|ƒ…ˆ…‰ˆ‡‡‹€†œ´ÂÎÒ×ÙÙ×ÖÕÖ×ØÔÔÕÕÒÍÈÁ¹¤Œu`PNNRPUZe`_W]cbdbdehmquvwnib]X]]_\a`ijiiih%%.9O]ns™£¤¢¥¨©¤ž”‘„}pW:)"0AR]q—ŸŸ¦­­®²µ¶³²²²°³³´¯­®¨¢¢–‘§×žocF[c/%-%)/.*++17/.1Tg6124..E=372/**3Qi~mL2*=X@;+$)%'=anT<-'*;jO@9RnaF2C^f_SSG@;Y[c_u€\Qkvq†wy£¨° ”uQ+'&)P ‘NO·ÓŠ($" " %$7P>-/.A;77O`hvx~qqlQ2&)(OISfck{v~|~‚‡‰………Š…†‚‰‰‰‰‡‰ŽŽŽŽŽŽŽ‰ŒŒ‹Žš”•™˜™˜œ›ž  ¡¢¢¡£¥§¨¬¨¨°¬¯­±²°´¶¶·»»½¿À¾ÂÄÄÇÉÉÈÉÌÌÌÌÎÑÏÏÑÓÖÖ×ÖÙÙÝÞÝÜÓ´f1&'/.3=;.-3F5%&9aŸ¢ŽŒ‚ŠŽŒ–’—“Ž””‘‘Ž’“ŒŽŽ‹’’Œ‹Œ‹ŠŠŒŒ‰ˆ‡‰…†…ˆ‚~…‚€Š}}„ˆ†‰ˆ‹ŠŠ†Š§·ÇÌÓ×ÙØÕÓÔÕØØÕÔÓÒÑÏÉ¿³Ÿ…jVIHPPST[`^WX^cca_cfjprrsola^ZWa[_\aecghldf&&*4CScnx†˜¤¥Ÿ¦«§¨ ™†‚r^=-(/:K`s‚—¡§¬°²²²¯³²³±®¯±´µ³®¨§žœ•‘‰Ž»ŽƒsI{(&!+*1&((60%,FfR2+)21*2@092220/Us~qS,+:N>;'%(#!,JbbC3&.EJ_]p€^Ql‚„€qlu™—®¦•{P,$$%3cˆiO¹ÚŸ0$%&$#&*3P<:8/ED23.47/+-514;DQRA/4;8><+*8=:=:R`psvxumaU8.('$%(.9m:(.7B3$&7l£œŽ†‚ˆ’—”˜“‘’‘‘’““Ž“‘–’’Ž‰ŽŒ‰‰Œ…‹‰Œ‰ˆ‹‰‡„………~„|y~y„‚‡ŒŽ‘‘˜­ºÇÍÔ×ÙÙÕÔÖÖØÖÔÔÑÑÑÍȽ­—t]LKKMXU^`_YVWafedbeflsunpi`b[X^Z]^efhgikijd##',4BOer‰—¢©¥©«©«¢’Œƒ|]D)&-2Mar™ §«±³²°²¯¯±±¶µ³²°²¬©¤¥œ”ˆ€†qK“x2"%#.5+0(+31-4[RB4,**252612.4-/4LnƒsL)&4K;H.'+$"*7E`aJ1%/aVE:8KdhYOMgfefe\L@DS`tx]Rp…‚jh‚Ž‘¶¦xd8'!+H‰}NºÜ²5"3$)$(%:OE><4GD2,24/--*33467KZ:.<792:-.7?9NO264/5./364.29JT:2/868/)07;7;N\hsqoqum_P/('%BJYhkupq€……}€‚ˆ…††ˆ„„‹Š‰ŒˆŠŒŠŒ‹‘‹‘’‘‘Ž•’““˜–––›š¢  ž¥¤¦£¥¥©¨ª¬«®®¯³´¹¶´´·»½½¾½ÂÃÆÃÆÊÉÊÎÐÏÐÑÏÐÐÓÕÔØÔÖÛÚÜÝÜÝÛÑšD:%.-32/*40'!(=¡—˜‡‚ŒŒ˜™’•’••”’’‘Ž’ŒŽ‰ŠŽŒ‹ŒŠŠ„ŒŠŠ‹Žˆ„ˆ„ˆˆ…„‚|}}|z|x€‡‘œ¤ª¯³¹ÁÅÊÏÓ×ÕØ××ØÖÕ×ÔÓÓÑÎʯšjXNPUX[^\ZW[\`dgkjlorspoi`_aYXSXZ^fggggh_bhc%04,)(+3-,'.0?39K?50+,-.42/4-+0*010Ru‡sE+./HTL?'(("'/#,JccZ=?gK8.;OM[[XL^stqvmnL?S[^WOf“€y””z—¦Ž\>EsÃœ±×·?,,+(%(DUD4;EOO20464-03094;8GB7*2./252,656M\hai`D-1NA;WjWJrslnfjbMSRZRIXu“–¡˜‡›š”<#(:TJ4:kì·Ó­9" ")GN=06LXO132.72(3.=766DC63-049E?4898KX`lmqjhfcc\@6'9064.5--,.2:,91.*,3Mlr6$&+:TN21(()251)776@OUV[J:2YO6H\eW`sji[^SPQ[]NPZv’˜–—Œ—›¡‘S'$-]P12j¼´¶Ð .$)$%"#)KFJ14OhY1+08/++62-*67N>34./08.23<8=T^jsroja^dmeD9',8S_Xtxwv~ƒ‚„‚}„„†‡Š‡‹‹‰Œ‰‰ˆŒˆ‹Š‹Œ’“•“—Ž“”š’–—˜œžœœŸ¡¡Ÿ¢¥£¨¨²ª«¯®²°°¯³¶½¸·¿¼»¾½ÂÆÆÇÉÆËÍÎÎÒÐÐÑÒÖÕÓÕÓÖÙÚÛÛÝÝÞàÜÏŒ9)*,'%$'+ +[ž”™œˆ”—˜™‘“—˜™‘‘–“‘’ŽŽ‹Žˆ‡‡Š‡…††‡‡‡…‡†…†…„~z|yyyŠ˜¡«²½ÃÄÄÅÇÆÌÑÓÕ×ØÙÖØÖÖÖÖÔÑÑÍÉ´¤Šo]XY][Z^f_\_`fjefllnpsqkhcbZYX]YYbaelegdd\fifg('+26Q`z‘˜¡ª­«­®¬¥ œ†mP.&%&/H[o…Ž•š£¤«°³·µ´±´³²³²´¶±¯®®«£¥—‘ƒtxhz²i/5143//-.2:?@:.472/4-14-01/-32(6O}˜Šn6&&'.KYB5#$(?;.#/:9757=H<.-N]>:YjZVfqeQcUGR]YLVbu’”•••y¡¦j( 2D6-1g»»¶Å/ #)'(%)MPN/9Hg]3/885.3=+/.;$(0G>0&3>D8)#4=2.08dP6Ofg`Vlk[X[KLYQPQbp„—š…ms¯¥‚wM*-.,09[¸¾¸¹r*("(,+-7WSV37G_O;85:5557641=;C<6.,*-00-9:7LWajkb`_nsut`D/1*?`\cfqx|€„‚‚ƒ~†‰‡‹‰‰‰‹Š‹‡…†Š‹‹ŽŒŒ†Ž’“”Ž’•–™œ››šŸžœž ¦¨¨©¦¨ªª­¯®°²²·¹¸»·¸»½½¾ÂÅÃÉÇÉÌÍÎÐÐÑÐÐÔÕÓÔÑÖ×ØÛÜÜÜÜÞàÛˈ1 %)!$%(!#3l‘’Ÿ•Ž„Ž‘“”••—–˜“’’‘–“˜Ž”‹ŽŠ†‹‹€ˆ„‡…†„Š…ˆ‚€ƒ~€|||y~ƒ’¢­¹¿ÄÅÉÇÈÉÊÌÏÓ××ÙÙØÙ×Ö×ÖÕÔÓÍɾ´¢‹scZ\V`Z[^]Z]dcjkllnppurnje_[^[\^]]ibjpcg`^^keli!!!&.6@H`uŒ—œ£¬«®­©¥™“rQ3! ,@Zn‚’š¢¨«°´²²±°°±³¬¶µ··¶²®¬¦ “•³zq61,5:/%(-0:A=11/.6+++&-,4510-2+3@l’’~d9#$%(@WM9+'2KA9/5=B9+$*27>64YX>CeleYrvdXd\CRH=VdoŒˆŠlq†¨Ÿkrn3&0#+1T¸ººšU*&!"%)8WUW);JUM//9;47812227AH=@3-+0+0;:5=R[\c]ddgv~{tdI6/21*&$.39:*+,-&3M|•ŽvY8$-(*2@D9*!9M?3+*?J>,('2;007Na?;TgY`jxsab\XOH8Viz’~kƒž¡žkg€N.1-+1T·¶­n=4:("#&+3VRG+:MQK009<00--33.7@A,*%""% ">Ž“Ž’‰›’—“–••”•“”’“”•””Ž’Š‹Œ‡‡ˆ…„†‡†‡‡~€€‚~}yx|†Ÿ³ÂÉÏÒÕÕÒÑÌÍÊÊÏÑÕÙÚ×ØØØØÖÖÕÑËƺª˜‡o`^W\^_]ZZY`eeeekqrpptrrgf_YYZ\_abikgjihc`]ehifb !%-=Wt‰™™ž§¨®¬«¦•†pS8 #%0?Ri}Š˜™¡§ª®¯¶³³±²´²¯´±·µ¶°¯©¥ š—…–¬‚hHF+.:0'01=D;136*'3*,+*'-85&$%.-UˆŽo[>02-035A2-)FU7654421@4(58,/,8OK>WbCYr{vlNDKEF:>Pt¤˜†–˜yYs¤Ÿy^Q>GŠ¶œƒ=q¢/$%KXOL2ELA?23961?=/-34884605C6317@<r—…zŠnb>$*$'(/657*EL42;6'.27.-6?-+11IF8H`BLnˆyt\:69<684<33C@.360276443;:2:5:/2F@.471%*-0+1::33/)BDA>FA8d}†d<499?FVˆ›‹‹ŠŽ˜™ }Q5zŽ„>Vzœ³«œ‚‹²È¨F###(FM=?1>F8DA:91:CD4./52:10405>6087;NVjqzv}|{}xxvdT.+$$*7Pmƒ‰‘¢¥¯³·´´³²´²³µ³´¶µ¶¯®ª¥ “‡€™}<1(.258:D?8))+9%,)3,-/*1-/"(%,8S~uNswT?4$,(',)/6:EM='+93!'&(/*7G78*&@J>B524Fm‡†nE.BFUM]ˆŒ‹’–œ¡•wJTD50;<3=D=<45BF8216734.372?/B>;JS_nx{t}|}€yy{t^F3/KY^_mpx{|ƒ€€‚‰ŠŒŒŒˆ…‹‹‹Šˆ‰‰‰‡ˆ†Š‰Š‹‡Š‰‹‰ŒŒŽŽ““’’••’–—žšžŸž  œ£¤¦ ¡¦¤¨¬«°°«­´³¶¶¹¸»¾¼¼¿ÂÂÃÄÅÉÍÌÌÑÐÏÎÓÐÐÒÕÖÔ××××ØÚÛÜÝßÝظO!" -bˆ‹’‹’ž•‘Ž—•‘“’‘Š“‘’’’Œ’Ž‹‘ŠŽ†‹Ž…„†Œ†ƒ…‚€{{~{zwuvzƒ¡ºÊÒ×ÚÛÛÙÙÔÒÑÑÓÕÕØÙÚÙÙÙÙÖÕÒÎǽ«›‡yfd`bc][\WRZde]flmpuutohf_d_\[Y^bcjjhhhghehoajkdVO"" '&6Kg{Œš¤¨¬­­­§Ÿ–‹|bC($()8Sm{‡”ž¢§ª±´²µ²°°­µ·±µµµµ±®«¦¢œ–‰…”€D12.;D>@79*$&+-+,-/,,103*(%.)=XzqI>nrC93).(*/.+9H;<)#=UA8GE4BgyqW=@Ne`b‹Šˆ‡‹–œ¡™’Šx`|Œ[c ©›uMQ^M;(,/(3GJ<6.?=1ND@322>=5:6?>2,15.2.4I@>OSer{yw{}z|{|q\F3,CZZ`jn|w{|ƒ‚‡ƒˆ†ˆ‰ˆ‹Œ‹ŠŠŠ‰††‰ˆ‡†ŒŒ‹Œ†ŽŽŽ‹‹‘•”—“–šž  £¡ž¦§¨¦ª®°¯«®³±·¶¸¸¹¼¾¾ÂÂÅÅÆÈÉÉÈÉÐÑÏÍÐÒÐÒÒÓÔÖÖÖØÙÚÚÜÞßÝÚÅt$" 4k‡‹Œ“Šž›•Ž•“’’‘“Ž’Œ‘‹‹ŽŒˆ‹‹‹‰‰„„‚€„„„…‚~€€|{{w}|x~‡¥¾ËÑÕÙÜÛÙÕÓÑÑÑÓÕÔÖØÚØÙÙÖÖÒÐËö£–…ufhf_c_]Y^V\`[bklpososnlc_^``Z^]aehjgiggkabeba^YWS $-+31.+))236FPF7&(3:*'/(0/7E:5' /TJ54<B8>8E2.3?;617?:3251183..M…bIUJ0-)./38=KQH6.&86+&$$,1:DF5()O_;@8>]xniowzviphq…Š†ˆ’uD?s‹Š”œœŸ¸¿±Ÿ_9)#$ "4aB*6L=1/7=>0<8@9,9;<21/?:7921569CEAKMZqx{€|{{xzsfR<0,O\[]fp}~€„†‚„„†ˆ‰‹‹‹‹Ž‰‰‹Šˆ‰‡‹ˆŽŠ‰‰‰‹ŽŽ‘Ž“‘•’˜““›ššš› ¡Ÿ¤¢£¥¤¥¥ª®®®´°³´²µ¶¼¼¿ÁÁ¿ÄÄÅÈÇÉËÍÒÎÏÎÐÑÐÒÒÕÑÕÕÔ×Ö×ÚÚÜÜÜÜÕ¯E'>€Œ„ŒŒ“—š–‘“‘’’‘““’ŒŠ‰Žˆ‹‹‹ŒŒ‡‹ˆŠ‰ƒƒ†…€z}~{{|xxz€”±ÄÎÒÖÙÚØÖÓÏÐÏÍÑÕÖÙÙØÙØØÖÓÐËô¨—Š|qmijkffd_]`__banrwvuoikgf]_Z[\_bfjkllggad^^]\\ZRRP"!"(6O]}Ž–ž¥«±®ª§ –Ž~oF,%$(3PdyŠ— ¡¨«²²±²²°²²°¶³²²²´±¬©¢¢œ˜’ˆyvkSC:;DH7,++++*/0.++..6-&-)8;;JYL/'*4^WQS<510,1/0?SPD8/')50/+'+46CL<'#+SaJ0:47KXP]ry‚{yq…†€˜oQ>Q€…|†—ž°¸ªŠxW@)$'3ZU2)AH>43=N=+=:A@0:?<2,5>;1/24215CEFOVdox||€z}||~{vmN;/.T]X`jnyƒ‚ƒ€„…ˆ‚„„ˆŒŽ‹‰Œ‘‹ˆŠ‡ˆŽ‡‰‰Œ†ˆ‹ŠŠ‰‡Œ‹Ž‹Š’–‘’•—˜šŸ›Ÿ¡¢¡¡¦¥¨ª©«­¯±°±±³´¸»»¾¾¿ÀÃÂÄÇÅÅÉÌÐÏÐÌÐÑÏÐÓÔÔØÔÕÖÕÖØÚÚÛÜÜÚÄj =}‡ƒ‡”“’‘™˜‘”•‘ŽŠŽŒŒ‰‹ŒŽŽŒŠŠ…‡„„ƒƒ„„}}€€{~{z‚“¯ÃÍÓ××ØÖÓÐÎÍÎÑÒÖÖÚÛÙÙÙØÕÓÌǼ¯œŽ‡ypojjjcjfbadba_cmtqturoiji`a\]`_aahhldjhhbi[__UVRTO" %(2Jo}Š–¥«®ª«¦¢–}lV4''+>Nc~ˆ”™£§­°´°°®°²®­­­¬¬±±­¥¢ž˜›’ŒuteK0/0-,$/FX<:;0&)0*,*()59GA6("*OcW:6.*3==Bgm{ˆˆ|}‰›€o_YNa~zˆ”š–“—¥˜€\I201260=KGKMWfoy}~€|{z{€{lH900RY^gjr|‰€„………†…‹‡†‰ŠŒŒŠ‘‰ˆ‰‰‡†Š‰‹‰‰‹‹Š‹ˆ‹“”“˜‘“š˜Ÿ˜›ž›žŸ¡¡¢¢¦§«¦©©«­®±±°´µ»»¼¿Á¿½ÂÃÅÆÆÊÈÍÍÎÍÍÏÏÐÒÐÓÓÔÕÕÕÙØ×ÚÛÜÚàÝ͆#!Gƒˆ‰Š‹•–œŸŒ’Œ‘”ŽŠ’ŠŽŒŠ‹‹ŠŽˆ‰Šˆ†‡……†‰„‚€„~~z{{~‡„™·ÆÐÕÖÙÕÓÑÎÍÍÏÒÓÖØÚÛÙÚØÖÓÒͶ¤™†~xutlngffdaaa`aeekkqqpooid`]Z[_^\dighffig\]a`ZW[TRQL!!"#"(/Bg‰–œ§©¬­«§ ›‘}tZ7)$/>Ocy†•™£ªª°²°¯ª¬ª¬««§©ª©¬«©¡¡›˜™ŒŒƒzwG;-/91..1,00+-+.4641--7S_^>62/(,;9d[O[[U8,8,&)4MR2@C4&)30*%.03>I1-4'.P_YA5///867Bax{‹Ž€r†•}{knVRfgo™y’©±¶¥yrˆr?5=RN9214B04@]LM][K.&814-;T\T=C1+,'4;AYx€ŽŒy|p‰Žx†cmhF>28PitYj£—Š•’ŸˆrkvtgS@9FH.7BH\[J9;325887/13//6HIIJQ\ir~{zx~}}xx_H9+;T`bel{{}|~„„„„„…‰ˆ‰‹Œ‰‰‰†„‚‡…†‡Œ‰‰Š‹‹Œ““”—––›—œžœ¡ ž£¡Ÿ¤¤¤¦©ª§§«°µ³¸¹¸¸¾¾¼ÀÂÀÅÇÉÇÊËÎËÎÍÏÏÎÐÒÓÙÓÕÕÖ×Ö×ØÙÚÛÛÛ׶W$]ƒ‰‹Œ•Œ‘—“ž™’ŽŽŽ‘Ž†Ž‹ŒŒ‹ˆˆŒŒ‰ˆŠŒ‹‰ˆ‡Š†‰„ƒ€€~~~||}€ƒŒ¶ÉÎÔ×Ø×ÓÑÎËÊÍÐÓÔÙÚÙÝÖÖÕÎÉĵ¨”‰€zwu{qhgh___ccchlifnnsknfac\_[[\\^glhgbildbcibRQU\XQQ%"$4@\m‰” ©¨¬­«¦£›‘…u]4$",8K`r„“›¢¨­°²²´®®¬®«¬««¯±°®©§£Ÿš”Š†Œˆ“q=9-,.5:62/01/>HKMSXenv{€y||‚€|zy_L@1FUcmgr{{}…„†ˆ‡…€Œ†ŒŒŒŒ‰‹‹‹‰‰…‚ˆ…††‰‰Œ‹‰‡Ž’”—™™”˜šœ–Ÿ¡¢ ¡¢¥¥¨ª¨¨¥ª°µ±¸·¶¹¾½¿¿Ã¿ÄÃÆÈÈÊËÊÎÎÍÎÎÐÒÐÔÔÕÓÕÙÖØØÙÛÙÚÜ×Èz" %_ƒŽ‰Œ—”“˜Ÿ’’ŽŽ‘“ŒŽŠ‹ŒˆŒŠ‹ŠŽ‹Š…Š„‚|x}|{€€ˆ’£»ËÐÓÖÖÕÑÎÍÌÊÍÏÑÖØÚØÚ×ÕÕÐɽ¬œ‚|wrwysjjkfafcb[cdhlplmnmaZ]Y\[Z_b^mlhhicgb^]e`TTW]Y[X#%/LYq„™Ÿ¨©­®®©¤œ“‡vV0%&*;Kcx„”›¡©«²³±³°´¯¯²¯°®´³±°©§Ÿ ˜“‘š‡k6FO,*)*2-)9--.+,697-+10G0:/15:55+4]WVOF@75,.>BL8307C<+-6<+93.,2MC&.8WisA$E,-75,(-;,.-4.431,-)002435>67.14NXTOHA5@7)AA44'/.D>-781-+#&(7A;1(9Uoj9%5I7 '85ASb}ˆuTqŒ’n\k’ˆdbtP*"%,G|2$-.*MO(!"-LJYIDHy¨§~mmhFS-+5AE[_t…rLdq]Xy’ƒ]v8&,/<{B#-*3W/! %/DBA55:OeX>IeƒiUN=54688=3)553GDKUUWciu||z€|ƒ€~~dPH,;MTg^lxƒ„…ƒ†…„ˆˆˆŠŒŒŒŒŒŽŒŠŠŠŠŠ‹Žˆˆ‚„…‡†ˆ‰ˆ‹‡‹‹ŒŽ‘’‘‘–˜–›”–˜œŸŸœž ¢§¢¤§ª§®®°®±²µ³¹º½ÂÁÄÀÃÆÅÆÈËÊÍÎÏÏÎÍÏÒÒÓÔÓÕÖÖÖÖ×ÙØØØØ×¾_5u„…‰’‹’—““” ŽŽ“‘‘ŽŒŒ‘‰ŠŠŒ‰‰‰‹‰Œ‰Ž‡‹…†‡Š‡€€|€}‚}†§¾ÅËÑÕÙ×ÑÎËÈÉÍÑÓØÚÜÛÖÔÑÎǼ­šŽxxupwxjkgffc\[_fbejfofddb]ZUUVX_geiihhik_[\]b\X\V^]W`[!!% #0/Nc~š ¥®­®¬ª¡™ŠqWD&'+GG_uˆ˜Ÿ¥­­­³²¯³³°³±³´³´²²¯§¦¤’‹›{kU45/).45:3+-..-.-2./3,,8109A=501+:AGLHC:;4-57<10+0<7DE6*.'-(#$1?50-118CPCG::23<<3,/7.1CFKB,1+%('&6H5+'-?WjHS9$">l]AKP[agzxyxsav‚viqƒ…{C)1=p`'))F6%.)-BGIA1,1LD24?;>G}iCA9//.3-129CGKSXZ[kqy{z€€~€‚€‚€ybS60PWeffv†ƒ…„„‚ˆ…‹‰‹…ŠŠ’ŽŠ‡ŠŠ‹‹Š…„„‰…‰ˆ†ŒŠˆ‹ŠŒˆŒŽŽ’Ž“•••—”•›™ ›ŸŸ¡¤¢£§©¦¤ª°¬«ª®±¶¶¹¼¼ÁÀ¿¿ÇÆÅÇÇÉÈËËÐÒÎÏÏÐÐÑÓÕ×ÒÖÔÖÖÖÔØÛÚØÎœ)!=?;.4L=.zˆ“‘—‘•™’•“’’‹”—“ŒŒ‘ŽŽŒ‹‰Š‰†…‰…‡‚„€|€‚„†‡‚€…‚‹–ªµ¿ÊÌÍÊÌËÉÇÉÍÐÖÛÜÛÖÕÓÌÆ¿±¡{uvvxqpmlhphgaZb_]baij_Z]TLRXWfcfkjjccci_]]`e_]`ZY]Y\]``&&%)"!&'2C`wˆœ™ž©««©¥Ÿ›‰y^D.-4AM`w‚’—§ª­­±±¯±°²±²±³´±·°±©¨¢šŠ’¡£qi6;7;4'45++,.)()492.+3-:EED=B1(0604@G==8??C@-+)161133J[5)'*+-3>B.#)>^[>6UlT<=>UhfSOeNAUeŠƒgnj]KZr}‰•ŒŒX.6Xs+,6/*'0.;?68+0;>6B552(,--39MOSVUchiqx|~z}ƒ€…€|xmSI58V[gnl}…„†‚…ˆŠ‹†…ŒŠ‹ŠŠŽŽ“Ž‘‹‘Œ‡‰…‡Šˆ…‡‰ˆŒ‡ŽŠŠ‰ŒŽ“––”—˜™›šœ›™›¡£¢££¤§¥¤ª¨§¥«¬±±¶··¸¹¼ÁÂÁÃÂÇÇÆÊÉÊÊËÎÌÌÌÑÐÐÓÑÑ×ÔÖØÖÕ×Ø×ØØÕÀg#E{}‰Ž‘”‡›’–”’’•’Ž’ŽŒ‰ŒŽŽ‹Š‹ˆ‚ˆ†€„‡€„‡…ƒŠ„ˆˆŽž¬ºÀÆÈÆÈÅÈÆÉÐÑ×ÚÛÚÙÕÑÍɺ¬™‰xrtrqospfmkbaa\Ycedje]VMIKNU^cgilhlfcdc^ZUbc[^a_c]X]ebc!!#$"",2B_tˆ•˜¢¨««ª¢¢˜ŠzaI5/4P]depyƒƒ…ƒ‚†ˆ‰Š‹‹Ž‹Œ‹‹Š‹Ž‹ŠŒ‹‹†ˆŠ‹‡ƒˆˆˆŒŠ‡ˆŠŽ‡ŒŒ‹Ž•—’‘•”’–••›œœžž¡§¡¥¨¤§©§¦¨¬­²¶¶µ¹º¾ÀÂÃÃÁÄÇÅÊÇÈÉËÌÍÌÌÐÎÐÕÐÓÔÖÖÖÔÖÖØØ×ÖÕΓ0Nyz’‹”Œ“•’–‘Ž‹ŽŒŠ’’ŒŽŽŒ‹Œ‹ŽŠˆŠˆ„„‚ƒ„††‡‡ˆˆ†‰’¨¹¾½½ÀÀÀÄÉÍÓ×ÛÚÙÖÒÏÍǽ§˜…}tsqoprmkeic\`^YZ`eff`YPFBLP\dhhhigefae\[W\]^^X^`\d[_d_[%%" &&"&5>Zuƒ—™¥«®©§¤ŸšŒ|lF..;>I]yƒ˜ž¡¨®±²²°±®¯²³³¯°²µ««§¡™’ žˆy71GF0(=3**.%%')95247TcdV;86/,--,4>D<=>;@6101@/0<36(3/CV)#,.-4=>5&,VcFA6DMfbA'%<}~ig‚[s‡}ˆ…nXPE7@Usw‰”oSY`.9G<$&%3B=:65/);>6I:5614113B30'6,/4<@JPWX\mhlqtx~}~€€€v_J74ITbgls}…€…‰‡‡Ž‹‰‹Œ‰‰Ž‹Œ‹Œ‹Š…‰ˆ†‡Œˆ‹‹‰ˆ‡‰ŠŠ‹Ž”Ž“•—’“””˜–Ÿ™™›œ› Ÿ¡¡ª¦¤¥¤£©«ª­¬°¶³¹º¼¼½ÁÃÁÁÈÈÉÈÇÊËÍÍÏÏÑÎÒÒÑÒÓÕÕÓÔÔÖÔÔ×ÚÕÑ®IS{ƒ‹ƒŒ•’‘“’‹‘‘‘‘”‘Œ‘”–’ŽŒ‹ŒŠ‰ˆ…‡‹ƒ†‡…‰†‚…ˆŠ‹ˆˆ‰Œš¥­´µ¶³»ÁÈÐÔ×ÜÚØÖÒÎËŸ¢“ƒyosljpoiiedbWb]\`efha^ZSNFNS[cfnniecgg_X[W[^\_[dc\b`ba`T++(&(#%#/9Vm‚‘™£ª¬¨®©¢˜ˆ~eS445BN[r†Œ–ž§©®±²µ¯±²³­°²±±µ·ª«§¥Ÿ‹œ£˜„i93WO62=**&.&,,/12:HQcZH9312-*-+69CE?=M;/50-2==5:87/-7Dg5**276/:A5:XI>E;FKirN'&%G…“”œkŽwYŠ~slbZOY`dox‚€„‰„‹ŒŒˆŽ‹Ž‹“Ž‹‰‹ŠŠŒ‹ˆŒ‹Š‰‹‡†ŠŠŒ„ƒ‰Š‡‹Š‹ŒŽŽ’’“•˜š—™›˜œ›šœœŸžŸ¦ ¢¤¡§©¬©««®´±¸»»º»ÁÁ¿ÁÃÉÆÉÆÊÌËÌÏÐÍÍÏÓÒÓÔÕÖÕÔÔÕ××××ÕÔÂk\y„‘Œ†{„‰ŠŽŽŒ‘‘‘–”–“‘ŽŽ‘ŒŒ‘ŽŽŽ‡ˆ‰†‡ƒ~…‚‡†‡†ˆ‰‹‹ŠŒŽŠ˜ ¥©¬©²ÁÉÐÕÖßØØÕÓÎÇÀ´¢{opilkhhmacaX[]_di`a_]ZPNFRXbfnpjhcfecZZVXaZ^`^eY\acg_YU,,,/(%#(,8Qh…œ¡§¬«ª££—„lXA65CO]u„‘œ¨©®²¯°­³²¯±°¯²²²´²ªª¥Ÿž™¥Ÿ…_A9eU4,7$%%)-#(;6@U^]O8-2'*.+.(+6>BA==>43.914;E>:<8,3.7^C'4:<5*4MMRI69:<<:Poh8&%M‹¦¡tl¡‚j‚r[dUG;BDiqyž{w€M†¤Š&",.5;:41/5?1>?63.9500438,.,-24@KUVUVemsvtyz€}~€z{vmW:1BTaagmzƒ…‚‹ˆ‰Œ‰‹Š‰‡‹ŒŽ“”‰ŒŠŒŠ†‰‡‰‰ŠŠ‡ˆ‰ˆŠ‰‡†‡‡‡‹ŒŽ‹’—’”›–••–™š”žœžžŸœ¡ž¡¤¦¥©¦ª®¬®­°°µ¹»º¼¾Ã¿ÀÅÄÅÇÉÇÉÎÍÍÏÏÑÑÔÒÒÕÓÔÖÔÔÕ×ØÖÖÖÒɉfxˆ’‘ŒŠ€rz‚ƒ†††‡ˆ‘ŽŒŽ’‘“••‘‘”ŽŽ‹††Š‡‰…ƒˆ†„ŒŒ‹ŽŒ‡Š‹ŠŽŠ’™ž¢±ÃÌÑÔÖÝÚÕÔÑÍÊ°ŸŒ€xqqspkfeg_^ZT^`bhd^]^UMKKTS]cfonkihb`bY]XV[X[e]d__^a_[QK**& $$(2Oi|šž¤¨«¬¦¥š†r^A::DI\q†Œ—¥¨­®±³¯°¯¯°±­²³°³±«¨¡™Ž•£¤†b?=`W952'('**+?NNZ\O>@0..0*,))++2BI58J=13/66;E@CFH;3)++G?17=2.)-S`a=105778Ef{Y6#%+HcpUnˆso|ƒWTK;1?3^z‚sŸ||s¨ªY&%6-1:3).'2=73010137/2-)350'/2:?JPY]bilutzyy}~{}|~{rbP8,DT_crv{‚†…ˆŠˆˆ‰‹‘ˆŽŽ‘”’‹‰‹ŠŠ‰ŠŠ„‰Š†‡ƒ†‰‡†„†ŠŽ‹ŒŽ’”‘’š‘’˜˜—š—œ˜›ž¡Ÿ¡£¤¢£¥©§­¬­¯¯µ¹¸¹¹¾¾ÀÀÁÃÅÆÊÈÉÉÊÌÌÏÏÏÑÒÓÔÖÔÖÔÔÓÕÔ×××ÖÖÍ«mw‰‘Žˆxovx|€‚‚„Œ…‰ŒŒ””Ž’•Ž”Ž“‘“‘ŠŒ†ˆ…‰‡ŠŒŒ‹Ž”ŽŒ‹Œ‡‚‡”ž¯ÂËÓÙÙÝÚØÖÑÌƹª›‡|vponknea^aYZZd]d`bdYVRNIOSUagllokfb\^ZX[YXZ\^bba_[bh[UQH'')&(( '26Jetš›¦©¬¦¢¤š‚w]G9;?K]q‚Œ›š©§¬®´±±­¯¯±°¯´²³±²­¨¥Ÿš’‡Ÿ«‹hAH]\/=22**1*0DPPOD6021/102300,29EB8CNA;73<>:D=DE>:;0,/?I:H9(**4Lnh8)+.390C^h_=C**1?:8P_lt~’jRE<,93IWtƒ­›“—°”9$-21;90-),;>7044.32.:+//3/.1/8=CHP^ajmqsvvy{‚~{}z{|oVD67N__br{€„‚†…ˆ‰Šˆˆ‹Ž’Ž‹’“ŒŒ‹‹Œ‹Š‰†ˆˆˆŠ†…Š‹ˆ‡Š“‘‘“””—‘“—˜˜˜››—›š›š›Ÿ ž¡£§¤­±¯¯¯¶µ¸¸¶¼¿¿ÁÃÃÅÇÅÅÉÉÊËÏÏÐÒÑÔÓÔÕÓÓÔØÕÒÔ××Õ××Ô¿~z‘’’ƒijmsyqxx{|ƒ„~†ˆ’‘‘“•Ž’Ž‹Ž‘Ž‰ŠŒƒŠ‹ˆŒ‘Ž•’“•‘Š‰‰ƒƒ’£³ÅÍÑÚÝÜÚÙÕÐËÁ·¥‘†vtsrnkg^bfa]YXZ`f``_UOTKJRXXgifgled_a^[YWT^V]\`^_]acfZTKE((%"!!-)+5F[r˜œ¢§¢¢¥Ÿ™€pdC2;?NXp‚”œ£¦®­²°®¯­¯°²¯µ±²´°«­¤¢›“†‹•®‘k:N]a398+*1+128=7<44392,3,050,11:C77OIE7610UoW5,,'+74GjkbACO*"1/,68Db•ƒnR9,01?EH„|³«´£j),324;=.0+4@69A450370-.+4.0*1,8@KPPUdpmmpus{z|z{|{yiR7/CUcXkt~‚ƒˆŠ„‰†‹‰Š‹ŒŒŽŽŒ‹•—‘‘‰Š‰ŽŒŒ‹ˆ‹‡ˆ†‹‰‹‹Š‡‹ŽŒ““•—•–”•–—š™›™žžšžžž Ÿ ¤¦¤­­®­®²²¶¶ºµ¼½ÁÁÀÅÄÃÇÉÉÊËËÏÐÒÒÓÑÒÔÓÔÔÖÕÕÖØ×ÔÖØØÊ—z•‹{vabgkphoputw~~‚††Š’‘•“Œ‘ˆŠ‡Ž†ˆŽ”‘•—’”’‘Ž‹Š………¢¸ÇÎÖÜÝÝÚ×ÓÐɾ°£Ž‚xrnqmljje\`S^[]fdf`VTXQLOSZ\dhijbg_`]_XRX]WX]`a_\Y^b[[TG?%%)#'#&+%.Og’˜Ÿª¢¤¢ —Œ†v[F:;=M]p‰“š¢¦©°¯°¯°±®®±¯°±³±°¯§ª¤ž”‡‚Œ¨’b8G`E=:2))1*2+8223.0500/1),<.*.4;=2=J>A8<2B=O:=.8<2496?:>.',#$*;[gA7/()-6LWuyoZ4RM%.A30)(7Ps˜[<,7;SO4Yqx«ª©z5!'-00;/+'&2F7472,1220*((,05/43:@NJOZhoqstuuz~ƒ‚}{{yo\B12EV_`m}‚‚ˆ…„†‡‹ŽŠˆ†‹ŽŒŒ‹“‘ŽŽŒŽŒ‹‰Œˆ„‰†Ž‹Ž‡ŒŽŒŠ‹’‘“–•”–——•–•——š™žŸž¤¤§§¨¨­«¯±²´¶¶º·½¿ÀÀÁÈÅÅÅÊÊÊÌÍÌÏÒÑÓÒÒÓÕÑÔ××Ö×ÕÕÔÖØÙÑ­Š‡vo\VX_o^gjnkquwu{‚„€…ŒˆŽ‹‘”‘•‘ŽŒŽŠŠ‹‹‡†‘’“”š••‘‰‚…‹˜•¤¼ÊÎ×ÞÜÝØÕÔΟ¨š‰|utqqlibe^[[T]^fib`XPJMJOT[]abikgdifga_[W_^Zbaea_\\_XXPID;''&*' "(&0Ni—›¡£¤¢ž¡–†uaIB==LVn|Œ“˜ £©®°²®±±°°±°®²²±®®©¤£›“‹}ˆ’];K]@4A6.*))(-./2,1370,*.,7>4+2=K59CA97647?LPC9.-4915AD7,+)'&)+GhP1461,+6Hk{xwoC6_=+=:3))$>]›–^3/5BWYF\BW€Ÿ€[&!13196/'%*9?8334*+7/,,%.(/,@G<63>:9D`UK;3*(1+/13/13.+&'+RZ7,766//6Fd|yt†i8CU<040#./6Ex‘u;3/>flphKMUš{K)'105D4%%'!#!$#+5Fgs†’›£ª¯¯ª©¢—‰oZD==AP]lˆ“›¢£°®­¬±°°±®±±²±µ´±°©¢¤ž”‹€|†‡aHMaI>D,'(-.,32354-80/0*1,0032=H91EJ=40.59GPRH;.,*1*)/871,,)+&4PY0'1AC618=Oy}{}ŠI2EL@,' '/7=CFFOU_iposwsruy~{{yqVD62=Q\an„Š‡„„ˆ…††„‰‹‡ŒŒ‰‘‘‹”“Ž‹‹Ž‰‹‰Ž‹†Ž‰Œ†ˆ†Š‰‡‹ŠŠŒŒ•‘‘–‘•ž“•—››™›™›˜™œž¢¤¡ ¤£¥¦§¨ª¬©¬ªµµ¶µ¼½»¾¿¾ÄÄÄÄÈËÉÌÎÏÑÒÓÒÒÓ××ÖÕÙÕ×Ø×ØÖÙÜÙÓ®€uXRPNEONbLLRWUVa_bcfgkmpqs{wyz}†„„…‰‡†Š‡‹Œ‘’—‘“›˜šš‘‘ŒŠ‰„†…†‹—¥¸ÆÏÓÙÚÝÛÕÐÌż­—Š~uplgf[VMOMNVY_febZSMGEKSO[anfead_[bd^\]Y_[ahficZ^^TVQL@=A5##$!()#(0G]o„”§®¯®°¨¢žŠxaB>BBJWl‹”š¡¥¬«¯¬­°®¯±²±³³²³³©«¦£ —Ž|‚waSN_QK@-%(*)/3:;A6/160:+-0,;6KP?7/-34SF+Iu|oj\d‡„ˆœuC:15HcK+1F47?<,HILNV\eusvywqvtut|vuyq]I0,9KW[fr‚ƒ€†ƒ†ˆŠ†‡†Œˆ‘‘‘ŽŽ“•‘‰ŠŠŽ’’‹ŽŒŽŒ‰ŠŒ‰ˆ‹…„‡‹ˆˆ‹‹ŒŒ‰Œ”‹‘‘•”‘“š•“–š™—¡šž›Ÿ ¢££¨¨©©¨©«¬°±³´º¾»¸½¿ÀÁÃÄÆËÉÌÎÌÐÏÐÏÒÓÓØÓÕÓ×Ô×ÙØÙÚÛÚÚÎWDNSSCYaMGJGEEDHLROQOTZ_WY\]^``ddilnnnoszƒ‡Š–œž¥£žš”“ƒ€€‡……„˜¢½ÊÑÕØÝÞÛ×Ñɽ± ‘ˆ{rj_X\TSQENQUW[a^^TPDDNUWdaisf`_]Z`\_a`Y[``aeijc`aa_OIK=6859""!!$&3+6EcŒ›£¦­²¯±®¨Ÿ…v\;5:IUk|†œœ£«ª®­¯«°±²²²®±³´¯¯¬¨¤Ÿ–’‹~|si^JL\^D')*'->C3220.//,7./,5AL783-CE>4-38=EU\32+)323)$&/90/+-,202),'))*8966GNNQU]knqvxyvtwtwvx{}eK6&+>WX_oz†…†„‹Š„†‚‡‰‡“‰ŽŒŽ“ŽŽ‹Œ‘‹’Ž‰ˆŠ‰ˆ‡Œˆ‹‹ˆ‰„Š…ˆŠˆŠŒ”’’“”—’•—˜š˜›œœœžžŸ £¥¥©¬¨¨¯¬®­­²¶»»»¹¾¿¿ÂÃÆÇÈÉÊËÌÏÐÏÑÐÔÓÕÔÔÕÖÕ×ØÚØÙÛÛÚÕ¥^IQTXFW_SIRPQNLOHQJILRRVSSRROXUX]\b_fcddon{z†‰Œ‘”žž œ˜“‘‘•–‹”¦½ÊÒÙÚÜÝ×ÔÎŧšŠwk_\WVRIKGLSYbc`^ZSHHEPYagchmf]]_\a_]]\W__eciee`\d]WKKE<726@G669946-./+0+89911%10Gt/"$2_t[P]j„pw¬žpUN70/ALCZV`[R^b—u.*64;777573.+*%(1A.((,/-.+-+.+1);::?HTOS[dspwsy{zqvtxvxts]9--0EYcfv‚†ˆˆƒ…Š‰ˆ„†Šˆ†ˆŠ‹‹ŽŒ‘‹‰‰Œ’ˆŒŠŠ’Š‡‡Š‹Š…‡†‰ˆˆ‰ˆ†‹‘ŽŽŽ’’’’“‘•”’™•š•›™šŸ¡œ  ¡¥¦§¨§ªªª¬¬®²¸¸º¶½¾¿½ÅÄÆÉËÈÉÌÍÏÎÏÑÑÒÒÓÓÕÖÖ××ÙÚØÛÙÙÛ׸bFRTZTX_RSQSRNQSJRSMJJLGMHHNLNPQQSVN^^Y`dlmp}†•™››šŽ—£ ›š•–“š­ÀËÓÙÝÝÛÖÓÊ¿³œƒxka_UQKHEJPTV^`ZWWQOKKPS]dhkgcd`_Z_a]Y[Z\g\fioi_gbaZWOEI@:-54''%%""'0GoŠ—Ÿª«°°±¯ª “‹~kC<@FWgx…‘•£¨ª«®­­±¬¯µ¬°´µ´µ¯®¦  ›‘‡r`p`D[[`8(##,37.''0.,(--,..@EG@3,./=GA02335?D@DG?7=6B<+))&//12544092BU& "(DfaITd€dŽ¬™jpX*17WgZm‚sb?=Z=.00-/0760>13-)&//51)-++6,.),5)+./<:?JONW_kqwzxx{vttywwuqcC/*&2E^ily‚……‡†‡††„†‹ˆ„ŒˆŠ“‰‹ŒŠ‘”ŒŠ‰ŒŒŽŠŠ’Œ‰Š‹‡‡‡„ƒ„‰‡…ˆŠŒŽ‰Œ’’Š‘‘“’••‘™˜˜˜–™¡ž¡¢¤¤¥ª©¨ª¨¬¨­±µµº¶»¼¾¾ÂÂÆÇÊÊËÈÌÎÏÐÏÑÒÔÕÔÓÓÕØÕØÙÙÛÙÛÛÙÆyMJTVQ`_UZ^YTWRSMWLNDI@KGJA?DFJHLGKHQPJISWaeuw~ˆŒŒ–”œ¡ª¥¡š—–š£¶ÆÏÔÛÞÛÚÓÐź¦™Œ~pbZPLH<>>FIPUX\ZSVOJLLP\acln^V][^`]_d^V[Z[aegidX^b^\QPN?6:335''&"!!""*4Gg–Ÿ¨¬°°²¯¨£™{jE5=KSku†–¤¦ª®­­±±°²±¯°²´´´¯°©¢œ›“^Rq‚eSY]_9'%)2;4)-1/..)-),0HHH?60/44LK9/04439FALUgb\€„j@74('80++.487HA3-++49./*+)&)'&)-+-+46=;DUUP]fiqvvtxwvv€yxuwjO7%'-ERijq„†ˆˆ†ˆ†‡„ˆŠ‡Š‹‰ŽŒ‹ŽŽ“’ŽŒŒ‰Š‰Œ‹‰Œ‡‹ˆ‡„„†Šˆ††‰ŒŽŽ‘’’‘’”™“•˜—––™—šœšŸ¡›¢Ÿ££¤§¦ª¨©«°°²²¹¹¹º¿ÀÀÂÆÄÆÉÈËËÎÐÎÐÑÒÐÒÓÓÕÓÕÔÔØØÛØÚÚÙÍJFNZSd\_`b][UQXQ^QPNNHLC<>CE?D=?@D?AB>B@RVX\kwy{€‡“«¯±ª§š•“Ÿ¬¼ÈÒÕÛÚÚÙÒÊÀ°ž“…si^SNJA:>=FKNUVSMMPOKTRVbfjmn^WYU\Z]\^]W[[`cghgga_\^XWKB;;:78<))#(! #")0EfŽšŸª¦°±¶°ª¢‘|yF8;FSdv†Œ›Ÿ£§«­®®¯±­±²°²´³·¶¯«¨¦¡ŽqKRy}dQQY\3(#0;:/*0,4+)&*-1=X@<:5+*--PM873/-9BD<=G>AEC=3:4').7=*847520$$+$,4.);agZf{~q}‘gJq€WjWf}s]H1'$0+..174;4,.(--21)((&&-*,'),))/37;;HXXW`hpuwrruxtvvxxulO5'$/4MWfoy„‚ˆˆ‰Š‰†Š†ˆˆ‹ŠŒˆ‹ŒŽŽŒŽ‰Ž“’Œ“Š‰Œ‹Œ‹‹‹‰‹ˆˆ‰‰†‰Š…ŒŠŽ‹‹‹‘““‘‘‘“’–“–—“˜——›˜›¢šŸ¢££¥¥¨¨¦««³±³´·¸½»¼¼ÀÁÂÇÉÇÃÈËÑÐÐÍÑÑÐÐÔÒÔÖÔÕÕ×ØÙÚ×ÚÛÔ¬XENZXd\_b^aW]^`WWRXLUMODKD?C?;>4:8624/44GC;8KB6>;?97<6*)2>+-:>>:9,)/5<8.$,Glj^o‰{s‡”‹hs‹_f^ONcp]I/(/(+/036=3,.,)+61-)'&)')'')+',,29/4>60.0A@6--+1EPF?3:?698?84=:4123-')/8?=4*,280/$(,Lcmmq‡™“xdu’‡knrPX_9CnpVD*')'0/7;1.*70-3..)**./+(")*-+*,3:CDQU[^ilqrrwnwwsxwsqhG2+%+7O\fr}ƒ„‚„†ˆˆ…‡‡‰ˆŠŒŒˆŠ‹ŒŒ‰ˆŒŽ‰Ž‘‘Ž‹ŽŽŽŽˆŒŽ‡‹‹ˆ‡‰‡ˆ…ˆŒ‹ŠŒ‰‡‹‹Ž’Ž”‘“š˜—™™ššœšš›žž¡œ¢ ¤¤¢¤©«­­±°¯³¸¶º¹¼¼½ÄÃÆÅÈÆÌËÍÍÎÎÐÐÐÓÑÔÔ×ÔÕ×ØØØÚÙØØˉNQT]_^dfdffj_Zb\Z[X[TRPMFD??=;:49/-/.1--,15;A\Woˆ¥·ÄÅÃÁ¼³¨ ¡¦¹ÄÍÒÖØ×ÖÓÌÀ±¡‹ykWMKD;9;?>IPMSRMOKINZ_chdojqie_[[XUYVSY]^[aebjibcb`XULI;:<83302000186<<697Ll€”£ª­³µ¶µ°«¦žˆlO==G[dw…ŽšŸ¤¥«­°°¯±±°®¯±³º·´¯¯­¦¤™‰`Y[|†_D><<2'(55*/,//9,+2A5957<>=>;80*:9=/371-(&,,C\jho˜¦“yeq‰…eYaMbZKc^NK-)'*,572+(,-03>;:9,-+2(&$***((.=84335..9FCGECACDUgy¢¨°²¶··²±¬›ƒhU>AJZhx…’—žž¦­ª®±®²­®ª°³²¶¸³´°«§£™€\^X‘hGA<1>+-27%,(+(31:?7-*022/7?-(,-17>8+*7HDG8??8:97=@808B5/&(,##'0AH:'+6:5//.+%<\ghƒ¥p„uIYb^yt|pU@(%&74770)'%1(+*-*)&$%.'%'((/20:GLFMV[bjmptstvvutxyjV8,)+/>L^ktƒ„ƒ‡ˆ‹‡‰ˆˆ‰‰ˆ†‰ˆ‡‰‰‹ŠŠ†ŒŽŽ”Ž‘”‘ŽŽŽ‹‹ŒŒ‰‰‡ˆ‰‰††‰‹‹Š…‹Š‹‹Ž‘”“”‘”˜›š–™™ž›šž›ž ¢¤¤¤©¦¬±²¯±³··¸¸»½ÀÁÂÅÃÄÅÇÌËÍÎÏÐÒÐÏÒÓÕ×Ö××ØØØØÙØØÔ¸fQV\_dbjkfhdfhffg_`\ZXVQRQHKE==7253..%'"#%'.6Ae‹©¿ÅÊÊÊĽ«Ÿ˜ž°ÂËÑÖÖÙÖÓÌÀ·¢x`OF?;9?9BFNMTSTRG@DJSZZgeolkfb\YVVSSP[OP_Zaaklhggd\\WRE;:A66:439;;MQNLLJFHFVg{›«²±··¸´²ªš†sZE6D?44<9<@1320,*'(4+&).9.10*2$%%1&#*Ds”µÃÉÎÍÔǹ¢™•£·ÅÌÓÖØØÓÐǾ«”{]VKI5;48?E<65AK97N7C>210./*/)43,'%+4<8.6]F5<311$$3Mhƒv‘Ž‚†xh\_ze?]‚xl-*+,38-.4)2*.)-()(/&%$+*1))-.>76<77@DHINNMIIFIJR\_giksgb]VTPJSTUQRRTOT`fkmtuff`YZVOJPME@<>86<__]^XUSZ[U[hsy‡™¤©²¶·¸´³¥ŸŽkODRWiv†Œ–ž¤§«¬±¯°°°°°°²µºº¸±¯«¨¢Šp|`mz_TV/'&+22(:B>9<908--4,.+502-4*4/8+796BHB25=DM9;D;@=0/*1//1*-566,%#6LI5=O;521+11+DDCq}‚¡«¡…s[eTdtyu6/.5--)/,+*,/0+)-*(# '''),+1>IOHLPVbhrsvqwswu{zrf>,*)@.:PWevzƒ‚ƒ…ˆ…‰†…†…Šˆ‡ˆŠ‰ŒŠ‹‹†Œ’‘ŒŒŽ‘‹ŒŠ‰Œˆ‰Š‹‰‡Œ‰‹‰‹Ž‘‰…‹Š‹’’”“‘‘—˜™šš››™Ÿ¢¢Ÿ¡§¬­ª¨«­®°µµ¸¼¾¾¿ÁÂÂÆÅÈÆÉÌÍÎÎÑÏÐÐÒÐÒÓÖÔÔ×ØÔØÙÙÚØÄvOTTXbhjmlfkkllehhg^a^TZ]VUNJQID=<;5/0'-%(,+Cl™³ÃÇÎÍËÀ­ž«¶ÀÆÎÐÐÐÉļ¤tYB6@65;A?JDLJLDDDGBKTXcfjknf`\[UURRLMQTNVXY\ckuqroigc_XRLIOHD><:9;BYYZ`]\Z[fb]hwzˆ™¥ª²µ·¸´®«£•€pTKWbesƒ–œ ¥¨¬°±´³°±®²°µ¹º·²®¨¦¡‡rpap}|c][9-,((6,2>2/340,,3301200-3313113022DA8+/>IP;?I<>AB*,/0)*,)1897,(';PF5G=7<4/,55D@CF[t~‹˜“†eGXg€xK2-56-1&/+*,+++*/($%(##)1//17?MMMKR^hgustp~vuwzwbK*($*-NNZctz~€…€ˆ…‡„Š‡‰‰ŠŒ‹‹‹‹‹‡‹‰‹‹ŽˆŽŽŒŽŒ‘Ž‘‘Ž‘Œ‹Ž‹ˆŠ‹‹‰‡ˆ†‰ŠŠ‰ŒŽŽ‰‹‡‹‹–“––———–œ››™  Ÿ¢¥¦©¨ª¨©©®®®±¶º¼¾¾ÃÁÅÈÆÄÉËËÌÍÐÑÎÍÏÒÐÔÔÔÖÕÕÕ×××ÙØÖÈ‹MPUZbailljlnllihbb`j]WZ\[UXQJRKBB@;/-(-*)+-Jp•®¿ÅÊÍɳ¬®®»ÃÇÊËÌÊÀ¸­”uUG95655:=C?EQSCAECELPSabgmmnj`XQPTMPLOONOXX`ahjruveb_`YUPSOTDA>8<;ECTTYYZUZ[dbdl{„¥«°···¶´®¤•ƒsZERbfq€–›£©«°²²±²³²±°±¶·¹¶²¯ª¦ †fmbr|v[VR>--*442/,+.1156,--0*+874C?1423*-*.;12/9?BN<4B71<<;9*+/-2*,6A@72#0=K;JA=<6:BAA9>GO>FJd€uŽ—€^bwXLA3/35/++*+(.-(-01(""$#%*-6..4:EIMPSTlkjtz}svqytuf>*$##,=LVeo{}~‚†………ˆ‡†Š†…‹‹Š‹Œˆ‹ŠŠ‰Š“‡Ž“’‹‹ŠˆŠ‹‰‰‰†‹ŒŠ‰ŒŽŒˆŒŠŠŽŽ‘“”‘’•˜™•™˜–˜œžŸ¡£¢Ÿ¤¤¤¥§¨ª¬°¯³¹·¶½»¿ÁÂÁÅÄÇËÉËËÏÐÏÑÏÐÑÑÕÔÖ×ÕÔÓÕØÖØØТbJQX^_fkfnkkmmpkkhcc[d[_YUNPRPJH?F;53.,5199Gl§¹ÂÈËËÆ»¼¹¹ºÅËÈÈÆĵ£•wZA;875167;EFGPNFCAFMITXakjkib\XQLHMJJOJKOTW^ccekrptjb_^TSTVVQM?<;9;DBVV[^[Y[bcfnr{„¤¬®³¶¸·´®¥”ˆw]GQ`gt€‹–£¦«®²°°±µ®²±²´¹¸·²°®©¡ˆdnft{vZXQ47.39-)-2..410-.1'3+.456A<4203/10*0+03:HFR;1:72>AF@-(011%&69?F:%-2:AIJ,621?CV:;AJU:;HsLh†Œ{x{>40*013/33).65)+&2)(&"!&'125.6/#"!*4OWfku~€ƒ‚‚……ˆ‡†Œ‡‡‰ŠŒ‹†Ž‰‹Œ‰‹Š‹‹‹ˆ‰‘•ŽŒŠ‹Ž“Œ‰‹ŒŽ‰‹Š‡Œˆˆ†‹ŒŠŒŽ‘ŽŽ‹‹ŠŽ‘‘“•˜˜“”•™™šž  ¡ ¥£¦ £¨¨­°±®³»·¹¸¹½ÁÀ¿ÂÄÈËÈÌÌÎÎÏÒÏÑÑÒÒÕÔÕÖÒÐÓÖÙÚØÔ¶kMSV^`hjninmklhehbkc^c^\^XRUXUMFGA>;644-078Jc…¡µÄÊËÊÇÆÂÀ¿¾ÂÆ¿Á¼®¥yXE>6334456AGLCLBAEDNNTZ]ckkl_cfSQLKLPRRMLRPVZcklrsshghe[VTQRSIE9:>@>C@VV^ZWbcbelnuƒŠŒ §ª¯´µ·¶³°ª—‰w^HY\ftƒ‹“š§ª©­²¯¯²´³±µ²¸¸¸µ³±­§¦‹\Yo{xq[XJ,...90-+0.1+29/.2-0-2627A;.,:3760/*,+2<;?D969/.FHRS51271+%/C;UK8*./8IX33;/5Gh[70ESYEMwGHdx‰Ž‚k4+,/16-,)1+/7+*+/,,)$"!)+,356BOLGFV_chinwyvsuurY:,!#*2=L\chtx|}|ƒ€………€…‰ˆ‡Œ‰ˆŒ†‹Œ‡Š‹ŒƒŒ‹‰‹Š‹‰Œ•’’‹’•ŽŠŽŽ‹Ž‹Š‰‹…‹‹ŽˆŒŽŽŒŽ‘‹Œ‹’‘Ž‘’‘’•““˜–˜››š¡¤ ¦¦§¢¤¦¨©¯´®±´³¶·¹À¿¾ÃÁÃÆÈÉËÌÎÐÏÎÎÒÔÔÕÖÔÓÖÓÑÕÖ×ÙÚÔȉOQVXY\egjnqqlmhhhgcbb_\_WUWWPMLKKCBA?4;6:>IZ€ ·ÂÈÊËÉÉÈÁþ»¿´±© viOE@24695:@EELEACBHGWUb`bfhgfa]]WTJFPKKNRTRUZ`hhlrulia^\_VRRLPDE=:AAAALTX_anihig\XZMPOJSLMLRNQYeblrruohea^^bVYQIDD>4?=DJGEIIV]cckkltz{„‡Ž›¨¯¯³µ´±««¡˜‰{fKR`gtŠ’œ ¨¤®®¯°¯³²³¶¶·¹¸³³±¬§¡•ZM{~wh\L4))(83105/,-03(4-;:3**906A70-.44-*013QQBOL=,-9=LVVT=*),76+%/THYgQ>7:9=mC*8K;BXWOCPWx‹–v@:O05Fbc?*1.,./)*114-++%*#"#%+3/2;EFNLQYhbfmkjkreO6'".#+.;O]bfipuuw|x„€„ƒˆ‚„††Š‰‹‡ˆˆŒˆˆˆ‡Š‹Š‹‹ŒŽ‘ŒŒŒŠŒŽŽ’Œ‹ŒŒ‹‡Š‘Œ‰ˆŽˆŠŠŒ‰‰Œ‹ŽŽŽ“‘–•“‘‘•žš›š˜Ÿ¡¢ ¤ ¥¨¥ªª¥§ª¬°¯´²·¸¿¼¿¼¾ÄÇÆÅÊÉÍÎÏÑÏÑÒÑÓÓÕÕÔÒÓ×Ù×ØÙÕÃ|NNWZaf`cdihkgffleh`\]ch``bc_SURSNMLUOVPOW\sˆŸµÅÏÓÕÔÔÍÆ»«¤’†}b]UM<@6545A?CLQJHFDADKRVZagjkmei`[TIIKHJIORMV[[chkouqodhb^XbZYQOJD;=CFFB>7:/-@6-.9A51)52168=721/',-1+8FZT=`^<20@:FRV[S;*-+-.+*C[OGTHA,0-&./-@HTbeihnsvxwx}€{}{‡‚†Š„…‡ƒ‹††ˆ‡‰‡ˆŒˆ‘ŠŽŽŒŒŠ‹’Œ•”‘Ž’’Œ‘–‘’ŒŽŠŒŽˆ‹‹‘‰‰Ž‘’“‘’“‘–•›š˜œŸ   ££¤¨©¦§ªª¬²°¬³¶¸¹º¾¾»ÁÁÄÅÇËÈÎÌÍÎÐÓÒÔÔÓÕÔÔÕÕÚÕØÙÕΠZNRUb_bdeeehbhioocg`_`c\bbaZZYVSX\^W^]Y[YZxŒ¡³ÅÏÒÓÒËõ¤}iUQDA?J@NFJFCALHRZ^dihlifa`ZcTJFEHDEDSQT[]]inqrsoleifg_\^PHHB6@D@DHEK@:77MU^hpoqsljow„Š ¤­®®²¯®ª¢“†wcUX`gn“œ¡¨ª­®²°²°²±³³¶··´³°­§¥špDVvmka>,'%)0+.-0>.-?:/3;C9.*3.1+ELGD30(-3/.6PRB<€a@0,72?DC9ZOUBFaŒ–‚HOG(9IBS9))'#(-11-)&+$%-/&,(*,6GHPPWR]ZRC:9J*&.'$2;CT]`ddhlouwwvy}||~{„ƒ‚„„„‚ˆ‰ˆ†ˆŠ†‡†‹…†‡ˆ‘‹‹‰‹Š‘ŽŽŽ”“Ž•’”–’‘‘‘‘“ŽˆŒ‹‹‹Ž‰ŒŒ‹Ž‹ˆŒŠ’‘–“–’—••™˜š›žžŸ ¡¤¨ªª¨­­©°°®²µ¹´»¹½¾ÄÁÄÆÇÉÈÈÏÍÎÏÕÑÓÖÖÖÖÔÓÖØ×××ÕÒ²hIMTY`a^ahcdfbhdggfb_idacgedUXWV[Xb\^`_[W[q‰ž±ÃÊÏÎÊÁ¹ª—za[NNKL@AC;:BIJMTMJOJFIFXVbhlknqiie[YXJKF>BI?DMSV]^_kqrqkqmgec`]]SLI@89>KEDFGE:600BRV]fifggfgu™¢¥­±³³²«¥˜‡yfZWajq}Ššž¤ª¯±°±²³³µ´µµ··³°¯©¥£›vPUogm[3,+*+0902>51366'4~`;0/:AWXi^P^L-(.74,*FnW<#%,769`[(4B7+ILS[Oly–nXE7>R4FB2,*%16/2*%),-(/41++05:BDIPRF:721,4&%,-6;JST[cfcimrtz{~x{}}~‚„ƒ„…ŠˆŠ‡‡„†Œ‰Œ‰…‰‹‹‘‹Ž†‡‹Š‰‘Ž‘‘‘””’”‘‘“‘’ŽŒ‘Œ‘‹‹Š‹ŒŒŽ‰ŒŒŒŒ‰‹’‘‹—’•“—˜›œ™™œ ¡¡Ÿ¥¥¨¨¬©­¯­¯®²µ¶·¸»¿ÁÀÁÃÇÈÇÈÌÐÍÐÎÐÐÓÓÓÓÒÒÓÕÖ×ØÖÕÖÁ†QMQSZcafedfamfgjhccdggbge`b]^b^cbbgd]^[^bnƒš«ºÄÆǹ©–‚bXRHPUMHFE=EMIFKLLGJCKMQW\dmsnpsh_`RNLOLG?>@;/+343-PY6&-52031AIH3BtS6,!1JSQizffkYD7.30/+MpY+*)6AD1Y•o1BD66CGcqoqnŸ©’iC/801I/#-)(0?.+4.0..(3////111/'/-4'%)-9?DRQZchhmmolpsvy|z{y}}||~}…„‚……†‰Š„ˆˆ‹‡†ŠˆŒ‡‹‹Žˆ‹ˆ…‹‘‹Œ‘ŽŽ”’‘‘“””“—‹‘‘ŠŽŽŽ‰Œ‹‡‹ŒŒ‘‹ŒŽŽ’—’••š•›žœœžžž£ ¤£¦ª¨¬±°²¯²µ´´º»»¹¿Â¿ÀÅÇÇËÉÌËÐÑÓÍÐÔÔÔÓÔÔÖÙÕÖÖÓЬ`LRTXZZa`b^e`jhmjjdghjdfbe^_cbfdljilmjdjdjsƒ™££¥¡Œp_ZPSHSNMDPINKKLHQRNJHEIRUYdghpsrbbZXUQHJMF@@@BGPS^eljmvwqtxrifhe\WPEB@@C;DE=AE=29/,,6C?JOV]Xe[ip|ƒ”¡¬­°°²¯¬¥žtbY_fo†’˜œ¥¨«¯²°±µ¶µµµµ·¹¹´¯°©§ŸˆfEIXM8*235*'+...41-4:98F@G4.31260Pe6*'335-97FE4JlM=)&3NdUh~xfu`I8;#,E7#!./-,&&4403-,1,,,,$,,)(()(6::ADMUNU]`Ybnpsvz{€‚~€‚}ƒ„€€‚€}„„‡„‡‡ˆ…ƒ…ˆ…‰…†Ž‹Ž‡Œ‰Š‡ŽŠŠ‹ŒŠŠ’“Œ“‘‘‘’‘‘’Ž”‰ŽŒ‘‡Š‹Œ‹‹‘Ž‹ŒŽŒ““••––”›™ž¡ž ¡¢¥¦¤¨¨¬¯±²±±³¶µ¸¸ºº¿À¿ÃÅÆÇÊÈÌÍÌÎÐÓÓÔÕÓÔÓ×Õ×××ÖÕлqHPSYUZ[\c`aadgolpfkkljjfeeibjigkmpoomekifoŠš•‘Ž…xgYUTOHKJKOKMOURUOLMKGGOPOSa_fljood[[XFKFEEF@=?@IO`ghskqstywqtifbi[TIHDBB><@@B@B9:10,,35=CWQ][_^`oz„•ž¨©°¯¯¯¨¦šƒyiZ`kp{ˆ“›Ÿ¤¨­¯®±³´µ·µµ¹»·¸´°ªª£žŽj=@OL5)(2.0--0'1/7/9//8@;<.594962Ri2,-64.15/>>7ZpK6/(58]bituclgK4-/*5C.bpa0%-"(M5A„yALM:=HUlzzc|‘ˆoaL53J)***+)-()+1-3:))*1(&%'(*947?LLNRVVY]]deciprvvywy{{x|}€ƒ€~‚€€|‚‚„ƒƒ…„†„‡‹‰…Žˆ‹‹‹ˆŠ‡‡…‰‹ŒŽŠ‹ŽŽŽ•“ŒŽŽ“’’“•‘”“‘ŽŒŠ‰Š’ŽŽŒ‘Ž‘Œ‘“‘“š–š™—™ž Ÿ Ÿ¡Ÿ¢£¦©§©©®±±²²´º·¹¹º»¿¾ÀÃÂÇÆÆÉÌÌÎÏÐÐÖÒÔÕÒÓÖ××Ö×ØØÖĆJMRSTVZb`cfedflgjjnqmhfcbfegmmlstorlojjnlps{}‚~xqfXVVQNQSPNUTSVZZPTPQMAGITXbeoggjhf^[QPJBDAI:;:BFRTchfnprwssrrnefg`ZTJJH;CA>89;?6781-332;>:DTYRYZZjs}›¥¨®®®¬¬¤œyu]cmrx†™ž¥¯±®°³µ²µ²³´··ºº¶®§¦¥¢•o??NL.#-8+.'-2.33-/1.:9=?>4?./D72Sj?(,97/35EFI<`kB5%,03]_iotmdjM6-'"1[ASpJ"$,=P4Lrf9BN54Nuj‚dJe}nlg9):+*.4.1+*-,)*$&+%($%./21;?=?GQST[^XY^cimlxsux|{x{zzyz}~€|€€€ƒ…ƒ~…„„…€‡‡……‰‰‹Š‡‡‡‡‡‹ˆ‰‹ŒŽ’Ž‘Š’“‘’“”•’’–•‘ŒŽ•“Œ’‘‰Ž‘ŒŽŒ‘‹Ž“”––——•˜—šŸŸŸ ž¢¥©¤¤¦¦«­°±±¶¸µ¸»½»¾½ÁÁÅÂÅÆÉÊÊÍÍÍÐÑÒÔÕÔÔÓÕÔÔÖÖØÖÌYFWRWV^]Ycbagfjknhmlnpjiiifdroptxqqpnmrrompprvqoic^ZTUXTRUTU^\VUPVVPNCKFOTX^edhls[fSQINGFCF>C=@@LR\jkjomprw{twqjmi]YOIEFB>>@9=A<4552///955:BIPQYVYdt}›¢¥®®¯­©¤™xna`iv|†Œ•Ÿ§©ª°±¯²´²¶µ´´µ¸¶³®§©¢¢”n>:GR.+04+4-9JG1,,)826@ED;8=88@?2KwO,'/2*31=>FJ[^:4'+,6JYgbl}nyd3'.%.O`Ii‚n1%'1RU@[}]/PN1Gyz_{w?6`vjqL390.-69;=B99/')((&*()1;=AJEKSNYUVZc`^fosrrux}|zxyxy|y~|€‚~‚…~|‚€€‚€~‚‰ˆ‰‚„†…‰Š‰Œ‰‚‡‰†‹‡‹‘’ŠŽŽŽŒŠŒ‹—’•””’“Ž‹“–Ž‘‘‘“‰‘Ž‹ŒŒŽŽ’’–˜—–“•šš™œœ››Ÿ§¦¡¥©¤ª¬®²°´·µ¹º»º½½¼ÁÀÃÄÅÉËÇÊÍÐÎÏÓ×ÕÓÓÓÓÔ×ÔØÕÔÏ­gHROPS]Z\d``aeenmjrpmqlejklojxqtttxpxqprnnjqpoojgaZVXZZ_[W\db_U[YXPFJFOMPX]_hnmcb[XaSPGOILFOF2290/*-:9547*+/28ACIJ9?38@=+?m\6%8.(00:@T]_T8/,+'5J^q[J}|xi3$/$ 2Y[`u€N+ ';9YJ:xz;1VL:dxbz}b8@oqaW66.---.1**(%!*&#,,599@FILMUXXW^`fecknotsxtvxvxzx{z|{~}„†ƒ|‚}ƒ~„‰‡‡‡‰†…ˆ‡‰……†…ˆŠ‰‹ŒŒŒŒŽŒ”’‘”‘‘Ž‰‘”“Ž’–’ŽŒŒ‘Ž‹ŽŽ‹“”•‘–—’“š™œœ›™Ÿ ¡¢¥§¨«¨©°¯¯±±¶²¹¼¼¾¾½¾¿ÄÄÇÈÅÈÌÎÍÍÏÑÔÓÓÓÒÔÔ×ÕØÕÔÓ¼|NNKTWRT\]abbfgnkmhsnnokiolsrtsstqtorstwqminfhhgb``[Z[Yaaa_gb_[UUXNNNRQQVY^gghgchTO[NOVKKJ@CA==OT]gilmuwxz}qqkhiebSSEKGB<88=?B<9687;0::;8;:=?INRQRWnuš¥¬±µ´³¯©¡“†|rfcmo|„Ž™ž¦¨¯°®³´´²¶µ·¶º¸´´®«§¥†^DdrZJHDDS]cgztou{wunkliea^TFHC>=>=;6?;5823:4322C:??@=EMMQL[nvŒœ¦¯³º¿¼º³¨Ÿ‹‡{maln…˜ ¥­°±´³±´´´±¸¹»ºµ³±ª¦¢œuZG;EH>>34@eQ22.(-+.?Dfb8/(.+'2Ddnj=Jw‚|i6"('%2dmf’oD-$ *>bVtwH#0CGerkwysiULDIG))&'+%7.*)(.1<-./58:;DNOVU[cblqpqpqppoqvvy{|{€|‚€|€€€~~ƒ‚}~‚‚}‚€‚„‰ˆ††ˆ‡‹“ˆ‰ŒˆŠˆ‡Š‰‰ŠŽŽŒŒ‘’–‘‘’’‘–“““•‘’–’š“Ž‘Ž’’‘”ŽŒŽ’’Ž’–’’”“™–”—™šš›šŸŸ¡¤¤§£§©¥©ª­­±³±²±¶º»¼¼½ÀÃÄÄÃÆÇËÍÊÐÏÔÓÑÑÒÑÐÓ×ÕÖØÓÌVFIRSZ\]]ccdhhhrnolkntpvrssvuyzzxtqttqqvmkjekifiebba^gjmjjgcb^XWRMRTTVV^acdaWPVPRLEEKLNDQKILAOSXbjqtqvzzyukkona^SMFH<:9<7A96340835.-55::DA;EIJTgtžª¸½ÃÃÀÀ¼¶¬–‡uhbju}†šž¥«¬²³³²³»µ´¸¹¶¹º³µ°¦—uNF:.AI@=46+1064,41/+<817-;;1.7>;--0-0:36@C579938>C=20MeU2(-17)?W~o;D&41.):hixC/TŠƒƒf;83('QrexwHM="%#/DSJ†W*$)6VS^kykA1-'=4).4((3&54*-/232/9=NQT[]ddfnmmqtswsrstvvxz}~~}|}|zƒ~€€†€|ƒ†€‚€ƒƒ€€‚ˆˆ…ˆ‹Š„†ˆŠƒ‡Ž‹ˆŠˆ‰Œ‹ŠŠ†ˆŒŽ‘ŽŽ•’‘Ž’Ž’‘””•“‘“’”“’’““Ž‘‘˜‘’“““““”˜••—––•›™ŸŸœ¢£¢¤¥§§§§«©°°±¶´µ·³º»º¼¹¾ÁÃÈÆÈÈÉÊÉÏÎÎÒÐÑÒÑÓÐÓÖÖÓÔнxFCMVQUb]^fikjjinpnnnrr~vzxwtyxtpuuupvqqqplokihdbbcdmppqrjkd^[ZYTVQ\[Zbfbc]\WUMLDB@JHLFCQBHOMWejpqxrv¥swuqibcV\VSFF>?<6;;9B84778275322486527E?BC@H`y«»ÆÈÎËÊÈÆǼ°œid{r{†‘›Ÿ¦ª°²±²³´¸²µ¶º¸¹¹¶°¥˜whRJ:6??81320(,:5-(7.-438EA:337=>;?>0+AVi9*)+),>k‰oC2#//14FulyC2@w…}T?7*-HUfeƒPIO0 !#<69:3:>1463838A@008?=327>JJh{®ÀÊÉÌÌÊÈÈÇÀ·¬pfpt€…šŸ¦¦­³³´´²¸³´·¸¹¸¹´®© ‰rh]@<976,4:>1+61..+0-7/7==5:9379IA>34:FiM&&+-2GscB1)245*?ug}K?@fŽŠ…m>2+$%9RivY-MB$!$0VPAl†d8%);WDNi|oaN*5S2%. +($)1137079>KMWW`^fgflprruuswtutttuyx}~x}~}|z€|||‚~ƒ|ƒ€‚‡ˆ‚‚‚„ƒƒƒƒ†…Š†„‡‹‰‹‹‡Šˆ‡‡ŒŠ‡‰ŠŽŠŠŒŒ’“‘‹““•’”’“—“’”“™“‘‘•”””“—”“’Ž–“‘“–•“”–•™——•–š™œ£œŸŸ£¥¤¤¥¨®©©«°³²´¶±²·¹¼¹º»¿ÄÅÉÈÅÉÌÉÌÌÍÏÏÏÒÑÑÐÔÑ×ÖÕÓÊ¡TMMPPUXV\[VWZgpmkfliswxz{w{zwttxuvptssstlskkljkhnnqusuuqpjjb]^XVX]b``cfdeWUSPEDJCCPBAHKFGQ_Ygjmuz{zzvxolmi^[\NOFI:@4;8?:9735;9:7;FR116781047<;>=Hi|‘·ÄÆÉÌÌËÊÈÈ÷«™sitp|…Œ˜ ¤©®±²®¯°¶´³´²·´´®±®§–tmNE>52(2=N:);03(14*@C646;4???C;BN9)34Z_%'/-.SƒŠVF1+14/)Gsk‚@BIS…‘‰uN,+(',>bnf.560.1>;DK\00515935((;QWBHnp:#3_IGXyj>`spc+#& #$)+,34484148:9;K73('285-,D/2?B?5=8B8>NBGGP3/,BkH84.0a‘hNL<+2089[ut{/:WJO]–Œp?-,4(/Vgzg/-?O9+2M[GFO`W,.HN@INQ[]Xccjjgekkwpmrxxuyty}uwzz{|‚~~}}~|€‚„‡…€€††„…€ƒ‚„‚†‰†„ˆŠ†Š…†„††‹ŽŠŠŠŠŽŒ‰‹ŽŽ‘Ž”‘‘‘”‘Ž““’“–•’’’‘’˜–——–––—‘•”••‘‘‘–––”™›››šš™”™ £¢ ¦§¦¦§¦¥§§¬«²°®®²²¸¸»ºº»¾¿ÁÃÅÆÉÄÉÉÍÏÏÎÏÑÑÒÑÒÒÒÔÒÔÓÆ‹LOQEVVYVZkegfbdjhhqvtwyxuutxv{x~xswutslqrurpuxy~‚wvpkia]]_^^cghbZ\USXSZVWOXUIONEMMNPYbhouy|€y}vvikicWXQS@=942/,/33483E:=FMRR[^00946629?37:@FhŸÄÃÅÇÆÉÍÉÇÄÁ½¸«ƒimu~…‘–¢£¨®±²±±±²´±µ´·´¸²­­¥‚y~f]34221,/:+)6;5)K624=<-:A6@;KXEUCQB:8:ALH8)5gŠYKK7.03:?Pjjy%3_MSE†š€^2+%0:X|d€P3.IG87;][>??W3'6MOQp|HT`vˆvP/"'%&+*17:>INQXU[_affjkiqvtttsy~xyxyuxxw{z€‚€|}{€|~†„„‚ƒƒƒ‡‡‚…€}„ˆ†ˆŠ‹‡Œ†ˆ‡ˆ††‡ŠŒŠŠ‰‹Š‘Ž“‘’‘–“””‘Œ—“““’“–š•“•™”‘š’•–‘”’”–—•–œ››œšœš›šž£¢¢¦¤¦¢¤Ÿ¢¨¨¨¬±±­­²²¹¹»¹¸¾½ÀÁÂÄÃÉÉÉÉÊÍÍÍÎÓÐÑÓÓÒÓÒÓÔÒÍ ]EOMPRUSWY_chcdjhkqspswzvzw{z}‚{uztuusqtvwxxsw{€~~ƒyurjh]][]W__c]WYWWMOVOT[VOWQKSJKOYZ_huuy€„}‚|uonja^YOKG@=A7,,/;777:CB9AKNaZX_660/55279=378@`xŸÀÃÂÃÉÈÈÈÆÁÁ½µ®„isuxˆ’—Ÿ£©®´±¯±²µ¶²³µµ·»±«®˜wihWW54870)5,-+38;0*8:<9C5:H:?>LSIYHOG117>AQ=1<†ŒM.35>>Lorx)*V^JHqsC,#0;R†e~e4333DG9N_[AA;>(45MLRiQ?Q]ƒ„~`0$)*(/=@FKKNNZZ]\ioeilnvrqvo{wyz{xx~{}€z{€}|{€„ˆƒ„„~…‚†…ˆ€ƒ†„ˆ††ˆŽŒ†‹†‰„…„ƒˆ‹‹Œˆ‰‹‹Ž‘‘”“’‘‘•Ž•Ž‘““‘’”™˜—–•“““•’’““’”““˜–”•—š˜š–›—˜›Ÿ ž£§¡¤¢¡£¢¦©®©®¯©°±¸´»½ºº¾¾ÁÂÃÃÆÆÊËÉËÍÎÌËÏÏÐÔÒÎÕÓÒÔÔÒ²iHHNUUW\\]Xcd`aggjjqrvstpvwx€}~}{~rwutpvyxw}|†€‚}~wsoffdZ^dX__c[WRUMSLLTUXVSTRSNKSZWanouw~€€ƒ}~|vmmh_TRRC:8159.56255:47@CNSXZ]^Z..224123;7:67DWwÁÄÃÅÅÈÇÉÄ¿¹³¬‡dmo}‡™ ¢««³°°²±²µ´³´··¶´®«™sd`VN37KN@]FLO4.75?TE5O˜‰A2E>01D?9Qwvw+(K^KJLh{†f=),;O„y{i80'#(:GKPY]dfb`++2/6/21<5-78@Rp–ÀÂÅÄÈÈÆÅÅÀ½¹´§€imxƒ‰š¡¢©ª²±µ³µ´´¶µ¶µ·µ³®­¢xIWZ?/9G=0&.+,/@A=)(6M25A9EF6??MG[DRJ?BA.)4,9SoE9LPlndtZ793=ORQNUYSXYcbjhinqpuruwvsw|}{z}||~|~{{~}{ƒ~~‚}‚‚}€‚…†‡‚ƒ€ƒ„„……ˆ†Š‹Žƒ…„…Š…‡‰‡‹ŒŠˆŠ’‰ŽŽ‘’‘”’‘“ŽŽ‹Ž–—’’”’•–•”š”–”•“”˜–˜”“”––•˜˜’––œœ ››žœž¢ ¤¢¦§¨¦¤¤¨§ªª¬­¬­®´´·¶»¾½ÁÀÁÂÃÅÃÉÈÈÌÊÌÌÍÏÓÔÔÐÑÓÒÔÔÕÅŠe\`]SXY^^]WX\daeolhnmwqu|}…ƒ…~|x|yz{zxx~…‚ˆˆŽ†‰€}}srid`\[bYVQWRLOHKKOW]_aVZZTUQUOT\^fjtv}~ƒ„}€wui`XONF?:536.-1-04.45;FEOP\`dhdb,,736/23;3/355Om‘¸ÃÄÄÈÆÆÇÁÀ¿·²Ÿxinwƒ‡Ž›Ÿ¥£§²®¶´³´µ²¶´·¶·¯³­£N_^E85G0+'+()6>F<"&6I+/KG?U8@>HF9FHETA95:IhaFˆ¢\:56LC%3;:Hrqq2&0QNKDH?vŠv];2@”]U-$252(02EBOQC@G/(654Jt`-)>_fISyZ:9KSQRRT^Z[Y]fdkklnnpqpyvzv~yyx~{}z|~}ƒ‚‚‚}{~}€~‚„†„…†„‡‚…ƒ‚ƒ„ƒ‡‡‰‰‹…†ˆ…„„Š†‰†‡Š‰ŒŠŽŒ‹‹’’”‘Ž•’“’’’“”—•—•™••”””—”—•˜˜“•˜–™•›Ÿœ¤˜œž› Ÿ¤Ÿ£¥¨¥£¦£¨©©©¬¬®°¬³¸¸¹¸ºÀ¿ÀÀÃÂÃÁÆÇÇËÊËÌÎÏÏÑÑÏÐÓÓÒÔÔÌvmpf_^X][]Z^b^abkhjifx|~‚…‡„„~€y}~~y}€„Š‹ŒŒ‡‡‚|wvld_V\ZYTQNHMJHNEQVY[Z]Z\\TWSPTY`^fpw~€z|{wqe`TK><;::33,)*2.46;DHLS^Zahdhil,,7B6/23;3/355Om‘¸ÃÄÄÈÆÆÇÁÀ¿·²Ÿxinwƒ‡Ž›Ÿ¥£§²®¶´³´µ²¶´·¶·¯³­£N_^E85G0+'+()6>F<"&6I+/KG?U8@>HF9FHETA95:IhaFˆ¢\:56LC%3;:Hrqq2&0QNKDH?vŠv];5@”]U-$252(02EBOQC@G/(654Jt`-)>_fISyZ:9KSQRRT^Z[Y]fdkklnnpqpyvzv~yyx~{}z|~}ƒ‚‚‚}{~}€~‚„†„…†„‡‚…ƒ‚ƒ„ƒ‡‡‰‰‹…†ˆ…„„Š†‰†‡Š‰ŒŠŽŒ‹‹’’”‘Ž•’“’’’“”—•—•™••”””—”—•˜˜“•˜–™•›Ÿœ¤˜œž› Ÿ¤Ÿ£¥¨¥£¦£¨©©©¬¬®°¬³¸¸¹¸ºÀ¿ÀÀÃÂÃÁÆÇÇËÊËÌÎÏÏÑÑÏÐÓÓÒÔÔÌvmpf_^X][]Z^b^abkhjifx|~‚…‡„„~€y}~~y}€„Š‹ŒŒ‡‡‚|wvld_V\ZYTQNHMJHNEQVY[Z]Z\\TWSPTY`^fpw~€z|{wqe`TK><;::33,)*2.46;DHLS^Zahdhil \ No newline at end of file diff -r 000000000000 -r be303a3f5ea8 make/make.emx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/make.emx Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,20 @@ +CC = gcc +CFLAGS = -O2 -DEMX +LDFLAGS = +LIBS = -lm +PGMLIBS = -lpgm -lpbm +WMLIB = -L. -lwm +WAVELIB = -L. -lwavelet +EXE = .exe +MAKEDEP = makedepend +GROFF = groff -Tps -man +RM = rm -f +CP = cp -i +O = .o +LIB = .a +LIBPREFIX = lib +BINPATH = bin/ +OBJPATH = obj/ +DOCPATH = doc/ +INCLUDES = -I/usr/local/include +INSTALLDIR = ../os2_bin diff -r 000000000000 -r be303a3f5ea8 make/make.linux --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/make.linux Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,19 @@ +CC = gcc +CFLAGS = -O2 -g -DLINUX +LDFLAGS = -g +LIBS = -lm +PGMLIBS = -lnetpbm -lm +WMLIB = -L. -lwm +WAVELIB = -L. -lwavelet +EXE = +MAKEDEP = makedepend +GROFF = groff -Tps -man +RM = rm -f +CP = cp -v +O = .o +LIB = .a +LIBPREFIX = lib +BINPATH = bin/ +OBJPATH = obj/ +DOCPATH = doc/ +INSTALLDIR = ../linux_bin diff -r 000000000000 -r be303a3f5ea8 make/make.mingw --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/make.mingw Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,20 @@ +CC = gcc +CFLAGS = -O2 -DMINGW -mno-cygwin -I/usr/local/mingw +LDFLAGS = -mno-cygwin -L/usr/local/mingw +LIBS = -lgetopt -lm -liberty +PGMLIBS = -lpgm -lpbm -lgetopt +WMLIB = -L. -lwm +WAVELIB = -L. -lwavelet +EXE = .exe +MAKEDEP = makedepend +GROFF = groff -Tps -man +RM = rm -f +CP = cp -i +O = .o +LIB = .a +LIBPREFIX = lib +BINPATH = bin/ +OBJPATH = obj/ +DOCPATH = doc/ +INCLUDES = -I/usr/local/include +INSTALLDIR = ../win32_bin diff -r 000000000000 -r be303a3f5ea8 manual.lyx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/manual.lyx Sun Aug 12 13:14:34 2007 +0200 @@ -0,0 +1,966 @@ +#LyX 1.1 created this file. For more info see http://www.lyx.org/ +\lyxformat 218 +\textclass paper +\language english +\inputencoding auto +\fontscheme default +\graphics default +\paperfontsize default +\spacing single +\papersize Default +\paperpackage a4 +\use_geometry 0 +\use_amsmath 0 +\paperorientation portrait +\secnumdepth 3 +\tocdepth 3 +\paragraph_separation skip +\defskip smallskip +\quotes_language english +\quotes_times 2 +\papercolumns 1 +\papersides 1 +\paperpagestyle default + +\layout Title + +Watermarking Source Code +\layout SubTitle + +version 0.4 +\layout Author + +Peter Meerwald +\layout Address + +Dept. + of Scientific Computing, University of Salzburg +\newline +Jakob-Haringer-Str. + 2, A-5020 Salzburg, Austria +\newline + +\begin_inset LatexCommand \url{mailto:pmeerw@cosy.sbg.ac.at} + +\end_inset + + +\newline + +\begin_inset LatexCommand \url{http://www.cosy.sbg.ac.at/~pmeerw/Watermarking} + +\end_inset + + +\layout Abstract + +This package provides source code for some watermarking algorithms in hopefully + portable C code. + The programs can be used to study watermarking techniques, perform comparative + robustness tests and develop new attacks against embedded watermarks. +\layout Abstract + +However, the provided programs are by no means suitable for real-world applicati +on (i.e. + copyright protection) and the code solely serves some educational purpose. +\layout Standard + + +\begin_inset LatexCommand \tableofcontents{} + +\end_inset + + +\layout Section + +Introduction +\layout Standard + +Academic research in the watermarking field has grown dramatically since + approximately 1995. + But surprisingly, source code for the proposed watermarking schemes has + not been made available. + The reason is most likely the security of many watermarking systems lies + at least to some extent in the embedding and detection algorithm itself, + and not in the keys used -- violating the Kerckhoff principle +\begin_inset LatexCommand \cite{Kerckhoff1883a} + +\end_inset + +. +\layout Standard + +With the availability of public robustness test for watermarking algorithms, + StirMark +\begin_inset LatexCommand \cite{Petitcolas99c, Petitcolas98b, Petitcolas98a} + +\end_inset + +, Unzign +\begin_float footnote +\layout Standard + + +\begin_inset LatexCommand \url{http://www.altern.org/watermark} + +\end_inset + + +\end_float + and very recently Checkmark +\begin_inset LatexCommand \cite{Pereira01b} + +\end_inset + +, the situation begins to improve. + Now it is possible to measure the performance of watermarking systems. + +\layout Standard + +In order the compare and evaluate new embedding and detection techniques, + it is also necessary to have some reference implementations of the older, + now often called classical schemes. + In this work, we provide some implementations of watermarking schemes, + some of which can be considered 'classical'. +\layout Standard + +It was the goal to capture the main ideas of the proposed algorithms, as + layed out in the respective papers. + This is clearly not an easy task as some papers do not disclose all details + or state which particular parameters were used to obtain the results outlined + in the communications. +\layout Standard + +I am very interested in hearing your comments, complaints and suggestions + regarding this software. + Moreover, if you have source code for a watermarking scheme not yet covered + or some useful utility I would be happy to include your code in this distributi +on. + Please see the contact information at the top of this document. +\layout Standard + +If you use the accompanying code, please cite my thesis: +\layout Quotation + +Peter Meerwald, Digital Image Watermarking in the Wavelet Transform Domain, + Master's Thesis, Department of Scientific Computing, University of Salzburg, + Austria, January 2001. +\layout Section + +Software +\layout Standard + +Most of the software provided herein was written by myself, as part of my + Master thesis. + Some contributions were made by Vassilis Fotopoulos +\begin_float footnote +\layout Standard + + +\begin_inset LatexCommand \url{mailto:vfotop1@physics.upatras.gr} + +\end_inset + + +\end_float +. + The software in the archive is organized in the following sub-directories: +\layout Description + +Fotopoulos/ contains contributions by Vassilis Fotopoulos +\layout Description + +Meerwald/ contains my work +\layout Description + +images/ contains the Lena image in PGM format; the default parameters of + most algorithms are tuned to work best with that image +\layout Description + +linux_bin/ the place where the Linux executables are stored in the binary + distribution +\layout Description + +win32_bin/ the place where Windows 32-bit executables are distributed; tested + with Windows NT 4.0 only +\layout Description + +make/ contains the +\family typewriter +\size small +Makefile +\family default +\size default + options to build the code on supported platforms +\layout Standard + +For the purpose of this software package, a watermarking system comprises + four parts, namely: signature generation, watermark embedding, watermark + extraction and signature comparison or detection -- with the exception + of Vassilis's code; there are only cast and test programs (corresponds + to watermark embedding and detection). + Signature is used more less as a synonym for mark and can be thought of + as the payload (at least for some schemes :-). +\layout Standard + +All programs only accept the image in NetPBM format and will also produce + only NetPBM-format files (see section +\begin_inset LatexCommand \ref{sec:prereq} + +\end_inset + +). + Unfortunately, most programs have only been tested with 8-bit gray-scale + images of size +\begin_inset Formula \( 512\times 512. \) +\end_inset + + +\layout Standard + +In order to simplify batch testing, the programs allow to read either from + a file, e.g. +\layout Standard + + +\family typewriter +\size small +wm_cox_e -s cox.sig +\series bold +image.pgm +\layout Standard + +or from standard input, i.e. +\layout Standard + +wm_cox_e -s cox.sig +\series bold +< image.pgm +\layout Standard + +The output is usually written to standard output, i.e. + +\layout Standard + + +\family typewriter +\size small +wm_cox_e -s cox.sig image.pgm +\series bold +> wm_image.pgm +\layout Standard + +unless redirected to a file, e.g. +\layout Standard + + +\family typewriter +\size small +wm_cox_e -s cox.sig +\series bold +-o wm_image.pgm +\series default + image.pgm +\layout Subsection + +Featured algorithms +\layout Standard + +Currently it includes the following watermarking algorithms +\layout Itemize + +Bruyndonckx [bruyn], refer to +\layout Quotation + +O. + Bruyndonckx, Jean-Jacques Quisquater, and Benoit M. + Macq. + Spatial method for copyright labeling of digital images. + In IEEE Workshop on Nonlinear Signal and Image Processing '95, Thessaloniki, + Greece, pages 456 - 459, 1995. +\layout Itemize + +Corvi, refer to +\layout Quotation + +Marco Corvi and Gianluca Nicchiotti. + Wavelet-based image watermarking for copyright protection. + In Scandinavian Conference on Image Analysis SCIA '97, Lappeenranta, Finland, + June 1997. +\layout Itemize + +Cox, refer to +\layout Quotation + +Ingemar J. + Cox, Joe Kilian, Tom Leighton, and Talal G. + Shamoon. + Secure spread spectrum watermarking for multimedia. + In Proceedings of the IEEE ICIP '97, volume 6, pages 1673 - 1687, Santa + Barbara, California, USA, 1997. +\layout Itemize + +Dugad, refer to +\layout Quotation + +Rakesh Dugad, Krishna Ratakonda, and Narendra Ahuja. + A new wavelet-based scheme for watermarking images. + In Proceedings of the IEEE International Conference on Image Processing, + ICIP '98, Chicago, IL, USA, October 1998. + +\layout Itemize + +Fridrich (2. + scheme), refer to +\layout Quotation + +Jiri Fridrich. + Combining low-frequency and spread spectrum watermarking. + In Proceedings of the SPIE Symposium on Optical Science, Engineering and + Instrumentation, San Diego, USA, July 1998. + +\layout Itemize + +Kim, refer to +\layout Quotation + +Jong Ryul Kim and Young Shik Moon. + A robust wavelet-based digital watermark using level-adaptive thresholding. + In Proceedings of the 6th IEEE International Conference on Image Processing + ICIP '99, page 202, Kobe, Japan, October 1999. +\layout Itemize + +Koch, refer to +\layout Quotation + +Eckhard Koch and Jian Zhao. + Towards robust and hidden image copyright labeling. + In Proceedings of the IEEE International Workshop on Nonlinear Signal and + Image Processing, pages 452 - 455, Halkidiki, Marmaras, Greece, June 1995. +\layout Itemize + +Wang, refer to +\layout Quotation + +Houng-Jyh Wang, Po-Chyi Su, and C.-C. + Jay Kuo. + Wavelet-based digital image watermarking. + Optics Express, volume 3, pp. + 497, December 1998. + +\layout Itemize + +Xia, refer to +\layout Quotation + +Xiang-Gen Xia, Charles G. + Boncelet, and Gonzalo R. + Arce. + Wavelet transform based watermark for digital images. + Optics Express, volume 3, pp. + 497, December 1998. +\layout Itemize + +Xie, refer to +\layout Quotation + +Liehua Xie and Gonzalo R. + Arce. + Joint wavelet compression and authentication watermarking. + In Proceedings of the IEEE International Conference on Image Processing, + ICIP '98, Chicago, IL, USA, 1998. +\layout Itemize + +Zhu, refer to +\layout Quotation + +Wenwu Zhu, Zixiang Xiong, and Ya-Qin Zhang. + Multiresolution watermarking for images and video: a unified approach. + In Proceedings of the IEEE International Conference on Image Processing, + ICIP '98, Chicago, IL, USA, October 1998. + +\layout Itemize + +Piva/Fotopoulos [cast|test-pv,hart,sub], contribution by Vassilis Fotopoulos, + refer to +\layout Quotation + +M.Barni, F. + Bartolini, V. + Cappellini, A. + Piva. + A DCT-Domain System for Robust Image Watermarking, Signal Processing, vol. + 66, pp 357 - 372, 1998. +\begin_deeper +\layout Standard +\added_space_top smallskip \added_space_bottom smallskip +and +\end_deeper +\layout Quotation + +V. + Fotopoulos, A. + N. + Skodras, A Subband DCT approach to image watermarking, X European Signal + Processing Conference, September 4 - 8, 2000, Tampere, Finland. +\layout Standard + +More algorithms will be added over time, I have implemented about 13 watermarkin +g algorithms in the spatial-, DCT-, and wavelet domain so far. +\layout Subsection + + +\begin_inset LatexCommand \label{sec:utility_programs} + +\end_inset + +Utility programs +\layout Standard + +A good way to check the effect of a watermarking algorithm is computing + the difference image, i.e. + subtracting the original image from the watermarked image. + Alternatively, one can also have a look at the modified coefficients in + the transform domain. + The following programs facilitate these tasks: +\layout Description + +cmp_pgm compute difference image, PSNR, ... +\layout Description + +cmp_dct compute full-frame DCT domain difference image +\layout Description + +cmp_dct8x8 compute 8x8 block-based DCT difference image +\layout Description + +cmp_dwt compute DWT domain difference image +\layout Standard + +For example, to produce the difference image of two PGM files and compute + the PSNR along with some other measures, the following command can be used: +\layout Standard + + +\family typewriter +\size small +cmp_pgm -p -i original.pgm -o diff.pgm watermarked.pgm +\layout Section + +Usage +\layout Standard + +Note, almost all programs will output usage information if called with the + +\family typewriter +\size small +-h +\family default +\size default + argument. +\layout Subsection + +Generating a mark +\layout Standard + +First, you have to generate an appropriate signature file for the corresponding + embedding/detection algorithm; e.g. + if you are going to use Cox' scheme, then you would run +\layout Standard + + +\family typewriter +\size small +gen_cox_sig +\layout Standard + +The programs outputs some parameters and a sequence of Gaussian distributed + random numbers (which is the watermark sequence). + You want to save that into a signature file, so you run +\layout Standard + + +\family typewriter +\size small +gen_cox_sig > cox.sig or +\layout Standard + + +\family typewriter +\size small +gen_cox_sig -o cox.sig +\layout Standard + +You can influence e.g. + the embedding strength that will be used in the embedding step by running +\layout Standard + + +\family typewriter +\size small +gen_cox_sig -a 0.5 > too_strong_cox.sig +\layout Standard + +Usually, the programs for generating a signature will supply reasonable + default values for marking a 8-bit gray-scale image of size +\begin_inset Formula \( 512\times 512. \) +\end_inset + + +\layout Subsection + +Watermark embedding +\layout Standard + +Watermark embedding is performed with the following command (for our example, + we are using Cox' scheme): +\layout Standard + + +\family typewriter +\size small +wm_cox_e -s cox.sig -o cox_lena.pgm lena.pgm +\layout Standard + +The signature file is parsed to obtain the particular watermark sequence + and the embedding strength. + The watermarked image is written to the file +\family typewriter +\size small +cox_lena.pgm +\family default +\size default +. + Now it the time to check the perceptual quality of the produced image and + also have a look at the difference image (see section +\begin_inset LatexCommand \ref{sec:utility_programs} + +\end_inset + +). +\layout Subsection + +Watermark extraction +\layout Standard + +To extract the embedded signature, we execute the command +\layout Standard + + +\family typewriter +\size small +wm_cox_d -s cox.sig -i lena.pgm -o cox.wm cox_lena.pgm +\layout Standard + +Since Cox' algorithm is not blind, the original image is needed as a reference + to extract the embedded mark. + The embedded mark will be stored in +\family typewriter +\size small +cox.wm +\family default +\size default +. + The original signature, +\family typewriter +\size small +cox.sig +\family default +\size default +, is used to get the auxiliary embedding parameter correct (e.g. + embedding strength). + +\layout Subsection + +Comparing the mark +\layout Standard + +The final step is comparing the original signature against the extracted + signature. + The result here is usually a correlation factor. + Values around 0 indicate that the mark has not been found, values around + 1 +\layout Standard + +In most programs a analytical detection threshold for some detection probability + is not used. + Hence, one has to observe the output of the detector for many different + keys (around 1000 I'd suggest) to establish a reasonable threshold for + detection. + A good value to go with initially might be 0.2 which means we claim the + watermark detected if the correlation factor is > 0.2. +\layout Standard + +The appropriate command for comparing the mark is +\layout Standard + + +\family typewriter +\size small +cmp_cox_sig -s cox.sig cox.wm +\layout Subsection + +Batch testing - benchmarking +\layout Standard + +If you want to run many test you can pipe the images to be do be watermarked + (and tested) through the embedder and detector. + The programs then act like a filter. + Try something like the following in a Unix shell script: +\layout Standard + + +\family typewriter +\size small +gen_cox_sig > cox.sig +\layout Standard + + +\family typewriter +\size small +for i in *.pgm +\layout Standard + + +\family typewriter +\size small +do +\layout Standard + + +\family typewriter +\size small +\SpecialChar ~ +\SpecialChar ~ +wm_cox_e -s cox.sig $i | +\backslash + +\layout Standard + + +\family typewriter +\size small +\SpecialChar ~ +\SpecialChar ~ +wm_cox_d -s cox.sig -i $i | +\backslash + +\layout Standard + + +\family typewriter +\size small +\SpecialChar ~ +\SpecialChar ~ +cmp_cox_sig -s cox.sig +\layout Standard + + +\family typewriter +\size small +done +\layout Section + + +\begin_inset LatexCommand \label{sec:recompile} + +\end_inset + +Recompiling +\layout Standard + +Note, that most watermark embedding/extraction programs use the built-in + random number generator of the C library, i.e. + +\family typewriter +\size small +srandom() +\family default +\size default + and +\family typewriter +\size small +random(). + +\family default +\size default +Therefore, if you recompile, chances are that you won't be able to use your + images watermarked with the previous version. +\layout Standard + +The Makefile options for compiling on the different platforms can be found + in the +\family typewriter +\size small +make/ +\family default +\size default + sub-directory of the archive. +\layout Subsection + + +\begin_inset LatexCommand \label{sec:prereq} + +\end_inset + +Prerequisites +\layout Subsubsection + +NetPBM +\layout Standard + +NetPBM is responsible for image file I/O and provides a definition of a + simple image file format along with many image file format filters that + allow to convert images to and from NetPBM format. + +\layout Standard + +You need to get and install the NetPBM library at +\begin_inset LatexCommand \url{http://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/} + +\end_inset + + or +\begin_inset LatexCommand \url{http://netpbm.sourceforge.net} + +\end_inset + +. + The library provides +\family typewriter +\size small +pgm.h +\family default +\size default + and the appropriate implementation. +\layout Subsection + +Unix/Linux platform +\layout Standard + +All programs were developed using Linux and GNU C. + The programs should compile and work with all recent versions of Linux + and GNU C. + +\layout Subsection + + +\begin_inset LatexCommand \label{sec:win32_compile} + +\end_inset + +Win32 platform +\layout Standard + +The programs were ported to the Windows platform using the Cygwin +\begin_float footnote +\layout Standard + + +\begin_inset LatexCommand \url{http://www.cygwin.com} + +\end_inset + + +\end_float +and Mingw +\begin_float footnote +\layout Standard + + +\begin_inset LatexCommand \url{http://www.mingw.org} + +\end_inset + + +\end_float + environment. + Most notable, the file mode for standard input and standard output has + to be set to binary mode. + This is accomplished with the +\family typewriter +\size small +setmode() +\family default +\size default + or +\family typewriter +\size small +_fsetmode() +\family default +\size default + commands. +\layout Section + +FAQ +\layout Standard + +Q: How can I report problems? +\layout Standard + +A: See the contact information at the beginning of this document. +\layout Standard + +Q: The compiler complains about +\family typewriter +\size small +pgm.h +\family default +\size default +? +\layout Standard + +A: You need to get and install the NetPBM library, see section +\begin_inset LatexCommand \ref{sec:prereq} + +\end_inset + +. +\layout Standard + +Q: What is the best algorithm? +\layout Standard + +A: Depends on your application. +\layout Standard + +Q: What is the most robust algorithm? +\layout Standard + +A: Depends on the attack. + See some results on +\begin_inset LatexCommand \url{http://www.cosy.sbg.ac.at/~pmeerw/Watermarking} + +\end_inset + +. +\layout Standard + +Q: I need code for a full-frame DCT? +\layout Standard + +A: See the files Meerwald/dct.* in the archive. +\layout Standard + +Q: I need code for a 8x8 block DCT? +\layout Standard + +A: See the files +\family typewriter +\size small +Meerwald/dct.* +\family default +\size default + in the archive. +\layout Standard + +Q: I need code for the wavelet transform (DWT)? +\layout Standard + +A: See the files +\family typewriter +\size small +Meerwald/wavelet.* +\family default +\size default + in the archive. +\layout Standard + +Q: I get the message 'unable to open filter.dat' - what to do? +\layout Standard + +A: Make sure the file filter.dat is in the current directory or accessible + via path/filename specified in the signature file. + Use the signature generation command to specify an absolute path if necessary. +\layout Standard + +Q: I can't compile the code using some Microsoft product? +\layout Standard + +A: Make your life easier, install GNU software! See section +\begin_inset LatexCommand \ref{sec:recompile} + +\end_inset + +. +\layout Section + +Revision history +\layout Standard + +version 0.4 (June 21, 2001) +\layout Itemize + +bug fixes +\begin_deeper +\layout Itemize + +wm_xia_{e|d}.c variable level uninitialized +\layout Itemize + +wm_zhu_{e|d}.c variable level uninitialized +\layout Itemize + +issue with random() vs. + rand() and RAND_MAX in frid2_common.c +\end_deeper +\layout Itemize + +added option to bruyn algorithm to disable block skipping +\layout Itemize + +added algorithm kim +\layout Standard + +version 0.3 (June 18, 2001) +\layout Itemize + +created a nice (?) manual/documentation +\layout Itemize + +added algorithms by Dugad, Wang, Zhu, Fridrich +\layout Itemize + +added Makefiles for Win32 platform (mingw32) +\layout Standard + +version 0.2 (February 22, 2001) +\layout Itemize + +added contribution by Vassilis Fotopoulos (Piva's algorithm, +\layout Itemize + +DCT, Hartley and subband domain) - see Fotopoulos/ subdirectory +\layout Itemize + +stuff moved to Meerwald/ subdirectory +\layout Itemize + +added Bruyndonckx, Corvi, Koch, Xia, Xie algorithms +\layout Standard + +version 0.1 (February 18, 2001) +\layout Itemize + +initial release +\layout Section + +Legal statement +\layout Standard + +My license is called "I-don't-care" license: (1) You can do with the accompanyin +g software whatever you want, but don't blame me if it doesn't work or it + causes damage. + (2) If you think my work is useful, tell me and tell others, but you are + not obliged to do so. + I suggest not to remove information contained in this other documentation + file. +\layout Standard + + +\begin_inset LatexCommand \BibTeX[plain]{watermarking} + +\end_inset + + +\the_end