From ccb87b12da9f4c8e65571d31da2952ff1b5b08d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Mon, 22 Jul 2019 20:14:23 +0200 Subject: [PATCH] Implement `button::Renderer` in `ggez` example --- examples/ggez/main.rs | 62 ++++++++++--- examples/ggez/renderer.rs | 19 +++- examples/ggez/renderer/button.rs | 144 +++++++++++++++++++++++++++++++ examples/ggez/widget.rs | 2 + resources/ui.png | Bin 0 -> 16691 bytes 5 files changed, 215 insertions(+), 12 deletions(-) create mode 100644 examples/ggez/renderer/button.rs create mode 100644 resources/ui.png diff --git a/examples/ggez/main.rs b/examples/ggez/main.rs index 87949dee..7deef072 100644 --- a/examples/ggez/main.rs +++ b/examples/ggez/main.rs @@ -2,26 +2,33 @@ mod renderer; mod widget; use renderer::Renderer; -use widget::Text; +use widget::{button, Button, Column, Text}; use ggez; use ggez::event; use ggez::graphics; +use ggez::input::mouse; use iced::Interface; pub fn main() -> ggez::GameResult { let cb = ggez::ContextBuilder::new("iced", "ggez"); let (ctx, event_loop) = &mut cb.build()?; - let state = &mut Game::new()?; + let state = &mut Game::new(ctx)?; event::run(ctx, event_loop, state) } -struct Game {} +struct Game { + spritesheet: graphics::Image, + button: button::State, +} impl Game { - fn new() -> ggez::GameResult { - Ok(Game {}) + fn new(context: &mut ggez::Context) -> ggez::GameResult { + Ok(Game { + spritesheet: graphics::Image::new(context, "/ui.png").unwrap(), + button: button::State::new(), + }) } } @@ -33,17 +40,50 @@ impl event::EventHandler for Game { fn draw(&mut self, context: &mut ggez::Context) -> ggez::GameResult { graphics::clear(context, [0.1, 0.2, 0.3, 1.0].into()); - { - let renderer = &mut Renderer { context }; - let ui: Interface<(), Renderer> = - Interface::compute(Text::new("Hello, iced!").into(), renderer); + let screen = graphics::screen_coordinates(context); - let mouse_cursor = ui.draw(renderer, iced::Point::new(0.0, 0.0)); + let cursor = { + let hello = Text::new("Hello, iced!") + .horizontal_alignment(iced::text::HorizontalAlignment::Center); + + let button = Button::new(&mut self.button, "Press me!").width(200); + + let content = Column::new() + .width(screen.w as u32) + .height(screen.h as u32) + .align_items(iced::Align::Center) + .justify_content(iced::Justify::Center) + .spacing(20) + .push(hello) + .push(button); + + let renderer = + &mut Renderer::new(context, self.spritesheet.clone()); + + let ui: Interface<(), Renderer> = + Interface::compute(content.into(), renderer); + + let cursor = ui.draw(renderer, iced::Point::new(0.0, 0.0)); renderer.flush(); - } + + cursor + }; + + mouse::set_cursor_type(context, into_cursor_type(cursor)); graphics::present(context)?; Ok(()) } } + +fn into_cursor_type(cursor: iced::MouseCursor) -> mouse::MouseCursor { + match cursor { + iced::MouseCursor::OutOfBounds => mouse::MouseCursor::Default, + iced::MouseCursor::Idle => mouse::MouseCursor::Default, + iced::MouseCursor::Pointer => mouse::MouseCursor::Hand, + iced::MouseCursor::Working => mouse::MouseCursor::Progress, + iced::MouseCursor::Grab => mouse::MouseCursor::Grab, + iced::MouseCursor::Grabbing => mouse::MouseCursor::Grabbing, + } +} diff --git a/examples/ggez/renderer.rs b/examples/ggez/renderer.rs index ae6e3250..d21c5ec3 100644 --- a/examples/ggez/renderer.rs +++ b/examples/ggez/renderer.rs @@ -1,14 +1,31 @@ +mod button; mod text; -use ggez::graphics::{self, Color}; +use ggez::graphics::{self, spritebatch::SpriteBatch, Color, Image}; use ggez::Context; pub struct Renderer<'a> { pub context: &'a mut Context, + pub sprites: SpriteBatch, + pub spritesheet: Image, } impl Renderer<'_> { + pub fn new(context: &mut Context, spritesheet: Image) -> Renderer { + Renderer { + context, + sprites: SpriteBatch::new(spritesheet.clone()), + spritesheet, + } + } pub fn flush(&mut self) { + graphics::draw( + self.context, + &self.sprites, + graphics::DrawParam::default(), + ) + .expect("Draw sprites"); + graphics::draw_queued_text( self.context, graphics::DrawParam::default(), diff --git a/examples/ggez/renderer/button.rs b/examples/ggez/renderer/button.rs new file mode 100644 index 00000000..2423efe1 --- /dev/null +++ b/examples/ggez/renderer/button.rs @@ -0,0 +1,144 @@ +use super::Renderer; +use ggez::graphics::{ + self, Align, Color, DrawParam, Rect, Scale, Text, TextFragment, WHITE, +}; +use iced::{button, MouseCursor}; + +const LEFT: Rect = Rect { + x: 0.0, + y: 34.0, + w: 6.0, + h: 49.0, +}; + +const BACKGROUND: Rect = Rect { + x: LEFT.w, + y: LEFT.y, + w: 1.0, + h: LEFT.h, +}; + +const RIGHT: Rect = Rect { + x: LEFT.h - LEFT.w, + y: LEFT.y, + w: LEFT.w, + h: LEFT.h, +}; + +impl button::Renderer for Renderer<'_> { + fn draw( + &mut self, + cursor_position: iced::Point, + mut bounds: iced::Rectangle, + state: &button::State, + label: &str, + class: button::Class, + ) -> MouseCursor { + let mouse_over = bounds.contains(cursor_position); + + let mut state_offset = 0.0; + + if mouse_over { + if state.is_pressed() { + bounds.y += 4.0; + state_offset = RIGHT.x + RIGHT.w; + } else { + bounds.y -= 1.0; + } + } + + let class_index = match class { + button::Class::Primary => 0, + button::Class::Secondary => 1, + button::Class::Positive => 2, + }; + + let width = self.spritesheet.width() as f32; + let height = self.spritesheet.height() as f32; + + self.sprites.add(DrawParam { + src: Rect { + x: (LEFT.x + state_offset) / width, + y: (LEFT.y + class_index as f32 * LEFT.h) / height, + w: LEFT.w / width, + h: LEFT.h / height, + }, + dest: ggez::mint::Point2 { + x: bounds.x, + y: bounds.y, + }, + ..DrawParam::default() + }); + + self.sprites.add(DrawParam { + src: Rect { + x: (BACKGROUND.x + state_offset) / width, + y: (BACKGROUND.y + class_index as f32 * BACKGROUND.h) / height, + w: BACKGROUND.w / width, + h: BACKGROUND.h / height, + }, + dest: ggez::mint::Point2 { + x: bounds.x + LEFT.w, + y: bounds.y, + }, + scale: ggez::mint::Vector2 { + x: bounds.width - LEFT.w - RIGHT.w, + y: 1.0, + }, + ..DrawParam::default() + }); + + self.sprites.add(DrawParam { + src: Rect { + x: (RIGHT.x + state_offset) / width, + y: (RIGHT.y + class_index as f32 * RIGHT.h) / height, + w: RIGHT.w / width, + h: RIGHT.h / height, + }, + dest: ggez::mint::Point2 { + x: bounds.x + bounds.width - RIGHT.w, + y: bounds.y, + }, + ..DrawParam::default() + }); + + let mut text = Text::new(TextFragment { + text: String::from(label), + scale: Some(Scale { x: 20.0, y: 20.0 }), + ..Default::default() + }); + + text.set_bounds( + ggez::mint::Point2 { + x: bounds.width, + y: bounds.height, + }, + Align::Center, + ); + + graphics::queue_text( + self.context, + &text, + ggez::mint::Point2 { + x: bounds.x, + y: bounds.y + BACKGROUND.h / 4.0, + }, + Some(if mouse_over { + WHITE + } else { + Color { + r: 0.9, + g: 0.9, + b: 0.9, + a: 1.0, + } + }), + ); + + if mouse_over { + MouseCursor::Pointer + } else { + MouseCursor::OutOfBounds + } + } +} diff --git a/examples/ggez/widget.rs b/examples/ggez/widget.rs index a9e0a7ba..657a3190 100644 --- a/examples/ggez/widget.rs +++ b/examples/ggez/widget.rs @@ -1,3 +1,5 @@ use ggez::graphics::Color; +pub use iced::{button, Button, Column, Row}; + pub type Text = iced::Text; diff --git a/resources/ui.png b/resources/ui.png new file mode 100644 index 0000000000000000000000000000000000000000..4fd3beb3de8034585eb8334c123fb2bbfdefb2e4 GIT binary patch literal 16691 zcmeAS@N?(olHy`uVBq!ia0y~yV7Sb{z_5dZje&uo(&VNC1B2AHs*s41pu}>8f};Gi z%$!t(lFEWqh1817GzNx>TWe>BPm|fX)%Cw27cb*I9`-Wbvkr%^+jZ#NKC1THcH z{?+mN=WD9Y)umleR^$0O^U7zA&t=kjGA^2T)~D8S{a5`L`_BLI@>_Y!yUT87vfE!a zeIC2vxa;{0)m-Bz$E7g@>$0i-q@vHFo^b3c$On(^sJAQqaN=TZ#$&haG#`SYkkEsx^l*{~rI< z6XuH)X*^lh>bEJ$=Zb&lRH;{*OJ)R}TDfFa)GM`inc`EH)7Q*R$n~Ptr{49Ikb+27M@yJ9sxzsBc-R4g@-(!5% z=JcA)XZQW#(q6aalh*2W+kTbJ4l=TSx8<|m?swaMFTCbw@o~vyf6K31F5ln$?bNII zx_^$>?r3NKOY^!u_4}HSd78T}?rjx5r}DI?=jV$P6@hFT8SCfVe3kU&)SRNU*~_&j zrBCqO8F{Ykv5{ua?Vlxgs^8feeLr4leB@Vo<>&fImW!|aC3gW4RhbWoE%eS`FTl!)WO6( zoGqIc{)*VdxpMc7E?(8r#!#Px!pGOFw=HdB3_QO?XxG}g52jCi_js0U;ClBD8*)rE zcixNf)%#?hUH{SR+V<|Nza7sWyZhr=VXc|CTJX1pe$LM8XP(kpm@dIr^Y!rcZQJ?P zHMW+C#jo;iXIiN^N47gQ;ilZ;Pu_CX^Q`y|#x3~v(z@Tcdh5Qalkeuel(}@_(e(R5 zl8PU83rt9UzDjxf)90u5&YUZe5WD)Fr0~NPmS+|$?Ah~YnZc~3QCzA_V!n4vmuwZ% zoNM}I?L^aZGuFtNwL2dcTUPh-_E|KtZ!c_PJ$WZZZ+2Yd?2|s*JszfQDqDKDcB|qC z)`s3DUG_yEdv89yw8K<1%)7jL>9%djVyWi8+SM8g&HC>weHXK6{@HkjcSm=)9BX%T zxqGg}EOdvrS9;sx@|j+WPA^sDq$ShqC&e)bCZwePTvN`Y7?*yz{>k$T(RU{wk>h-P z?>HM%s7L<2mJZ9@QyM*z$N7p|jSe%gR(V&>FjG^#ku|Aq=JM^f-Lsz*^`Gj=o_Vp| zt~~qalVeYkPD{ruSQ)lv(fyeV+mpH$x4fHCE>)NvFw;Ea9Ao%}eU+2vGF=eu*xkB; z!@pqakGG~pH_Ik;?mT;I-?J?o{Z9@ShylWRyry$!&vvefcWwCkM3s7cDYz? zw`8yA9y{MOGoJKI4yHy0QY+>wWtFqgryq|M4>>N+Ycu1PobP_A>!O@>(Oly{x>+jtR50Q@_{-Z)(#P zTI^gh>Ed4Zkc$V}Yemx4>thzFc72`s$8q7_*2vR`HP099Fw{uc!TFPY-kTlrhn-p& zUe-N(cf~N@Xzm`#?>BseZ?qm^ynH7!Xab|2lQ@gplVIIS?b*Vy57`4IJ<{05zM)-v zZgNmc%qs?tj~fnr5%_o_cv12(JEt>jTa=%_?eV?nH~VPr)Vf?IKJf+T_zKp0IXJd7 zote|odhU;LWCMSDX|Iz>O{a+4>p)veuGm27>_E?eKlf6bIJ#FoSAVv6mr4X*RK1q1D$=z)Zl&|oQgO<)7d5g{;;B7ByWP1I>Za+Q?6u5kIj_|+nR~ySOQfM4 z?-r{Mk2nfuSuczJq4`bvKI4rJ!)qa*70;Tyne8~s`cmX}X180%^p2chSoO)_6~kOt z8>j8N4)4BmLugN=#;dMxa=WLtI51@T>szw>FNon>EV=J+jqb$LLGMy8$T9Ttx4w|o zn4k58&E>G;^V>%C0u}isLCSBMA2jivmfDf9J6LPZ5eL3h9uXe~K0ChBMmuS<*Voo& zHaf@YJ`wECT_vv;u=>7-BlE$A>B<47bv$pJpM+1D*<_}3m8nd?tm^5uw=ceU?%l<` zcc#WXai^KwflnJ(aDCF9wNZsh-s*7LDIc}cEfTC1s$#kN&&p1v#l16gb<9{;7i^oH zx>BI!md$pzU<2GfxUuQTCImFj$L^|(Xq}HEVusCANrD*@{yw4p^ zwjXiS@hMy=bW&cUV9)*w)0vm-Tgj5=dEi8+=hFVzmiv;W6%yAE7AY=2uI0Cd&8GB9 zmP?D_5!X!j+fFfy)`uu4Ukuk}(`ab7DN?=oM)+d!3nqz4_ukCYRR2{HU|hf-$eAc# z^3TPFInwEwcFIvD4#VZyHpXo8HeJ5C3*<{~N5eU%O;L9T3=wx!{(4I?s&2@%D*HQ<;VF|`y62Us<3dIfWVQNLIt*mk`-=E5OG-X zyfb4_@9MWK^Okj-Q@PV4Ush47^mwUlL)LZivt4r?HZI(AIqYljQ69F6L!F@!0t@GT zn%LRQ?$dO9=VwV<#+oLcMG`3@fmM3?H7U*$x1M{?UDdE{!83sur5_}fC(7jBn9Nx4 zk#B*>^-oJ1duQ)6WugU;>?Rwy;`Fz@2eY~Pj1GEw4Y?tGOd{y5=6 zj!lmrH|bCO%{)Q&0^i)e39}EB3B+|Q-B^EF@dv|;m@^KI(-}809P%iQ(X8mTa}jk; zXLxx~_-Rk`k`K`Zya75#Jd$coDjRPKnQfl2=IPUm87p-3q$hMN-IU@h;oz{k;=0Ly z(+i>kuJ<1n#S8xaVLG8TQ>tK>Ue`M2#tVNOjfDF2ZVQU>%@9{PbU;_cieK-*8Y?%h zIOWfU2R^tu1t{LAzPd}grl0qi+}9daNsUVZ(b=cUom?hFx^2$g^mfX`?(KgcG#yM* zIO@ZZy>n~oe~-Hv2Q)?bPIwgXUp)A1*%6CHWz|P5UH0hSFkD}HTO;4~poqVT&9*&C zuG~6YVJAY^ESjX+%R6k!oqjJBW)kv|<2l&Kr0k)w>;Ze;p@f!z&BjK3!R9mkv^{cp zPBFFiZf5Kjo5`@;Pjvd_bmsqOr!wl@?6`gM39l=2ZESk*gB=qlSZ=<3;~SH#^39g@ z3;q7|-Pr%FRibF?BO3t*(~|ppcb)z4;je+ksV1@A3+mf=s!AtChV1Kc+4(|?V~XK6 zkMo=5c^#5!`xCxRn>aC{)cAYDOs4pZ!~k~P0;v=J&DH1k2s)(vKApS%zS{reFZM0I z*cq`}+x?|8*V1)tS1vnmeP}9p`d;FO1@RNje&yS|6Z$-hDQsc+2!g z*rI(RxIq4rjXQ_fzq*#ae}uTW=4HHi^VNuHy3Et{B7QqUW!+ovSF0{u{O_Pf-1`1L zu7roNrV}Bd+RlP!L$MvcEs^)pb?df#Z>GzxNvTNz9z6F{L%<#Q)-B>z1VD9Qkg>SCKXlo<|CFdz#dUL4zhVX`~vk$iT{W3V* zv7901@zjfpdQ?BkIIQVgxk>PLK4-a%X-e@%UA@i5cKMbkMM^Z^%A`jI?b?0P!m#K^ zx7h3qjssIutXd!LXlt>yc4fRY=S9vVzW$1f0dglQ3_491UmuaaQNWl!&pa+#qFA{w0Py`xl7ri7*n5`fL-c{jTF&mDp4ziFqdu8@vyazE$f~B52-R&UV3V4eNPf zg>#V}J8p}pyfv~m3Tu;?%k(3q;a;+of^UPB;!l%*Y~pMZ!QR~xA2ot^>&(9tR?Kq7 zFnIE`Z+mrSNrf$57RnlB){|`cuIz(>0>`i86Mx#;yy?hE&G>d_-OY0bVyBMJyUL>f zBv`6GKY9bB@V*qKGiq5&g}$$Iy3f6;_rl3G))}@hm^o)2+Ok6UiOmzED@!8y5)5K{ z9BMObUB1chF0r|cKSW=s=D8&wsl4h`Y&=JG|8~!9Dw;K^2X#{g1J_Ch zNcI|)+^l?}HtW9Gm0iurXD>Nxs(yHFpwiXnm}r=mu_EfrK9yr>1zDD}Sa^=TPQ7zB zH)@V%aBI^BfzAuuQVkmFAq53&6a26Gq=o*mirBU&&uwCcD4)H1Xm!E+%jwTvw_nXt zig?(OTkdij z64O6P{Qh0OUZU7bXzt&#gW2nROe_(!Eqs4)@Nt6o?t zvy9u5d*6^8Y{AoSBPuyJ`ooJq?!}g*fu6^55>jg_bt+{O=m9_lzk&-3mNBgcjKR0{XmEqE_ zaqdOnM$-i*p4+d<3GzmF8%KEsS_DaRX3Q1ZGKHau*IiThg?X+>)6O4!&F6L>d3|{C zrDbBXjQ_q5Y*M-RkatV1aqPFK2QxahUpsKAA;o#yucQaJ7uUI38=TV=Y_u;Z7oDP5 z8B!VOmHSEa$(mH7sNdh5Cf(-wbk(8fWt7KfiOFX!Y&J`F3_tKjWflL`=|A`lJ*^+J z9h7fT%Hy)QB$eDB^hR*H!v400)6Zx=o*>WJ^|eLZwy=4Q0gLEI2gYixrFTQa-T4~y zPjN)J@AnUmnJ_o{v|EHsntE}jW}75rM{-J%Z%oG+Rrz4`IJZ9M^xIG0!vX$BP4ZGSmyiR{pQ_i{Dq4|FXkX zeaCq|{-b6Sj%VIeNt%+Fur|*&wWC6R*TO3PJ3bHCzc}CDE;v#6#nr~&=fiW)1%AkW z9@*f=_*VUf3$OL{b}{ehJZ~-5hen0vwUK}1TX&vNi!I&KwqJ9~MMaM;tAx%C$#?cC zO9^k2@mch?d+nFMo*a^n=9hTaw%qWF+s!Q2tNCboV%kxe^-CT${gPenUVTD-;;efr zg&c9)>(=R699`A7b?dWj2d3PpQOk~#*6mI(*KLx`Ke?s=IdX1x@$02~PE!*J2y@JO6iHd{$Nli^o*! zI5Bd(B?nCzn$X|9O?oINL?z^?hGy zo$9-3>7O5O7m$(+n*94>ru@r4Z_=2{Bz`SoIDP2x)_X#wK8%@X$Go-f+9wmn zJ?Ch*LiWQCt2r#n77v|CN`ecY0Tk#cP8R%ORrdm5r&Y=2_bT4;XkSd}i*^>3Mf zpPf#B_W1DSSt|BE{Ta)ve_xzu@7pcMI%$$bu2NX39z(RCrpk}LJG`=!4Zj#=Jh>2N zm3T3uQjS$IV>5r|8dv$ysbT-WPg0Mz&+nNv-@ja8+tbnqhc>(~lq~rB`TY~;N%|M% zh3-clx81k@^EbD8zx4|y268t4YvBp{5~a0ATI$B!Wx=urr{+e*&l8_;JW&EKPDx3-mRIbyhL|B;pj!371zQ}&gv$zT;( zYI>l1&6?W1O*)U2CYaqgyxgI|@#3o=EQJ>yw)R`h+3)#({yr_f8!2o4m~ltjC`zRK z_0)^aYJF~-+a|<%C-#!t&ubS&mRqGwYd#cf#ap~ZwChsekAMEtGZwXl~N2vI($v*VPt)%T6uZQ9L=rkm{mFEo9yl5*y)n$H(4*@ zM70RdzF9mQujzN^cdLDsK6+!tn+qEpEpF^K5p1yj2 z{ojW{FIXd`YCE2puy4;>qp{JYGjgt1>*{04rBdgTY$kmOm95C~>78c6>^f1sz~{@Z z%D#Ilxe@>E4?Ibk>|*qJ(wQrY?l}xnF;Wia;?kE)J37fC-f-pWMZXoiHd)K8Y+34e zOvTmY$?dImi}!7n{rgKMq+(sgZU#*wReRw{J~3;RZS+%)nNQlfcNM$Mv)2)m&YqV_ zxE`30bNbkh1Lq>NU0i1LM0v|T;QAm~;Aa%LVJcsh_DL14_xo3`&!5jeseyH+mc!NO zukUU@{Y}*8-#q@1Ae&z+rus|tXC2Hsz3gb6`Kv?H$NINO$Gv}W_=FVe!()dfl3%2p zDi`~CIXq;__VX_l$~pP9yZrX`M8x-Sv{lIPrt!V}X*FZ%=Nf$@nNOC%DH-y_9NXBkwLJAJg>VkWTso49?Qqt-{8rn2SJ4qMyv={{8wz9n9^$0$+M_E@X_n~whH zX3MQE|7gEF?~Z%x_5a?jv!fqfeVSg(a!-lJO8)re@EvRT4_({+t}g3{&TEzT3S|rO z9NDw2!c>-E@EXr@z;BY_JeG z%J^sFEt$N&Z=bD%AGObA+xWO~|2COWkIt$Xd~l zF%nV#?Kz!2w~Dp{ z&Rg>4()_cYj9be3wuOaOE)2b%Ecfj%)6@4KznuSn)^)DUo7kXvR!bfq_%ToEySG8m z#h>chYE|DRFbYYr8SMOZ@Z{pwr+aN~`2lVE=T511ZXT|FfR?-|#B^r0Qx0 z1_rhyZ+91lc7_QI-L-#AmohLga29w(7BevDDT6R$#Zvn+1_lQ95>H=O_Q$M}OmaeV zJI@I)Ffd4#xJHyX=jZ08=9Mrw7o{eaq^2m8XO?6rxO@5rgg5euGcYJHc)B=-RNQ(y zx3VI{_1^paq0i^UO)3#`65~+l7Pz7C+Vz*lLo64N~HFS>LUlwrW>>%jHP|ll(3v zl&?Ae`Gdsn-RIW7n)7R3{MGelM$b;IPJGP&>r&92dFc!d0(V#@l$3}ne%toPU4-pW zqZ7jim8E7kFVOM#(Ip?O)tD>F1xD?j~h@^5gOk`M~aq4O8Ua@2yh6fA`&Kw{0 z6_3nj_$F&xwWaXJhD0WYZ}0AU&-F`>KUb+;J>`<#?ZA9UiD@b9};+EECi+mEm^+2eDxt#CPsr}0byZnr%rhlocn)JqWX}@S^deA zCRO;q7fj{}4Gq=M(#rZR)O7o8UuVItsAr!(73sw8`ciEeIjyv?yK8FyF4YBoEvbfP z!J${{Jq_p1o2niDEWqpf@+C`R?8@FmOqw~9v;8om6UQ9C^y%x5TefG;5^!?3UK$b> zmh}DIT^$*|_s{0sFZ%Hz(TOASec5jP{h!ZSd#0tSO`1G8IqCfS?~6BW5?a6Sm)7Od zTJwhJY5MVTvTwJR#Jb1E#-8TB_x|{?Ug^NlP*K4t>s|}$r&cRRdsJ3dN*JYZ$ndc< zD43gXKYo5$Zrz?Z{XQ8>A;Az0kwZ z_d1cmAvsyt=kS^BuCMriwaxkAIeE&tl>$!hE}6XT`uO;G@`D472EM|();V)DCK%k9 z``R&3B*1IpoH;!cmE8|LEYP^UEmt~S;@BBs-v!!f=jZh%9&X#Zsr=22jd?dupE|{~ zRHXLT7ss$Lv9xn@R{nXLUoV|L>zNOOziYMb^2;~9SorOJC}d@4Z%jJM)#9`;%-3@J zZC=;F3)}PKW2)b7{ZL_JSZ|j5*|_M5$CYc>l3rh1%fZ6r;pLT;8FVU3#@t8JAc4Wi z$S6UAt?8gbi@@D|GX#__T{HI;K6&!wiF4=N^78cd#Jv}B;?UdqMCi$rCkG68WUR~9 z9RIdz^=joqQYIM!YBiaHHpBwSzB9+-#=beQ&jM|K(=!*xf&Oemo}q@mh5LK?5F} z?{|t9Xs(+wlO=_NQF75Lu1%XaO_)3Ns_uFg2EFCnddsr7hZfk%iB(a+D@$vnW->jK%Df9c==No3H z&iOnee!ijDOa4GFS#@(}-oqU`_s*InRbeBy`~LG6C%0NW=V(8?H)206 zPWbiZrDw~8di9n+-_7Fk4VHfSzHys*>8mRq^=BRyfMjLA7DrcVN}ip3g!l3?Uujp( zyBU$!&Ubfpo$@RBcbs_!`+>WD2@e9+d|r?l<)Xr{K!Ypo%#6lm%hYo2?AUmCOOVf` ziVt>`Efa2sgwEww2oAlPT7IYSxD3PJkkHyjfk%1EJHO6Mjr=e7_*sg!;@mfli)OYe z9aZ_c@V9e$kk@0fYrSjL8mmc2U*{ahf|8~gTZ#{R0 z71u;>L(fNSu7O$?j0CqWYJT=0Pw~i{@As>DJcl#oN@6s&p=Yc5m^V z&)XVX8J_>C|6Q~1{BFfddFP9t%vrp0W%lY;P>47O1_mw_cqFHIWV?Fh^#7+NqPHg= zX1g{w+sxFoG%}#b(5I7|gZ(Hm~pHfZ*Wf zQ>VNPj$JD_cU|79gd;RG^nwX5GaFCGn-`abW%$_Hcq9ZiKL1*EP$F7bow4t-ne}er zf)^Xkr$mM=>2!41wRKsi(5+Wh>ZU1DOH-_#=pHu6`~PIJ|GG;iy(wvFN~We;kINmt z_v-bHjmbB*W=}tAdEZC#FH1vG+u&@S^ho~Z>fF-19UY#RujIXDytt{+i+fkyr#1c4Y`>_yUHrOg z@3PG9KXv~n=|*q+Q}g1&LJwcxw;RhJ%{l!1^TXTu`&%<-x%O;S@0YW^l`u;!G_*8O zLnP|cA#VLYHD_iRdieYIckVrQ%~)u`RC)K!^G#;)yDdpVGOsz0Rxo_{ zIqN~$Zl&DZ>6b4qHlK3-``=m-nb%8GtkPayTFT_0+aS)cXG7LiEe40$+P$wnR{Y{p zJQptVG@PN0`NeIuO3eo5X{n;YUi&YX-Zjs@wuW!Eh<5n8oYeFG{`A-XSv+gXlq=JN zW;t;vPD|}wJmnwHft|VW2b?-`dp4HW*xjGEd|p-8+?CbI)jqM;t^b^zdE=($tv@Ro z3l9cTO2eS4~t6YWS*XlpKayN>x;VXJo&UJcG9$I z%eG$sbGh{Ir(?(5SeP2^Bc^RV`Lt;7=S$xDxj)Y4*Im9NI=kQg-;bYp+ka1QnJ`<1 z@3`vUUtcd56&L$QT8Q(t2S!D8B^XpNE-lHJZ&!OSa!gwWp^6Z&Y=vCuQxsfJ6H|ltseSS1G_4G8$7J*<>-`T5Iy*gT1S^4V2!^0D& zOkr7mxzcOFfqN&n?Av$m^VRTpU)#DrKfY>eYHnW_z5Sj2GT+%@muBug+AVH9$M1QF zYv41juA-0r^}m9@PV&}kJpR}*C@5(6w`0B1?aP*_onJn`&T8wHEnlj(->!ZAxZnPt ze7BgcR_D{b3M~iT=0)z@mw9>FiS)9RbFaTDnVXC2P1oLZ|L4pnPyWbQm1umDWNh%( z-yf8BM?T%=_nXb%GiH6u*8~#@nH5=lF1KXPT5gga656^fbE5gPMrQU6 z>F4Dn+6pHamfZ%G*NLq4Z#Eu(7a02WW={{#^SkBu@1|C(s;XA}{dzrd)-%U*KXdtQ zzXbTOEM1lLq=kF`{eD&NX$%=R3yPkcm{_ngrocjG$J1%i4?b2X?Ot~*%l!JePs#3# z%#93Dd-L>UY@_5fh2@=gnOR!?d@mkb5?EDNXUCyvz@xlrW1YK37t{39tiG2YeE#|2 zr26~^FD@>A|7w?A_PaYfL*Fiq+>mf^t6cx{_t#^JeSf7+j}_Zk{^!R>zqhHWsjhEK z&CDLj|Np_xCvW#>UFNLKTwGkMk|f?9xwO>#;pd+RERSFIx6l3ld%-HLU*FzJ-^~A$ zv*5K=S9kZ@#Z?CB=VUB1r1SrLU0=WV+{1!BlcrCfUiYw7+=-*{*|W6jD8G=uYZ44P z5)3%{k2ibk?-hxRj5N2Hdv3pO{JuT87nr!k_4fFMUJd{B`SWG>emU8V;emmIQ$ej5 z8S65hg9!qenVB;z3YE@TKA$6P;`{sdp32X^jxD-0ZQ8U)6W!%HIaY4kv?=ud*-biE zu3lZZVg<+2rAuYmG?S*zU$kgZ$AmYJQAqHG zc+gbg+bwFg?tiMb`Scg574LRFKNlKW>RVLw>Bj8*eUg65jf)Z@%L^=I3U=Ss(AGY@ zE%$apNjbtj8n+hds- zmalO**xz=knyTvE_hq}~=bB_r(l$00K7018ZQk$QF?u`h=H=Yp#@o&>|L>T|S!-Fo zX-B&*Of3yS10X*F-S-URG$aNItYlhr30f#YyqZ z{QJLb9e>^Xb1s%|c@zhOX6>)TQ}1jN+-Yp7`%Y`#y*rn_a+zOOx={{T|~QIHkVWYHp@e z$7dP7<0}FeyE$?+K0e-m{LZ}@hRGscFZXB8y7uz$41>f&3Qi}ITPEzj&9zch!Obnm z>;D>!Q~xE*^X7>4pATaV{lppi;N%HcrH3a^w60&qv%t%aL8VGEBy_K~va++cr)OiL zgrV$7a~@_-PfrQ690@NkuXQHA#SBZotb2I4J-hbTm(HDgPo47Okv8KIk11f>mVdu) zY33|uxtb3LFK?6o{{H@aAI-nYici}5)_HSW6mhMz(A9mb(XgnZdY%XaOS(si&|V&= z4)5PzUNSGgEcrRGrh1RZWs@b#mN|u9^=6EjHFGBC^wXtoZKHi1Th#U7%YTAS zZHzOdo<0rcR18-4nQ=k=pUq?yyL(wv`ZipbEq(6rB16glTZ3|gV9Nx-lP6DJFj*VT z?&O|){$+`hwl+5}FR${u-S78>-M@bIYU1y2Z&$2c%c}Tf*SA?^vK1>fPPt^lz#HT< z>6=zZbCA^K%inHQaXWSVJzx0fzT{SS&DLd^3=b@RZYf%z`pP`(ipGmweVW0`cwRkv zYRsuv7+$_~hDti?{`>Wxx|NFr=3Rc-B5>%%qeVyF$z*FD{gUj+5tu3AW`FF4WTaO@ z{O2P(*N3Jbo|id`gN2D9;A+{PGj{dUg18iqJdfQI{$I6)r{#0@Rsr_evt}ho9Fx2`*CRCa#jd_ptF#Kv@s|bU z2{_paJ54Ej_({ItT=K2>UEgkHN6YTFOgzM*xs2tT&+b{XW-WMKfP0D z`SE-A`+d@vHGHd&=ljjE5PW>BcXE=KgJEt)Mh1tOsj1`TEqwkPUu$iPICbh2!-M$@ zvvR8K=JU^5rl_s0{p=f`oDGN5346wp9VLIaUXR->kzD_Djy>0c#W#6>TRbl|%e}S5 zc-r^6M@Kqst?Gim&3x4VKdI;Kjs5lid7Ih!+fF}qGLU#vxWqS5Bx4q6TxQDj>Fta; zi9Mz_zm>hcReJct!^6te&%a)Y3kwT7a_{;4dO5p|M+=w#b`TL2{i)_Z?~hAV)U8CP z6SXZ9E@oJM;9-TXTyWx25r!~L*pMsFhrRI5eGC)ms501jg0+04HN-!q02s{cpcH{5N znKRir6?c3-XT4h{V#mWaX@kN?E*5jod8l0cm;U{(l$6x1x0gN7Pf55_|Nrlv1q%`; z3p_ezTm9{imAX2+q@?7;n=E(N-soENVDou9=j7zYCncgSb8l_QXL#_iUH+N(G@Y9) z4~|`rum5}9($ez8nKLeaetfG|t=g5UZ*DH$B9L=$kEE%osakT*(?zb``(D1!^^Ab^wU>C#m<2uD(dRZL0yw33Dx}ldVN`Hr2e$& z)3@L9_&w2GE)%3{*0Y0;9wmi@hbwDpa_-!@Gj`MTsZ(1Wo1>1!mcP5xslWfvr7b$I zkFHv^Dlh+zZcB$x@uu_hw|*A!y{G0gqhZUIEhionh9p@O-dp>2p~dr9P~Y*Ww=&%3{~SY1m?>p{`Z2~(zA$-Hv*o7>5gx~CiL{(cFr`T2CZ@4&EQ(FvYV1)Lwfy=YH9b4-enw@BeGoCu_|%{d8+1Gy9_W{dIwr%D3YR3k|pB-o7Tn z!!~{PvY!`>&)ZyH>{-8UMjMZ$(8@QWqM{3?l-;;8+oDiO#Fg>+p3{vox19^meSEk3 zeVOLkoM%VXRhMO+Td{6k+}_I1&$9J)y-@0rvz0n|@?^p8y9PXur#Lk3J;-^%DEoIa zznz1D#1-AsS{nNL^+^v8wJy(HZ}a7Xvnr^e+@tK?x2Epj&*$rRzS(rzAn_23in@C8 ziwg?_Z$|Gf(|z^&b?LDP$I#HL!sl&1`}CKaY@8jrYL$|)vGCTdTPLnacE9Luz5edq zxzmEUj_tB5jOx<#yJ+%ucY#Gs{~`_UZ*OmxU%t55ojs=DAnS>9=h_ZGv{<^R0JB$#p3>Z&YH0s($CME-6vydlyGN9;fwqG z?dSMC*NnUP{=2dO$Ai`D_Z^yNTkUh%gx}!Uyw$5#MM-lj&J~%_xN4PzWziB_O|wU$ z{>Pu4on3gh^!nF~KWnV3*LfQrRV-`Ce0OK(z5DVFTh-~Vgb4RJ=#{|P|b+@);w(m~*&R_qdx%}RqO8zgeuje2B`1ttx`p3QI zc_kJy%9}QAnlSHP)#6pJUS(amdexC*qbtWp#pgAD7rA!x9sd<~Pv`QrCs!Is$jEWEu2XMO*_wGvCN#9v_W7Ph!)qqB zzrN&Ewu{GA94y#<_r3jx1I*T;p|Ns&?d|f`Wp94H-}n2SNOjkuHP7dm7o3~Dh`0Xx ztLX{V@@%u53uix^l2RVB-+PPEny9U>rd+%v9$#blsXQns$YlDz&9-Hqj!Ea2{5V`- zQM2*z!ynd5zr-*s=gF8`ey{SasAr>C`~?Jrc>c=Gj)ey}!LZUzXvE!QU0ek#^@Q`}>Z+ zJf~B2^Gvt!yPePHZO(dsR6KsqhgGZBy}GooW=c>@;ZacyP0gJG4C{8i(z>ei^$ zR|MtymxumZ_eH+^-5tr5Ps(ms&pL4Qrc0mk-wwr=hT?lm>($Hua4LTI{Woy=*WZ6* z`zGCtJ0Eu{|GdYGoU}vN)<#!vaa(P@*>6dD*ZeNom8tbVPscwfu$VA?di%%6$LH@k zp*O9gV!!&TRZT%$`|tNB7;qeuxRYltksPrx$u*=YWA_%NTWa^Nt&Luq{)+cT^|Q*o zaSSiQT3_(qc(})Pv`xFq^{sMb_d1dYZw_OE@ieCd$X`% z(j+04X2*ha3p1rGo@;1mytuU0?%$8(oLgHoFO_GXmzHd6JUiR``e8GgbXQN*A(#^L_riPl; z&9twtTf(_1`8eN;U3{UT6KBnmx@@cTXk})){&Ni-9hcl(U5Vrst5$XWF<OB~Ws~sy_Oc~QSU@u$3@+!^zP-L)UQ1j1@jYcvLsfG8D|?G|KLmURWFw=@8EE7>ROR(D9FVjSHDwrOZI->FGen!S_~C0mrhrj z`maQ3mSM8nlmE}p&5e!>4=?}z=H}-A|L#@4kG0FZq;hFq`zG6-OK%=vbtf{=$Eul~DS> z>8UM&U*A3#IK!g2L@>nH|B6vTTGi^f`8Hej-d_{7mFvLw*K=>(F5R*_B_(CY=g*%v zr=6YkwH`D-kiCBAGbxtlgB=Uz_^D5tH0i^?-|rtkIM^KR&#{oLVQ3!( z8xjx8C>}BLdg=T4cz^!Wsdj%pIM;l=8vfcm@6L_~E$&v491HhWf1fvLU;Y1o7ni+{ zO?vduO`}ib$E!Z35bqA*(|^B;>i%RsaJbjN)P3P9O=IDuJaZy5@>catQCzY)eUY#9 z>*kZMUcYXZl$4yxASU26NyK$$+L;-KEDUAu?r8GKSbX?*tXEn*=k~U>MORma9=!kW z+xA?2!8_Y>qeEUYvRv#AJm~ZwQGSKC=)PG-KeA2%+w{=Vwm&KJwb z(3V(}^}R4`ZItMngwpKK+j4JP`P{$V%EF-acugQ@=+a^_mcp;Bfm?Q*-;$u_vV-r? zhvvd-91LCya;8nSNzo5A=-0Y6VMo27!R748l#N1vzNH@Xw->%OPx0N?s)@5_b5B3b zdf6n|uJ}(&`>Mz-85eWE-zoO5XQ=piRJ{N9-+#Z}-rn90O3OD{Za=uUxB9m4{n@k2 z)*e~HQN!{;E%ApUPyHd$2QL4j7ipfoC(0CYP)POt{pkW#KDsF0MDxH=ca{>E!C_s(bcg!17rfKmYy6`vb2v!{S*8JNcV8p_}q4@amJ6*ja?&|+uKb=$k`c{p-(uZSLr(BxJ8Payh zD#6|4s{lI8SfV5pWXVYBi|;SF>``x{75RlaH@kHszepmNUiY zxXa((GF`oWisPgQNm9mXXJWe+i7+`76&0m;ubek0w|Lox8Bndz=Mmz`nd%9Rtpe*f5|%h!IG(KYbF=bs7B_lr+)?9x2Auw_DxlgFL# zL)&irw4M0BMZbAX*Iox7b*sai@e}Utn?6Uy@rcSqk0moygf!JUUAjD#CVCipss#B6 zb&5=OQ94RkZqjCl-M4QasnUNPA@p`1-`<5hlj0QAE}IDNQ~K6sVXsSoCezq_?H zd)k_=y^CjFU-8{k~m+^xicM7HP%#~-tHWBI8La6 zp<#~ZOHS#qbyb@S!}2woRSq7VVypUAuT`s+;ek&fQ>L!5QpEfpw^v7JUWodavFHMG zmA9ScY)*#GxVBg3v*V^+H9R=Gl50vO!vnAKgHjTGug|z0xyW81Tda6TqHXT~xBxcI zWi9WG1D^;xJ=!O;g_AutW$> zbx4U2lzi~Xonv~NXW;ke<7&f)4+HAy@M=EDV`F&mcg>G_?iLXSo+ieY1%e_kJEPeiP7U2? zUZHlaNK9w#MIr6SWpy(d*yHD)NL6TgGc|Ohct_`J-6XExhXVR{3LTy+SFHFZ+cI+Q zYo?eFhg`In4Lw&IMI5Sf3p;wGJ>{=b?1dDjS3Y}=*<5F>*z9nYy;mjO>sOZ7%QG$7 z%+Fgx^Ucmp3f(APp{7`&oG3S;(sF@Yv?CWouDdpBD={w%cgzv7G! zM(5JJ6u&B+pYrqbmhGI1=BinYEdsBz?Q?!X6Qg08s9F)Dj@obONfv^^huzOgw+L`* zYACuSK6XEA{UmwH5oRt1mi<@FceGpVVfe(U_>xmWX}v&F++DN#LO(fF3ooZ<{dRP8 zWQX*I(~ecJFi1 oD$o$=s%Wh^-R~mA`(OTI&sB#FCU-tCFfcH9y85}Sb4q9e04JpeivR!s literal 0 HcmV?d00001