From 6a2edcde49269c6baeeca2fcd851482a46b9dfc5 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Thu, 15 Nov 2012 22:04:02 +0100 Subject: [PATCH] added frontend --- frontend/Makefile | 24 +++++++++ frontend/Plot.cpp | 108 +++++++++++++++++++++++++++++++++++++++++ frontend/Plot.h | 50 +++++++++++++++++++ frontend/Plot.o | Bin 0 -> 45680 bytes frontend/XWindow.cpp | 60 +++++++++++++++++++++++ frontend/XWindow.h | 49 +++++++++++++++++++ frontend/XWindow.o | Bin 0 -> 8864 bytes frontend/cairotest.cpp | 46 ++++++++++++++++++ frontend/cairotest.o | Bin 0 -> 33456 bytes 9 files changed, 337 insertions(+) create mode 100755 frontend/Makefile create mode 100644 frontend/Plot.cpp create mode 100644 frontend/Plot.h create mode 100644 frontend/Plot.o create mode 100644 frontend/XWindow.cpp create mode 100644 frontend/XWindow.h create mode 100644 frontend/XWindow.o create mode 100644 frontend/cairotest.cpp create mode 100644 frontend/cairotest.o diff --git a/frontend/Makefile b/frontend/Makefile new file mode 100755 index 0000000..20ba1d2 --- /dev/null +++ b/frontend/Makefile @@ -0,0 +1,24 @@ +# adding cairo.pc +export PKG_CONFIG_PATH:=/usr/lib/x86_64-linux-gnu/pkgconfig/ + +# programs +CC = gcc +PC=pkg-config +RM=rm + +TARGET=frontend +OBJS=Plot.o XWindow.o cairotest.o + +CFLAGS = -Wall `$(PC) --cflags cairomm-xlib-1.0` +LIBS = -lm `$(PC) --libs cairomm-xlib-1.0` +INC = -I/usr/include/cairomm-1.0/ + +all: $(OBJS) + $(CC) $(OBJS) $(LIBS) -o $(TARGET) + +%.o: %.cpp + $(CC) $(CFLAGS) $(INC) -c -o $@ $< + +clean: + $(RM) frontend + $(RM) $(OBJS) diff --git a/frontend/Plot.cpp b/frontend/Plot.cpp new file mode 100644 index 0000000..df81556 --- /dev/null +++ b/frontend/Plot.cpp @@ -0,0 +1,108 @@ +#include +#include + +#include + +#include "Plot.h" + +PlotSeries::PlotSeries(PlotSeries::Style style, Color color) + : color(color), style(style) +{ } + +void PlotSeries::draw(RefPtr ctx) { + ctx->set_source_rgb(color.red, color.green, color.blue); /* set series color */ + + /* determine maxima and minima for autoscale */ + double min = DBL_MAX, max = DBL_MIN; + for (std::list::iterator it = begin(); it != end(); it++) { + if (*it > max) max = *it; + if (*it < min) min = *it; + } + + /* stroke */ + + int width = 800;//dynamic_cast>(ctx->get_target())->get_width(); + int height = 400;//dynamic_cast>(ctx->get_target())->get_height(); + + ctx->move_to(Plot::PADDING, (height/2) + (height-2*Plot::PADDING) * (front()/max)); + + int i = 0; + for (std::list::iterator it = begin(); it != end(); it++) { + i++; + ctx->line_to(i * 2 + Plot::PADDING, (height/2) + (height-2*Plot::PADDING) * (*it/max*0.5)); + } + ctx->stroke(); +} + +Plot::Plot(int width, int height) + : width(width), height(height) +{ + window = XWindow::create("Frontend", 1, 1, width, height); + surface = XlibSurface::create(window->getDisplay(), window->getWindow(), window->getVisual(), width, height); +} + +void Plot::draw() { + RefPtr ctx = Context::create(surface); + ctx->set_antialias(ANTIALIAS_SUBPIXEL); + + /* background */ + ctx->set_source_rgb(0, 0, 0); /* black */ + ctx->paint(); + + ctx->set_source_rgb(0, 0.7, 0.1); /* axis & tick color */ + drawAxes(ctx); + drawTicks(ctx); + + for (std::list::iterator it = series.begin(); it != series.end(); it++) { + (*it)->draw(ctx); + } +} + +void Plot::drawAxes(RefPtr ctx) { + ctx->set_line_width(1.8); + + /* x-axis */ + ctx->move_to(PADDING, height-PADDING); + ctx->line_to(width-PADDING, height-PADDING); + ctx->stroke(); + + /* y-axis */ + ctx->move_to(PADDING, height-PADDING); + ctx->line_to(PADDING, PADDING); + ctx->stroke(); + + /* arrows (arcs) */ + ctx->move_to(width-PADDING-2, height-PADDING-4); + ctx->line_to(width-PADDING+5, height-PADDING); + ctx->line_to(width-PADDING-2, height-PADDING+4); + ctx->stroke(); + + ctx->move_to(PADDING-4, PADDING+2); + ctx->line_to(PADDING, PADDING-5); + ctx->line_to(PADDING+4, PADDING+2); + ctx->stroke(); +} + +void Plot::drawTicks(RefPtr ctx) { + int ticks = 20; + int intv_x = (width-2*PADDING)/ticks; + int intv_y = (height-2*PADDING)/ticks; + + ctx->set_line_width(1); + + for (int i = 0; i < ticks; i++) { + /* x-axis */ + ctx->move_to(PADDING + i*intv_x, height-PADDING-3); + ctx->line_to(PADDING + i*intv_x, height-PADDING+3); + ctx->stroke(); + + /* y-axis */ + ctx->move_to(PADDING-3, PADDING + (i+1)*intv_y); + ctx->line_to(PADDING+3, PADDING + (i+1)*intv_y); + ctx->stroke(); + } +} + +Plot::~Plot() { + +} diff --git a/frontend/Plot.h b/frontend/Plot.h new file mode 100644 index 0000000..e43f0c8 --- /dev/null +++ b/frontend/Plot.h @@ -0,0 +1,50 @@ +#ifndef _PLOT_H_ +#define _PLOT_H_ + +#include +#include +#include + +#include "XWindow.h" + +using namespace Cairo; + +struct Color { + double red, green, blue, alpha; +}; + +class PlotSeries : public std::list { + + public: + Color color; + enum Style { STYLE_LINE, STYLE_SPLINE, STYLE_SCATTER } style; + + PlotSeries(enum Style style, Color color); + void draw(RefPtr ctx); +}; + +class Plot { + + friend class PlotSeries; + + public: + Plot(int width = 400, int height = 300); + virtual ~Plot(); + + void draw(); + + std::list series; + + protected: + RefPtr window; + RefPtr surface; + + int width, height; + + void drawAxes(RefPtr ctx); + void drawTicks(RefPtr ctx); + + static const int PADDING = 20; +}; + +#endif /* _PLOT_H_ */ diff --git a/frontend/Plot.o b/frontend/Plot.o new file mode 100644 index 0000000000000000000000000000000000000000..f15a33b0b1a50f888afa1334eca400c27b5079b3 GIT binary patch literal 45680 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 ZuXzGb3j7Lzw+I}0cweY>2F~;Be*iS&f7t*4 literal 0 HcmV?d00001 diff --git a/frontend/XWindow.cpp b/frontend/XWindow.cpp new file mode 100644 index 0000000..5ae2ab2 --- /dev/null +++ b/frontend/XWindow.cpp @@ -0,0 +1,60 @@ +#include +#include +#include + +#include "XWindow.h" + +Display * XWindow::display = NULL; +int XWindow::windows = 0; +int XWindow::screen = 0; + +XException::XException(const char *reason) { + fprintf(stderr, "%s\n", reason); + exit(EXIT_FAILURE); +} + +XWindow::XWindow(const char *title, int x, int y, int width, int height, unsigned long background) { + Window rootWindow; + + screen = XDefaultScreen(display); + rootWindow = XRootWindow(display, screen); + + window = XCreateSimpleWindow(display, rootWindow, x, y, width, height, 0, 0, background); + + XStoreName(display, window, title); + XSelectInput(display, window, ExposureMask | ButtonPressMask); + XMapWindow(display, window); +} + +XWindow::~XWindow() { + windows--; + + if (windows == 0) { + disconnect(); + } +} + +Display * XWindow::getDisplay() { + if (display == NULL) { + throw new XException("There exists no connection to an XServer!"); + } + + return display; +} + +void XWindow::connect(std::string display_name) { + display = XOpenDisplay(display_name.c_str()); + + if (display == NULL) { + throw XException("Cannot open display!"); + } +} + +void XWindow::disconnect() { + XCloseDisplay(display); +} + +Cairo::RefPtr XWindow::create(const char *title, int x, int y, int width, int height, unsigned long background) { + XWindow *win = new XWindow(title, x, y, width, height, background); + return Cairo::RefPtr(win); +} diff --git a/frontend/XWindow.h b/frontend/XWindow.h new file mode 100644 index 0000000..65ea58b --- /dev/null +++ b/frontend/XWindow.h @@ -0,0 +1,49 @@ +#ifndef _XWINDOW_H_ +#define _XWINDOW_H_ + +#include +#include + +#include + +class XException { + public: + XException(const char * reason); +}; + +class XWindow { + + public: + XWindow( + const char *title, + int x = 1, int y = 1, + int width = 800, int height = 600, + unsigned long background = 0 + ); + + virtual ~XWindow(); + + Window getWindow() { return window; }; + Visual * getVisual() { return XDefaultVisual(display, screen); }; + + static Display * getDisplay(); + + static void connect(std::string display); + static void disconnect(); + + static Cairo::RefPtr create( + const char *title, + int x = 1, int y = 1, + int width = 800, int height = 600, + unsigned long background = 0 + ); + +protected: + Window window; + + static Display *display; + static int screen; + static int windows; /* reference counter to open windows */ +}; + +#endif /* _XWINDOW_H_ */ diff --git a/frontend/XWindow.o b/frontend/XWindow.o new file mode 100644 index 0000000000000000000000000000000000000000..53ef8be126dffd747b921940f17113647592541d GIT binary patch literal 8864 zcmbtYZ){sv6~Bp-HEivc!Wcu{#`BtWEu(4NwN3wwk~DVvvLtPY>*AJXuH(EkW{z#y zFReSZTD1(sn^$R?kl+JIe1b_sh))w5e;SsQw5Xs8RZ}%hB7hJPn?weh+7F0w&b{|I z$Jg(5syNc~efM|%-gD2rzVE&m8{FUA)FgOxugy zidKiNMXRyvTCX~Eqndc%u1?>wtLGrfvmNdBLbO9>W1*!(nyG2OBmH{AZL+P}(9&oY zZSM~?HyGUt_wAPR5T?mSBRcY0d{^dZ+$vwy*eyLuB|5Xzq{k;Uzd1YIDhDkyIJ4OF z@~pcWLW4xBWcb;m!PJRiwtEx3hvP6+wYb3iGZ!%t(ueKMtxQk9H!o*z(EGb&4tnd~ z##HGk{gcwrHd22jdF6Po_!s7Prrqxfio)&vrPm19$3)z2YjSvH^V`3E6G4eM+uH&s|#WyyB zzs7Y9We1De_SzwCDBGSk49lK5w=CQZ7hB+676mQZ1SDV|lp1RFv@OW}<;onY+#N-_ zlCet0DdI@|G>1P)z)$H8Sa)8O{y=g;a-W<^umZ}s%F?<)+7=bxW$9q_>ijOLw|X#TA|7X*Vr8$I4~V zSt_W`$xJ5Y$kIxIUd{my$#rDYfhMx7~$4%`Erddl&k&?{NM7KKd45xP)=P z<8)qko|9YB3Wvr`2%a%b40#qZfO_NsK?tm$Pr*a+Jd8{r+!xWm;YKW)015+{zP4<&!FR{zpVAm`8WG-g1%q;vzGGGr5c$(JVTiAUjfX|ztDAm zzt*S5jDIOW-_rUPDeBhj{}ph*_?NXH&p&=2n(?oKfc)a8b!+C!>^Fn5pZ}d57WjVon+z+7omwBekHJIww0?0-nR}nqTqS?S39YYsYOd)WTV$KDBW|H# zpf~g%!{hLdTe|5V=f}_gWh^$Jq`@@8Q9?eyDAyuBy6wXPe`ZxEsgStOPaNb|2jJ%J zLUznmOE~VJjTG`dL1A9-rlyfXg1$!Tc_D!}IgJz&I++G5BydGFQb^8}AO2_~2uMg) zRy|8)#(%a#wJ(=?osg`idJKCZ-wH$AC=RU}@?8-q@4qNR4W}1nC?xbE&~~W_)vA~f zA-2HlT2?1i=TVJQpVsP8jZi+77yabF3pm=}2`$o1 z)rg-$8)kKAY5W(^`q}wi0RCtKhp9Sl(@kC*)Pru0XXXW$^Qg!zj=QL@Gx7ymiBu+ zz|LX-{&4`_0{KF}+jQPu()QOu-!IND2H@R*huOYFx^{s45x~*!RcMj0UXe-~H|x^_ z{Bd~#RdRH$eKP?6J>X%szfnBzNql8rr5*eOz)41VP`_(oiwU!Rm3H>^fcwc0NO}G7 z0w!wzH2U7DGgB;zJ6u0(SJw|9L0|OU`jRh(YBlh*yu~Wlfji2XlH=qh#_t~RPGcY= z%I>&RDv60=DVujE1l%>c+@zAq0!;zTE%_BD z#hgP}+%1%xgLuaPca}N0#O%)(r(Ka8N*A>V8%T6(>=ch8(gnlSm!Fa|o*S+ch<4R0 zL?iY6NY_cnjjDT5JyUd2+5AKSYxHp3NN0oIu2ia6fMRt@ zre@7Mtz=lf;tTNn=e8oclf~P0{;$6Y`ba2m!9(&-!#fhH9w9Z z5X$3fC;1$LK!|t1LwE^6AjI($ML2%{BANJ$3U09PG5iU5Cp+I~IFCo&*DL$@A4l?k z4v=4F_>)YY4$|g$AAtWAB*ZtuL-rqIIFDx&!*MQ1zE9(3p8J_R&MC={1mJX^jPY>! zG?T|~IF`SR<62qSXkCeB6 zGo06h1?LGQWbcKC + +#include +#include + +using namespace Cairo; + +int main(int argc, char *argv[]) { + XWindow::connect(":0"); // TODO parse from argv + + XEvent e; + Color blue = { 0, 0, 1 }; + Color red = { 1, 0, 0 }; + Plot testPlot(800, 400); + Plot testPlot2(800, 400); + + PlotSeries *demo1 = new PlotSeries(PlotSeries::STYLE_LINE, blue); + PlotSeries *demo2 = new PlotSeries(PlotSeries::STYLE_LINE, red); + testPlot.series.push_back(demo1); + testPlot2.series.push_back(demo2); + + double phi = 0; + double last = 0; + + while (1) { + phi += 1e-1; + + last += -10 + rand()%21; + + demo2->push_back(last); + + if (demo2->size() > 400) demo2->pop_front(); + + demo1->clear(); + for (int i = 0; i < 300; i++) { + demo1->push_back(0.7*sin(i*phi/1e3)*sin(i * (M_PI/30.0) + phi)); + } + + usleep(0.2*1e5); + testPlot.draw(); + testPlot2.draw(); + } +} diff --git a/frontend/cairotest.o b/frontend/cairotest.o new file mode 100644 index 0000000000000000000000000000000000000000..088565d72d71a7c1e95e2044bf185ff8e9a3c8d0 GIT binary patch literal 33456 zcmdsA4R}=5nLfz{p;RGSwOOS#q-YTp69^g*H3EY}`7uktMhXr?W(b2J6O)MqixoD+ zG6G7iC?dABrCYYYv|U?dsf3>`*zVf&&t|QyY=2y;K2Oo@(`I+6?Dw7XoqNAI_ngd( z{du0<^DuMHeb4uPf9KqD@12<(?vKo!Ra#OabSV)xiQq`1LiCOe+I6y7C!P{JrR-EV zM$S!C*HJy4>X}r}qB=_T2dJJ)^?a)9sa`O|R4<`=Db;sUy^QKO)lF0< zs7_MdOm&LtyQprVdNtK)s_&+{gX&JI@1eSj>U*hPNA*XjzMty#RBxcVo9c~JKS1>+ zsW@+V2-P2ldQmj{>suB!L^r%%Rw_jHTch7Pdp4SVx(upBbn}qQ z$AL^V8#z_o8{OJ-*;(v7ehM%V-MU>KZtXbD$?~+&`X&&b2Io`7y6iEK@p1nbH zU(npIoBL5rh|@Pmvpv`!J>Ju+`;PaV2%3FCvtKtk8Ceie1yl#N!5n?I!oxUqXg$lU z9fxYcxQae|G`d+j9?cFJ3r%!9nw>dzIJBi_&@O{Ex{i1`W$0z1KXn>9OnuTTr4M7# z`Y;%5qdttrs&4>0w)UV}7#a*L+I?hrH2dvn_9rx8JxXRf24{52+(1&xV1#vBK>N*6 zWm^%0dMIZ8%~6eq-yC(ml#^PshYwVrd$cNh;t#JL{_oQ4iNgbzU3nziclcy!iF(U^ z=gK2nr~m%VQR912nNq5hU>iarujEno1%D8zLyyUgI837+@7>s&8Kp_OZ?g)U4v+Vg zgJSgdHxEje$4lVNQFlnU!He^-^UYCr9+n|!V8y6$eIWFGh;RFFND;V9L`}E@Vs8v$ zM~zDG{GQ<|7D~T73S#M&dP+8Y3mv-(%vl+pJBs{gQTh<1L7e&$xV`i!w4~nb zeFM>K=jrI?$Y}`zKD7$oSlRgmmS=93P~F3ID`a`)<{!WI;s5;2^9OD|d$wf8Z9|U? z6L${%@-VR)TMw7Q)ZJS;^y9(_aT1~EZww7z5yM>j9RFadgAqbfI; z+hRElKq?2)DbRRItHWuLbNF+=r~6p>hnC8b@U2N#w0B38Xa1>Zc*bQ}+n1_Pt}Hqg z-5NO^4bB44diuGeYNWeguaZ*P&XdvXqJBsRywG{yC|q;~06yvR<*#Z5JlkAm4Tr{g zaBolu2Pq0M_rVN@YiR^(%J=3)y%1#IrqN@0_}#~%Fi1LEq{Fa-Rhrx7_huYT&junhqFizda#?fp-`?X;I1lWO>0F(W% zHNycoB#i@Cf;Kj?8+$&icBJ$v+7C^thc^7%wlflrKquP zVx0dUyw_p*%TyK2E0}gLua8FtaPfcbe8?#vG#cHJfs*J}nP>q0*$Gnt(iRyA)*YDq z!BxhmXU#QFk?8DJobXyF=T&5YoFu)z%iI!-%e>PE@RH|V@j<`3Vk$8en7^uWZKwaN zes{lK;pZd^t2QjtaNBrjI5?|jV^42p1k5Ywxd2WKt4Du&d~e5xU?jmloY&wuEHG1! zz#72D1jh|vDWJ}O9J1h!1Nt3fMw5#o25Y{Y#am;%ObM_|Q}u?(=~0j1ee6(`UU|m$ zMN4|4C4JGuC*hty&#N*bz=Bqk_2P+4<<=Q9rdEtww7j!5(|PUORBOCF zT~RaPx(So6sqU2ECHF26C0%7Dm!3OpI6fha1{_~lF2J{2MwUHLI^(=^ z=79hl>b{bD>*q@5FnI72!qfZ;IM5$yR1FaV{slVPx`%85an!LMaVRzTrfsAH8@myQ z;_B~}y>NevwdU7%dr44%`cEPb{mp@XeJ6Sa?~e!l6}X5%xg6g#e_7C9NBwoY z|HDE5vON6tdHB1je;n7}6zK2GqyHrJ=j3N$w}&ChF@#Smu-Noh0A4};>!Iz(5ByTf zVFkc5N#=1bb34ea3;bM3GGn;RlAwPR_5Tg;U#R+V9<@>b9%$#xCG@3n1PI>pPK>87 zkDmPn>M57gSqPgyXs4F?M?l-pOC*S=k@};&zjTHaKzc52Z7X|wFQ~yZb zKRf8}&(l9Z{o^?wPZ~Hz|H@^O=^WPcJ{I)XQoqapM(TI@-$nf{|94RTb=<$Z1N-}_ z-{pTl^^fIz=Knw*{rJd=r4rwC{7VD-wbXwZ?_V7BH&VYVzAoy2FX!J8@OMzZYkuvg zewTm!)IW#oFP$X~;P?(uzstY!bC4*6%fDLcclp;y{VxBysNdz^jy(GJQ~!nNq#mE! zg8cR8;Sc2Dmk&e5Le$}#)=%qt1wggbe-ZDmSN0JS6FSze&cv5PooQF~O5JKtw!|l7 zl3f`wAra5S#f0S@9YO*VVvAeXtggRDOpr3|Y1QA{)D%m0H6`0JF;LZ#q;6CJjQI_j znwC^YW_EpbReei3(~xXWB|948vm2^ok;s&`&W@F_YCVG$XqOyNw&u`>2{g20@5_7SsnPGh7vFu`SLq?d9pdx8Vb)G2AeYtnc4&d7H@4z z&Thy|tWse%rCWKhFy1hCsweB{W104ND$_B0VJuQTIgwhiBH5k<1+mQ9wq&GXQVjkX zGs2h<4u=h?T1X6}y90EF2Otp%nW!f3mjh)sB^P!0(DyjXKG6I<98i?_6-A%wJLF~e1M=0rTFgA7*3V(~GFMb4b)va`xig!~ zo+4My_RgkEq`qNd3}$6WRl%8ZCLb@?gQs7g*@GtB9aAF0<4DL0ke*{OOwI+NRW4Y3 zMh+s}*2X6Hd~@_Ef{8kU`M93uIbCK$itqE0#g#tZM7+<6LH ztFB5U$;+gi0jrIHDp*GrjCQ@8Zb2a`c z`OVc7F>+lKd)v8&`x{q&-Qy)MynH0wqQ*Qi;;3C6?~3U=WPO^smF2SG8vM3=z>v9J zIpdq)N(2uWP3hIEldbU3(VEUAC)_%J(KT>`*mM`oCQI!4D)Ar zJ8-TL=UepD5r&^PV0jW=8{tKd<$mqr%g&gFl)2>w0`|1(AK_gnaTis1KJ_@6C;f5O6_Q3Suw!v9jU;m<09UuNNd zr3ikxh5ywe_!SoZ*Nfnfv+$oTf?s9ff3paFt%ZMU5&Sv}{~JZ{qZU4{NrldzdJF$x z5&T9A|4n;3f5&TUS{_G<7+bn#%rW87V zc3Ak&6~W(a;eV$H{$30J14Z!nS@`%}Ori1bxA31Yg5PW5f3FDs2@8L25&S+2{|80z z`z`!=Met8r_%B%a6@Z~AeO(1DRZbDVM-Ld`#-X?ra1%q(-FGX(aO%W+fBddhUysXG zx3~goG(}$*6AItQn+{QrX$yaMfjV7$3d7fH@~fdo#$W1-$cDBrf1AR(OnoznZ_vdi z^1q64v8m(NF#bT=^a=a+;vc0z(RsrB-2gAm*Er5e^vSfZzrWlBeY}{qnxNAbe;s}Q zD8GMa3QRk9LZ7J<#e2zr9Y6Yi6TD3S@tMYEKU1Lnoxr!*KW(vJXR-fXhyA@|U;eHI zWOOm(|2A~k>{r~Q7*Qf({L|rO#{ULjw)lTR_HlmmV%mQlI&Jn>l6{{4nILQ0zZ8ty z?2jZtJU@9c?OzOJoBbUY`?EliY5x|7{TdRyoEwL>X@8o-{t2?L&lAjl)MCHGVSh2% zuLBM*ru|lj{gamX@%m}T|80l;odw2!*kQkHjq;kuk86c#|5b~AVC|NRd8`z`U`Zn5vdh1)j%`^f%!9xSxM zTuyn*VZV>;ZzE|u{~O_D#$V^KUo}DzA1A)9O#3$g-!}i2btwi_^7H4#0Gamha@apX z_Qz<$RGapU;e(3=`i{K;ouK>ry}iPTx^>BUpV6Lr@&7WAM=m*3TFIcA$hj( z-%IxM`M=7+KT@FoN#Mi3P&u(yLEQg1K&JnXJM6DGSMl@t|FVOBKk;c8eg805yet@M z&tI1KQ7#N^lRppmw)pqotB6&^$MH+T%Z&f~4*NeK`}yu4|HWbdl*N9t#r{aR&$i8< zbL8KS3ULYfuPbx@z61ES_{%@680AF7_*3vQ;~(R&UqSZe?;lAAR%ZTZIQSDBeAEB6 z4*oRak7u^AY4S6U_^T}OuLiyu|FaJJE6D!XJocY)*pFK5r!Dpc+$Y<{|3R{!Z~py{ z!~Qa|&*wir(wgzlaoB&B?B|<*vw&}#f7>ka<9-FE{Z$V8{bWDi{Cmp5e}(whvn&`ENP+zaTzUz7~^z zBitw2#_u!{-|I6~!{pZj-!^{3FLLx`;R&7k1tbc%a^}i2fv2+7v^L?y#9=Y`&3)}(E{zy zbnq7xXn!;D;V~+wtR%iZUv#H=`~dK6`5&;1|D&Kp^Y!}m2-&aF2B>Z$`&St_<_e3h zpCrCQgZC$iA0Vowc^cnGeDl26P5efv@t57FBzD8|1r}U?cEC&Xb^PZ8 zX67CsG4O7D7veDJ=f(6Nk4@jD{9IyPr0QKz+16iJKCSjeT=8}qc{J@Ssqj0>4H0jg z4fmiu^R7Zkd7{=P4)RkR_|y=N%SH*4=l*)~8;lSI^xqf;0rBKF2H`GG)P+GQKiz@P zbl|fbc+`P^z=7+*&h7TZ{9J&JJW=n!@e{&u@x;O~2#6Y+JWPf zVz_t$pWwp96ZB=3(d7wzVhR^ebcI1cJb_Ob;o=Fp7#Lli_=th1Lr>iAz}GwQ4Gz59 zf#XUTE}pzYwBeh=ARwN=JF;-`#O5#vh$pr9yi|@=B=M`dxWw ze%md?i&DV6ixT1@xv*cX>3;n|iC^L$>qbK275dPx@00kI{;_WCk@$Fh=-29Z858_t z-T0%Fzg8dm^);o~oai6x#@|Z3Mjz(Xo_H+hSRZ))U5`do?b+`DApf>I3mg|3+*~z) z)6Gf=ganXlHMz1GE8i+dd z1U+OJy`C^`dZ^#C{?Z@qhUYC(Jn=3=vpV!dcs?t6ezpZvPlV^WlBb)*KvcFo|5Jn9 z4o~g&kPE_*7y6W1iFoqYH6d}39~}mzp7%I#^C?(~dBXg3M&lI@J!2err2~JT10UYWe#mKHbNs zQfsHgXZrZn)OtqZ!E=f}6Mh7^%}?By#fHD^z<=w&-*VtX;nHQ(e*xf?@)tJBaeXFF zk$CXjR7Y`bkoa6WqWzEHXs5*I`*7XA+P5xYjcSZUrjY^OTmy@0Tjs^OU~Q!=|f%Cw)CpYE{Awq|KlCfLF5TCVfR; zCGlookDlkdB;MlVTK>4iQ$DWm6n`Y~;5kdL$RpvFrBa0Rxk%!{^Ve9?xJBZ@^OUyx zj}i}_%e0@rllVQpKi5&K1`<`tp4YUW^8mNyXQ=~EOFhB!+IZ6cj6?polwaoiqsOrn zZpA9u^PP_ODv1ZrciR6CNxUhf=P8K?&v*I`06#~qWY2?@#5^VO^}ZgR&(UxTSSdF6 zxW2=fA@P)t>%7%VyxYeiOj$A#-{|Ao?l&av@JjKJk86MCN<5s04vBB`<+c9DB_2FKUPuxz18$pF z15!R5*EMkKTqzz2>0c^w^)!c_TK^M(+w_0cfj{TKUvS{R1iZrcCTP3~c%=xB`^Df) zC3{ZS`I#m0ZN37HuabB;UeOd!wZq>VcVs3swY7=Z;)cvz*i|K!PPL{oa99JIU%;Os zXHreDD^DtuinpZhg`;$9EZ&-c%~xP^3)po5kE>EC5xaHnZPRa=3zW{~vDvZJ@l-45 zSUk5HR5oW;!VW8mSRBOfNyggliNJ;iAvDtt1l;u|&;Boy^X~s*R|9`OULe)E-2y7e zxBm(nms^QUhQAY62f2ShJ~QY*m(0KShrbgKc2EGm`|r|WyOKavu8pu-V;g}%73b>G zMh0^P5+j3k%jD`Ld9|aKnk%v9uC7>Hvb`hS3NtOUHg-=HrLQS6qndKr0j>HuO>&2c zrU>?5-}u2)Ya+eode{e~H3_?bG;~N>$4t$M&u)t7gBsk03v}Rw#r?cclyA)iUGp1a zlN&N?TauBu*4MLTQc$Vma%f+EPrCh>fpFQctVw8z(A`WCgWflS2~Bs)4`FM-(NL<{U@rloX(wB4NH z(z{yFc2>;3Rjkl`yqF$JK-hrJ9qeP{-Wp8p*ahm$ga-P|9)CY9T=xD#8*+u?V^+-( z&bRfJRHnCDaqYL|6kBzz-+4pMa!L7fQ>?s^%Urr` zBd=oe8s5DN*lNCnwl6E@aYk;fg~Q^WM}x=3H`tO(>h-ahTqR&*Py!KE`nT4nyOgb>IgX&gWGh!}+}WDZ_U#{jV_m35NgPfuA=7 zgrHy^cEU^hImUrs&2VmaKH+$NQ4?B1G%)#}z_Hff$mIK_q4)*U$ardcMr$tD%hr{rL*K^gOv0K`4mtgO|o{ zM-U3)Uxk;(mm>%T@vp&49nbGvskoZDT+aBi1hr?_37 zho^z7{kewe`3A#hF#MYg=Xu!AaGr-}7|!!>fZ^+*jRo_t176x6yhdX|{GZ^Z@h1_4 zg7`srX?!=du^|2}cxjx+dx+sYUY>s*FV8=Zx0mTz4s9%Gm*@X45icLd-Dnhw8E>V6 zC4L0jIuHDOJj!ss?j2+Jc&6u{8P3TM6T5l4qhRv`5(KC`O}HM%DB(Y1^7@*NUB6?vp2LX$(a^IJK`5g=Rb%&iR8ziBW4Jz- zv119t^=~f_U&rtY1gPv{_!tdBeURam41bB??_>BGhL2_V=ppI={lA>y(-^Mr@vwUd z!{5*3*D-t?!*?44=sGml!^Y;b$0L!|>7Pr~|Y+nc>qIejUS?F#LLkuVZ*E r!*?-!3d0XFTwims`z40oz~s*`d>X??4^s!|zswzt(=-Fu>+}Bth?9To literal 0 HcmV?d00001