From 40bc12f0d44fbfbabadc0c2e6aabed11ca4ba320 Mon Sep 17 00:00:00 2001 From: Gevorg Antonyan Date: Tue, 1 Jul 2025 14:50:30 +0400 Subject: [PATCH 1/3] Issue with 3d model animation ( model is disappearing from map or after some time of animation there is tile loading issue ) --- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 5 + app/src/main/assets/blue_car.glb | Bin 0 -> 50532 bytes .../java/ru/dgis/sdk/demo/MainActivity.kt | 4 + .../demo/ModelWithAnimationInMapActivity.kt | 147 ++++++++++++++++++ .../layout/activity_model_with_animation.xml | 38 +++++ 6 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 app/src/main/assets/blue_car.glb create mode 100644 app/src/main/java/ru/dgis/sdk/demo/ModelWithAnimationInMapActivity.kt create mode 100644 app/src/main/res/layout/activity_model_with_animation.xml diff --git a/app/build.gradle b/app/build.gradle index 8ba072e..8bcff26 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,7 +17,7 @@ android { compileSdk 34 defaultConfig { - applicationId "ru.dgis.sdk.demo" + applicationId "am.ggtaxi.main" minSdkVersion 21 targetSdkVersion 34 versionCode 1 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 36b03ed..3e66640 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -47,6 +47,11 @@ + )~0|J}_ z+2q36T%En0{p|yN{MqE#wC?!(c>4sfx`HjNDxS{XPR{uN5kInQU;L-C<6%hWkUbX6d<=1g~Ir|dAS9; z1^=^Z9~kKG<`5JJ4a3>=^$c$s-PF^)Oj%dYKu1}dO-@vR%}Cu$RZq`A%~pg>P7Dl{ zbv4y>jo9SG0f7HV2zmHl$Oq*T`ER6v053N$XQNPGsAMjU zgnhkT0h#|)g{Zi+G%HjZkP~}H04Ko5|8Fd)eto>1y#xR5mJ}6}5@2)m3GxQ*BPlH= z34sPmT8fJah>Hn{i%E-$$%;!!h=__yNehUJ3Q0+dNs5X}%1TK|%Sy?}0RLWYpnog{ z!3II7%tS=Rq@eaemPtetDaNa z|6%*$KXZVMe_d_=nmR;-$;f{V|FwKH^sguM5%<4Co@Yg%(=JDgfXx49B=Xn3&*(iH(U(fQ12C2!{X%0~<_YViF%mdY@uXP?}RN5L1xi61EUh5M<(K zV)x)I!IW_`@t0tQFkYArP7)3U0W&@`J})c@X9TQfV$)+UV2NUGVD{iB=H0-TTsXpbl+iXJ-&2Z>N7#3f9^ z(YZ{m5TsrWuy9@)_<g+#y*a1_cJ<_y$!hJgY2mc(nog*D(t01=&m6A07>CL9}% z5XFQbAQ3@CCxi%W1mYU4H7x=OM?!@Cizs?9j|-$DgDQXw5QIR$u~8^o!e~N(0qF-^ z(856yIt1VgC<%Q*{;}a80{m|RP#hRU6ap%RLP#7q7{lR7q$4ECmzCoTxEIB2!0o|d z2C9NEC=?8iL?B@R4}1iWhd@F?jbJ-tHIPM+(E~yuO~_DydrnY1(1J4-pb~`wV32TZ zUKlezoX8o7jsP{{2cmKUb|7RRG7@9~ReuDiQ>d;%K!{I3EY)9nL1sOmKA>qG0#L`m zDH1`30Fa?FL4ve_CLkLq9;_PN;D9C=0s)mLB;W~f3^pOE@wV}l2|p2_fNWp~Py@&X zDanFBkfBi6a3}&`2?=3={6H=#0F{6{z+W`Pvh$@Dg;+$u2UHHA`T(8KMg)=!fxw0% z0Ywl*1jGuNA0#eB9g-Hb7mP2f-90}Y_c z!G?MUDnnol11Mo239tZ_8-(Ig5a0_uAyB;F&;!vR;t-607f?|MG9A$Omz+VAlfkLr zNI1wMh$xy6h{6J$3lNJS7iB_oe0p#|g2zi85D0dN3M3fAiJ;Pix&gui9bjaaLclN2 zQ(y&(1RPf&ad1Jxa`%w(QuvW8lYz}-2t!B<1QC#r2>1XKAdkxnf`o!N0{sni07S7s z#|wx8r-kAH_$9<8#K8I=jBq$DZ~%uz;3naiLs*eWP(4Hd0X9H@4UPjMI2qKlED&xG z1|bO!bm)hB1GEJ#FoIR%W#R)H@P$x>t8i~u4MY#>4+SpW(E4+;vE4>lwxkN^&f9|Qph7YGKb1HliO zV8f}P8yu<{AT10974oHjum%DW0Y(8xP{)7-;01*ezC5L%0McLvG#2P~@Os&R(uT7v zU}b`Q5P$iDnin7jd7%JA1b7ibeL8|o1(JYD7#MaUYr#E$_@EsX!H4jrB%s9rbpVkqoExM?1=IsI2nTveg40SE zfs{vpT3^7Tg%smP0o>3b4Eh9u1rh`!KqeW$!1xytkRp?0ffxq8=RmUqd{FrToTJ7%(XfLR>Z|m;?OM z!Yx5@!NsBYaBc*`5Uz)W9xqu6fo2h!P>WwC3-o3In*k6azyoyJf(iq1E^oq6#^6LC zgWkxTSc92vowf@GP(m4mSkPm!$-92JI+~MEbyy9-s)3 zRPY+8c0dWZf)zNN9fcf&!}-BZ&?*p70O`XPaNa?c1I-e_<&i)FZs3my&_D(E0hVN7 z(H0I47N|EZ5x`OtWTOclz#}$X8mS6k0Fr6p;vg#)=-fcFg9##d3|NMHAmBhTNCY2Kto@&X0f( zf${|^Kr8~+&>Ior0GQhXzlfMi)WD%Dl)f}{gGvekSObzFLVzrwI(&c>AR*{O94-yD zn>08I!B%d7P8e8URRpI#%I$`jQ;D`7DKB)i)2?$gGA`*iF^4~a+sX21@dL@Xc{@B@019l%kAJA&Rrlp?Yq zgnEzAAzN%X zdI*^NfF=ZqL8l55oC<(-1S%h*%@$}22tb0}aQHqv0nh*r&^j;)$c1ocfr?^*K!G{} z;J|AK_|$`chC2e)Kn=j*U5F!K@e+W9HX)%#2B#bXtq4@`fQLg8gI@~}Ft{EHyf5Ke z5QAt5dap@mS8`yAOktm!jIr+YyiU&pydbI11NBS=rbH{iqHd| zhCoWluZ**1|ncSUs zXInIEaC+2icSbn({FDc?}R$?QU{{TBJr&#l1@y!>xDR1T9 zhFwkWX6}t{tyRf+k{$_P>eZ2tyJPn(>L(UFE;w1f>@}nOO+VA)N~sS+n0M0di(vaS zN3K25(v^1>Jd;<;YSyTI!ic!|Vqi|kSZwt8yy>ffka|SVjmAEjp1Zv1SM+VdN+sSa z_f^=i7)-Qu{zsIGbain4;JE+F zfsxqo+U=siMtzYO zBjrWT7X`vRddb&su3pV!xBErJ)JFPVZGZeV>PnMLImHm(`(5t*Q$~?f=}9iH|$s z=Td{;sER7#N~lfbc!IArC>WD?ZJ#;Fkmzfar(y1`wb-H1enB$1CkFMO=Se*S`KPO& zU~Wf8k!a}R5X!y(GZdEaK(!-p_*tUf)TZ1vR?b?vdPkgLGIjLArVt~;=4#c7%^Ay& z*Du3zt))Ix>MD&1EcD;`5lWg;>1UcKpFX^v>-w!FU}Nnk7ycm0YJiEmORdh_&x5eZ zxu_Ps3mdB7DD8>rm{6vKLMaTYELWWXuiK=GZc+1+44-rfcst5&d#&fB#jn-ca|K)YGl=^gE%b)w>oiHOvYrDA|1&@}9jiVsFe3 zHSW00SkO*0Z4GnOCHFv#X2}UVYmK7A z342%7iv;bV0shLMDp5K8uv(cZJeHTSvy4oWH|ahtQTX0y+~Z_Pc@-K7n+aQL6@SHe zan54)ybZ^z9)F%&?@N!(k*9jaa=mO{F1RaLj6qFY(=9}#^z1vVM~+X>TfwCbZnb=~ zTIILo3x10OGH=@S!^r6b456yKvp1s~CfebV$(Ub$yfXC4RoI`-`6Bln$JFR4t)Bc+Lwde4*bTW>iNZ@@A%3!7KzH({dgoq&@3 z+p6xAn&v-wTcil3QBJ@#M4XkKs?p74E)lq)UXcs*bw zHi12^O+BlZ{ZrKM*~_#~L3V?%j(`u@bw9oyo^EYfcBxyn%{JvRv%j3H*zoP#e|_+E zM%BjQ#Z$_o!XXRF*ZAEZXKRHtU1F7jHC2!IhxtP-Ri|CIOj33Yc39bss!0b8SFuIkk<8*& zl*hdDzdkz5cQBgKX&fWodu0%N%p^9 zp}*yhOsMA^zOk#|)U)r%IB(y3##6u`*b_5>htZRIis{etGnAhq*_-0gH3fFn;a_*} z`iIG<(5@*`evK})$ykZjmo~EFJVMk|*us|493)><6+T@p5_cA7Y7EIb_2jlmBZ}{% zq^f(Y&KDTGD`R2YC_3UrxHpT}dm$Rv9h>r0e9+^Yz@AsrS9`BiIp>z}uHXP&QoR?| zV?0yR~ z3xsM@Seb1^l(0?OpEwoehN24_GJOiB1zx@gmSPK=b$6V&{faVY+l?{XCFwz;X3%J> zLqV&<{i^qZ`&W2=x#ymtr(o6Gd{3_lFxr$JIeyR3GVPYFGL;@?q|ryVa+?;vJvJR1 zyJIo^xi!i#n^|DFRd0-#C$Eg$07ogs_j1W@}DNl6-V{ z-f_Vi3XZJ9o4R%C7xTuwd`2mrr9O1WcS;j>$SWnPCa(D79C%mp{Q}u_ zEUTr5jcRH}n+YNNW7o9P^&Y%%6Pr_*?y#bHVD&>&i|zLzK6^dQ-j=^+)>08UzU`KY znO;vb;kOE+4<3Y{?kW-){~;vu9$!gK>(@f_^Z8GkSUbOyv+!j}QpLK%8+l!$yJ2Or zM;=MZaA)C`_QfV?#xBP7CG0q#yX1&p1&o^Bu)Ib;4_t-<=9y;v0sdzZZw1*Yuv58P z=U)>zW7hk!%T?t0R6og8VXOpy<5Mw7LLU}~5l3-$gs-ZbPTL=hG^ zBSkJs3aeUNvJ?Hx;!%Xf!DK^FV=J*#7XAeBVf!bSSNEc)Mt8r^FAR{s@zWjrsBri5 zGppilan3i_?{&nmP#s{VR@PUY`gL;$u`W-H_)wJbsOwl!1wY3hBnadpCXI<_xr3HD z56gf3O|WD)r^o3!)(0H3)^AMoTG{yG$74j%PHmhdqhXJSXHJNjV$NI%Y1++fCx}^R z;$xY9$()+EMoT8`I!f4d%zKrYE9M|2B2+ldu zW^0xEP59hxwUf_S!}}`F4u0!r%fU~cxqV2<<_XD{ zC;m5Bno7STzL=rOsy}54UB_CQn5k2ACP)xR(=*b4czhf4YJCyoF{5q+yZv_e^(nq1 zy*a8z0b}FaljX#rT@{0J8|CI6H~QBVDCbJ-EO{TGADr4JQ0Lg8cHL<_`m(|{?J)h@ zxLzV!^@r>S!<+`M*`?WeWX>e#i25qUd%P-WicWLP768z1he2^I~q>j`v zs!*ZecNA`VAy+R?qfq8*?de%FXZ zU@TMb;I80h7XNXmvj)ChTIH7Fpcq#OYGy_l8^P>s9#4?0s5<#BFU0W1=&qeD7qiCTKB)?8=PF!M;DX4`E(l zz9DxzmGmP@@Hx{iQH8tW*K(@VTO?tk78>JcL3S>1Edlu-YVu)A{Lhv<41Lp@h8`P; zHW7ci`hhCy=HqzDRg3(o3VmeFwRw}V2bGdiQ?fRcUB`n85$a0VCgZ~NOgOl?>jKWi z-n`q})E+oDP6hQfUJaMwUe#et;J3WzZmw0R)L>>Sv0|Q^_~Vvaq&}HWL%Z=e)CZ)& zg?s+gGSz*_&U?4ZE*#)b-{m&d@?wvVWx&?d?Z%dku&-5Ne?P9gW#3ns(>~WEAx__U z@H=koS-RtzA%9VHcf2BsC?3Nl@^EWrxAv}YG2k0-x$S}#AN&Hd6O*7KTGL;mektU5T`Sq zC@fepUc-4UW93+0^F0eIMSZdcyHa#e>{h4U`&d!m*9R?veB4=qz}ZWYMb|qO!cFKh#+Zg?;HXVaXm=G&L7Inh8~nKVg0o zx0IpFV9R)HY^>?B-Ak3Utp9e`P*-N{lxHM7_VW#%styUm>X-*^u_4Ahy6c@w!QYXN zh3NkL%Ip;eJgm@`c~J`Rul%DdwjH7|evdyC7LTqx=`L>S&x)@P>vz(qh@-EXceOgB z|9a=y3(MTEJ-vNlk0iB6mdmPig#Qo}UK z8pRf32NFIa36UUG$+~Z|9LnM%_xRL)ITdJ~CR>Tme7}Ozb(hj{!Xhq2eMo4i-1G6X zhdrxQNha@*5=|C)(@V||r@jOkml^Gw7MXG8JWbBdHtw?K);luBb=9^rzSwES`PM@; zwQd$gVY;lQY{S-h+!G~LLV@c}=zWdLlcU^V;^8tOc?^*OXDZtkS-EwfX-I1=-x@ws2!mg3| zM_9A_amLs(?|gVz&Dq}YF04YbUOT0yyQoTi>=8kcZU9qO)$f~EyqM3o4h!RKEU^Tw zxFRe&w(+gPRnH$)kfT-(t`)!@-Fj4V5I7+JknGKH)N}L|>4ouwob8t9^|BG^mk*vrHNrf?xL!7Lv$W|D#SM2 zGLan!*_C?Wjl0Hpl?^?dEWXq?bolgU@+QTpJJszi*l+dualP?3<96lx)`1E?6K6Ko z*B|cV3r$@WX}Nw!n9G0vs{i{+>SyfwL~+vM(w9EM~xUBQ~D8UIGodZ zttY2zuKtT<%l(J7_dD>Jq<`N0U}R67w(3Ql%=hiB!jgOW2PA`D>fYKd=dYEf*=ENmRY}#KB^9TCAL8 zV^Y2Dl=+$p&*+rW;P8UHr%IRW3nlq0G_+>QGDItDn(9tCQL0;06;AePMuNTTI_`3w z2X30CGZEySSrI>FhO4Bw3T+ZrNMx6rZg9q*Z>M7mQ+*@O;c*td z%iSy!mxHX_Cf|xF(m8RBTFm00IRhy=$yG^T*49?8b-|Ex7vC`p_3CT8>Etu}Q|H#k z<>>CKROcdfdOzS-|&lqj_)tI3DTs=e_ zch+<1_FqLLei0Gq@{$N+Q%A?h@}bciWHr58(PimHp9~+03KL@AsvLQS-#_GGoQ|r`O+D|A3qPjc^E8YqoDGnAF{^D+FyGHXg7B_l`l{I@ zSkAdx?b$lSPex`;4c8T}e)Dc!Mn7)Bw7j}|wKutcd&lLM;aTVFmBJu6e@Q`-u=?nS z)iO!t`fJ-=XK^W`ZO3;deq?kYN{zVslRj=vxJ&zMgJ#S$L1*@{vs^0@+ z8kqL9ZTsapE^<@3Y)E^dRyzA>HTzl+Vw z!HAD(4u!mkh7qi;%#ik-WZmH_eD8l@n&MCd_bh;4{O3nw19roAzXe+SN!}VHOe4lc zOy3AI{2T$En;nYRbur^+mf&{?Ep(fW(w$=CvFk2)*O z@lFw`xb}h9&hP08H~neyi++f;xF!hrAh*1T%ZkIfF_^uuPEW7X7-!3|D&Ht9iZ(FX zG3lr-x)C}2ky$wZJ~yBF>`Im^5+*$<)}rbuQx)k&OT}P(#6|r%#sKtqOS9`%BK?r&XqOc{ePv zcqUICY{x~9zHB(oFOk*7FMef3RQk|!y)k3t$L{xU^cfGj!d4ynFux|9l}vS!kB~4t zMQ^(b;B@z#*e~-*xa^I^T-@(VYsl#w&5>?B+;Ca9U+fqeqMgt1!ymmJzd1yHu3-4M z_~f2j)C<$i3d$N|F4V2LX%EAmSte~<-eiqd9Y6fElxK-1qv#!R!mVcAc3P2li33{x z1sI>3?F$H`7z)4WZ{$6Fl0r7)P&i%2kRm!YIGsx>TWc~D#+&|;ssFV*yy+o@jnZnp*vuQD|QWEZ;BQQL4=}a}?4VnRbG4 z6f~-978(SIeUI9X$2TO3HOV?6*)Z?J`*E079J)dJm znL#Wk{mFOHop0V7rkstYF_4IG zEW#x;{;a94kyGzVlj^+iNh_|d@3M{E)SMUl^^`j889_^|)M6juSCHSI zTAFM8orrzo3EiUlxR4>{{TH4#^RJ32v>Y&+?qd=up?{~;I0|j@1qe+%G;h1%^|6If zCZOK+*l@5_4`qtLt+CJZ4em2$lbiFu61#Wzy;WIS9PO`s%za!;)jyV)4Mm^Z``pck zxy~rN{c?uK+yqAOP!_`{^{peAKLco&BRE-_jxW~o?w)Ju=BI4L*V0Lio*gMv3b3D5 z^}B7cjS@PxG+^9_NVZ?St3!keCX^c>I&beK6q+zkP&p^;Ch%+M3|ib{5AVD3MAdIH zwf|P_3Wh#b0UclC71p&5t|eJ+s_ON7(|5LT&is^CS%>y@)Oz+mi=g+NU5oa|15tmz zAIp2AZz9aEj(4wp;Qwj8Y!|6ofzBBzfJqSFup)bAw2)8LjHmngzAu@NfXdW9E*W(# z7F9-pFlQiN+ExG`j|YukzB@B)anoa+K5pqV#i!bC%qZ^*ia#C#PAw+BcU4Cn)sM>B zd)cnwA9Y-m`%xk7;$DJluW4~ z|K2z|MknmLym~FZyad+E0K!dcLV`Rr+1Hfpny{WM(}Xqdl7X!z!Ot0GfrFhVxnIup zX9j;-iG|Sw@inYD^;#nachWsRa}*9#Pv)%-OyJzQ6Y@4&nqI60TWE*CsCKf!=josa@C2ln`mha$6vgGNfz+t z2NQY7bor>qnRD~> z#Q9UCmPz>p9+u_TrSUFa+~dxd@U|b`eMG9BGf?O3zg(ZN`=y#xfo2!~&X8a9+|{5f z65Z4orQPm}$zi_>e$aGm44W=xrq-SRt~UN!>e5{J+VPEszk9{ZelF(TN$$M;=NHYC z!V=ju!=DD5HMR(ZEcR>0o*%r*CRmb_56i|$+pFg|dh%se^MLh8`PGjK&Z3QC-oWQ| zF$KoVf^|mI5d?t*!Yyi??oTrKN}o^s4i-?AK(;i0zemO1%c!HRO)Bip!R|9YF0}EQ zOw|kZc;L=qNxmNH+6qk`i*=cNMAy%w?ZG<2w$kv^%&ynCMHA|Uaer`OAEjL;?(9Dc z2|H^48GARSE&wf9B4hYo)sJgL_^bUlha=`j-#Ud@-?#eMep)ZLjMBex?!JE?Yt`6H z(zyc@R4vtzN;o-TYnYv5X7QHVjokX2aNuYCCBMR&b!3I`;|;oO*TQEADTWEXCs$b9 z>FEl6XH*W1n_j_(uMg1wcn@O==E*?GRSnr;j>jk4wsDozA@FZC{2|40 zj0Cg$W<{9^i|l3ced)2OS#KHYlD^2IBp0lyn~9TZ!JxdB&m}LZMJm)LNc}qf3g@|; zS=Z5n`)?^MogQGq$qP7<>9$jqqmy*WxM$OMyyu$t#(v5W7-D3tA0W=9OVkGyrqum7 z18huReIqi2$9+qjBHou9>3#ys8HC}wNj9G9=gfjni%4E>SCKd zsA{o1rt)>;TY5oS1v;WI{ZTyP+PB&BEVi5*hp$7-tsj(B)1I!n)o!Uok1YK(r(@e& zzt<6H9!Py+7cMu`5IA#WR-+PPdD}*_qHrWeHh43DSx>tBk5>4^NBZIij@Ku}mU7GA zw8v%0d}a;wI3_b2Ve*$4j!FG)QlC=&OO3;=QEj-o;%Y*WD<=$tyzGG=Pj$SYMGrf( zN$g#zZv*)+`o36ngwMq6*qUeBp7FW%UFcA3y!iY{lel1wT=WAUD|JL{l-!nC!dlTS z4%%;bh@RrnWKD57^h(Z*V2|_sdMWkTAkWf$q=c%y_-*q=gcb$K)i>JaFxO<0?L`wp zU;ndcT}zajF>=pR-HFxftN8AU6m0Q(QKEXm`SL!*tp(HVR_uWv|?BdLg-Jva~yBs$je)+uc$zL|! zVid0>)GAV?8i^HbTD+2y5s8go6LY%~uG67jSq^uZ`z*A~x02pPI3K z{ul=y);gUIWp@iQzqy$?zr?)dmfJsRF%of+t0W$`1b2v?hzR2sWlbb9%g4gitm1g1 z?teZX6MWx%HXuRIr*n1cO#vPQ%~S6MgYel+rXdWLxKjN_wYao%V(zcfm6WAoS~ar#R&Y9KDSmG) zSxC4@ff+NuInBcxV8(28rzuIhmmtK4W4W>!iNZfnW^JF;75!$VH^9BV%EMpYeg(Z2 zJNgRaFk@81XIs5QkW(TAJ6Ku3!-A$fT zz4h-q^G)DI@og(O> z{E_;!^)`;6UE-3Snu*oH^rzUVAG+_YIeMZWnc8Hvy2SN2PnqTa;Vp|S7D~&^fg4K7 zFx98Ge95b%`U+34zCO_$M;qgQKxR8;cSx=}{;ru+bA9MgUNE8?nf5mFVAZbZnVX-1 zwMlx4->XA9{Z>KVC*ANk8$}(a$wY}qya$9GGr#T}Fce?0Y(8*W$dx%2{Br!UKJC+E zyF*6f^q6a3d#NLBLX`fTNK8dVf5lwn%QN+=!7Kkk6*Ja+D*b?xIwdAozn@rEbXYL{ zy;9df;owtK*~5#-caLBB&J=wokZTFvzM6lnj#tzWd+z7xM`LxI;pt)GLG^`!iqXWN zdja2q+e#Sg*ooNmxvdVd2H@#So5gkx>4ix1;uHI8RN3 zU!<+NF7AHPGl}$w*?0jvoZH`1CZG4xUcLGChJ<+?hO;Dx(w@RLyY1XJE=hs2ke>-U zcPnr_eyqEEX9!qM;Kt5alejb7lyW6|l$63+S_@}lVwUE~$8}wWzy_wGZVu_Agm`lc z8FJdsjKe$LwuG5v<@HwA4<5Y}bR7}asv*`}%rB(>&5@!Dm#kj>E+jdBVD(9dv*Y>$ z$tPK7D=z{!^!I&OSCjH+ijHVz`pdFbU0&)O*wgUV+Qes4n;CHIGRRotdMMh_H!I&D zd%Q2;Gv)J~(zKpZi>1LY^tHULL3GPTy--I=k7CPfHOlwHjBQaNVlC_P{O$x;qt83F z)nD)pB${0B{FSr#n>;$|ZW+;sm9i=RC)wQ&33`0@YsJMkO2u!il<^-wAXqHp;bx6# zRZcJA+AERiAg~}G>43*KCiKSl{jkv3H}Wy2U@eGRJ|rv{Cw-|Yv8$q)z%7{dM{0n5 z*XNefd@pUJcaFl6B-vA?=dAXg;l2;0CY+{=)*gA_(A^upW66(w|0x@Wti8hy4*mXX z5vz@5tYP$TGD^Aq1aoXSW?FrR8ehwgCyMWy$L{gnnV{yygB6NhUAM~kn8j|JHR_aU zEs;*C(e8YIt?g3U(zaxfd6-K#`!6rd~ZnRb&R6S_czIb@>pVyi?s+|Y@<=f74F)??(7<8hsMzq zVW&FAk2|77Rn@P|vg21OWl+hgGVT1LIfaX^%Y52`r5RRXrLl(N=qS6f#zg+PxQS{l z$E=xE8ra8CahIG#ALozx;m@)>dA8WEn`l`*nG9q0Dkoh0oHfHfko2~(qU-GI{bi=> zrap;6z4uc6gREpTs%v8RCA0gOvx;SWif9DM-5C3yfBQ`05!2dcEng<@%}@Q!=7ilW zN~tv`GQOsH zn}7G!n8s0r-*;ZW=7+Z{2~*sjYrHR`3$}J&WO`{f+4Swnc!sOCdCtUSOvic1jCk)FIN_a4Zn?m{4KH`Dl
-@a$A7_)S zXqro>W6WW67Rxy7 z;dR7wti%}|#CE2e+*h~#>MPRT39{yFKKCYRT)F0(uslndl1WDBWh0qcox)}`{YdlxYTRM)JS2C|x?--LQ7Pv{CrZqLG(-Uw# zp^l-&@i6E#YB>o05HG9D(HiQW@bea_!hju%BF8%#&W>Lk6JPs#l9z8)M#Ix*zciP6 zIJne?AEf4uhxzV!EtzUcVELD`9#Y~98KZ1@1EZq5i8l9dQ!-L<_b5DXtk*t#yUXsl zgH;hj@W=CN%NhQM?*vj!I6RxJhK0+yft0~B=;re7r5qC37NKVwFM_bdWQaz85)EIx z#4+2$#uU)jM~$ipelL_sS|`G`ViF>srJHDKj@{3F7d-mx4d<#2>C=*w1|m!ANB4}` z>JV68m&Y`)WIbimI`{htJ7_VRm9FICib`AA=c*$=nCz97E075$wW@k`E@GAS`yYva zD?hzv9THl(uP#RHV41Ydhy8Ap*waV!5AVN`=UAx_ z`Bk^JL*yoH(p>Pnsqq%kgPcjfmPXmJw@NlE#N_=ebD}n(Lvz-r+l(093%JDex#mw+ zMQyCT`f%NazvFT^JDE>kOZcst`asmVRzQS1Fkb3qEKHlz-Svf;lq&w}9%|&*a~|i= zFaq3w7iUh#6>6C{;j;uk9GsD1@3zBDzQ+dl^yeS<<~437^PN59A;#__-^kP%AkoGj zs(N>Fwkh^Ki-lwJPtEV|Og!bhURQ)Sr7L8jj}BDtoHd%;y^)U)>R0=$t#2h7n_*Y| zR=Aa8YJzG}=Ga?aM{}e_sUg2KZs2?4?p>**+*j|@nOe>653_l%5Zo%oxo6`xvSWWc z2)m-12EJ{@Cf{{+P;}rRYyHr$ZKq6!2P-7{ed$mqn(O<4`pfTkm)k1X@>}Sc|9Erp zBI0S5S|)b4He{=wrniE*@WF=Em0JI%YlrM>_vlAU`4|@uVz_bZ_X*0=8uy8990G3U zoc2;R{BSTYUOO`&yZSx~jZaBaHg(*$b#tt>V>^(wQe?TDpE6hilvgC|Ko<<{V zY_*s#vrh}tNgjQ$BlJrbQ#iMM!uCi&I+BggjqzajF+*XvEhCl!?K_5nh*~KI6*Dh- z>K;Lcmd}G*5++@^CYlu1U(r6WzE6UjZT3F#wP|`C9T~!H`CAeO@8~Q1+V9ktKAMuE zvw2}w5aOW)_xDY=x{%$jub(H2q@m#m8Fz|e3U(fSt?)IusLA3EGu@YG|fCldwAxJpK(w_Cd5(oYprQJ<$l~<&edvsH}cZGiJK8FI~>l zlfgxEcQ~m@RlCV5IpsZrEAP{L;oAOL(X*y>9y>7)xCk}Iu{ly!4!8D+-cuP+oSRCU zvXRR{Th;5OONrmwHy0fIZQYt!CEFoNx;H&LWo3Ku{SEwROzS#@l~OnguF`_LCgb(m zlVG8Jtphi|oC#;5pu?L;qs2hMep`tRk4s+q-BrCm2KXo$neLAjQy3awIR%Fl(dY!z z{sKirqOcalM^8_wNz6@*&^9tc{^OF9GI?71JPNghPv(28-uM@d85N>Bo{(8igo9rL&EL!X)(J( z{ys%U+>XT?A|4AB^}59OJx1T2r-gJ3xZIuzTm3b-QDy5TSe;xyE^qy-X7!m4UbVGD z-(eA6iXR<1IrVAqDe?W?!12PJXQcPU-gxPDdSA8t?&ZS!{OxU0hc|xH#NHRP<=J7S z9E;Ku4EJVtrH^=-jp&4od+4eY-X$@RQh6J_{4yG!A-xjsbyDnNI#=V~GT}+|qgt_+ z$Cu#^N{RXIYW7}qdTFhILvOaKCI3+MhUTEAC~;0`M13}U{c1vNiqoRwz=91P4)YoA zF*SkHd)aB1 z7gb&Vy+S%auYEHIQ#q^RR_?wU#f|+jXJ3s!$=W~1&nHyyQ}8DTI$5oamRLJi*OFGh z&f6uv7Qk-U6AyV@ynw%M#dk>+Euu28W?(a)pDrT z-v=9CKcN+a{kU^{{nn148oG|-(I4){LZs(1-30D+zp#=Ia-4D?99+4H+rr**?5#^-&aDtD#C)UZ|&KWL6o zTbMQv@$SdW=dvc1sHupa;JsZR>Z3SXBiZs8)#)CNC)eWDe%#$@^KxM>c1tDarwyhJ zn=c_pj0pa@%G`6cz_V`Ck}BsGANOzJw8){TqADhs{YPbr8yD32YrCs;@6Md!_2tuQ ziKM(Jh~(VyVvRo!HJaQ<6ijy)&zaJD53XtTw1|h;bgR2O`y+8WG=%FuLS)43%y?yg zet-5N;Lpo^d=8A=)8oC{PB(j&iF6-pwtFroFP^-a8oR@`b$y*mA8VbHYMKA>uh=N@ z^?4Jf4*PewEr)g{*GX<;kkvy%xEwFbzyu z-=td{7F#+|TP2eZMdAmOOA@@_#q2Msb?ra7CY^S^6~S=C_33Ad(je@78Lciquo5vI zd>A$5tUP2)r}5k_^m+a9{0q8`-4nKiYfpBLrb3*~ADPjI)N}A{6aI0RPd~DK_JApO zI0DmA=gAd}vjaP}JMq)?inFC__UW-El9u7Ia?73M?5mOaf@81z8N>C<3x0%ak`%IE zgr#O9U9^O#q@59Ky5Jwy9KOY$M3ZY?0?IQ$~H*Zd+X!pMR0h^{gO~ zI6}e0fVbRt!nC@SZi4|o_s+Kv1h$RphO&xo(v6zw^T&6_?&K&WQAftZkC7RNxd&5* z7W(uVU%Z~(b>Z10PJO;P-1|=(v*(pu>|!i0EANkrBTrI}yfe;@tPgo&c-c4= zTE@`(JDs=YqMZ=K)`V)B^?gchVFzWK3$8U%_(#+t2aWBYr~XL(GI$=7J^Pf44g5!P zow5Xy;x@{@{hFA(s=-nzUxMa{hiWUd8Ta-Wy6!)}-WW-Ut%`$n)xe{mp}XC)bHG|2 zvHX^q>fEk72`%II=)5$-aKFI(sCu016BBxYiY`f?kwowHt=EEom?qu2K4WC|{U{xX zDs(K8Ebz5HQMtSMt+Qr{P$`O|BJ=D9rxs?dt+?cEsD;CBc%r_A0UapYzUT`$R!erX+F%9m?@M^5ZIU)vItyf zLi^{F@KxQ=p-#k{dx}q~wQeet&l$pY_DK2r=Ra)M(tfahQaWtvi^r?SWYvQm4{=`O zQh{NA>5Sk=zP(4H`hv?t*nqkB8oFSZYwu2mB+C>msNr;q*+=mz#L&<0q)s57T_%FCxCQ0fkqGqG+FGqhHBi;0u?0mXv zqtCTCt&bI?32Ql#Ul(zn`*mvrk44oTki?S4DQxM7_3N z7v%9Mm1|Gv88SQk94cTD;q%9^YucqyYlRmJP1hW=o^?wyYkh1Oy5(Y z;OfQzkA%LMj-4G`yg<||%vDqQbYMR1juVwu?D5vS&^fg}udL15HMv*D_nAIw?S!Jf z;suP2eWhZMfHQlw5mIO~)Za!0_Uhwg;K)9Bs~Tb%9NL!4{DbWJo}~u8YF8oMQ$l7* zlf%esrnAXr!|SNIG`*3p#x)NUhjFBtF1AOSVA$>CVroxk|37CzE|L^)Y(FFm|U~0v1{& zG(enX8?B3W`eRbgE|R}rRqs47?Ipa=xx1{bO`*1-ccZ86*1h;OGvVhd#243PxjsI8 zMu78T@xu&E#@(cV_TtlL1MbKk$Z5N`J#FoFd z-N!`iPF?Fol@=x}&dG^ijVkByT!zJ9RBaq6S*` z8E~Icj8NgY>*mXGR6x+ymW^2U=C?<5owwSE!ko;JQBe8hP%?o6I)GCTn$-Dy!~_!}X)^R>$#&y=5`CRx|vCY1td_!Bi2J@x(2^XDo`}Fibq%Jnq8VIgDYxw-0T9k$LotC6&nE zrHeEM9v%Vp>j4xDV1x5U3*=shi4SND=({wED`upxR2U_Y=v*jbBf1z@w#6 zpY%legW-X@F=o4jOrJpA?)9Qtn8)cES4>x2DZ#&Y&r}yM^BAqu?hvws zy93pss2+4Qo7H#*1>h?hB-9Qo*IQL)v*^&-XX~;H0p_T)!m;G@l#gO~uQ{&<*o z_H)-75YdhdZ|*vR!#bZ2B)8@NRB1y}6if+}734+nSS8cOL4%4#u;DxDHM-6Pn=>pI zdHM$miA`ZoSgVwzjGZpgP77{VD^g7bDL^;;6V+NKk)Vd1C~!P?QIT*^1P?_evs3Hr zIppx&RQuP2bdv>gtM^hQdZ50&woi({;r{>8nG9)`1Z`5Wq`X>XZF9ZQr37Yk-ASiC8Wv_9&73`Hsnu7jl{>kJ+^Q6 zTb)ARE1^0VFWP)m)Sc(}ms~>o~lox73hAvGN)asXuPXeo#mY<^b|+a zbKV;ilosKBv6UsV5uTv@Q@Nv@F^LQN__(F@QC#;>yZAz>eD*BNcm%07O)jUG`-J5f zZNT99+Hnb?+yvb_*Cc+6*1X(k_n*rAWX!oR?ejrs>Pgn0CE+QMFjpZq$`-GdL-D&~ z;RMpPAO5&tLDwYHiA~Pu%AT1RE`jP9vRmMihqtYY!>i}-f2G!EfLfWvyPD?Xh8tR! z{T^R)U-f7tJw=2@iPz>dEQt0RUxtYV8-G;D+3NeOSaGE;;<({U7p-e_+1#$NuaL-4 z<6t;FOQWSIE&mp3Idq^z_3)b8-6Zq2Zjvasg++(P0KCUQ!6X4HAB_7NUZ97H754e@ zjr?nw^=8YT#k>x?ol$Ab7R=%xiou9W994{Vu`ruW&|S4l6O*um<@WZG&_GdHx6N5m zFwtkR`*Yr}bQl_#{8+B>nyusnA~@k5079+`%`%tHxBD&Kpu0xwQ3CZlV9@b1kIsCF@?}-p6J-RE(e}C&fm}syIIr5%o-(KAhE#7t?7B7CgZX?j3AII&7bIw1pD@k* z4|f5Rq@K~omIa46nQ(YxU4WMwkOy~9^X$X>Skm9&gLltXh@y2_s|r@CM4vhZS-WKt zt*fOOOy6Z>-XLg=N!|{yES2$7#1`IG&QQ_B;yJV~FC|*X+pKCW-HF6_w~o}Xs9mSx zRk%i&!YmZB?SAIZGMm4Pe=e%tcf6vJc8=V`DpA3HkMy1XFuM!%fjjzpx-h1op4if_ z>EUz9-uKK=U5snsHOfxvAP+^D1NZad7Q(Fq%cz-pAgSOFy;NN#YIV0`mg}Y|#4ESv z8Y?SBMd5j2goM@Gs9OnQ%e~^|XTzwfnMN%o@2EL#@x4%;#uXg_ReXH!#MoLvw}3Gz z;^LrfiO*R6m^b@=JteLYKGZBsy`gmp0IF2U0)FYzv_n15lBr*bA7nz*O6Y38$DMT^ ze$En&8i~7WY-_ zUAisti>U<;nB6!~V(sQ|GG8^feEe$s``LHd)QL-L7LtDO;q`k&{>P^f)fk$uwIaVI zJUcDZA$FegYn8M%h`HZBf*-v%D&zypmJ6B1!e50XMF|qhIeBrBp^_M-JF1d>*d*$3 zTa9`6$MS<=us&sGPUp%0hhWA0hxN)z5YIRcUA>|-CvwVSo4ckz&zGG$RnAb@!)rR{ z4=pSf`^k{HFni4{#(I>#O-Y3Ss^$V}JTE}#m^tr)e~YJem@Crn%p?FyY<{F#9k%_p z4+8pLlw}l`q=7|_;PpCQJTnjdynY&ff}o3cchQ*8$*DXeOjc19cWKb^a)Yv5z&l0J zUE7#?*l1Yhf!uZYRn+B$*^x&n|0&+aj{y1(wA*2B&6Dxp7tK5ohP}U!x{k9)0RrVl&KdH4ZH2l z!LB}7etbr$gI?n#9#dC@gb$a!0dK*;XvL3Cej#qR!j2+5sPV9ZNmy7^^x{seQ)J!L z;&i2$b8p#Yb$Ze&xq0~}Zv9wst%FtAB0_oY`^a44kvdzB=hOlZe};iDL$UUlqRsq} zT1jEF(hunn8B1-p2c!m!>%=y}X0FIHo{r)ggen)gtkQ?GKXSNiA`%Yv{p*sg+qWNk zv+)VhqYa`XyolL}95?^T7scTq?Aa8Ge|+nd_amez(WnBwaHmapTe~1R>aZ}ZDFG|! z7BhNKZdrQ{J1Gex&QNkLUsn-Z)*>JZAyb0LwYNbIujF6rL7KPT>e9Xnr>ti=MxSX{ z=e3l*hwnD87^?udSYS(lDuG@9kN}mdq`qH!6?^={z+k&R=pB)0sjwt}lV-(j&RsB>>z2<|pFJ3*MK?d=-;96_6zOY!$uoxs zYPrczZzaE;livuj0^jC|4I?q_h?O$xF>VTp5UkMA-uSZSwVY=^23}vfAB)E+A&I*p8v-uRdoN8&&+v!Tq_8> zBzngCu3RCHK>sm8LpBUlftbRimrcw4{zn3Bm) z^|wW8z2-1{b{>3XWo9aCO9e}|m5OpEQQ*4=|IVjAIc1a^M%JXayNW`Q zD%ptNu&LOiVzAZIRhxubx=+8=-tjH#cJ_H8MytJ!cjNauDVuG3_;f)h)^DlgN_nUD z@Ij>_QlGC?kDN=5t@D5fVP|cn?%}71*ivW+S!%4Tw3tE-Y=)5G)xY>Juin(`dQoQ{ zG@dIlmzJ-^r><-DgtC^MTi>o1=n$JH`+dbzq(4j8wEYwAQ*S4c<#4*S-}RbwZb4Pl zemW$-f`JXy=!A`0>a(&b)f2D1*MD5E^M0uZiEA2ZEgIiV3}Z;P z9nd*otZy**n%Yv}#KD3Hy@}PgF0^h=J=U^|-4$^fWM!Okwa(~|db*!Z5j^G0ZS@s> z8a{3?Om}ZNd%&V|zDTm?qT*gN+~D^`dKCNTq!^Spkg$*p#+lSMj3{KwrXhnn796wb zpvXCCmyH^ai3LvLK_hqgH(tg>LK`aL=ZU)*Y*mP0!Yt;jI{Z$`Y~K30dFP-n+yjX= z(z;bG??$TJqQt{y5(tP4{fGcP`cJQxQvXHg8XnPJKV!YFZ#AN1!R8Tk=j@a~?YsgG zX!wfHfAA&I`g)-JSv>pa`pl1gEE&OeHXVKjb5KY|$LUE`wPBkvn=eQ_${uK#> zd8Y=}B?FP%U)_D^`24cB=0B+y7h#}V2)TXX4PXEP0Vacm0EF+d`48o{Jtm-8OOKwN zniwAf=4YoThJYX#AP5LVjt;^A;R7*1U!rv`#hK;$3@5CQ~&Kwx|j=*1@n zQo}>=3k3rR#-m38W5AQ)87~eHj1G5EKw$J26!;&H9S9|UfyIA`fq>i)5IYeD(EbIA z9tDIAhXsP*jDa995DbQg@gQVyR`4`182bee&hG^TjtozHAqkJcX_LJ~;R5^z0VjY? z%?81M14F?7!GJNa{|EFX_QD!Y8}C1K(0>4MF<iy`2W{KpE;`#)MQ)`ed$O2Om&aJ^pq z7q!6ugZWUzo{=a2>5rqoG1P6Kf z0l{p{ATBr&JaTjlYXW^HyFkEK1h>-s% zfxu8Oymny#iNPQXpc*+byaEvex!GR|^F>SI7dyd?_hKJ>5I#9RJs3hv%uFs!tQET4 zL}bsKz19`5*N~7A*46cITnrkU;oFEuF*=-rLHpf=z+efJphN;h+hq^Ir#i8*SQ~Qr z)qga~s7_?^evhfe^7)-uyFFzs`49BIU%k9+;t$k7DoDVYZ=>;Lm9v>AyrpO3sBG z3eHqIMDD)QU9=*KpvZEol7Sy_#$A`_)b<|;OTHIXL3L_Zy9dGmiD^^aq>Y&+g(+YkA!2;h)BZCn{}xA*rAE1a{N3n%JL z`UrlMGNz$YYN9NP9k)4Z@0;op>h@WhH2t(K__Kw#%%{D}J)EqdNxIIBZKJ&DYY1;3 z{^KECcs#8S%T2*1F7-bf4UjV>fobn)M|MFn@9Q_Ukqr4Yy-`VV;?1=Y@4Nd3VC<_) zOcP(N1z{RjrP2_8vd*k%GrERsRjI+VEc8(F`%9YsC#*rIgGDI&DaXG6$m1coNuZG0 z5nbTiXC@yDPH9(uJ^$7^7-zP$%r;lu=ZeyAuz55;Q)RWD?B<1V{hN#rX-IEYSxl%H zR`)Vbok|uB73vYcFuJgzvb2Ncq$5cn$kZ`KILlSltjpBzj1i>(U*zh zUnJ^(Wo23CJNY#D&MHZN*e@Ov*liN=YE9w&zriJw6-kTY3o%~hzZ5oQ;on#NJ2WMz z`SyAE%s&iu=pTFbNV#PAMC+8d<8wC3zW#_;9oO-jzq$z}FapI-{y1%G(fV&kwKo-d zUYPTTSv_cEg2vhh!ThAnLed?UnE6jmYL7gfJp5nIwhh$u#WZgx_YpaZOU&)cc)6%V zj=D#zpP|=cm!7r?hps-RN&->Z?3;BHXHwsA{kQa}Hf^74#w%<);g2*Fh;OV7Z$*8f z-l{Cj&R#Pv^##W^4Ma5p^6NcKeakUMF3scq6zfej$A?LZB7vAuj4h~rhj1dd z^r?mmBZ@dQEV|Y0%d11gMYtYBlGx__Zq@i(T*;A(IFN|fjl0-6=M$(aqGv!kiRJZV zqV@*%jId)*~!pLJH>b6qqiHcFudf@ zBf833Q zA)C%>4?hdJ=t%SdQ<(oxjV|;T=>2I{AKEcILSghn;aM)7+L9BpZqbhKu7~+2z)z{?{;P+kgl(Z~Dej~5YkYrl(IE`Y81YrCe9J-VG zcm-W7Go$xAUZ~lrlpg(%8$_K%`6jBh6Z@05mz{(~!*pMQM0ZzNV*<*EC1I}H&^JG5 z{#;kxq034RMe|(FA!#-dMNao*)_JZ>LEPaC!!R|z_-O!&#bBo6$Xhge-4w`E>0!2+ zkhaSY(A$ryz3@J;SBWDhimpqJG}q$9-n=vL{hW*)9yKi3|G)qRLGwXCbW(i+K$g=PQ^5n|M z*HOi@)7~8mBq#9?%m&cXEN|3OFfh6qe%TT45(`Y1Q0HFbjoA4axEgTpWtS4zN8u~{ zHoZG=-Gx$}8Wam7uL6qgBC{1Ixcgf(d42lY`Ik3P;Xux%(@Emr?Y~bP#uk+p(%i;r z+h*1hNbhd&Jt=7S+XcNT)GEg11~c2vOj4*(o@a@6be;kBj+% zce5Pa6oCopH0ogiodgo5K;LuzK=PS~uSqn&&?R2Gp0S$~M{B&cF%KmA&`)NScgMr- zzvK~pgxdeDbzB*@1(c34R*kWCMQajptqg3Gds_KqywOE<$`I^Z)Pa}mdwt8|M>s`s z9_AO;-E&G2a2D@(!dc&%vmB1uOC|Ttl%kyydR8W{8<`&q@vb}vTOmud>2Kf75R6ii z$W8)d2X-fwjH_j-Rw5I{nE#T}uu4SNX}PkGbopxum&@AA*Moy{g)1d(<#>`!{#B;q z_OtPVk|WA@rO5mHTxiZp(7++sgfj%qLZ_b0xJie4eXt-RJiAYuVp){|$kaD>_f(ua4q? z$`zOk>Ux5aM!A6K_b#qe38|krwz;E)ZHZ`tJ;hZbzl`a4k?|5ytw(8Awic@Hod>b= z|1T1)0>i8iXUfv5Ow)H7hW<$8L=zd#)SA5d*vBKvKy^L%%Aq*N1_7y%oO1lnZ6fD9 zf!nxvsaiU0ne_8$B$vKNsi1PPn38w)oTGcxB#!5bMPTP&?VL;$zguq0-@dqc`^Eh2 z<^ON@u3)i~)YO!p5J#@Uy=v)@Mqb|l@{94%b$HsDwreS&t6H-@R2}GiRl?0?C;=ow z6BpxbxT|EiCu{t_8bydDsux$eX1NG>>r-4;6q=0^1RnUP<=zs6qCH(`^-1t?t%mFG zY~_m#uFJpHGUXHrlNX^?JVTw*yH{8n_`J4pv(q0d*HX9X2gnk0GH+Xt4U0F2#Khpa zb!&^mOLj=gy_@A^rYjZh!?$^6k49ZfV0XNpERA2ebaxa<;5%~q8Q;DeaZU~n*6r>Z zvk&QCwklHAhd7L@;d?uB;ZdC5r;Lk#7q`S+dgGBLIqM8mozEs{cmCpW*wlCpm45oG zOA-7Je#XN;_<;{-@Dm*nFo7({8}RcUYJlpP1z3g{>Yy6HnCl|o6hfT5RnckJi(<>C zP1eJbsNcq;8$OBdg(Y7aQGHXbcGGk8`w9EwG`l-rw-VZxpA%}Bj~OO|TuJ9tZ<6HR>nK6b@zt5F{WaM3$s<{yc5?hdkoZ0+%MhN!i3`V+SY{enY57tr7k5~sgNr7`HNaJ3_ z*gfuf2ZDZV+5?5W2AUad9N^KPnymx-Z3Y28$5-r*VR%@8`M!`<30-<#hJOvW^Q9YF z-B1d*i^6gUMP*4u&WI?vtJldlKa4a#*xwd(KaB5olR_>jj-3a&*^*R@NNC7`yFbbi zQTHjW6+gB}a6QQJp7;~%`-$RI@NiZ!G~s&pZNYbLOJQtQ+uv-`U#GGT<$|TNst)p1 z-C?XFCpr7<;7yQ|du3j#Yn(+yU!qnT3L|mCrxP)Z%k`Dd^0?;i>)nv9P zbAtqNXPT7oEUi{4q`0kGUD4;VX_^d4%6u=S^qQEuZo`kfJXu|pk?4IgsQEiq49dL% zYjP>hSk?|$&l{Ezl&@WuitaF;M%S(1e6Cpyah-Uy|08sAzBQria#XJAaOtm6ZjCn} zA)lbM&sBvG__Kb16igngS%=pPM99LjYJFan-Nuy)0t`I z26Fy_%RK(BE<=KW{l8D<&l|VGu9ejE!l$fXWmTk#NT`h z3;nt9T3Ph>{_^thqw7(+Fhp&I1{+s(qi9Nv?Z&~gF|{>~3&#_hWw~thNBIgwyoypI zZU*~HCQN=YujDLGCF%*2$sH}8xNhf~QyeHZaq%|^P?Is*WGq+d5HZg#1>$4m_>soY zGx(FKeE8$Nnnmf=h88flv6NQBgu`ufH}YYpNO-b8ajnF?M-*Cca~yG%^2H1%9vNmb zk2&-2?-_=2-LudYy%L0SmTeER+mTKTNK7ggsr4P;QLzuBWMF2UwZu2 ziokr%S1}}xFZZ$G6?t<2%9(LGekfxi+EkcrAX#fAb{rzH*dx(7KI_4>H|_0cQ(Rkd zlF2<+VL;`{*xZFAVSeKrI+aw&=84j}cA42(S-k%#wLK6)plPA5_Hm(Ypwm;L=1yiF z3ivMBVR9bHJh06f7NkHPi=^G}M)saN3UeKR%C^#_IPcw}wOnY1s5`wI`|Mn)wYD1W zUC^6`Yi@Z*ZFP{?cPz#%iMJWrhi=DNe{?1sRA`CA3F2p~o*5^FN9l1QW| ziH$EozPJw*MkS8=!O;8l+mR^k4{_6%-vyUSl&vDja@7JV)MRO{Eerf>?8T6MVu_{L zB9fW(Q$Gz$P-rT*_PoUyr{`L-3o`?7Q zPH#3oD7-wPZkuQ{UkGh7SDpLM#!$+zC?l&R9vYYI)koOQ54`gxlFYs<|tC&SaIQN*F@ z;&t{Mwp_p>G-;<|SfB6oy|HGd^ajl^uZw#|>6^i<0~TcAwvYzLgm3S3rGBh`VMadB z<*?JudHwu6t?`yu^J}{)a}&E{do#`?X&iOOYV6i~+hWxp+eJAiLSN3#Ad@)2wT2`F zk`o3wqF%q9_FmTPq;$W3)qKQrINgwR#593uPFHbGgIR#vv##I5=l5IPwK6PawKE5C z8mgu$8M0Q<3jZGTZBTty=XWhr`CXd>I#k6;L8^-q+HZDMz>+ z@Dx#$JNd}W(I?zr!krRu9z{D8@3u*FT3eBP7jAAJx?!T@GSJp@9h6ocd{vZ_RjEq= zszT_efmINFjSw%ALmj{`G>p1M>v(tK(AblaXF?fntKn>Ap&=cY4DHLJq{@EKaH9i@0xRkgQ4Zyu7fNH;idb z#tZ|PAoQX2nN9sJXt8E97!%URpfwD{{zdUxhAiw42OLp6VBM^ide-Q5 zxKE~NYUUS4GE2uwk}7K!R|Qp8+v=>7vB)U05Z2znXf=YcXxgVV(%QRuYYrabxnbg% zTU^I4W>b?bw9%HEG4=L5#qp~6wzy{nG%bT$@HYh8_?WLQx)qgfN9oQ57S-SB?3x{d zGaK!i<*DD1{zCN?WBod^iNkV+CJotnmp$MID$^Uf{LivgctQYlAy()OTwJO^nxMNb)f3Hofj80@0 z>*pw@J1>#*X@{zUl;8UCvq$PT&MdacS`4Pq-oQOo35>{}qX~P861brysz|4`9DG5F z5>v8&c6&?ZH~-KLigio9WgTcd&Jt{oEc%$D+OAaGmfBgNRMndOIIHoXiTx8#Je5nl zSxPjdGOuK!l+AJHXcFUCb7n5-MQ?N|rzmw(tG&Q{*s zzbVhIT*k44L$a)$%ZNe$X1Btdi~wL`tg~S`DkIfa+OXm`{nUwzcRl~=)X>9jFhPH% z;)L4L*pUq@jH=V=vQFhIGHuH<=m*I-PQNs`RkG24XTQHrY8l%?Cu$mQ2_71TgnfRJ z$R<2Q{zIEp;X!t${e^XiGF8!%h|bxDV^w8gnE&4Gw>_I7dTSGw91>fTC=>qoGA&|^ z)uY8y`OYWebB0L-+#%cggWj)hjSTq)2ijxYV_O|tlSG5uTaz6avVgT1NEq0X0iA{V zF!~if?-9SE<)oYqn`$6O`;_|Hu#amO=}^9qE@?>L1x|ej;k!3RnEnFXy8wEgfxC$4 z3>fU!l%!cKm!?iQJ}|00R6)9UOoMjo;fZ)ORC44l`k5QCkD1jHk(rPsLp;Op)kQ-r z*Gcw!Dvelbph`xhVo)f!KD7t&FC%-%tno;?+qa_)8|`)UNJKpTmFTxlgvUtF_@P-8;m?Rzvhc> zwf?nZ3X|a0^4^DL9~ZV3MCfL`LUO~$-7#%v`_ot)pXqiv?S-4o9SSjTVw=bFdLlDDuQj#{FGaR@-3)l&V19 zD1XbW5`W8OKZ-V76TFQzWbnVeJxbJ{!I^q?$~$hH@-t!f7zIxN5@C z$`5g>uC0sd+h`R9Xk*$%DJPF;d#EJwl_HP! zAHW&e^|AMxG4H`jp%CW3d-}Bg&j>p+8&`(3S+<6rx^$wRxmD+AXqJ>28#=a_BJvye8HGH=X zh(Cbi+H!o5fo@{`05_!$9Q?q%aOIetg>)FzrL;I^W@U+$P!HX^2WM|!u6;^(j}MD_ zmF9RRFkJ35UhuXoIfJ|-zGKcmrK?7y2ES|EP;CHJi>K5dKz0jUE!$9-X90dY98 zMYskdk`P{`>QQH07$@Ai0G>f4#ePOaw=2PXz#(9)PX_s#j2g)axjF2uE7}%@2|Mg7 zO!$c%7WK97^@FP#V(I|`6{L}TioGF!+zmGicv!j80#ZXj=0Trw1nl+gY{Ay>hoDGT z2tbfCHxe&`^wb87MOe!LKQ5jPn#K(ICG!(O8NfDIsDL5JNDfOr0Z}31NSEV6uk8j; z@IaBvgIbih-VwfqDAZUbeH9QNVho5tBlJ6ikOiL=S`l3g8iY|CWFu!&J}!S`KnVTu zU;}(=8;1haFaR-9vWt&o9wcpGJu*az4_Nw{LC9$&)7YTBdmY$83XdQYLRoC#6Ll@F zqy>sQBx4My@*qdO+>eESgfNhv%x|xQ#Ox=DYL=u3qQ?H^i@ygUEat(btvd=ieX@d9 zjex*Neh2CVSHg0zFKNj5`T$(a$WCHe73p&G@6c~hvP7wR2oV&UJO(>I>)$sPJ!qfn zSKK1JD_0~e<5&cl1<|xUPA*h%)mGno%Wd3UDDJsdFRQ41c>lN#tdb@%E7T7;7%3S= z5loGQ#bSXDu7+Y5i0A2mx!n<*N#zq?0i5s=@W3&X{mn5k5JCg3AYq7^Aq>+s6{+DY z7l}E5hSU;4^u|5QH-my{|15`qPk%;c-k4HGbw}HldtJ^*`zKj*4#9VmTw}D{qSUFl zs%%}L5`Yx~uQmvZ2oP9v9BT6cLQFP+b(7Poelgg0RQ3mO7);HZgb30tPTxX6e1&ANvISnC@NH0H0%-tI+Wp$yHlLK$1Tz~o?Y?)~uRjZEy>L$L^@y_`#*}2&l?lR7 z9Q644E0e1nKlU$+$8L3+WIqn+W__chJ*dE=7TvQ9- zC!xMt)d6L6L|rPdlM!<>B{oknCphyd4-V1y$xRS4Z&AHX+$ZEHz{%_@|Cs@(s4u?; zAr&(f{l-U65Eb@*j75}-S)6qWg=o1}%`E`wJzz8>0z*%c(cvijiBROfsCqmm5RzFr zWV)(8W>CiJl?IG7#IEp%*LQw^fik3D{Zjyu?W>-TN34lHI9t(+)Yg<3Uo1d-K81+M zyA+}1)mtu9-Utq}dUPI0qdUtNRx2iUhOoh;@$x!~DFx)lnRf_b!Q5F4L! zAX2S(hJcZBYKUPG-9^7L-mMD`JzXgW4PEI7^C7FsuNQO)WBu=Em z8rX`9vVJ$9n}5V0(WChi=KA}XB|s!YF0x2ga4mh8LY1cVq6??=#D)ai-v1M;zi}M3 z3T?u_@oN`*6)p$Uq>E)^r5o)A!`fP7wNFIPxJGhyrH6rUBYZTbQhbg{)uyp>hIo3? zC!w@)0xJlS$ap+K7E<*>$ z-3sjrX~C%4SNC8Bt*^lvTHMzI#-!ZE^+P>|<;3GAVvTKO8*?KRa<^e*u^+y);H*Kn zPP~MW-i5j?yuBC*p1nLm#yLs;z;Pi(7=1okfe+~hiK=;wHdN zih&xfI*z3?)F+SljWGyq&=9eJbdUtA_dpoL#R%vdU5D8K)R9Kni(|I{V_?qEvDvBd zOdzg^N?<5o7;iWd&6_XOq``CIxwbgQaWr*>v9%OGWAmzr+5zVd38TOw&b>DHsjs=G zZ(;n>TQi{VpjgylNl{|a_MDTjsWIu;9OfPqA{Cf|EPypfC#i-4WFO*cR0}CTCCwig zZ=BN2r+gj6TCAiGWsQ_63AV?lE=Gu^o(N^kLp!=&k>Q5K7h$o7R-+85^-(`s5$9ZZ z{6vh}#nnRFiu#CO>>Oqvy7)d!Iuf@a^bkSRFZnYd=#yPOT18YmCurNj3jPpb=g`hA z14SEH?&DC(N(|kH8H&!^0gRqN<*uaCQ%Y7kVQw=iuds@gAiUw|JJcD%k>ViyN?GKL z5~?`vi)};r?%(@{3X*cn=0uWm0houNGgC>@_|tS4R96^qlA3UiL`pwceNVN0rEaL4MUl4WOX_rKXrGliN{N+j z)`^wAjCtLrJ=re-!ips7HVY>@XPsZFu2Qm~BZq~=&DH9Ptk=3ziME~#D&q5ujbtp&V^X=E_+v2{P4w+QkVCu6;Z zzu?(=Ha`u=^(rWCUcyjtO#DHVEv<< zeOH0(&&+n_z*c3(!CY0t{1~}VRd|nm+krep-$LwHh?s*YEJG67=#I*c=pLuZSU)cL zA+c{1+dF=F!nMQslrt-z^UpjLU__#XO+*v>VH~qX=4FgRQ$ecFp!^>m#1o|Q7nl25 z+wHtyrNbr0)eUw|^`LW!82t1T_@J2pvUJAVhSL$>(!PAu`giZFT5*>(QSaDMs>umF zK2A{;nJOyNnJJ}ai)pO*_bYYtSG-ietnYxB?;u+D{8-QI>nup!tTC%n%%Y(%XBGEt8GJCLosQ5QzHgi;Uxlc9c-h+a z*NOh2A4~lg7B3@bZkR|YR?QJ5!$uXf87Pxu787$sD(VzrS~6!fXgz*BQv=;OC&M0G zW5L6rD)?9-1BjsLm0Ec+vJ_T5dT$0YX2Pl`g~@T`u@P2ZeAeh;F@()fpYiu}7>BmE8emAkY`_P)|r`OwZKRlM7gW6$tW91>YjbBAx;f zDcH&T5}|#_TutTDmYSl(;KEAyeZ);?SsP}Q%o_U1Yc8l<`DPpqngs&N^uHNb!?wRi zI=18tmO^f%j(UIXo}YX8IT*!+aKsA0MhX+ja5^tb5r^Io;2jrM%Lb}b!{1TaPQ;yp zH0**%nZjE6kar`zlU>RwY|z|E-7V7Hq3A6vd&v8=11y+i2sZdkqjDCkO8u68>ju2@ z)(l#pex`2-u+mfuLOR$N?c{&Sk<~GNDCpm+*g=0h&qAmi^24z;B!mhoA(TyD50!|* z5ErDs!w5`(tHFDU1&_oImYKw^RmF3HwJB}`=19|+;>^PJztNqfUHgHvkzW{{spT0<%tf_4Zt2fEOw1R7(TX>* zDEz&~S-?T*YOKp4O<4d%rlT#SXjF?PIf`~7a~!#s4lgE}wpaA+Pd}q`2^YL`LGXQx zfc|cjko(HEIgwES3Z2k9PtAL#)34r7yt6q&mz3~+C!`zrzClKYheD~j=% zG)j*6_A=?WBE*?$EEZkZH9N3;2|_tc$9k}YOiR+ggA|Mj;_S-^s_GMfX)XkDtP|Xk zFcwRA3y942B7#v^p^!g#h0|P%uvS-03natAn=~z?*Gy^L6c*Wyf=~+t6^U)-{K>A! z+HZpOG-@*6D){NqXAWSj6l$gm{i#rAX*CRo0r^DfoDW){6zM*}PRLaNZ6zQ!)(lLm z8n;EOpkj=F^cMjqsjZ(T&kV)aNgkirLhjn6*HCawE;-zUoMeJzS2}VU-ASPY^rsao zjI^eMv;;T1mz>W6Au2M|3J_z&5^8l=A{ok<+<;F@F^bGL#;<1SYBg$!%17JOxV4)2OJi>?=G z7;^@UNU+)TerfZ}8IRvMQb3bs)pAjUi}yRO*LEnc;$NpGlO!4Y@#7(=BBFWR2%r%E z`fi)Wg*Z#+=TS>*F~*b&x>5f_|HWdR6=Z5Xe6NPO|35#q=@uQC<(~9<@our zij(a_{3W8usT!}i$9W-7pu50lq}a>QA?XAqY7lQnAp6%H(R%mGfLcfhzVjA*A%^kR z7PtxoW#lKBV?{0PLzH1>E~}!==A#C_SB^=R#2R68EIWT+RO+eDL;B#osQZS53vm*G zNv#f)jWAzCsHnk89e~2@^wks~gHN0(z*DakZZUoXfyO`lv}!;nfDdR$=kw|>Byu{O zRb^O2)1-P*+eb2Gz;=H8R_NpNT2}@E&JqCZT@oa5I)8S`5mvQ62D4>>D`+eTXGW{?puQCx?uL_x0DWkS&Xnjz*Y`0}^B`pxc{8E_wytNc)WJmW*HQ!wMVPReOTu#0c&tcRpn&Hfls>CTMj1xG&ia6JX5&gnK~-uZuKI zgK!gvX1_|}M)GpYJTgLQi}BDXJ?Zq%Nazc}d}g#RwO8xe3DMwoaekPb!B)n4^+PxD z;WQ5G0S>K|&Om6?cr1EF>XCobdXTgo$3kBz@uJxR#}^ z1?$&LCGRmp^7qg0dxYli=@?tc_p7Jc^A`qknjU{hw7^Vjj@)>^2XnR*j(HozL`_wC z|5zCCuK8c>y=PccUE3{suSI~+LlKaop-59O2r5ksMT&|L&ZvzBnFPR!uMusOcA!8el_S@GhLn$FdEdq2c?)b}W8 zTI14d%u#dys@(L-g@P(+d9b&`F>B|ssZK6gSt~wPyy#k1CAe|^Z37cvdrCOxpI*1Q z>#8hWo;8*%I=ArD+!;Nu`;o&*Y2L`b-M)n#R%yvkjn1!H8ItE<-+#}`E5Up{J^hlP zwESlkbH(ma+Ht{;$^?u9>#U`9@Y5-Si>KFrx@faItD7MFX4-wZW6;<8!bfhlp*sJ# z-3`qiFi^k4{V$z5%dN)pg4fvj*l*&@l1W}$txLRVnN1CYP0TiGM4FnFGTp{?=e2Af z#qX=Lp=PpzyF`mG%_-6x=yluF_>pKM-*kXSkJ)j8vpe1x_fH(%f70BK$DA*9*Iy z@Ox9N{KL`zal2-O!y=yt^IUdp8a&_|e~G8$V06fUUU%fPBZA$gl|BF5kTpxkDL0@b zC9QTZ&UQ_we;u7VxU2hv1ij#AS!H{Dygz(?UaG~Lwua`?MEHG>b!hrWl^VTJ$eLo9iJ_K9W!J=xxQDrqo?8CtG9|a zK1u95F#E!gsgvhFmdHIuXG~m}7-P|35uH^bH%95l*b>T~hNwp~XaeO!4@ zE1i?uW!~(QYbQpWKbq~?L;v_V>lB+RjT4K6pC=it^4dAGviJRGMrp3oPxsu}IPvh( z^gl=58cekcvDS3)>hUb2`!}rzR&wkB47F9+41{+M@~KQ>)O|PuwLJjb581=mUtb?_KaDZebQ?58KWra7|df z?!bzU7uk`+>Vp$*FHwGSQh(H}&4?&(>AF6NtE>X2Zx{E~|Mw^TK6LBA9$}2x56qLC zQ?5)GW(J$eDb!sPK4ybsy;fH}tsxzMD}U8Z9=f>o@1NniQA5&4cwgV48u3=yxl7d6 zKQm1=ghuYDQ?BnVn?3me?J%u;s@_)rztt~%8s!FB zyZW_loDzI*LD|txzJ|V?o!9x%@vD{vZ6@cJaC%p7I9Fu#{j#3*q>d-I4+;2jqG$gZ zb$?&1?!Q~`$#8ytO14D$RemRQ%9>*C;&IbDySO*HeNPA*Ra{X0q1S|_7N?z$Vniw1 z0C>XkYg`>P4Btx=eP$?E-eY=52T>kCKnLV9n4F51`#(kX=#@F3927Yk%H1bioepz1s zqhpsnY5u)UH=SUsTMm?~vJi@#nEk6RMpDi)sPMX zU%N#)v}D}YUbAlOooV>=iNS@2rFTZ^f4^qwK2O#7+tIB#a)VaczHMXpjprLv?|U(a zi;4`qVy$22b=?-cKC9qkjpOOQM-HVW4IIFFUHf@@ZOoyKn>)HzzO%bjJ9u^HE(!N6 zCxjo$=xnsT*!DwQ`Y*jza|hn`*HtPu6*olWr@YgV3pY2t(|vJr=ftpkQR$Oo#QlPX ztkT~mIFh0o{v*6+ncNof8L^KRRt@RY|KSd+x2=IM&TM)8++Q>0Ov%avwOiajE>2aQ zd97W2xS_81rM?AAxhl7Z2Z#EZe)D^N@N=*3l>zf+pYmUE^Ma@0?LBqRn(z58pA#E% z_I@Y#K%Zr+2I(*DyT{FCR!Zo8rP%)Acbn5w8h_Pk=k=&x@69IGe!Ta_#Cz&MU*7Xs zQxA>QpS3yr!UjdcnQ_M(ET>n`NgNsdc7yN!W#8(<@Uws=$HYrc7s$7*Ji0z+{nCZM z58ItR=Vu#j5pkhkmr`%LD}O^0onE=U4WANv#d-NaeUBY3-uVIP*A`dl33;iL+@|+f z_tc}mq+?67GDy$jt9+nceBs^W-#>ApZcG`v-&KRNRdBFd)aE^lbT^6OhUteqwClhx zzw|!x_3Z3;sfYLXGP9w>6Y?_-U3xY7&M(Vbp7-zZb?&AlZ#0==|8vQ#Tk(4y#;SHF zcMcCJOr5i4Q{l^s)pxfulSbd^f8e|I)5-%wNBS<*8D`<9WSa z5Btt|@F%*%F8J6@mZYrFpWg2)}k&%Z7*Yngn~HmlzJWHC)#oM)G5y?V~n zff4pn+ii_8!5+X2_N5?NRXdRKYeT`x5rL8lk zc=`5kTSBMnqqf^#-g2W+i_fLFof0?o?WSds zb>Z5Jmg=ppp@N6shU`sIAzM+b$y>)gA~xJ~DV#U?lH_!QkbdwwV9MWbFHE1B{n z%XM~l<@ngtS@SBW_jGe=v*S?FMI-Gx{5n5#WA?ahmxRsfsd|uwTU6EerFlqTcJ-)#oqn75=4I2tA z95x(W*3>KO{LQS^TNQ&|jGEirblT~_w2I2JqEU$ttxu;nBw29!Xy|;s5{keY+OSv42AFGJOrm=o~84?rS=aaxZwEG2y%pA^n#?|mTRHIT%0+L$_q1T6LLY~00zNI*AxGQ@9u@$DWiEIIHy z@kmH?C+|ZVM$qaw^F2d6t@IKdQt6uYw+kHxd5@&_FcP7#&u6hy{zg!6S z3cfvDkdkEgBl`f{y~$bI409h)4JRy=Xdjo}EJ%X`!YfphW)Q-X$dREbb}P3S6O~#~ zjp?#&7)tb+XvC{D{F@EbPm6NPbh6M^r$O%%uZAHmP8yUg650`!$B{C+&$qQiiWS74 zx;bneoT?>?4$Q=zkOo|v7SN68rvZJwnKD{~gbPW;*DnfYN%)ayWM$e~%;025%8uhK zF|9a{=K%godcpTD(YC)`;` z%5*lArBv3*b8Lndk8<_6z1PWLDyS0N%DQM0yJc6lkWs6o>7}% zGE;4WsD`LRlHL_WRTV+<^3x9{tK*B`XiZXEOpZ)1IqWRLl>HTU4dt~wDEH9Gv-8PBserY zwa7D(!Xd6-x)up)hYsnsQkh`bK~}Xwl(5$PvP#uL)`jerv#Pdy@R(y+r<5 znwS&JAlfXAujU!zM&MflYzs)5szEhG7wwu5A43wJ(Y+5`kn*s>_$0hAz>7W_KPL}(N1)swFd|CvWa;62S=c#QG=MVftXDoCi3kj=eK(^ zaen?$OKceToq z;c*&NyEHgXZ+LwaH58# z4js(yLFy2xKO!Dx9Ij2z<4lAARH=x>YqSc{vzDduz5Y>}B(BvUN8cp}5bc=^1r5IZ zpBW6FUSjav35KG-wTU_Hb9p>bV6HcM^xUTep;lOvL?TD#PZ7WLWHNAAA4;O4FfJJK zF_1**97mSkuyLj}8_^A^?sBj!i6I%Ic;*iK$Y>bx3dYMj0i76$_ocg#XsR{I(zP6* zKdUiR{}zyjc(*gXU>jfU5&n>p6pi>&v}3_u9Zv-~Kx|Ds?=#S?Md$jpw7<9XysnH< zzd!zQJ0j%CL9RqKL>JUpK+}I=L4MdMxcN#%3*c6t*By#$>|7Qz|;Bnc$jAGHMT#4^f? zSW`*6eLnaEkQxho{KAW`z8B!4*Y+mN;NiwlQc+&%|_zpr~&c!e*nUR z_0wG)O2n)@0g;l}B}XwTVasO6?a*+>ikelGqeKkAr{& zk}#`uE81$!iD&liQ$O&)h$N)506ILEAze-mh=`93R9lvWK=AA}NV1?vi$wpBWKewO zO1R`WY%E8E9QtuZMd4~(6a|vR?CT-WA;XBIr`KzPNe076uvhd10((7}Bo@`$K|}|G zNnR9gh90V0n@roYPb^=}r}orKq4EeC0E#)}{8Q7001ji{MiPzZ+kwk`Rihp$BCG30 zV4b(i9feusP!bL5Mm26E(XQGJE_Wr#Ph$=l5-*blbDk~2WEy|9VYC%|=G)~T$t4n7 zrZTi-6U!xv02vEcJn5juF5XeUxWuY#4}J>A?0q{@uHTd8p!5j=$?eXyEFcmBluF`j zpbF6HQL!6CXF8I^s{f^h?e7iVh*3$@Hg@m>44^V1VQZBg)+zz_2h=amgLfpUCau>Jgg6U%^oFrrqa3u1<^U zk?M7?!$6I7htxcZ-g_bk;#;tM!fOP$SAoKbXrU#E^y*@=;aYj}8YI#|@iHG=$?J+p z-MVE}f!-<0451zLO4ocGXjCsr9f5(<7~oC9YN(U3p=JUCe&Yi>SeM9QX=*vbSn=)d zRglGsOX8J9=zLv^R6J2q9von-^r_~}K?ziR5d$RY)}A&Y>M?s5azZa#f9|x00ov3y zrR0nTDNmJxeFH--)ChY`4LiS6>=U`9xU=z1hX4c!YeO z-czDIYn!j(J~mf_y0?^}0+djow>H)_LFfuk#7dZOhataED=7wlvg=nS${xm^q&40z zmcs{2|Cj5Ku}*d~W2lMYmFqnTs+>^*;Tw|RLuvJPlS9HUX zOJqr@_1&~N#Et^2 z$aA=e9mcLtMuNwa$o^oC`VNUVc?4?H;HG~7)zT0j&;h z{Rri$aer{E4KZDbxC@v5aNr|^Cd7L*|ClA%zxkU1DY_nQ`;9l}N31dB6h2$dSX z0@gX7`+FLt#{kUAGb!#5*A9$DD${P(f?c{~W~zFOfIbM*B&GYqV}Fr9%L}^wAQNF0 zq^f&5y#bat>67@+mN&OxcsCL}5!^&<{tQfgf+346zZt>ZU!P=1Rm}psXw-|sm5FdZ zT#uCIC^`y@ujJyv=CDw8g)o(O6DSO_C*@P0Hn_l_kEnbSm-{m$xmpp18q)sb2dIlM zZ*Llw26BjS;z3SFZrF+iW?&hj)8}z8M(q_Kz#7mubpzHR(x5@nC)Fi>&V?h|NXPK( zMude=D*lTlaEO$%&!B!}X=OS~HLtW_fd0siT1d5f!C-BGMYeJ~M2MAXZvq84a;d{A zxF(!N;)}vTkhOi38{`=Y>(?+c-SidZ=t#Cxy@nzqBeW>W^H!n*(KTpEHYW;lJ(6<$ zg+heB6S>5h#DP3!bR{>w4vs1dIB$?21*!p~5r@4PQtDBU^|K)TYI8mD#fA3SscYW$ zKL7&-FwIxLE5I#$;A!9)wDXBozk$>eX*N$j34E%E`UHs8K<1F!sVvY|)IcKLv=!G7 ze^!#`v3#C-<&v3g?$!%+m>zj}ujr2!6FMAH1~g2Mq?#a?NH{eDd_K_o2jDZ3QSgI=X zD!}YNN%GH&H~FBWF-@@cbVV%2>Cl5?Jx>5O_V5ZyDK$z(7~oOi)k1`f&J86=ZN}%_ zn6k#0l&_8~9t*iLHz8T^yFE}ENdikg-}bj5_)dtnBhg+6zk17!kgyb_Sk5K+4U}%K z-PPfedM>yNW=eobQP*c`?NGnEKAi<_)>vtisH(BkaX2$qIvQ)E(RG%BJ9ul7@ZPr# zmjTWYq8zaAI(E0C8lPi^1}$pSDJjF=Vn1*yxVmFwGDi0+U?^_KA5&e3O}_=&BtM&X z3{mIxKgZCGrQat(ry8^=z1pBft(E`v8kqHDKhV@7qTDxupP`<7l$(FMpMt$&)HMHU zc0cFwEYXs#(R+~C$y{y5oWQioj{OZ0D{K(X#n!?xks)}yYRFhDP5O>|A;h)^!AlS{Ku8NvmBPBn zhdyeF=EH@5rxp?I6c!;+;&=@*=L~NFBPV9!LHpk-h*nope5sAuhsjv*^EfVw1J4)X zl3N~`3Qu&&=-DHTt4FqzpR47&ot})dnhg3AjJ0raFN#$2d0LJRo}*-et0pd*+tRmy z&TdRiKu8=WXQe^jYIdeEBHi?NrE07T_6C+B>PjxnFs@kSK$NaQfd%Pcr<4(23?2x$ zbS8dT*1zODSreZNKyrBb{E)fe!%&i&Zmz(|k027R+Jr+C;X*sz)Ml#j#YY2}iu$je zp1AVR03rG>wyGaQAL7Y2pZTbMi24KpuYBs{y(u2~yH7mbw0&hTmPZyJy|70kN1B#- zd%mgqCa@7dkxxQ4*T0`1i1vx3LEXQB66S_fToZo~#`d6|w>$&TOP5?TZ^XexE6O>% z_X1@9j4qA5=?`mg=u*>oE9oI_buqIGDSzF2^9g!>fppOiGQ3)dW5%FE*E=JXM~0&&c5LB>L%Libpzd4nrHM1+2}#a&D-Tb z52gwX*OZ{%Aug-H-}PxvO27s1!Nm!sdWjc65@bLY<0ISml-@!i>X{5{;+2@r##zM< z66Hk(SfHP@%L!q&dIPydSU!eCodhR-y?^i>3Lxe4A?j~TT_G7L;q|K3?B42(!ukK> zkf$cN3nE4V#P4ZbiLh9cVn-x_hZaL9H{*mqd1Pb^;wUA5AJT>1TwaLmU$> zXg?;j*PvP5ZpyK+<`bQdo!H(}UcU7P9>oq*^R?8?5mIPKH67f~SwbIP6HQB9Sqre0 znv+-|oPdoc4g$?5Kk0&Z7n1n<%LkQgy9rVZrap_~6F*JL=klebU$e1F0}EF~1w)z; ze?eYHO_CIulE7%>Q8lj>0KAmpbCzOxcOzccQ0OvAo%XtgfXSWDBn07NbHW9N)Lh^7 z3(s#-4GPA15vXdh3*d2Kc6hG75J)3)?DTkW9`ol1ZCSv<;bJX@EAz*ahNZBVeqR&@ z0vBu~YA~}M)$}%)g%;HTQaZ)$N2Ng)xOxV>8=Yn3*@V93Ja+{r0Q;tiLKDLF1M{%;jceTei7{~p1 z0-BgEsl%ox^8*7@Cm0#3t$TMj%$>!j&d%As^N4 zz|;kB;Nk<1m&jgM9g;cOl3)YcdM^Jh!%c>dDab#grTK8Eb25GIm_-Vm*?+x_r9`{){9+ z#fi?HSWP;U#{3peen1q?mgq z7a&mKOpUDpbG=^AArgMpB8gs8njMlLIzFUO4Br@Gu~t$d9Pa9g8S1nUtJ!Hc(r_Ij z&vJ$pqwe&C@~zRKiTSGIP)rv(x6WOP{Y5jfz4`(dTOSSTu&j#BkD};1fF_ ze7Udh>!C8b!BG4cA&lS;F%h@-H}H%$ftwqkEF2qjqa0-TcC zzuOTB;o5hC!%)O@qHZ^V58rMpq3G(BMw$=iq*o9i7iSm`yoSo*qCO4!Jrp@;eiMWU z${xCt;Q78kGZ-9mV4`OBxv>kPDOkA~N3?>^I+W|n-|!ogt%w8m#{W4F_Ao;4(kpG4 zU_WY_XCr^{`2Z(}hTQq_4AaJGy+e&~wP`8blTGGe=~r$2`85Nf8LBWONpE@E7sTmA z!*l381)@gi_@-6|a|&L;xDgfn`Bwr3GyD>B<|9c#AG7ioP+zT$B!MN5z znBMet8Zh?~lg=CR7Y{fhf-mAXv=J8Vb48s^xeDjIG09c?CCzdeMXqa(CP>V@s4vn~lctX$R#)mzd}fZE|g zsdj%IgkFQv`x<^RBu3#?u8v5qIwCe;VI5_*rL-vEnqeQ2j=~-U&moDh|DXtmj7NEKx5zF-4&WP$CJKU5kkpk!tKD z1Cnad4d9a+=EEQT(Y9(%x##uMMp-7C^mLZG-#jM+O;V6dYTxt(G{u&r)qffa>zkBY zB5(&SQW=#&#*l01sp02k4BD;NrpU3k#yb!-ai~|fvM6+$LDD6CqhS+3U+Vkrdg`SU29gwa0`>QU`0Y*VM)guHg=y+9 zKCyiD!}x<(DVlI0jSrKGJaE$8gZL@FNzi~T9P((1nSfHD1~kez-EOohw`=TdA_bQQ zq~4kc**a*C^K;>6PJ2&jOF%4o?tmu&_s5`6WI5EVjMsqBc#`Mu?r*ekibqPraRJzh z<+`yHx%2o~%-&vp@`zF2MRV0;q$zv1reV;lx1i49uRpNx#jTW~$PbS+5w&s>?dx-D z5u`nvL%TNiz={kPI(j%xMu;{WQN>G-b-1$!bFnv57^+br>VAB2%+J3SUQdJ z>vr-+4P!F^KU@`i-wpO^p^iWVK?N{d$2=*RbF~CruJeC5$vrxXOB|pak z_i`?+ZGHa-LA4x2^z{B=WQHP0_2a2o4U`5CTRy!7vt|F7^YM<4%aBa0@+OeN?eBp_ zggN+MiH3IaH+OfyWx7_DCh@#?2ST4jZY1^>-a7?6!8wVKRyD}e{^G08Z%}#gXy>@M zDTw_{E`^@1g-$E1khBd^tF4f6r*A~AuKTeUhL_$VnyW!7h{mT!0oL7!7V}8BX=gR; zz;_yWTgE}9E4Y;1FCnZeHgIse&HmSM5Y3Qs0v(5AJPqo%0^Ql%n`(~gQVjl;di+%o zq^77Fse-}`far)vY66%fqbKQ)`_Nx{0I#=bj?AEdA{ZhKlx) zu%u^~c7`eq)^09CL|FMA|C0!*#E2#bRm=lLL5a|Tq0xY8B=K8?@$D4NE%A5USXLPm~hQ}u>aM_ zM;kiuNwqOe3%fAEMiTxFm<`l^AaRLTPuOZ|NY7;ng8?-G{dnqS3TABXLdp&b8=Su9 z=AkgsFN3v$JeD5*I@txao*{W$j1eQZZ%A&KI`1}I(U9%!n1skk8Hq`@O-~SWKSREY zdrZK4r0LLDW<#{wjKm)Os_{4<2Zb4`Td-Z5cwco+U~YylEN*MYG+**hc|yldG=D{& zG-Qo7g8L|PnDx^Ug`-F9&IA4~;FtQP{t2_tDa)?xtX+BqQ~&1+_O2EU3OCTTLeW45 zkrAOW?S%$0*p8v)0k1D6pk5ObA}2*fA?fM^YBl8led^yU%UBT>HuOP!8SDSPZ-=aG z!Pkpu*O?U-mW1oSuV-#&?&3~I5-|*odZ2-x33LBNN(*itMurB(EnvRnTshjM+&CjS z{;j#rhON%>@@YN}{8Mi^nN_li6AM;vj*!`y@Pa~5yk@$+l&{}Q6VAQh92dj5&KY2an@9!^P?=@}gl-hap(!CZJdp4Aoh8)uS^1b^h zQ+^=FTZd0kzsrU?OX=YVA-jXalR7OOcgR#oAKm#(6w4KE3OxP@5B)HgNu3x@ZseXP zAMwy4y$InZVwDBa)92x#OPY?kk;Ek4cRu5XhhDNKN=GSqe=r@f3lx~e=p>p5X-DJg zBZG)3IxGD@ZQ2FL#%nG6vp@f&^U=${n{I{&3Ue(|16j-7zenuaxom>+(5I%=oZ+2Q zOA)U#K>-6_zdarBD@*c$Vag~~8`moG$&RwqbO0kx8WdHYE8*}M_5AVll-JQ29 zHd8T{Dckf>Z~vG}nidh_A&j8a!ZJ{=%V9^UPvh*dseIpVQ8lVrsdF=;d;h+_%crdb5@TKoYL@@3go=~sPU5{vDx>X13CfZ49c-`#z3t6tX**r$5 z$8eOv8&BRwx^JJAvBR+gHD8o7YB#Y7msgl6gNZq%eDk@1W7uYSH@LjH%_XDr&0%%7 z*Z3ZGmM;0N@k?w|kQz{xE9^Sxp5~ld<2s3HQl!oNtBe<>J<_3K(fYexj@n6wTkk8h zO&^?p=3!5cJgzw6Oz+emqto_XxpnDg%e^t&t!EjYo;lu6eVl^e&4w* zv;NPg?qdo%XB?dsoRQ#_Z{&XDb&kJK^X}&X&D`28LB1U{I;>xAqMWmqPTi=!wt0Wl ziR#_6nnvmjKL3!XR1W5di#o=*g%nDPk`CDW&*zBqEQZIPbFSar$BDnYKg;Bl^lDX} zE|mD)y)Na}WUe^dAy3yfoL*l0E4lReZx1uZrqe28?W27rIIQ~7u$mTSPXFOGMq{yk z{nH1-&wpIV$z9VnMH2hKJj-+Qz1X-Hfp*fFE*XAS-fOc)+zdPw*5Q4Nd4y)M<=mYY z8~`xO>#XH>LO3%^RbQnRSz^Y_2{}TIeO$Fytwi1h)~*-}{>R zSF;A?&#y0hC_L9;`o=z$b9xIeZ1RuXu-0FAw@lW>wpuo{#WL)?&z;$&Lql5g_xk;a zc{NSc=jT`Z_{&lC`u}+_<07ZfJK>Y5%b@RD zhJK5wJata@6LF|O_pZwEdOyQ{?8?+Ki9rQy}OiGb?!ym?Dw2m&r58_zyBM+aAaPd6K-Dj zKE2NRf%`3=wxz~CYIe=jfM1g(V%i27@!b;*hsAEagy60P?V!JU>SIDWq0gsFw{|y@Y_L( z|64j|jVa6Jr(VUUJ2^GS-pA$egruXtKXN#}b@1@kgA9&p~nQZGrdtz+MDV!;F7{;$^^;Gm1+~?j`LPF-A zGkwHmIN}21g1sTc)JdEV8nawQghNC~2G)dEgW?=uUuKwWr6CrB(p~sz7d|tjY+%1(>F57rvZdE>2@ES*wxN!xAEGO7L3_o`q@ z@-Z!U!E~oQ9}gJtYjF7M)#TXYiLi(3E-Armam*C-p#+`D1b6nQ@ zUayR9<&6LHsRtX8Ieb`Q$oY4thW)-J9+d6g_L>u3^(Dz>lkQ zANq54&!i@|j@FS56I@&iZZ9`wiz=j*1LlV%_08Qf)_u3T)vx!a$wz;gv^2aMGw$cC zmrE=jTO?F$|Li;X_nG|1=iU!HvQ#^wT=sb7zD(hm1920{_~Mbt?{=Ow;qLeRc{W$?o3W5tbM!;K=;aHEOIz{F`k6jvcb`q-h>tk5-6`ymw0S^b*8@$5NBY^` zeHc`HMYG3>DJeakzuh-RVYI9K=BwK8+4lCddY#T6<=%T;b8I}K#g|uv=QdZYPFy9m zV~X0Wo{C09Of+Xg*lk04%;w{VFPVT7;&(EsJ5v{^`5`RXXNh_LUccOxcgz|z?DS&i zyt1j#saZL1lu_^aS$Ai4PVS$$@lf8fbpuT09@6>e2F~{{)mtq8VJNYf>v!kF@A{x# z!rTb)C4Wj9Gu`o8634t)Bd2RtEKdf4t=6A!0er9R6U=_<~vFVX__xIc!fuf%x`wa>`8Z1u3?f(KU CDt3JU literal 0 HcmV?d00001 diff --git a/app/src/main/java/ru/dgis/sdk/demo/MainActivity.kt b/app/src/main/java/ru/dgis/sdk/demo/MainActivity.kt index 3f64685..ed2bd18 100644 --- a/app/src/main/java/ru/dgis/sdk/demo/MainActivity.kt +++ b/app/src/main/java/ru/dgis/sdk/demo/MainActivity.kt @@ -26,6 +26,10 @@ class MainActivity : AppCompatActivity() { private val RECORD_REQUEST_CODE = 101 private val pages = listOf( + Page("Issue with 3D model animation") { + val intent = Intent(this@MainActivity, ModelWithAnimationInMapActivity::class.java) + startActivity(intent) + }, Page("Compose Examples") { val intent = Intent(this@MainActivity, ComposeActivity::class.java) startActivity(intent) diff --git a/app/src/main/java/ru/dgis/sdk/demo/ModelWithAnimationInMapActivity.kt b/app/src/main/java/ru/dgis/sdk/demo/ModelWithAnimationInMapActivity.kt new file mode 100644 index 0000000..788b4f2 --- /dev/null +++ b/app/src/main/java/ru/dgis/sdk/demo/ModelWithAnimationInMapActivity.kt @@ -0,0 +1,147 @@ +package ru.dgis.sdk.demo + +import android.animation.ValueAnimator +import android.os.Bundle +import android.view.View +import android.view.animation.LinearInterpolator +import androidx.appcompat.app.AppCompatActivity +import androidx.core.animation.doOnEnd +import ru.dgis.sdk.Context +import ru.dgis.sdk.Duration +import ru.dgis.sdk.coordinates.GeoPoint +import ru.dgis.sdk.geometry.GeoPointWithElevation +import ru.dgis.sdk.map.BearingSource +import ru.dgis.sdk.map.CameraPosition +import ru.dgis.sdk.map.Map +import ru.dgis.sdk.map.MapDirection +import ru.dgis.sdk.map.MapObjectManager +import ru.dgis.sdk.map.MapView +import ru.dgis.sdk.map.ModelMapObject +import ru.dgis.sdk.map.ModelMapObjectOptions +import ru.dgis.sdk.map.ModelScale +import ru.dgis.sdk.map.ModelSize +import ru.dgis.sdk.map.MyLocationControllerSettings +import ru.dgis.sdk.map.MyLocationMapObjectSource +import ru.dgis.sdk.map.Padding +import ru.dgis.sdk.map.Zoom +import ru.dgis.sdk.map.modelDataFromAsset + +class ModelWithAnimationInMapActivity : AppCompatActivity() { + private val sdkContext: Context by lazy { application.sdkContext } + lateinit var mapSource: MyLocationMapObjectSource + + + private var map: Map? = null + var movementAnimator: ValueAnimator? = null + var rotationAnimator: ValueAnimator? = null + + private lateinit var mapView: MapView + private lateinit var root: View + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_model_with_animation) + root = findViewById(R.id.content) + mapView = findViewById(R.id.mapView).also { + it.getMapAsync(this::onMapReady) + it.showApiVersionInCopyrightView = true + } + + } + + override fun onDestroy() { + super.onDestroy() + } + + private fun onMapReady(map: Map) { + this.map = map + mapSource = MyLocationMapObjectSource( + sdkContext, + MyLocationControllerSettings(BearingSource.MAGNETIC) + ) + //moving camera to car location + val screenHeight = root.height + val mapBottomPaddingOffset = (screenHeight * 0.4).roundToTop() + map.camera.padding = Padding(0, 0, 0, bottom = mapBottomPaddingOffset) + map.camera.move( + CameraPosition( + point = GeoPoint(latitude = 40.209339212102556, longitude = 44.51782621674358), + zoom = Zoom(40f), + ), time = Duration.ofMilliseconds(300) + ) + //loading 3d model + val mapObjectManager = MapObjectManager(map) + val fileName = "blue_car.glb" + val location = GeoPointWithElevation(40.209339212102556, 44.51782621674358) + val modelData = modelDataFromAsset(sdkContext, fileName) + val modelObject = ModelMapObject( + ModelMapObjectOptions( + position = location, + data = modelData, + size = ModelSize(ModelScale(0.055f)), + ) + ) + map.addSource(mapSource) + //adding 3d model to map + mapObjectManager.addObject(modelObject) + //animating model movements and rotation with animation + animateCarMovement(modelObject, GeoPoint(40.20949240044926, 44.51422545018235)) + animateCarRotation(modelObject) + } + + fun Double.roundToTop(): Int { + val intPart = this.toInt() + val decimalPart = this - intPart + return if (decimalPart >= 0.1) intPart + 1 else intPart + } + + private fun Double.normalizeAngle(): Double = (this % 360 + 360) % 360 + + //car rotating animation + private fun animateCarRotation(modelData: ModelMapObject) { + val currentAngle = modelData.mapDirection?.value ?: 0.0 + val targetAngle = modelData.mapDirection?.value?.normalizeAngle() ?: return + val angleDelta = ((targetAngle - currentAngle + 540) % 360) - 180 // Shortest way + + rotationAnimator = ValueAnimator.ofFloat(0f, angleDelta.toFloat()).apply { + duration = 4000L + interpolator = LinearInterpolator() + // Listener to update the model's direction during animation. + addUpdateListener { animator -> + val animatedDelta = animator.animatedValue as Float + val newAngle = (currentAngle + animatedDelta).normalizeAngle() + modelData.mapDirection = MapDirection(newAngle) + } + start() + doOnEnd { + rotationAnimator?.start() + } + } + } + + //car movement animation + private fun animateCarMovement(modelObject: ModelMapObject, newLocation: GeoPoint) { + val fromLat = 40.209339212102556 + val fromLng = 44.51782621674358 + // Target latitude and longitude for the animation. + val toLat: Double = newLocation.latitude.value + val toLng: Double = newLocation.longitude.value + // Calculate the distance to determine animation duration. + movementAnimator = ValueAnimator.ofFloat(0f, 1f).apply { + duration = 4000L + interpolator = LinearInterpolator() + addUpdateListener { animation -> + // Interpolate the position of the modelObject based on animation progress. + val t = animation.animatedFraction + modelObject.position = GeoPointWithElevation( + latitude = (1 - t) * fromLat + t * toLat, + longitude = (1 - t) * fromLng + t * toLng + ) + } + start() + doOnEnd { + movementAnimator?.start() + } + } + } +} diff --git a/app/src/main/res/layout/activity_model_with_animation.xml b/app/src/main/res/layout/activity_model_with_animation.xml new file mode 100644 index 0000000..bc76b0e --- /dev/null +++ b/app/src/main/res/layout/activity_model_with_animation.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + From dcc4ef3af276cbf190678071085b4f62b36e3ea9 Mon Sep 17 00:00:00 2001 From: Gevorg Antonyan Date: Wed, 2 Jul 2025 12:03:14 +0400 Subject: [PATCH 2/3] Changed animation using AnimatorSet and Coroutines --- .../demo/ModelWithAnimationInMapActivity.kt | 69 ++++++++++++------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/ru/dgis/sdk/demo/ModelWithAnimationInMapActivity.kt b/app/src/main/java/ru/dgis/sdk/demo/ModelWithAnimationInMapActivity.kt index 788b4f2..88b3240 100644 --- a/app/src/main/java/ru/dgis/sdk/demo/ModelWithAnimationInMapActivity.kt +++ b/app/src/main/java/ru/dgis/sdk/demo/ModelWithAnimationInMapActivity.kt @@ -1,11 +1,18 @@ package ru.dgis.sdk.demo +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.AnimatorSet import android.animation.ValueAnimator import android.os.Bundle import android.view.View import android.view.animation.LinearInterpolator import androidx.appcompat.app.AppCompatActivity -import androidx.core.animation.doOnEnd +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine import ru.dgis.sdk.Context import ru.dgis.sdk.Duration import ru.dgis.sdk.coordinates.GeoPoint @@ -29,11 +36,12 @@ import ru.dgis.sdk.map.modelDataFromAsset class ModelWithAnimationInMapActivity : AppCompatActivity() { private val sdkContext: Context by lazy { application.sdkContext } lateinit var mapSource: MyLocationMapObjectSource - + private var mapObjectManager: MapObjectManager? = null private var map: Map? = null var movementAnimator: ValueAnimator? = null var rotationAnimator: ValueAnimator? = null + private var movingJob: Job? = null private lateinit var mapView: MapView private lateinit var root: View @@ -46,7 +54,6 @@ class ModelWithAnimationInMapActivity : AppCompatActivity() { it.getMapAsync(this::onMapReady) it.showApiVersionInCopyrightView = true } - } override fun onDestroy() { @@ -70,7 +77,7 @@ class ModelWithAnimationInMapActivity : AppCompatActivity() { ), time = Duration.ofMilliseconds(300) ) //loading 3d model - val mapObjectManager = MapObjectManager(map) + mapObjectManager = MapObjectManager(map) val fileName = "blue_car.glb" val location = GeoPointWithElevation(40.209339212102556, 44.51782621674358) val modelData = modelDataFromAsset(sdkContext, fileName) @@ -83,12 +90,14 @@ class ModelWithAnimationInMapActivity : AppCompatActivity() { ) map.addSource(mapSource) //adding 3d model to map - mapObjectManager.addObject(modelObject) + mapObjectManager?.addObject(modelObject) //animating model movements and rotation with animation - animateCarMovement(modelObject, GeoPoint(40.20949240044926, 44.51422545018235)) - animateCarRotation(modelObject) + movingJob = lifecycleScope.launch(Dispatchers.Main) { + animateCarMovementAndRotation(modelObject, GeoPoint(40.20949240044926, 44.51422545018235)) + } } + fun Double.roundToTop(): Int { val intPart = this.toInt() val decimalPart = this - intPart @@ -97,10 +106,19 @@ class ModelWithAnimationInMapActivity : AppCompatActivity() { private fun Double.normalizeAngle(): Double = (this % 360 + 360) % 360 - //car rotating animation - private fun animateCarRotation(modelData: ModelMapObject) { - val currentAngle = modelData.mapDirection?.value ?: 0.0 - val targetAngle = modelData.mapDirection?.value?.normalizeAngle() ?: return + suspend fun animateCarMovementAndRotation( + modelObject: ModelMapObject, + newLocation: GeoPoint, + ): Unit = suspendCancellableCoroutine { continuation -> + + // Target latitude and longitude for the animation. + val toLat: Double = newLocation.latitude.value + val toLng: Double = newLocation.longitude.value + val fromLat = 40.209339212102556 + val fromLng = 44.51782621674358 + modelObject.mapDirection = MapDirection(70.0) + val currentAngle = modelObject.mapDirection?.value ?: 0.0 + val targetAngle = modelObject.mapDirection?.value?.normalizeAngle() ?: return@suspendCancellableCoroutine val angleDelta = ((targetAngle - currentAngle + 540) % 360) - 180 // Shortest way rotationAnimator = ValueAnimator.ofFloat(0f, angleDelta.toFloat()).apply { @@ -110,22 +128,10 @@ class ModelWithAnimationInMapActivity : AppCompatActivity() { addUpdateListener { animator -> val animatedDelta = animator.animatedValue as Float val newAngle = (currentAngle + animatedDelta).normalizeAngle() - modelData.mapDirection = MapDirection(newAngle) - } - start() - doOnEnd { - rotationAnimator?.start() + modelObject.mapDirection = MapDirection(newAngle) } } - } - //car movement animation - private fun animateCarMovement(modelObject: ModelMapObject, newLocation: GeoPoint) { - val fromLat = 40.209339212102556 - val fromLng = 44.51782621674358 - // Target latitude and longitude for the animation. - val toLat: Double = newLocation.latitude.value - val toLng: Double = newLocation.longitude.value // Calculate the distance to determine animation duration. movementAnimator = ValueAnimator.ofFloat(0f, 1f).apply { duration = 4000L @@ -138,9 +144,20 @@ class ModelWithAnimationInMapActivity : AppCompatActivity() { longitude = (1 - t) * fromLng + t * toLng ) } + } + + AnimatorSet().apply { + playTogether(rotationAnimator, movementAnimator) + addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + super.onAnimationEnd(animation) + start() + } + }) start() - doOnEnd { - movementAnimator?.start() + }.also { animator -> + continuation.invokeOnCancellation { + animator.cancel() } } } From 955081c83dcc42160fbc2609ca568cfa54b5dedb Mon Sep 17 00:00:00 2001 From: Gevorg Antonyan Date: Wed, 2 Jul 2025 12:05:01 +0400 Subject: [PATCH 3/3] Changed animation using AnimatorSet and Coroutines --- .../ru/dgis/sdk/demo/ModelWithAnimationInMapActivity.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/ru/dgis/sdk/demo/ModelWithAnimationInMapActivity.kt b/app/src/main/java/ru/dgis/sdk/demo/ModelWithAnimationInMapActivity.kt index 88b3240..7c59cf1 100644 --- a/app/src/main/java/ru/dgis/sdk/demo/ModelWithAnimationInMapActivity.kt +++ b/app/src/main/java/ru/dgis/sdk/demo/ModelWithAnimationInMapActivity.kt @@ -39,8 +39,6 @@ class ModelWithAnimationInMapActivity : AppCompatActivity() { private var mapObjectManager: MapObjectManager? = null private var map: Map? = null - var movementAnimator: ValueAnimator? = null - var rotationAnimator: ValueAnimator? = null private var movingJob: Job? = null private lateinit var mapView: MapView @@ -121,7 +119,7 @@ class ModelWithAnimationInMapActivity : AppCompatActivity() { val targetAngle = modelObject.mapDirection?.value?.normalizeAngle() ?: return@suspendCancellableCoroutine val angleDelta = ((targetAngle - currentAngle + 540) % 360) - 180 // Shortest way - rotationAnimator = ValueAnimator.ofFloat(0f, angleDelta.toFloat()).apply { + val rotationAnimator = ValueAnimator.ofFloat(0f, angleDelta.toFloat()).apply { duration = 4000L interpolator = LinearInterpolator() // Listener to update the model's direction during animation. @@ -133,7 +131,7 @@ class ModelWithAnimationInMapActivity : AppCompatActivity() { } // Calculate the distance to determine animation duration. - movementAnimator = ValueAnimator.ofFloat(0f, 1f).apply { + val movementAnimator = ValueAnimator.ofFloat(0f, 1f).apply { duration = 4000L interpolator = LinearInterpolator() addUpdateListener { animation ->