From d2bc28754f1170495b8dbe4cc518f99f0e10ed94 Mon Sep 17 00:00:00 2001 From: gered Date: Sun, 26 Mar 2023 16:57:22 -0400 Subject: [PATCH] add visual tests for RgbaBitmap blended drawing primitives --- ggdt/tests/graphics_rgba.rs | 196 ++++++++++++++++++ .../ref/rgba/blended_filled_rect_drawing.png | Bin 0 -> 4184 bytes .../ref/rgba/blended_horiz_line_drawing.png | Bin 0 -> 1805 bytes ggdt/tests/ref/rgba/blended_line_drawing.png | Bin 0 -> 3871 bytes ggdt/tests/ref/rgba/blended_pixel_drawing.png | Bin 0 -> 2239 bytes ggdt/tests/ref/rgba/blended_rect_drawing.png | Bin 0 -> 3618 bytes .../ref/rgba/blended_vert_line_drawing.png | Bin 0 -> 2704 bytes 7 files changed, 196 insertions(+) create mode 100644 ggdt/tests/ref/rgba/blended_filled_rect_drawing.png create mode 100644 ggdt/tests/ref/rgba/blended_horiz_line_drawing.png create mode 100644 ggdt/tests/ref/rgba/blended_line_drawing.png create mode 100644 ggdt/tests/ref/rgba/blended_pixel_drawing.png create mode 100644 ggdt/tests/ref/rgba/blended_rect_drawing.png create mode 100644 ggdt/tests/ref/rgba/blended_vert_line_drawing.png diff --git a/ggdt/tests/graphics_rgba.rs b/ggdt/tests/graphics_rgba.rs index 2f0f043..b54a07a 100644 --- a/ggdt/tests/graphics_rgba.rs +++ b/ggdt/tests/graphics_rgba.rs @@ -7,6 +7,23 @@ pub mod helpers; const LIGHTER_BACKGROUND: u32 = 0xff2c3041; +pub const COLOR_BLACK_HALF_ALPHA: u32 = 0x7f000000; +pub const COLOR_BLUE_HALF_ALPHA: u32 = 0x7f0000aa; +pub const COLOR_GREEN_HALF_ALPHA: u32 = 0x7f00aa00; +pub const COLOR_CYAN_HALF_ALPHA: u32 = 0x7f00aaaa; +pub const COLOR_RED_HALF_ALPHA: u32 = 0x7faa0000; +pub const COLOR_MAGENTA_HALF_ALPHA: u32 = 0x7faa00aa; +pub const COLOR_BROWN_HALF_ALPHA: u32 = 0x7faa5500; +pub const COLOR_LIGHT_GRAY_HALF_ALPHA: u32 = 0x7faaaaaa; +pub const COLOR_DARK_GRAY_HALF_ALPHA: u32 = 0x7f555555; +pub const COLOR_BRIGHT_BLUE_HALF_ALPHA: u32 = 0x7f5555ff; +pub const COLOR_BRIGHT_GREEN_HALF_ALPHA: u32 = 0x7f55ff55; +pub const COLOR_BRIGHT_CYAN_HALF_ALPHA: u32 = 0x7f55ffff; +pub const COLOR_BRIGHT_RED_HALF_ALPHA: u32 = 0x7fff5555; +pub const COLOR_BRIGHT_MAGENTA_HALF_ALPHA: u32 = 0x7fff55ff; +pub const COLOR_BRIGHT_YELLOW_HALF_ALPHA: u32 = 0x7fffff55; +pub const COLOR_BRIGHT_WHITE_HALF_ALPHA: u32 = 0x7fffffff; + const BASE_PATH: &str = "./tests/ref/rgba/"; fn reference_file(file: &Path) -> PathBuf { @@ -132,6 +149,42 @@ fn pixel_drawing() { assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); } +#[test] +fn blended_pixel_drawing() { + let mut screen = setup_for_blending(); + + let blend = BlendFunction::Blend; + + for i in 0..10 { + screen.set_blended_pixel(0 + i, 0 + i, COLOR_BLUE_HALF_ALPHA, blend); + screen.set_blended_pixel(319 - i, 0 + i, COLOR_GREEN_HALF_ALPHA, blend); + screen.set_blended_pixel(0 + i, 239 - i, COLOR_CYAN_HALF_ALPHA, blend); + screen.set_blended_pixel(319 - i, 239 - i, COLOR_RED_HALF_ALPHA, blend); + } + + unsafe { + for i in 0..10 { + screen.set_blended_pixel_unchecked(5 + i, 0 + i, COLOR_BLUE_HALF_ALPHA, blend); + screen.set_blended_pixel_unchecked(314 - i, 0 + i, COLOR_GREEN_HALF_ALPHA, blend); + screen.set_blended_pixel_unchecked(5 + i, 239 - i, COLOR_CYAN_HALF_ALPHA, blend); + screen.set_blended_pixel_unchecked(314 - i, 239 - i, COLOR_RED_HALF_ALPHA, blend); + } + } + + ////// + + for i in 0..10 { + screen.set_blended_pixel(5 - i, 100, COLOR_BRIGHT_WHITE_HALF_ALPHA, blend); + screen.set_blended_pixel(i + 314, 100, COLOR_BRIGHT_WHITE_HALF_ALPHA, blend); + screen.set_blended_pixel(160, 5 - i, COLOR_BRIGHT_WHITE_HALF_ALPHA, blend); + screen.set_blended_pixel(160, i + 234, COLOR_BRIGHT_WHITE_HALF_ALPHA, blend); + } + + let path = reference_file(Path::new("blended_pixel_drawing.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + #[test] fn horiz_line_drawing() { let mut screen = setup(); @@ -152,6 +205,28 @@ fn horiz_line_drawing() { assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); } +#[test] +fn blended_horiz_line_drawing() { + let mut screen = setup_for_blending(); + + let blend = BlendFunction::Blend; + + screen.blended_horiz_line(10, 100, 20, COLOR_BLUE_HALF_ALPHA, blend); + screen.blended_horiz_line(10, 100, 30, COLOR_GREEN_HALF_ALPHA, blend); + + ////// + + screen.blended_horiz_line(-50, 50, 6, COLOR_CYAN_HALF_ALPHA, blend); + screen.blended_horiz_line(300, 340, 130, COLOR_MAGENTA_HALF_ALPHA, blend); + + screen.blended_horiz_line(100, 200, -10, COLOR_BROWN_HALF_ALPHA, blend); + screen.blended_horiz_line(20, 80, 250, COLOR_LIGHT_GRAY_HALF_ALPHA, blend); + + let path = reference_file(Path::new("blended_horiz_line_drawing.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + #[test] fn vert_line_drawing() { let mut screen = setup(); @@ -172,6 +247,28 @@ fn vert_line_drawing() { assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); } +#[test] +fn blended_vert_line_drawing() { + let mut screen = setup_for_blending(); + + let blend = BlendFunction::Blend; + + screen.blended_vert_line(50, 10, 200, COLOR_BLUE_HALF_ALPHA, blend); + screen.blended_vert_line(60, 10, 200, COLOR_GREEN_HALF_ALPHA, blend); + + ////// + + screen.blended_vert_line(20, -32, 32, COLOR_CYAN_HALF_ALPHA, blend); + screen.blended_vert_line(270, 245, 165, COLOR_MAGENTA_HALF_ALPHA, blend); + + screen.blended_vert_line(-17, 10, 20, COLOR_BROWN_HALF_ALPHA, blend); + screen.blended_vert_line(400, 100, 300, COLOR_LIGHT_GRAY_HALF_ALPHA, blend); + + let path = reference_file(Path::new("blended_vert_line_drawing.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + #[test] fn line_drawing() { let mut screen = setup(); @@ -209,6 +306,45 @@ fn line_drawing() { assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); } +#[test] +fn blended_line_drawing() { + let mut screen = setup_for_blending(); + + let blend = BlendFunction::Blend; + + screen.blended_line(10, 10, 20, 20, COLOR_BLUE_HALF_ALPHA, blend); + screen.blended_line(10, 100, 20, 150, COLOR_GREEN_HALF_ALPHA, blend); + screen.blended_line(60, 150, 50, 100, COLOR_CYAN_HALF_ALPHA, blend); + + ////// + + screen.blended_line(50, 10, 100, 10, COLOR_MAGENTA_HALF_ALPHA, blend); + screen.blended_line(100, 50, 20, 50, COLOR_BROWN_HALF_ALPHA, blend); + screen.blended_line(290, 10, 290, 100, COLOR_LIGHT_GRAY_HALF_ALPHA, blend); + screen.blended_line(310, 100, 310, 10, COLOR_DARK_GRAY_HALF_ALPHA, blend); + + ////// + + screen.blended_line(50, 200, -50, 200, COLOR_MAGENTA_HALF_ALPHA, blend); + screen.blended_line(300, 210, 340, 210, COLOR_BROWN_HALF_ALPHA, blend); + screen.blended_line(120, -30, 120, 30, COLOR_LIGHT_GRAY_HALF_ALPHA, blend); + screen.blended_line(130, 200, 130, 270, COLOR_DARK_GRAY_HALF_ALPHA, blend); + + screen.blended_line(250, 260, 190, 200, COLOR_BRIGHT_BLUE_HALF_ALPHA, blend); + screen.blended_line(180, 30, 240, -30, COLOR_BRIGHT_GREEN_HALF_ALPHA, blend); + screen.blended_line(-20, 140, 20, 180, COLOR_BRIGHT_CYAN_HALF_ALPHA, blend); + screen.blended_line(300, 130, 340, 170, COLOR_BRIGHT_RED_HALF_ALPHA, blend); + + screen.blended_line(10, -30, 100, -30, COLOR_BLUE_HALF_ALPHA, blend); + screen.blended_line(70, 250, 170, 250, COLOR_GREEN_HALF_ALPHA, blend); + screen.blended_line(-100, 120, -100, 239, COLOR_CYAN_HALF_ALPHA, blend); + screen.blended_line(320, 99, 320, 199, COLOR_MAGENTA_HALF_ALPHA, blend); + + let path = reference_file(Path::new("blended_line_drawing.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + #[test] fn rect_drawing() { let mut screen = setup(); @@ -237,6 +373,36 @@ fn rect_drawing() { assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); } +#[test] +fn blended_rect_drawing() { + let mut screen = setup_for_blending(); + + let blend = BlendFunction::Blend; + + screen.blended_rect(10, 10, 90, 90, COLOR_BLUE_HALF_ALPHA, blend); + screen.blended_rect(10, 110, 90, 190, COLOR_GREEN_HALF_ALPHA, blend); + screen.blended_rect(190, 90, 110, 10, COLOR_CYAN_HALF_ALPHA, blend); + + ////// + + screen.blended_rect(-8, 10, 7, 25, COLOR_MAGENTA_HALF_ALPHA, blend); + screen.blended_rect(20, -8, 35, 7, COLOR_BROWN_HALF_ALPHA, blend); + screen.blended_rect(313, 170, 328, 185, COLOR_LIGHT_GRAY_HALF_ALPHA, blend); + screen.blended_rect(285, 233, 300, 248, COLOR_DARK_GRAY_HALF_ALPHA, blend); + + screen.blended_rect(-16, 30, -1, 46, COLOR_BRIGHT_BLUE_HALF_ALPHA, blend); + screen.blended_rect(40, -16, 55, -1, COLOR_BRIGHT_GREEN_HALF_ALPHA, blend); + screen.blended_rect(320, 150, 335, 165, COLOR_BRIGHT_CYAN_HALF_ALPHA, blend); + screen.blended_rect(265, 240, 280, 255, COLOR_BRIGHT_RED_HALF_ALPHA, blend); + + screen.blended_rect(300, 20, 340, -20, COLOR_BRIGHT_MAGENTA_HALF_ALPHA, blend); + screen.blended_rect(20, 220, -20, 260, COLOR_BRIGHT_YELLOW_HALF_ALPHA, blend); + + let path = reference_file(Path::new("blended_rect_drawing.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + #[test] fn filled_rect_drawing() { let mut screen = setup(); @@ -265,6 +431,36 @@ fn filled_rect_drawing() { assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); } +#[test] +fn blended_filled_rect_drawing() { + let mut screen = setup_for_blending(); + + let blend = BlendFunction::Blend; + + screen.blended_filled_rect(10, 10, 90, 90, COLOR_BLUE_HALF_ALPHA, blend); + screen.blended_filled_rect(10, 110, 90, 190, COLOR_GREEN_HALF_ALPHA, blend); + screen.blended_filled_rect(190, 90, 110, 10, COLOR_CYAN_HALF_ALPHA, blend); + + ////// + + screen.blended_filled_rect(-8, 10, 7, 25, COLOR_MAGENTA_HALF_ALPHA, blend); + screen.blended_filled_rect(20, -8, 35, 7, COLOR_BROWN_HALF_ALPHA, blend); + screen.blended_filled_rect(313, 170, 328, 185, COLOR_LIGHT_GRAY_HALF_ALPHA, blend); + screen.blended_filled_rect(285, 233, 300, 248, COLOR_DARK_GRAY_HALF_ALPHA, blend); + + screen.blended_filled_rect(-16, 30, -1, 46, COLOR_BRIGHT_BLUE_HALF_ALPHA, blend); + screen.blended_filled_rect(40, -16, 55, -1, COLOR_BRIGHT_GREEN_HALF_ALPHA, blend); + screen.blended_filled_rect(320, 150, 335, 165, COLOR_BRIGHT_CYAN_HALF_ALPHA, blend); + screen.blended_filled_rect(265, 240, 280, 255, COLOR_BRIGHT_RED_HALF_ALPHA, blend); + + screen.blended_filled_rect(300, 20, 340, -20, COLOR_BRIGHT_MAGENTA_HALF_ALPHA, blend); + screen.blended_filled_rect(20, 220, -20, 260, COLOR_BRIGHT_YELLOW_HALF_ALPHA, blend); + + let path = reference_file(Path::new("blended_filled_rect_drawing.png")); + //screen.to_png_file(path.as_path(), PngFormat::RGBA).unwrap(); + assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path); +} + #[test] fn circle_drawing() { let mut screen = setup(); diff --git a/ggdt/tests/ref/rgba/blended_filled_rect_drawing.png b/ggdt/tests/ref/rgba/blended_filled_rect_drawing.png new file mode 100644 index 0000000000000000000000000000000000000000..7441a226184723363cbb3e6096358817f25b8d13 GIT binary patch literal 4184 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 literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/blended_horiz_line_drawing.png b/ggdt/tests/ref/rgba/blended_horiz_line_drawing.png new file mode 100644 index 0000000000000000000000000000000000000000..1fe8f040ba8b7e1164f872c0b6214d15d22fb481 GIT binary patch literal 1805 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fP9S3F%DLn`LHy|XcUPAbFk zkGGFndYlMo^3YUuZddX<=-9Nlxw%=g# z+Lm59?>YZT{kp&JE@s`nS#$7v{QPxgw&y?F)O*x@yu3Yr&ArlXdlPPdwmJW~{TZ*q z`OlI2cl4X^7h zWM2010hP`9SI_)n|B1?Z`jyNlKJQ_a`3M#M%5d*%P8|ctGoQELW4=>*O}+tWn84ph z&)RRF`}OcQ(8`~Jd*wiGUC(~vbIrBWi63p|f34T7Ic=jbkhBEx)93r;&-*-mzOVTDzU7m}=ljf#zy18f?Z0;Q zaXH!yhIu|dXCpal`r$`F zPlA#ZTfq@)D_{aE#^qUvF1~JH(3m4)0MmYqI0uGiC9}mNSy^C`utZK0c%ln=|{$&+ObQz-o@c)78&qol`;+0OEw|(*OVf literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/blended_line_drawing.png b/ggdt/tests/ref/rgba/blended_line_drawing.png new file mode 100644 index 0000000000000000000000000000000000000000..1cfd00b9fccd72fe609fa119e035adc7f43edcad GIT binary patch literal 3871 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 literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/blended_rect_drawing.png b/ggdt/tests/ref/rgba/blended_rect_drawing.png new file mode 100644 index 0000000000000000000000000000000000000000..33db3fd95f3c9efa393f5702fd80c5eb2021732c GIT binary patch literal 3618 zcmc&%c~nzZ9!^MUY8m0!o`I@^nc6CK3Pwvc0x{9L)lsmcmZb<`#1RDrsUSwk(&`zo zfN>ec5t8U}B(*Fd!^j#)lp+Gk6Cwl!L}hs-0U~(`;XSgUxjR$`|g5w2?WC2tzT~3Ngxo{f%VIG-Ugq^esu}pT(foK`rXG1#(HmOf86O! zep#PQo;NRoern07vaHNap7YLa@;tZXc=(q;uUq_H&b`Iia~3b!_~_)RvQr=XuHQH3 z{D!kScwcF!AOKM)29$#C-QWvqUx}Tuul{rCHO}wJja#?c%iL#DWszZ)FaDy1^ zorbE<&HYu6a!vW8^=g>St+!>;>PHLZHf=eJwf6C9bWU{jG0i@8tg1KNdNZ+D-?MT? zZCY(_4`y3CDTz@5^RL+6w`hl2eR>v&hsR5NYGmBLGj$9IK}`L9SUPRU6sAz1M-my!`zmbB;amp;2^qu|o-^5Ms%& z(rES$5bta3=Z8k|)qM>4!~t5Dv`04ML${DO4nY5j^KH+d&nH5&l-W_TBk)Owz4q{~ zbdCsyb&49BB(X&&HJrTb4j~zz_A|-h=~lAa3SMoMe$Y#a(EIO5#iW84Sdm$rQ9k{$ zBeKtj$*!%PM$#x(GNOl3l|T(+{`yoYBVCe?Jz_CTVIds*%AWnFxh?)X)y%bZHdvxo za86i*Bx?IJBSuj~(kR;x!k)}K~WBJE8T1W?(N>y6k-fJxXVxIL8dZYZ1 zA+Nt9L&Z=AyFDzylDS$-Dc3k4TLADc0}ijwB${18*tV1-xy;=YqMu*5&_^?#9QcKb z*V~2L9l0NoZ?b>q2&KT5@X(1=ZUQBSM;t%ew!fu3@aW53a30rwYe*-~&!dR7~0*W5emURef z^OuVAs%`fh;6j7jz5c}Uplya-u-g80>4@FlF1Jj9iD9ni4jeg9I9?ukMUll=2aKgi zq^_)Mi+89nEc5rRt%6E|-#WLixSlcG?+;)1C~MP^a)ySQ#F6~k&6F6Sn*0IKVMg+o zIAzRmzD5vrVNvm{wj|=B=vF)VM~@>RIPR}C5eqr|)M!eKFO|u7@RKpLJg_)W>i+2^ zknvrYLxUjVS&u5hHt5L+sTjcsv21kWV8tYHQo%O|#Hq~FPpa7*z6_-Bc@RV#_IXGS zhfT!02E%~r&=_eCeb9iN=DbM!Sy^_AB_=csW+Vyh(nm;U<&C_K(~PLDHFW+fr*wL*X~b;@{U1Qn%r>DutwrtSdgo>POSofUxMt~R`C!=t~h zGHA>8;vMl-Zhq?W9|FiQ+w@9mbSl1S34@UWvu7lBz3OGA=d+5Q7Hye!rbhB#Xajlw zkaJvYy)M10FoJHTq?X4nzVn?`xb3o?H+sbwGkd}S>28juTxG0dh}7indo#l;`AcT! zy_sf9WQ2umw}&pES;Px78Ze@@a$$`9XY(2)ksKQ?@uErii(Hu$YzyB#?bmvLMKSE4T% zN}G{I06!Bld>wqjv0jOR_4%d=Iz+iZ9VgxIU%lu>F`$0SrYRsWzJ<=+7?*ooBtFUV zZYYTt!D#kN&p$#)wyBZBN9VXFhi1ZT+v1F5%Cpj=tLPBYG@Lz6Xu^LxcC&iPYd*)1 zwD?hh>^WN`7zIm@yYnC56ModN-viGfX_pFI``tB=2Oye8#L$s>;kJ7_@+K;JCd8oTjo(vtMsCt8GD^&!+c(L*Y!1nWLDVsEy){bFk<%I}#)e zEXGUE`@r6~MW3?4*|p8$C}AE2qTJ;fZuj(^#Yv%60DBBDM*I!y?+giGT?askwkR0+%Dbz=e-$>Wb9 zz`oo=a+v_y{~QpM^CYDY}BwhTQcYV%f_{rhpf~hJsE&5Q=xe4F$6{_ZOOyH6V0K zC%A6zjw76{R>mCyRPhlWc|$=vZuBKaB}jD`Pn}Z5RaDzkixWzM|AL# ziD;lJ!lfSI0o{0l!>2=3z{-Pct}NQy6DPD8TEhrz5vy2D#(~u_05y5(e#Nk;;RP_{ znmX&?8mU6w#X%sink2hvZ+nJWpI4)|Bj1`Ecu6Vwavnhh3vTatO1|v*eD^Dk!*}%y zizjY@SGkC4x?m<2QcfpijG5RXc$;;Q!`E!T-a zPs@Ujg=WDh8*A2;8CG7FJuNvQf+KOdM;o!`X#x_Ul+{mSAnO}k14C&#%8z}`x%DW2 z8hfHc=ujT6OcRoNo7B-_m|dT;R8JZelX}(o7VWl8>ZoZ4ZBuu1$1m!jR7F*CNh>ex zvt9KzV5WwMi?AFI2$`_x6YIb~qvjA41L$^VHX@da`QPxDOwy!v-N7g}!|ylSx<~M8 z_xujLZ_uF!UNy^D3cSAgSc)pPc*n68wWBqKj6T#`S1#0=>>l!*4<$dK&n4i$A7SgJ Lkd38Z#C-o>VixxP literal 0 HcmV?d00001 diff --git a/ggdt/tests/ref/rgba/blended_vert_line_drawing.png b/ggdt/tests/ref/rgba/blended_vert_line_drawing.png new file mode 100644 index 0000000000000000000000000000000000000000..c83847b4174e53e37f21de3a2947136c1f3b6fed GIT binary patch literal 2704 zcmbtWdsGv57M>x?rVG{Vww3g(7+Q5}U3t`fxFC~+t+YN?&^~PGfjp?ToIO&7`pAP2 z()H}pmKLgQrB;XOteNXY(@$ph2+*Zz|; z^LyO;ec%1=oxHOE@QTok2?{m``VlDB`wHMoP1t4H|!d!;uR4qWkkoZs?%Ee z5ti0d8o4g>nb$FI_B0+;xm*_fP6xxdQ9edUQ2Z~N_z!UMfcI5*TFV)p-Jw3@@pMJv z=6Ty2o5^K6dX5#@Qw(z#FkFJBxvR`cHh|@`JJyQ%@g;{VdU@EFb~XLc>AgyfKm^i7 z4P^1Prgv1EMp(k@K`y#B$Wl?7e$+7HWC=~HltVS>Bkb7$Bje$-zM{98 zg!^zO%fa*Tls*Ul#-SvnOmwLRClD^T!o_mr6nWuB)Wp`G)wzhtq>tINi`PV<GBy7Ei<+-URoLgnej-t&ywAmG1B6%4M|w>Yp#XQS24 z2Y@tm6`qmH%Du1G3chL2Tj7w%j}$0=?_+clo?GRgvK%8UN2=~Wv>>fr*JxHX{i3O9 z7HW_OL;x{c??Qj_n%VmGKunKE1}^24DJ)#Oo2@^G;}SWClfx*nfKZpdrKb-E7-*+fT;p3HHKIpPXSiK5t_^h7r$kC5)-v zdug;i~VAh0{oqJ2flqmsl&5Z|!|YOlAD3 zIA@iSI4<~!Q-Iq=3vK7`xEN8IR{7c<1>WjT)%OS>bn-^@eiQwZeL$2UKI5q_K;2No z5}qI>XiXVgzm_17q}ey~wvXTv&IC`ve+(7D>WlRcPX~0+L{2`-0jby5otR%tOLjap5{%ZVpM5;bPba-_@z_THiP4xaw zP<5>~vT!dgP2$NtFgn@S3T0NnVr@}4bdYv5c5XB_W8rTCx(0i!f3Q0DI~Oobk~?y8 zB?%O?%tjXOp>?tL@;`s8CvHiZLOcz^X2+svhf5a1wlx}C#@CdtKXOH=c!0$kC8+-V zl7;AMz7#9g=1<0qd14(T8cjPIyJz%AcKSGA7hCLT?4X1xtjgT{E6TtTV-?>9#u3;f z3zQQ>wD`-7UqP72#Z#QoL5RKiz9kF#D=Fl}kgmh369K!lLYgdOGN!n6>$*WV1UxH^ zoP1vfOzpa_(~O0$tZ{wDXw?`dcQho0Q z7rbePl*n`C|Dt~qNvkfIRGTp!C!iDg>0-`3Ft{zAHdCoQU{8S2a0RtH=G0`kCgHmQ!-!BN$xh5u)R7b$L}ie?6}%jT@$>!C0{pq z^75en{MFb_FbH-s9oI8A{ZSL%&jbh&0p^0yM4nuc5K8*i3ztE!%GhAOU%zQy@1I}( zLz~pDdMb->ug)2atU3<&89;PDjt<_Lhe9}B(L`Q^1LuZ; z$Z|oN{^NrrU&C?;p8@s)BO)+6U;h?ruw59Ca2hPM#IbGDvL-O!m;&E9Fi^l_plSU>4x$Fk3egcUde8`Xns1s1B-#{^TP#K~@V&xj zb@c$mX+A?GH2ec6>-dZk)tU}M1G=OAU9jzRQ+?BY7|zv1if?&>ZC!hjqnv8(U05`s1?*;Hc iG5;TFupelimHI0?3ifg0)_{MS(Dr9?vm2il{_TIz2je9G literal 0 HcmV?d00001