From 084d0ae4132e1127fe7088fd7bcd2fa0e9dac742 Mon Sep 17 00:00:00 2001 From: ada-dmitry Date: Wed, 6 Dec 2023 10:33:15 +0300 Subject: [PATCH] added test --- Project_1.2/functions.c | 10 ++ Project_1.2/main.c | 1 - Project_1.3/declare.h | 6 +- Project_1.3/functions.c | 25 ++- Project_1.3/main.c | 15 +- Project_1.3/out/function_zeros_calculator | Bin 21168 -> 21200 bytes Project_test/Makefile | 25 +++ Project_test/README | 32 ++++ Project_test/declare.h | 15 ++ Project_test/functions.c | 187 +++++++++++++++++++++ Project_test/main.c | 103 ++++++++++++ Project_test/out/function_zeros_calculator | Bin 0 -> 21200 bytes 12 files changed, 407 insertions(+), 12 deletions(-) create mode 100644 Project_test/Makefile create mode 100644 Project_test/README create mode 100644 Project_test/declare.h create mode 100644 Project_test/functions.c create mode 100644 Project_test/main.c create mode 100755 Project_test/out/function_zeros_calculator diff --git a/Project_1.2/functions.c b/Project_1.2/functions.c index b18c0e3..d449bd9 100644 --- a/Project_1.2/functions.c +++ b/Project_1.2/functions.c @@ -64,10 +64,20 @@ R - начать поиск на другом отрезке: \n"); { case 'C': // Выбор вида "Продолжить вычисление". case 'c': + // Включение символа ECHO + term.c_lflag |= ECHO; + + // Применение новых настроек терминала + tcsetattr(0, TCSANOW, &term); return; // Выход из функции без каких-либо изменений. case 'A': // Выбор вида "Завершить вычисление". case 'a': + // Включение символа ECHO + term.c_lflag |= ECHO; + + // Применение новых настроек терминала + tcsetattr(0, TCSANOW, &term); printf("\nКорень уравнения: %lf\n", *px); printf("Работа программы завершена.\n"); exit(0); // Принудительное завершение программы с выводом текущего приближения корня. diff --git a/Project_1.2/main.c b/Project_1.2/main.c index 438878b..2fac51c 100644 --- a/Project_1.2/main.c +++ b/Project_1.2/main.c @@ -9,7 +9,6 @@ double a, b, eps, x, *pa, *pb, *px; int main() { - double tmp; pa = &a; pb = &b; diff --git a/Project_1.3/declare.h b/Project_1.3/declare.h index 9e1b174..5096fd8 100644 --- a/Project_1.3/declare.h +++ b/Project_1.3/declare.h @@ -1,5 +1,6 @@ extern double a, b, eps, x, *pa, *pb, *px; -extern short method, *mth; +extern short method, *mth, sig_flag; + // Декларирование глобальных переменных, // как внешних для последующего использования их во всей программе. #define H 0.000001 @@ -10,4 +11,5 @@ void choose_path(); void fork_method(); void chord_method(); void newton_method(); -double numerical_derivative(double x); \ No newline at end of file +double numerical_derivative(double x); +void exit_777(); \ No newline at end of file diff --git a/Project_1.3/functions.c b/Project_1.3/functions.c index 3a4dabc..366a869 100644 --- a/Project_1.3/functions.c +++ b/Project_1.3/functions.c @@ -77,6 +77,8 @@ void fork_method() // Функция поиска корней, использу void choose_path() // Функция выбора действия после вызова сигнала. { + sig_flag = 1; + char choice, *ch = &choice; struct termios term; // Задание структуры, определяющей терминал Linux. @@ -94,11 +96,10 @@ void choose_path() // Функция выбора действия после в printf("\nC - продолжить, A - закончить работу программы, \ R - начать поиск на другом отрезке, M - выбрать другой способ решения: \n"); - // Очистка стандартного потока ввода от "лишних" - __fpurge(stdin); - do { + // Очистка стандартного потока ввода от "лишних" + __fpurge(stdin); *ch = getchar(); // Запись буквы, введенной пользователем в переменную choice. switch (*ch) @@ -147,6 +148,7 @@ R - начать поиск на другом отрезке, M - выбрать return; case 'M': case 'm': + __fpurge(stdin); // Включение символа ECHO term.c_lflag |= ECHO; @@ -154,7 +156,7 @@ R - начать поиск на другом отрезке, M - выбрать tcsetattr(0, TCSANOW, &term); printf("Выберите метод вычисления корня:\ 0 - метод вилки, 1 - метод хорд, 2 - метод касательных\n(По умолчанию: 0)\n"); - scanf("%hd", mth); + *mth = getchar(); printf("Введите новые значения границ a и b: "); @@ -193,10 +195,16 @@ R - начать поиск на другом отрезке, M - выбрать printf("Newton\n"); newton_method(); } + else + { + printf("Fork\n"); + fork_method(); + } return; default: printf("Ошибка ввода, повторная попытка...\n"); + __fpurge(stdin); } } while (*ch != 'A' || *ch != 'R' || *ch != 'C' || *ch != 'a' || *ch != 'r' || *ch != 'c' || *ch != 'M' || *ch != 'm'); @@ -205,10 +213,15 @@ R - начать поиск на другом отрезке, M - выбрать // Применение новых настроек терминала tcsetattr(0, TCSANOW, &term); + + sig_flag = 0; } void ctrlc_handler(int signum) // Функция, заменяющая стандартный алгоритм для сигнала SIGINT. { - printf("\nТекущее приближение: %lf\n", *px); - choose_path(); + if (sig_flag == 0) + { + printf("\nТекущее приближение: %lf\n", *px); + choose_path(); + } } \ No newline at end of file diff --git a/Project_1.3/main.c b/Project_1.3/main.c index 1520639..2906229 100644 --- a/Project_1.3/main.c +++ b/Project_1.3/main.c @@ -2,16 +2,18 @@ #include #include #include +#include #include "declare.h" double a, b, eps, x, *pa, *pb, *px; -short method, *mth; +short method, *mth, sig_flag; int main() { double tmp; + sig_flag = 0; method = 0; mth = &method; pa = &a; @@ -32,9 +34,11 @@ int main() printf("Введите интервал [a, b] и точность eps: "); scanf("%lf %lf %lf", pa, pb, &eps); + + __fpurge(stdin); printf("Выберите метод вычисления корня:\ - 0 - метод вилки, 1 - метод хорд, 2 - метод касательных\n(По умолчанию: 0)\n"); - scanf("%hd", &method); + 0 - метод вилки, 1 - метод хорд, 2 - метод касательных\n(По умолчанию: 0): "); + *mth = getchar(); if (*pa > *pb) // Если пользователь перепутал границы { @@ -84,6 +88,11 @@ int main() printf("Newton\n"); newton_method(); } + else + { + printf("Fork\n"); + fork_method(); + } printf("\nКорень уравнения: %lf\n", *px); printf("Работа программы завершена.\n"); diff --git a/Project_1.3/out/function_zeros_calculator b/Project_1.3/out/function_zeros_calculator index 7cdb0c53864197a98be740a5465ba4527c7e5572..6a3a588bdad7da1cce4de2ccfb9955b6423c67ab 100755 GIT binary patch delta 3809 zcmb_fe^6A{6@Kr*QbT@-fL1s3oJr~xr3AQ2T|WtBEcA{7}cK^w#vO_PAtndr*U zt*o1Eu-8d#n^dPsrcRPJ=r+-`Mp4re+RQ|oItfmOpxERA&M0W&D$473f3R#O)BM$) zS^RLNmS&F%0|E!+assxFBsuDg!=-TuU_RM4-kXS#9a z)cF1mk!_LOcE(jrEZV83Qy5Td#wi|2&xTVk#2?>T=*iYN4fPNML~n0jr_ zne7!&xWEZOM`6)p2t8!Ww#;6kK>M-)UTe3wH;VlIzg{T*XU^=@rjhwebZ zRK?9y)P0dL11%ZW*0NZ=cD;*blZtFkifpFQYyxUr3hhOwo(PBn;<6zEeh1^vrpxPq z=ccwhE-y8khSr?HlYmXJqg+v2YDiCn)1&y(w3Ahze-Le70H{)ouo|9nL?&`76$Dd z+aEy=>0E~y0jrbs0oxjo{-Xn9e4QsylBBoYq3e^_%ypjmrp`tV%~;ne9b%6PF}BCf zj~WI!WQ~!F$PsJulhZlZr4MWC=tjWgi5A9J6L^SacN$en`W`l`I)np9?1~=#7(++X zJ+K*)w)%)*xL~~e`;5?G$$VfVbLC8kk%dABjTm_|l$EpFkcXO zd8fHnE)UZ3Qut$dPrQtcJGLi=^1`LkJu#3+h8#cKguCcH1Z12*u0Obat|PGRIMDey zaq<>@wW#ClDSB{l?>o$^zL3P~(la@17tltbU$sD$9)>dk_0{B0$tiWWqa?}K;SNmp zQZ2k!UhD*awBkPK4kYfRyFxy{$mqr3dk+GLqYk_{E7RhKTJKGolbX(b`hGy3R>3VY zCq1P`|3>@-ok~AIef~r*lU27mZUUC$FSrRNN9} zUL9s>xI`KkDfFwObJyWwf#%ohdoiy^GWT=>|Xn*}bt za|7xx#I&ptG9BYj9L{BeeblgSy&g$g$Vlqn7)e}8OYy#qb?eV85F;WpNr^LYR-GuM z5?Nr|>c)cBG}?Nj7U=S)v*gbNC@C$nPt#u&Z9R2Orf{uUtb zRu!Laf|%|_%JZwA&k5gl^e+EQM0X&{H_d9?EB%Z3`FMl(#oB9$?`~LTNv|2=a5%nPN?i^OLJ_PLc zyN+n@NDE6e@9XRi=kO8D``ZXus(GJ}fOVR8R|I@U^KOfP8#Qlj1pI;KT{RBXg<0UJgpvxtm(*-72^5Kkk-mX5X%R z+HrLa#?T)b*{CLuRx|#luj9q?1+`*4Uy3p;MO)W7`r|3}E`(y-!FSW&iaVA&RgNx7 zlcZqg+<3*-daeT#OH%8(B|{B;t#5~}E@C*Co#%`qtMVt4hWsU-z!!#5H((g)gWS^R z@A_uz-;Q?)jqe)wKVr*_|4Ra7Ye8uYs}6rid%?7t!cPt3Fo3PwFg}3Ig6)M3!M4I) zzGN67*egATVZ$~}{M;}KVOwC=!CvV#j6JaNeTMNW?4hfM@jmRN0g_WV%iaK)85k~= zO*B(84PV?gQX6@?Fw^eFRH;tsz0g_Zfx|gm2gFIN8 zBmaZcm0IPm$Tnf*;9xdEwkFU;IOBkT1-kmPvginOH-tukjrJY@_ka` za++A3h`mIbT~@Nkb;DAJ^WFkh!zwmNQi7Y8HAKZcyLnS>{gZW@g6Egl%E8=<-YBKs zOcGY+#JV#$5m~KRxeN*KUpdD#{x4?N$^uh$A*WOaO{@0G@?&IwrAKxX%OeG*)@3~O R1gQiXUe3`Ja^d^V{{jzNm;L|% delta 3753 zcmb_feNa@_6@PEnr>=E*Y$_}ZE+1mWj}{a~78L=P#q|?S0g0g~DN@>KjcH76O|w|C z31qvY@ir|aHqAISIGv2aY^_d%5ywVJOk0R?M&lPIroMGEMbXxc(!Boe2kSHKO#bQ4 zyt(h(-|zg+x#ymHAN1~#JNL*tCY!D=eqrjxF^6pu`yIBC2jpx^uZ5evWRaXN$CGXH zZCg)1pNoy8)if|}jCK8?$17J?^j*+u*1UBlcc|d)PeQ*i*QyH|3n||lRO;~JZB-tj zLr_WK)+}x%a4VZzc5Y4PRxw%k^>knQ7rO2Z`q%2Z{wF5bdi;n9FWSL>>w0rk-|T?s z%j0Q?6Iv$7hh(7P55NJilLLpSr*;4y-ax`@^8f{uU(+FIZK6Z#ad10~+%V+^mEAr* zsm3cN&QZ6O%}`PzT;+ z*`y+yq46wxt)6BRRF;Y4Dq&&))(sE=zq>&#Li*D%r96zOo9ffnZ>Lgd)lr007SdQj zWrgrg;!7*Rtf<2Lx#VJ+(`Ki<;d~2_6ZvWCBwzoWd$UkkDGExrPy6sL%WIub_QO2F z_HY_cxL)MHp7H|90Z6F_r3QcZ<`hUhBHWe(_3nbh*|fqq=hHP8d3Wi%`m9!5(#$=`+CWNL{&aT-btKj zipwC8#Ba%0iNiieew|dU zBV8nrRKEH!E+JUQF$^y!{7cAVZa1GxLLT3tYkG-M#Uc3v4k!)+&D7?h=u@1X4trfc z?0PcGG0EpK`mBM^a2X~Vfie!zGStvA*tr%JuN7rb?#_-K0u8UU`wcsF+F{tKGq+g} z_sy2bS%)k6SAx#=VlO+8Jmn2!TJj`c6@!(9T%Xl9l8Cy`=kr;Hd0zKDTt1Nlv{GjN z%Ic0PT0hB)mAVMt}NG z8JOA|#Nu?;oij^PYqvKz&QEVZDDcBaMe zp}9O<4WH9KyE%NL?z~0rq&io-@52wV%XR=Hv{rvEl~wxaz`m4QgfJsb<%x$FNi@#s zC@*~*+;)>MoD-Jhh`2>mGN?2Ob2^KlJOpPn6pd2FU-9A0KB_)niM7+WCzSAFyaLb8 zC6A`&ExSE~T09)|q6sv&6MU(WK^9}IsO&D7d_xxS;HL!83?O_AwitGLM9EmYGrkoY27v^fxV+&4^5+ z2(GQR`##>Ua6xU~4Ytk!Vg8ny0i|bptd{SP3u&owuV7-hR9ZK&q)+jE&oG7RHI6e> z?_sX`6ra<^!sOL^lLKxM?&ftCZXTq>ryzj^EKLC;J+jqw;1- zza_*vV)P*_IoyweVkwt%xOQ{Yr25~db7+3yu{q}PD9&$qA4d-gbQMd^vseA2G_OSU zU!fo205>00{WYfzwp;ZdH<)#*|DeHqT=nlYnBP_X?FMt1>VMu~ZczPO@6yvWsu=Mj zqjr!>8Hq)w26X-1V>i{*JC)wnPrc2b#kc-!2&+4peQ#f|u=6~1-okIdhnH_#sCYuR zl{{u?dvkiGJVN?LV|^%VMw}^BIn!=7!y+j&9i(Y?v2XF;b=`DL*MEYb`(wjeVb@drte-*pxI;-nFbayfKV@&!;*IO{k=X5=avE!ny zC!xJQ!sw!Hc1hQ3Fn09odK1P|AM5(>FxFqu^*_`3Fj?-J>S%%7B)ChZqvGi>5f83* zsgu0m%5pR!IGd&remD%$6L{8=K9@a1MhdUtI+8qb@z0vv){*Aln8%J9E#adly^iNO zVktOz;PGb6OKaO4R2ebQdCQ0^g@O9m_(Gbmq@ipbdotH2<+?reD@sdL-qm&s4u zM=al@x#8y~C8ZmI>@T%D;&G$V-x|cEzfHIb 0 - точность вычисления корня(до 10^-6). + +## Замечания +1. Для корректной работы программы, необходимо вводить отрезок, на котором есть лишь один корень. +2. После вызова меню выбора действий (Ctrl+C) можно использовать как верхний регистр, так и нижний. +3. Не рекомендуется бесконечно вызывать Ctrl+C без выбора действия, это может повлечь ошибки + вследствие переполнения памяти. + + +## Обработка сигнала SIGINT + Программа обрабатывает сигнал SIGINT, что позволяет давать пользователю выбор действия +при нажатии сочетания клавиш Ctrl+C. + +## Авторы +Антипенко Дмитрий Андреевич [C22-712] - https://github.com/ada-dmitry/ +Кузнецов Даниил Евгеньевич [C22-712] +Никитин Михаил Андреевич [C22-712] +Ускова Екатерина Александровна [C22-712] + diff --git a/Project_test/declare.h b/Project_test/declare.h new file mode 100644 index 0000000..5096fd8 --- /dev/null +++ b/Project_test/declare.h @@ -0,0 +1,15 @@ +extern double a, b, eps, x, *pa, *pb, *px; +extern short method, *mth, sig_flag; + +// Декларирование глобальных переменных, +// как внешних для последующего использования их во всей программе. +#define H 0.000001 + +double f(double x); +void ctrlc_handler(int signum); +void choose_path(); +void fork_method(); +void chord_method(); +void newton_method(); +double numerical_derivative(double x); +void exit_777(); \ No newline at end of file diff --git a/Project_test/functions.c b/Project_test/functions.c new file mode 100644 index 0000000..84a27fe --- /dev/null +++ b/Project_test/functions.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include + +#include "declare.h" + +double f(double x) // Функция, заданная пользователем, для которой происходит поиск корней. +{ + return x * x * x - 125; +} + +// Приближенное вычисление производной по методу конечных разностей +double numerical_derivative(double x) +{ + return (f(x + H) - f(x)) / H; +} + +void newton_method() +{ + sig_flag = 0; + double left = *pa, right = *pb; + right = left; + do + { + printf("%lf %lf\n", left, right); + left = right; + right = left - f(left) / numerical_derivative(left); + // Используем численно вычисленную производную + *px = right; + sleep(1); + } while (fabs(right - left) > eps && f(x) != 0); + return; +} + +void chord_method() +{ + sig_flag = 0; + double left = *pa, right = *pb; + *px = left; + while ((right - left) > eps && f(x) != 0) + { + // Находим точку пересечения хорды с осью x + *px = (left * f(right) - right * f(left)) / (f(right) - f(left)); + printf("%lf %lf\n", left, right); + // Проверяем знаки функции в точках a и x + if (f(*px) == 0) + break; + else if (f(*px) * f(left) < 0) + right = *px; + else + left = *px; + sleep(1); + } + return; +} + +void fork_method() // Функция поиска корней, использующая метод вилки. +{ + sig_flag = 0; + double left = *pa, right = *pb; + do + { + *px = (left + right) / 2; // метод деления отрезка пополам + + // Печать границ для отладки и для отслеживания хода вычислений + printf("%lf %lf\n", left, right); + + // Проверка, какой из отрезков [a, x] или [x, b] подходит под условие существования корня, + // т.е. различие знаков на границе. + if (f(left) * f(x) <= 0) + right = x; + else if (f(right) * f(x) <= 0) + left = x; + + sleep(1); // Принудительное ожидание программой, для возможности прерывания пользователем. + + } while (fabs(right - left) > eps && f(x) != 0); + return; +} + +void choose_path() // Функция выбора действия после вызова сигнала. +{ + sig_flag = 1; + + char choice, *ch = &choice; + + struct termios original_term, modified_term; // Задание структуры, определяющей терминал Linux. + + tcgetattr(STDIN_FILENO, &original_term); + modified_term = original_term; + modified_term.c_lflag &= ~(ICANON | ECHO); // отключить канонического режим и отображение ввода + tcsetattr(STDIN_FILENO, TCSANOW, &modified_term); + + printf("\nПродолжить поиск корня?\n"); + printf("\nC - продолжить, A - закончить работу программы, \ +R - начать поиск на другом отрезке: \n"); + + do + { + // Очистка стандартного потока ввода от "лишних" + __fpurge(stdin); + *ch = getchar(); // Запись буквы, введенной пользователем в переменную choice. + + switch (*ch) + { + case 'C': // Выбор вида "Продолжить вычисление". + case 'c': + tcsetattr(STDIN_FILENO, TCSANOW, &original_term); + if (*mth == 0) + { + printf("Fork\n"); + fork_method(); + } + else if (*mth == 1) + { + printf("Chord\n"); + chord_method(); + } + else if (*mth == 2) + { + printf("Newton\n"); + newton_method(); + } + else + { + printf("Fork\n"); + fork_method(); + } + return; // Выход из функции без каких-либо изменений. + + case 'A': // Выбор вида "Завершить вычисление". + case 'a': + printf("\nКорень уравнения: %lf\n", *px); + printf("Работа программы завершена.\n"); + exit(0); // Принудительное завершение программы с выводом текущего приближения корня. + + case 'R': // Выбор вида "Продолжить вычисления с новым отрезком". + case 'r': + + tcsetattr(STDIN_FILENO, TCSANOW, &original_term); + + printf("Введите новые значения границ a и b: "); + + scanf("%lf%lf", pa, pb); + + if (f(*pa) * f(*pb) > 0) + { + printf("В указанных границах нуля функции не существует.\n"); + printf("Нажмите Ctrl+C и поменяйте границы\n"); + } + if (*pa == *pb) + { + if (f(*pa) == 0) + { + printf("\nКорень уравнения: %lf\n", *pa); + printf("Работа программы завершена.\n"); + exit(0); + } + else + { + printf("Нажмите Ctrl+C и поменяйте границы\n"); + } + } + return; + + default: + printf("Ошибка ввода, повторная попытка...\n"); + __fpurge(stdin); + } + } while (*ch != 'A' || *ch != 'R' || *ch != 'C' || *ch != 'a' || *ch != 'r' || *ch != 'c'); + + tcsetattr(STDIN_FILENO, TCSANOW, &original_term); + + sig_flag = 0; +} + +void ctrlc_handler(int signum) // Функция, заменяющая стандартный алгоритм для сигнала SIGINT. +{ + if (sig_flag == 0) + { + printf("\nТекущее приближение: %lf\n", *px); + choose_path(); + } +} \ No newline at end of file diff --git a/Project_test/main.c b/Project_test/main.c new file mode 100644 index 0000000..2906229 --- /dev/null +++ b/Project_test/main.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include + +#include "declare.h" + +double a, b, eps, x, *pa, *pb, *px; +short method, *mth, sig_flag; + +int main() +{ + + double tmp; + sig_flag = 0; + method = 0; + mth = &method; + pa = &a; + pb = &b; + px = &x; + + struct sigaction sig; // Инициализация структуры, отвечающей за обработку сигнала. + // Замена стандартного алгоритма на необходимый для вызова меню действий. + sig.sa_handler = ctrlc_handler; + sig.sa_flags = 0; // Очистка флагов "на всякий случай". + sigemptyset(&sig.sa_mask); // Очистка маски "на всякий случай". + + if (sigaction(SIGINT, &sig, NULL) == -1) // Обработчик ошибок и инициализация сигнала SIGINT. + { + perror("sigaction"); + return 1; + } + + printf("Введите интервал [a, b] и точность eps: "); + scanf("%lf %lf %lf", pa, pb, &eps); + + __fpurge(stdin); + printf("Выберите метод вычисления корня:\ + 0 - метод вилки, 1 - метод хорд, 2 - метод касательных\n(По умолчанию: 0): "); + *mth = getchar(); + + if (*pa > *pb) // Если пользователь перепутал границы + { + printf("Границы указаны неверно, запуск задачи с исправленным условием\n"); + tmp = *pa; + *pa = *pb; + *pb = tmp; + } + + if (f(*pa) * f(*pb) > 0) + { + printf("В указанных границах нуля функции не существует.\n"); + printf("Нажмите Ctrl+C и поменяйте границы\n"); + } + if (eps < 0) // Если пользователь указал отрицательную точность + { + eps = eps * (-1); + printf("Точность отрицательна, условие приведено в порядок, запуск решения...\n"); + } + + if (*pa == *pb) + { + if (f(*pa) == 0) + { + printf("\nКорень уравнения: %lf\n", *pa); + printf("Работа программы завершена.\n"); + exit(0); + } + else + { + printf("Нажмите Ctrl+C и поменяйте границы\n"); + } + } + + if (*mth == 0) + { + printf("Fork\n"); + fork_method(); + } + else if (*mth == 1) + { + printf("Chord\n"); + chord_method(); + } + else if (*mth == 2) + { + printf("Newton\n"); + newton_method(); + } + else + { + printf("Fork\n"); + fork_method(); + } + + printf("\nКорень уравнения: %lf\n", *px); + printf("Работа программы завершена.\n"); + + return 0; +} + +// MEEEEEEEOW \ No newline at end of file diff --git a/Project_test/out/function_zeros_calculator b/Project_test/out/function_zeros_calculator new file mode 100755 index 0000000000000000000000000000000000000000..25ddb11f9c6207bc770ffad1c6b18a0b8c037296 GIT binary patch literal 21200 zcmeHPeRNdSwLeK1i4>S1P!Ot&THnJ0BSAn!kw6$6%7=)_6I$>x$;>39`Eq80L0b)k zSjL!wzU9ZGRk5qDWi4I4NI@f?30OXCZSQDbi`v%U!mf#EjZvS`s`GyPoU?E4T$A># z*Z0=yA9J#1_SwI)_dfgV^Ks9;nS1W`EnA$MlOs6giE9OMU859Iqzej`>I_Jcm?K8u zdy=?NoCAJ{#8i2aA}CeqRBk5C*LWT%>5Zq%0Q74L7EIYgqNF!iT7Rx8VJZp~PkJuO zYTii?YMd#TTlGy>c7%f#=ms&h>rrf0&r^Dk&+Pm0GV->oM)ofndt< zq?piWj*h33I@}gcy-Ka;q>Esa5>u*!(v5G$ga4cQR%*Tc*~*TSRw-C8<@#=b9>wK< znsj%HRl2^x`eB#u2c|l_;_|9U+3cB@R|Th4MQZ9BrZvo&J#F?(Z>-ikL%KkIdGMhz zb=`_m0W%$h=`f1iM#Zx|DjTEArF_ZKX;nwQQ!-}rj*)kt`S{Vof195m8S68i$-eVVL|TDbeS!#Tef6ju`$DYrInj$ z8{B_IkaJGv282d`G`Bf9iT=kLEay4NhG)+`cZPZ1^x12JNxo+(s(yv*Gsf z$m5LGHCj(N)oJ;m0Cldd+8!oTAx?rmfSL>H5*lxqA4o;8QaE=|7?X=agJ>EmVjTHr#E)O&hMaPPWo)HXDI#1hNsxMj#u3 zf2;_6;J)xvf73hp{ubA(^M&v?cf@nkroZWh{G-y*^sKpnd()R*4dR|8NWPLvdb>}j z)9LM!rwvMPchcf%W76B*Y4NmS=*a(*~ip`+ke3jX`hsCX1&HL2vhM z7Ec?2-tK_K(*~fo`v!}r4N!0Q0*j}OKyP=U#nT3$xBDXI(Ykl9rPeJHvVGu79sF_! z?{o0;9Q-T?Kh42k>fkSM@M9hP2nX+S@So#xf!+U)?0n(7OA^VO{fRgIO=o&mmiP)g z3Qzi5=e>w1q{qGj$q&O`_awTL!2oET_X!YxtE-pDRekZX7#hz~9z)~YbeDTlBgq}r z6!Isf{H!BHF8jit=<#>{dA`51FVCNI%%A)sJ_ZJwwSoL}S6KSV`ZRtT=e43()K4k( zH_a=ftUvKqe7L`5UKmVj%@^r(Du~WH<_dw&SqELKe$wy09fg!Bg`R)YI~}kP^tTMT zbh0$%>nrRCA9pp7VS$VxGiV__6YwWoYlyVE&QshJ#SK^7rHUJ=xJineijAT_(YzkD z9`~ils=rlo{-%z6f8uy*96Z+0K3SYNc9`Zw>gmtZ>88GP{rRZx0X*6w;Rz6Kry11! zA!JaHPzCLznR*Hu{+6+iUW1|**Y}CEj<}sj;uvHfv&(i#S=Uvv^myt9Vq0DJ+C|m@ zOI6}4aRlZJNQM&y$jw5o*Iht$%uw011P4NGAl=K`wjc>H zz`OL-(z_lI7|BHm8R}N76w=VIq@W1<-8CJliD)hv@k=AFefF|60@CYVBg?|>_fAS@ zE`&4hd`&r1Le8|h=4s!2U{Upmbua??4kKCZ$W#6Y>_={{$sdlLzEZt&?)I`r$)>&>DLPe)jscDS zr?opTSw-VeA#8khRYn`vDLK`~E(k;SHm!R<>-t+t`-1){W8{2|yHdMQaPlZmXmpsb z5B)-4YdY|e+=xpiQE#p7RH3Hl&nK_M5k1}*;bRkWnEvtgH+pitSjTtbQy!x95s;0gD%9R%f_du zC0$e^b1Bq~0itT`KyaR#2os6p^6_x$KR%J8nna}~h)T~-W65C8HI$%m0c7AVJ}OpwY&?1Xl;UN`ME5GVj)XJTZOQeaC@$(TxS+wBq^GwH-$79Uz1eSJzkY_rmbhtUdMIiQshWaSkIQMElP-fQ6#H4W`s z>+7LucgqBdx0-g3k;VRL_pnvLdsq@PVy~y&Z*8%c*Bwl|BNY4o-91Hh-eD9U*DN!oAg>@O6O4{P3Z> zOCJGmf~OI>6Zx(d->!r&)#5wQ)b&xqcfj9D>PHUI5KvVNqbgcmN53k2E_LUJl0Bo@ zDq>q)p(|ABcfqE1;fwY!(&Mcd*fQgOR=5v!G^G|a^%c4wKC}!+4j+Dm+17r z@}@sw`uC~-rsN9$MMwP2FS{R?i`*3ZO|6TK6WMUiaez0RphkFZM zH~kzhdyD2MpL5`|zDCo|<;S{3J3ip6=^0F@?vrGt#r2yRN|-LwBz-5h-;#bFL!kQy zO8O_3bgq=XQA=NINgG(+yQ`&#u5aj4k5zgL)qK6O^-b8~wFwoER>JCv?S%%gf7S-x z=;d8Wvn)v^hF|a^SZf1hNsx zMj#u3Yy`3q$VMO=foue_5%_Bn$iZ(H?WzAqo(eS|Fn61K%{^v&a>EXrd=NH?1w=6R8L`MQLPY}C~TMqU{tpJ5G=LB z-T@V_jJlM&9`k4Y-oS7(9Dqmr5w7GGWDc79lJ~$yyL1e7!g2!Mp0wZj2hkj=KKj^?2P z64RrLdixLtfUGvzh${D>`hAW_LSb)mEBOTb+q_;hVwkx@_B8oO6iXf6#t z{2s*I3H%vy&TLavAJRcQU>=|zq^^`bs4Hmmip90jTSakYZ8RuWgl>=HhtF1O=pM}&hMoY8)iSltpf6zOAAG(%hVj*ok%;93;~jt0@0cBOi0sDj zl&c+j4@)0S!NXXeHj}g*?ilYs!qDEQCNxDy&7x;8*xE7NWQ?dA)u^Y)A{7}$t?%yL z`SG!~Yw;f(N_VRQ>$@mtV&2tNVCkn(<6ldscY^kTo&e2%J)Q0XJq5ZIwDb4rbRXyg zUFr0AJS+b>=p4{1PN&mrL5(-l=|<4CXVU2(gTDM$I{gCiZ>Q5|Kq=t~xJ)^BtP(j5 z1vwLk56$0>GQ#ou0O3bn|3ngth87U{IzBV;se4uVB1RT09y$J-?yuaQ-zer!nEQ<@ zzJ4*uk^WkICc}5BNFWm7aeO?$O#*bHy6E>Eov1HKzf<##EVw7Pc*Hq*C-UHu^yMkQ z(Kpg*{6D9^{1z&OJ$!zNPczEp`oQ|Wro7zs{W3j}`88ywQu}Q(c^BqLArIg&DEl2^ z`MFc(JtafFQk>fm-wk$|ylN>x<*R|8gSg*I|FYtG@-_|Owltu;E|pF%MX^<$yHGhw zSThvk?;=fCYPw$2I!zlj-LC0QP1`i> z(A3nlOVb`ro%Q}Lp5HsXuDE!vXL4y-eNDXHQ&{Mo>772UuwJr-cg>jLoj&t24gYnE z6!#(G{j^hx`jy_fyiW(-qXp<)!-3?f-*ZKQD6qez2+X7LA_q=;G?M3e2Ueyf_|Czs z8NX8TJT6Kl{#C*ANR zb`}kSe+&3P?>GNJN+BFmooCl59^aV-YXTbl_5=X|7rU3Ui zFk374*O#wcToq517wxs$qt4Th0c>fFZ zy69%$6we|@JOdi9)HvK$>BjPCywF>V*Zc!z5hEU`5CCHF`f%7=F8YrIFyhrlIUNcR zgJiJQsHmzf3sf1wcx^Oh1nL_^d2MxFRVW?`dZ!O8L1!jJj6gIR*l2`m;?a#F91T>5 zj9`6r^+u@JI0KUL3{g5+0se&RYvf4?G2{(n@u~&OeTHwvA_K<~ELyW-!SW@=fN_L} z;q&WK|DsjGxNh0?3l}Uiu3xYc3eetP)YHtJ)cpn$n(kUguB&v2PT-v{AOSuCdAsj06HMI+@jm_RoK;*kv@k$I9vh8xzw z7#XNK8Y2VBJW#_bx>BB>VX+h_!@!9bJdo%pi~-NLkcV|R^z3JWWERm77IguNrV*~f zv=ZLf#_D*W3^X29w32f;xg!*<6W*HIc*t8(Q}3;d)}lr6jW(#PK7vzmB0&u;Sh!>w z%~mO18HiO1Z*XG`s!$ZikI0e@p=gYb4zV)^%A%pF04eBPT~%CorORGqy%n`!DH98o z3vWEs0G6gNq-*5>^@b|-gslw18gt5qnz>4Y^QbCN9f2{Wj_wy;EE&~U33w&?yC_{2 zaf!j+QKj)%?0Cwh)*Pkeo4 zjP}WPecq=t^{}9(PW_vJ;}wTm_Mh)RnNHSveE;e6KY((&_hkK3y8TSMD7Z-EBV}2i z?-L`yNQL$JewQiV-$FztZH`%S8*+5-$ohQ0$kgdS%Q3wR`gAYKymXYTlfy{*viBwb zRjClI$WTmKpYM;Ep3;KO_;LFm*7^&z9N%v<<@ zmGeY@h>u<0qxG0}k&rDp%!{9*%&w13gi4ySJey#iX`4g8fb}#rSy5BgWBR;9zf0>e z{q@L91FXj={hZ(Kf15{@Fy-ewEbp8@KiB%)|GW=ons0TCvf!-$C5JxW|1quNiZylC z|GGoJfff`brjJnLY>CGYLvJBNA=1;`pwM