From 777a5dcf5d22ef789568bcdfc215eebbbfe62614 Mon Sep 17 00:00:00 2001 From: sugan0tech <71312159+sugan0tech@users.noreply.github.com> Date: Mon, 2 Oct 2023 22:45:51 +0530 Subject: [PATCH 1/8] #2373 add: Vertical Slice Architecture. --- pom.xml | 1 + vertical-slice-architecture/README.md | 44 ++++++ .../etc/vertical-slice-architecture.urm.png | Bin 0 -> 112171 bytes .../etc/vertical-slice-architecture.urm.puml | 125 ++++++++++++++++++ vertical-slice-architecture/pom.xml | 90 +++++++++++++ .../verticalslicearchitecture/App.java | 41 ++++++ .../verticalslicearchitecture/Runner.java | 83 ++++++++++++ .../customer/Customer.java | 49 +++++++ .../customer/CustomerRepository.java | 36 +++++ .../customer/CustomerService.java | 51 +++++++ .../customer/CustomerView.java | 42 ++++++ .../order/OrderRepository.java | 39 ++++++ .../order/OrderService.java | 54 ++++++++ .../order/OrderView.java | 43 ++++++ .../order/Orders.java | 56 ++++++++ .../product/Product.java | 48 +++++++ .../product/ProductRepository.java | 36 +++++ .../product/ProductService.java | 50 +++++++ .../product/ProductView.java | 42 ++++++ .../src/main/resources/application.properties | 6 + .../verticalslicearchitecture/AppTests.java | 21 +++ .../customer/CustomerServiceTest.java | 74 +++++++++++ .../customer/CustomerTest.java | 28 ++++ .../customer/CustomerViewTest.java | 36 +++++ .../order/OrderServiceTest.java | 74 +++++++++++ .../order/OrderViewTest.java | 40 ++++++ .../order/OrdersTest.java | 27 ++++ .../product/ProductServiceTest.java | 58 ++++++++ .../product/ProductTest.java | 21 +++ .../product/ProductViewTest.java | 40 ++++++ 30 files changed, 1355 insertions(+) create mode 100644 vertical-slice-architecture/README.md create mode 100644 vertical-slice-architecture/etc/vertical-slice-architecture.urm.png create mode 100644 vertical-slice-architecture/etc/vertical-slice-architecture.urm.puml create mode 100644 vertical-slice-architecture/pom.xml create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/App.java create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/Runner.java create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/Customer.java create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/CustomerRepository.java create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/CustomerService.java create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/CustomerView.java create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/OrderRepository.java create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/OrderService.java create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/OrderView.java create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/Orders.java create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/Product.java create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/ProductRepository.java create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/ProductService.java create mode 100644 vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/ProductView.java create mode 100644 vertical-slice-architecture/src/main/resources/application.properties create mode 100644 vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/AppTests.java create mode 100644 vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerServiceTest.java create mode 100644 vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerTest.java create mode 100644 vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerViewTest.java create mode 100644 vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/order/OrderServiceTest.java create mode 100644 vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/order/OrderViewTest.java create mode 100644 vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/order/OrdersTest.java create mode 100644 vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/product/ProductServiceTest.java create mode 100644 vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/product/ProductTest.java create mode 100644 vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/product/ProductViewTest.java diff --git a/pom.xml b/pom.xml index 2bf8874fa7d6..2cdf24a2a32b 100644 --- a/pom.xml +++ b/pom.xml @@ -207,6 +207,7 @@ context-object thread-local-storage optimistic-offline-lock + vertical-slice-architecture diff --git a/vertical-slice-architecture/README.md b/vertical-slice-architecture/README.md new file mode 100644 index 000000000000..9356119f9b2d --- /dev/null +++ b/vertical-slice-architecture/README.md @@ -0,0 +1,44 @@ +--- +title: Vertical-Slice-Architecture +aka: Layer-By-Feature +category: Architectural +language: en +tag: +- Decoupling +--- + +## Intent + +package the application based on features. Each feature will have its own set of layers ( +Models, Services, Repository and Controllers ). + +## Explanation + +> With vertical slice architecture we can have high cohesion within package and low coupling +> among the packages. In Conceptual term + +> Consider that you are going to make a backend service for a online e-commerce application. +> initially you make it with usual grouping of controllers, models etc. but as the application +> grows more it's requires implementation of new features. Let's say that you thought of having +> orders, customers and products associated layers. But now you need to include another set of +> features with Cart system and wishlists. Now it's really hard to integrate those features it +> requires lot's of dependency modifications and mocking. So if you make the package by feature +> it will be really feasible for future additions. General example. + +## Class diagram + +![Vertical Slice Architecture](./etc/vertical-slice-architecture.urm.png) + +## Applicability + +Use Vertical Slice Architecture when + +* You want future modification ( new addition of features ). +* You want to reduce the amount of mocking. +* You want to make it more modular by feature. + +## Resources + +* [How to Implement Vertical Slice Architecture by Gary Woodfine](https://garywoodfine.com/implementing-vertical-slice-architecture/) +* [youtube](https://www.youtube.com/watch?v=B1d95I7-zsw) +* [medium](https://medium.com/sahibinden-technology/package-by-layer-vs-package-by-feature-7e89cde2ae3a) diff --git a/vertical-slice-architecture/etc/vertical-slice-architecture.urm.png b/vertical-slice-architecture/etc/vertical-slice-architecture.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..1ce57837d7dc2c03aaa1ff659f5b213cd0888903 GIT binary patch literal 112171 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
-qQ8J zMB|A)K$yz&WI~(fLh-UUVe-Vlou9xaGb(yPn;L*981(+W+>?+{ zlV5xFAVYK}fT6T?LcYmten;lhWDyBrT*IYb%!5}$L&NjuM@>zDWq7s7;Jo6B?)6Q?Q7+ zHlX29NLZMlAeBElZvu+`gAk3}7N+<8XX1<4wYumG&1Rr4g5HU$!$20wUGIcrCE4mPUZRG>GZr3nt4 zEuOv(f>2#;?M@pO74lw|Fn7w2NJMdQ81?2uZ3%}Y{RV^S6g5Vf;&mrdqjI>1K-BYo^9JMGxl55% zQ$K|NBZ)0?dMxGnK~H9UTpYCjSS9P$=iepk@ct7jsa%y7{ z;NT3cS=xi(v{$ybx@KfTKThqlRcvJZElz|qY$Ul{sR})&X3tNRm!z^FSE2K;jq_-x z|Fwi2>NH=R{$qm?krn@p&zSUT#Wv9W=Z17%>p#JeJkz_4UeItu@90s_DR@0oBy22P=YFHY?09mjs^Zq*>Q9>?r@$)-W-JOjIy#`049+G&6XtvD zkp)3kHa1R9PW>FE0QI%z=4Ptc>FH?%#+^59?G2&KwI}f;9Po86iZk4xq^xRgPS4MO znBJKfA1@xk-tsh?*`wwf4I05+MdazT0Si6b@}uW6zm0y2t*Yc|DMK$c_Sq?w3}cz1 z;@zw@KH;lAy|H1_{R~NZcECqtM@+&zjj1}h;u(exuJ5_)nf!{LV$T?kU3IqcAYjw>#X zV1@US`1L{gkt@ozvc7I@ZEbI30~8(;6>zm`YHAiepSRCJ<6uoW_$JS4n+z(D+bojm z$GG9ViK&7(;wSi4ghlOA?5=GS*b!n2aQ`#&56Q`PPd+inbgP+uDdWxgftUFZS0Th#QSucp5eG+k z^sJraQte(g-*@vSW^>wV$JXbVS)$?XCul3v*VMmPzf?u!qt`jS)PK-CbRqz}{&UK^PS= z5k6X(E2beV>;@KUWW+#_1MkKdx+8RA^!#NPjF{Q;r_V0+u-P}w?ns^$9OJIvySJy9 z^#wW7>+IgA=&_hyaK8R8*ZZW)L+Vw~RVU*|{Z$)n6pPVxbPV03`q~}scQ;bcv>ZX> zW3qWki#dc2goMjyyn=lzfz#KyhCN|nVGz)7Y1dr})@Ej_u(5`A5b!cM3*88>6vDuO zwoYip$qp~b+g5>BPQj@zDDC5%MMXuWr7ujaf%?%ZU!o=%k(ih`kZ&r$azvlmLyHrR zKRP(A8uLKRha%Mveh3*L3m2OOb zp5x5(B2x7EFB5#(RVVe=1cfo*XWn}}CZexDqikFvID8y>M@UGbp%8l$(L5~irTiKW z=eK{|ue+IWJY#%fB2hjCqAN2K)7!q!=STWLtcQbP`9($gEMY(>B*w*^D#Du>hIYAS zz$MUR{viH=pT2)Ji8JaHKxAZOD)e9+4Q+pWQ?tfI@21tQ1~Cmu$!0ifUIKmYTwKt) z9~c!S5jHt@D)xk#`)lp7_Q<;X}MA>c&F4{nq)#-atmQ!S~`|b<|d^`o)mjWT|N3c`MZpamd?)gAO$rJ z07;^v_36&LGvFg1jYl88+`*+iBL8v{4ecsk@#o8KKTwJW-_ZAHk>ju7We}itd!~JR z{wpx}e!N1tySrQDR7`6oF{A7bl^bflN(9xonq!3)e+Yd@rS`u08;#7vOOo6TptN zwaMz~U_#eAh`Wdf@OFh5d;)@$loWWgSq;OcqPlwXZ7K>1zoClLrf@8u0f$$H>UJcE zvi{jPI5?Tts)~PnK3f%3jP8V8!~d@{z8av56~d_AR98oeODrxf4mtq-n^!8U9-Ja) zf9^>x^W$sWaIgycb9-f)d2*cAtDKZEX1R*p)=Nhun|9ZMX8_>re!T zIh=C|!gKJxu)ofRdW&`SuZAkq5GEaR#iO~|HZ#+|`}8k7 z5PthH1)J-p!YGK~0a1_+NI5I{aXAbB)A3!!Vm|ZzoYEROolC5y+;I7;th4t{UQ+Zs z9Ov!tjD>~a10?925wtQNLzI@50`3+jw$*}@%5Y3RhDzv6y=ry@<%)`m%B;nnc1HFd z@y;vgft_?E0{s`dF7k@AI7dboXfs_D`ljRN=TH1B1wpZqHG}zvyeSA6QN0xEh7nu zb~Yg+A|zWjg+$SiP5jQAdeV5_=l9q99`Ab`ecku{`CQ|?&hxxtN@V@+JSmbtb7(yz z9AR)D-2QzO*#iwvnMBCl{9l^`x6n4&blm8Y5dA&n)x++fy6q*IfZC5w7 zrx??O9|aQ+S6GBA+!$O1IZm>#pISE5H8f0)jXfDGNak8zL3|^ zKIxA-SY|@;<{|(4moOWv=Dwgu_QA);2U?nq4J;tUtl&^|>IpY4c}s4|WMrl4q~b{` zvUjoWc`nvnPX5|WEQ@GZVU(Kj{fo`L8jrhqJ&DXD>Q-wV=6$}3J(FfGaM(c0Wwm=Z zNoGEBPX`PT(lB8mBO|+a@E%5V21Z5);y~c6yx}_1gklUyAC+x=T^*kUoF8!0F<)3O zb~i2|VJk1M?-+aJoDrz{yEmcP6i|O{H!44I@??XF0P1QZw<{ZK8rg2e#l7{Em|7q1 zhgk0CN0a$rx;seOBxu9GzKoYkIo0#*-ce_2s-w_AR76_0h9?qyTVWp6yz_c1TV^+H z1oM))BFVzIV4<+UkE|s7pya^&wi81Q3qwdremfm|?kv6a{2nb-Ozh{6Jnp20nH4Ds z7c+18GyK!h(d$q(xVz7QYCJqTswS$G5h-HFv1^xh9MseM1R+*9asS_K2Quce6b~#rs>Y%* zr2zHCz}cVz2vZ!Xi?cHTtL}k;fj4iGz#ql~a*EQ0KKUMu z>@x*i?YOv$OT#hw1!?jE%N28%p7*CwRaR6~Xg++^JwSm<(%_(uPFvcZI{{hO@Yb8w z6?!Rmkp|oaQ@j4vtH3n>@!GSHyW<2F6%{$>h(n+#Wb-OA8wLvDR)dgGq0EZm)B#=k@QbK(nwB8LDknQq?7^HeQg^Gz+^2|)u)a+ zIyydiD(>&=Hu*>&pYj!ZlYa5!8KR`w1lxiUh*_IK0|s?iBZyCxi=Tew%1b;2=Ybf9 z2!Shny*x7^ApxQF<;yLcoSr_-ARZ^#^?gswzr29kY->K6AO4;|JuY0J&{BHe_9Nx) zG{32S_>`TdB703+n~ty#xIPEG`g?oVz29_gy^TJDv}NUBR>|%cDQmaP3m(*xhU>)s zQbUHz-EtQbSXgH!m}KwZ!1(cY%cEm?`$cQpMn)XpSjotcH|3sqBWZ7+>gQJpUh-W} z0Ea2!#dx>=Nw`#?^|^e^e0M!E5>kJ~0eUkROG`^O@6XXUH~Nd9z6tUP385Fd_xN#R zW9HEJT)@u5V)P>~CaMK28{H?L(6F7VJ|4rr^m zAJl`~*ZoSHZ&W?Jc%Gle{>{&ZRBSG(Gg5kcGX7{Q`wtovx(4u1w|m_o<9Kf!lWwf> z_T`=&M&-hLL~0jNtJized?@@Lu5U(WtdlZmLa?Fhq)0XIaY{pYR| zJi_N$8eA#Mf}r^UJXAY$3|geowp2i_tsY*;~V@8F4zR2O1ICsODx( zGi7;sy2Ye4+M$*yYfa}JBwq_D!|KJ!8*ZN2c!l;a2P#UgHO1I3H1x=9YPAFP6BCxx zr*~QM6AzW1mX`VWF`Pgi-o4w0`80Y8y|(hJP31XV?|_yd-n{_swH+|brp=q#+K8mv zjM~l16N(Tx3|%rZ{Ep%z9t*fDD+Z`%@AM@hL~-==s0sA$i{yCw_-r)WKON|Q7O|E+OL|gWg}7kq zd2Zi8lr0swG#E$;tu)`THp~DJmi6@3i_n@LxO)(jzHrD)`N`3D0Uq9G%^O@js9x-*4f2C2eg7 zuP|#IlzZ^9XZo>qos`dw-i6(VU`tscjLwl_{KV;40dt?;ebm_tgUbQ>r-i{kqGR9 zr{%(8f0BPr`w@f92k_P~GT2LgdloBVHxs;l@}Gj_jJLOUUfv8~EcFb%dr$n^+uPBz zD2MT#mF>o-1sEFUJTg3t=pP_O8&17siGDkUK@TXu20h^TmXwzpNIlRD&1~|epLbtm z%2dKjt~VO6;K&_P$J@)ZeOre93bWYU;fL1C&(fb{+MBL$g6GeoI7uRif(tfUgtM&H zM)J9$OCdaw#J2DU(mA=RNiu2KmH9vTyh0_s%v?jG35w!Fo9iK^aqKQxu6lp}ZSN~r z?CtDede;BpLrbO|=OjH59p?5|`hNtIqFgBV_9^*M3Yp<)j8{i@t8J#r} zUca0D?U+QVFe&>>NF}RRhqkvLeZ@YrQJDU(_vf@p=IL?%%s^8NbabO1iCNp zYn8M0mpVuybSXKKlInHUyrLpDol|Q54ULT9ze+TJpsn@}JKOd>XW@FOX{o1D)-%(UhK_9OHT~y@9 zJhRAjM6l|3tOu}*G&eI-6w=_j!bqd1uEh}hP4K+1s3_{oy83#`i0-^a&kO#nR1N4> zk}Eau3mYgpN-xFG}_G~^u;Fbwr)Z~LXh9pK9-yQ>jjzDHHxmF$9D%$9Vz(6 zV?C|{D~_#2o?S9dO%m6q>7yS}pwRQ%H7ILf(2YC^S;Cf&#urLUBVu!MT)_qhYGF@^ z>d-L?RW|X{i_=osrT_hp_Ql~`R*11jSkYMc^#}3wO--g#yA_(l#j6hV8pFOrARo3O zbWOSoj1L^3OVe_SHUv$mPm1l3&3VSXUsJ2tTmE`)riN}ypdb~aSostoKVbHv4DOkv zqZiVRsWV`tGF@yQ^9VNRws0cM%F2R69Yl3tfeZlQ>wF}YWHvZC`Y8&9dCNdw-H-52xU*_%YJx0KXXapLb}#V|L+c~0jEaVa zjKoBLdyck)o9iL*GOdMyF7zm}Q@E2g-CbQ$q`T} zLoZxRY=;NQ6Qr5u=4N8m2XL6jT5fLQO^@#1&lb95LvAZ}?C8<xf=H@QWw9W2+>$NHxS9M`^2r`0wODnVD{&s_RsHRcUtq>iMTJJelyd!r{hEm1Z z6CYk}IeBsvytAy9`uewT-q=iy*(B#U4rl@r$5brmXjEVz+Z0P`RSVp9fNz*)%!P2y zx{+Y&-w-h07=Dt%Xa6e_rTZt2jdPw-elio^lOM=c~`uenl zgi3=Qs&`AZJG)S~G5JW3-4yR?X2DcsEo@>N0h%p4Kl%oh1O|M`uh0c!w@a3#t&^M_ zC4t^h_>igD@o8|zCRPj;t;aN?;1&GwG3-JvJYPi43X0f;Ln}}u6#KEd19$QDrS2LH zrKPctcz7xI#ok6s2w;19EdB-Nqly_k!N+K~P?zz~+S*_4A4pESfUQqIee_M7b<}vn zGx;s!eeMQVO9yY*b)N`i^}0!YJzaK=UET2)mM6Ncq;b@oC=DBpK1wNc81@9!-u7>WLUM)G5Ltt zbS|=~Z);OZhf7#o{e84W$RPZO6B<&iP!Bz`9sQ_tUU#3Mpdd$fO!{q$=#tBe=Hbv` zR98K{O2bx=y!f-Pp9h5Y(9w5{72OL9j3hUsu5y={IHZ5D*vN*{dss-1vHWpFW;08Y z-=8a?7uo0P@~ps_$)i2P_$=~-IJ~5Q+cqQ|JL%vMM>CRoFTJ6rhV8va^Nr-Qzok*$ zgJinhe-;ho;d?KBZ&zM!%($S2bjYtqZ zJ=+r1)S)FZuJJlCiHM4`$KVpm5_kW;!o$O?qK=9t1`G`&S=rez;X^)CNZ(Ta)M>D1 zXYJ?!W|B!aE`a}-G&-OGzK~$Yc*RM#k(4MzyIN-h44J=d7r_*$S4eBQD~Ivn!}K4} z83_rwFaH5e?G9K)IS;Gcwt6!upY5ODq>C$jZ?&rsV0N8M+l_71R8*pH%xlnjd0d-P zh2?wMfwRbd%I9;gnB}3(36mp3&SFjbm6ahh_PDdX$!G-BL?Utrqhg%x3k8 z2L{C8JkfW%G~awQMw}4QzI}T&JiG~RbX8UU5fN+PmA$JKmUOc3CMKL~1VHgX85poB z;4qaP-;F01E1nta>$8cm8DjP~v><}a8)zq11-z=SACBml;`ma21-I<$@bDI>F?4 zJu%e=@yd;P|5OgCeRGuqBIX+Y{FQTch>Narke%Ji?*(t>g`&O*KaP!CZhvY~80-D^ z+&$Mh>{E-2uB9K`#$UgCx5KEML0@1bC?rH$v);_X-rinX+Cz@Bz>;&r9p%4tQ5QTn zpjHdYqlA$RW}+DXSwv@wFeoauYa2g2tUz6MI#6N*+9MRrG1>IfX3J5^Pks9)=LxQ5 zFyrLJ1X9waHUK$XT$i>y=d05~0|+TJr()P^pnxad5H8$rrY`<`K|;mdt;|%tKZk!( zl5g?V&XdRz1h$7uejn`GJX7ohpACWV#WjYjZ)Vw}rjTXs?{83n~9Z|~SxC_&^hva)u*@lLxC zo;%kh0n4M!06dPSwr&7O98L_3K0mR}xC@^i`@AFf%d+E~Y*)5>;r+wH>E6SKkszu= zL1Vh(=P~A|qo>(EFO__DE_AW zv9hTtGb1C^qM@!1rgIUe-9l|0 zFUvVvc`d93+@a+46N7FV8jRc8vm6vm1d4@&oW4ys=&1pkY;mkoWShGW(gmG*|8$mI z$%%3cer2uv3+l@oBs`sea>eE}o*>zDuYIk3ZX8KzX;(Gucdk_`td9RdS;^Ps(Bdp( zzow{ClfCHuhYyRpJX$yEF6dHZb5RL9A{g-{I8n>VLhu5nQ4_^5XH@W?RV z`8Qa$);}Ol&tSw+jac)Yf5H=Vp$HutrWYmZoEbE3+W+JmGY_*SscBYb-}dI^LqMo z2J1QAk&Ws93CU$D-qhm@7v63;@R+n?qr}U&<;%`D&;XYlf=}b;&+4frs%X^4U5I+F z`P%jCyI{2l)|-#?cDM~-kRimke*M$RN^5xk-;zk9*y`}JpXqdbQ*aT!@BLVpP)~QH zoF@Ft?c49*E_NmI67flO&Hjn~JrRk$A3m&z@Ob(?Lpb(rH8M558|}Sv*M+-FegJmS zB?TOdxqcxud|pNrlF>tF%Va10?6oazt?ONFcMJ?N{7Vt}-xCsn|0sc-_FrB5~F5Ul2B2?`e)zJU&($n_jI_nrvPviK|%0s!K$csD3PW8k)R$O z!e{qLmw591@>5ZIKWUx`yD^woymriL?*y4$#$*-u3_fC@56CnGe6R6f0HA0BQbc;X zBRmojVK^Npnjd0~Q%nnZe<=-C;gf-bnCYNvN2=|$f`AUlB8r64k-6y>vM-9o@s^th z?)tKb$!AmMSk8^X92NHO9~l`jN^zC_7sSZ-qRRNewu@DD8P8drw(z^gW~zw%;F5;z zjhM@f2Gu=ax1oG?*r{V~4k%P(_wL==+RSUOMnx%S!6rjz%>^dU70;TPk9c1zFB%}* zZby3h&!M=d0>?HsHp$rP$5~m>|0&(Cr(U}BlIViF-v^`UR#>MFzx!4jHzcU@LE)st zNL~kDcuMq<>BWl|7wAyUZe^^A$E^-JHigOp1NG%DQc|R8YRJz>zo<%<(I3lB!^jo3 z1l0rRXz-FcGVN~9h0*QXgB%E4pQTqQLJzflc6N4R3$~awS+LU0D=2c1k@{ob(Q926%`|cgEw0WXs>O% zzV6kH$IXw^jhQo2ID%M6w*DQEHu%mR6ADcX8<}3SZKEhn9dq*R!m{4{-)=6C^P4VZ= z_LnpG18S97QoS!U^7}=$qon#08c-QN#-IGOm;DyyMGVBUB4C3hzlh--MX$>qxZdB1 zw1s|u+C2Wt%`8{( z_?1?bsd7r#?{PHEWvtjR3<3AA$|U8Vwzleja7Lg4|D^<+G@}zz8tygD@LVIsN@kRQkwt_jUH$Lzh=^gLPUm z&dk72Qei+Pat@#>*0{Ex9GBqHO1~nmTdVseXWa#GNr1T$OR-u}v~2$e9Zigj+bAe_ zDDD7kDT0M4Zzo|H1k?ret5)>^BYpY&xv_BGN%?|*0zUt~ZNHXvJ(6$BXA&;tT$_lj z5$idsw06ac?O4_lxnJg74Fm#mK^!7&?vLMM1P=-W078rrz!gIC($&?~$3=H7(5kPm zZ--SY?cz$BrTUh>_dPXQwu|h@U;XEyF$j}8c)uRj_Q_S2?2TB2fB{jHm9nzm?c2t) z$(IsVyIr3?<)QlnECi+);T!;O5nv>#4#GjVw{Cw&F;}eOf~>oKFPjf_#Mt?Seeu=; z;Sc#3bjDYdl(I4~+&OTUo=4pubvyA!7d|{J>M~-{b9R~zWESbhTJ4Xz;80I(4xond z(5CHy9llTx=%2K+!>9zaB0VKZ>zo|I4Cw}+-Z@WC@^QoRvNGq_pCSu>CIv;+E59B+ zrhZw2r43cppG9u4yw`Ky^ESQN?iQ3 znQuoF^fk7Ni?Wu(Z7vr!W-&!!_wH@B?TwG;uqj+86)J4tGso;vj3t;o3m>GW2A6w2 z2v(eiYQsMIZDsg(aB2%X4|^B-d&o<&ZQm|w6T=z9Fsh^F*crK>xkN2n|JMq7%%kkb z{4w*~W6cGBDWTUBCA7`K;vO{dC@5V$tNF$*(Md?;VFf2(-jEO>o6fx|;CjS#Lz1R4-Xs7Q{G4WC10&rj7!p+3{h?iOyQ#AlV*m&_}hj6zKQS zOOk7jUBCD}Z01r@MR@u79ZS+*On_c!kk>R*OE3Cakdhg0`lTKP!S-10X%TL2Zxel3 zrpwD;mX2NSN^Z!$TYI4QFK=tE;RxQ4U_CZEM&P%9>xT;gwEo@?^X)6q6%n-EC}q8p zugT{G2t2k*8=nN7dAp$0kf!P3ojbbOpgDraOy6VISF@4-R!q!UK}NE#XE67|Z6fnd z5Ws#|HY`(5Lz#1AgvP#{q65Qn|V1CbnQD=grty5TzjFQqXD3b&c@Ja{HE5 zCFkOjeIisil`o3uyPxKkD8s8{LoqfWQ2KDJuZ4|tbB1*XJXzoM_XG9NGs{RUPEQvi zL^>-UUQ}!^cvsG|@^6$r;HLk89kGhZb}&XJk=wiH;4BUP-+_-Vn$tUC4!q#^GKf%r z7WvVb?nlO7x*GfLrcW2D^oBBTF=#T`Z~3V`2Y|~iml2);X$Ayz>@Gs#3d;Em762x` zDNrrG(e&uzcvbeI3tJcPFU?WV9rHK!LyiqI7f27&^1fIZuEF(_;}gC?#`lsk#nH0z zmmL<3yK`J;0q%s-Jcv(t{ET=fIhxb>SSK8#l9TykzRY#_h3|&?YM<3(R=liGJvOPR zRg>p*MY-fp=F2UbXQVW1&`npCmC;4f_9V^G+l9Ckeg)6ca+Vw7y}|JDRtp%7m`yS? zPx}*I61#8A)5H*MewE7GueG0YTzihK;7$XL9*=i>53KPxly5w!?ZfmF&T1S=*SZD9 zsy5f88dtJx-I@R;D4HG*4-W)&h|P9_$t435W?FJ=(o$@@b&bClF_UlhHmj^zPw$r6V=qh?Sit3{Yu9TsnM2`oXotoO( z(vB4qf~Wq1SvTgxuMC-C+wo%m={mNu*y=Tl)x&N8@}9U~{~o?WST! zeFnvs1S}>5PP^XxR2x2*B}PZUn&zPY3O(N3CL zbwP+PPX?28Qnj%413umS0n8bLbrCR;HLtS0PcaY7#kV}m^{9F zchkm=`(mpvopX^{FD~v@ba|D1g!awvxVp!<$Og!`47kg%e{ylA$_$*Xm3glgS<-Ao zq}rN0)(LUX%ojg*zAkJn!kaE-U19rnYcKa|0~g1$Gpv_+cK;?0#PAeob>;q!p^~R@ zs*Dk(>5otOhlMfxR?ys@jEn!P3U=pa35h6s(9AJn*Zcf}8|k;_qv`e|RcxA4(%-r{ zB}}cXazQWvGk8F^KPqu{B+gpnsd$wu`2QocsV%s9Cy2mfmhrRh%mC=pEH83;jL${k zk%{Wkx2`LT&G-I(ZQlgSK~r62B7gz`O0gfDrhKdKZ?Ah(8S;(ONRu($`q=5GS8&2MjxWPJV85DLP;>&1|GTEeTq*`KPw!PS&L8sLABcQ3W1?Tf zKOxa%FCPLsY~i>Y6^HT9^ZfdD*J@Qqvg?u?|Wg+`$G5LYXhx4_n~0G z!p;C07L7EsLr0I^=neNTo*s4gsLR_kpEUtqN_J zL1^1%nV*#nTkzkW?#EocL@Brye@9^dvE_I6a;xe386UwA*Ar1PO_49c<&$TT-t;tj0_{92? zOrE>|wC3V%+rE!6-Uz5q0!BJ;zaF*o3i}x*XXQ27Ypx7}sk#*e9+UM|_vju5K_PJ9 zIIvo=%ZZ$>&IW+ko(8*5jHy(g=OPC3BYaevA*(mq+Co1K$_R=fy{PYV{M~wgdkwKy zqJpRk?vJ@R;GCqG>A zjBlKZhqZ!GxOU{Wf=yo*f;YNug(^qG`)=n+8HtH%EGal*vxbj!+y@uzHvIIk1Vq7z zy@i~b`O=ju?Ct`KTxH0^uj}NqCm%AvPlFOksA(JbT#B?cN})}WL%Amb>O^;j1&Xh3 z>(Iwhg6jM0HLL`Gp%xrznQTh1dqT4{4l{a*Z+;K>-8xv-{}AIo0&wzOjeEY*f?WyY zg)fjym6uz9Y;9tK%;e+ecRLn1abE~jtBZmuWn5izK;h?3cw+mpRitwO>!aZA=M0}zf z7L5y@?(*3IGf5FXzICantl;pQgC5N!m_-C%g*o|9H_&%$*AH67#~$5o+-jUonWWdt z{^9+5V&xxLA=pGoWmrP4FLKEEk7Mrl*;|40hSSW;B=V!nlw4a3^eXwd6n`54Wz~MW zElL*{6l9DAf*(IVsy2Z~SS09cWUyTSPDL9sF2+(h*6Gil-I_IkZUJ>+p%dy=N=vrp z)$>3gx%zRKm$)Fkzya!APY-F9Tv*{D-q_wvnbR%laa|7%-pgi6ryO+0 z8D-4_m3Js=QfXOhIcx)HSy=WO(qAe-++iLh_mP6ysr zbpIPxvyb|HmEb{xkC!Uxy$zVbGbyCN$9n$j&DUfhArPgFxIfmsb!`eTXW(b$Kb3qF zk+tS*h=ks9M5;5YtKVXr7=NtdxPYoeBjD@cAhevl*>*fHn)35WRO|Eech^9k`#iVZicexe%Y{Z=0Xa#G<**SC zrbJ37LFaJ%*jhU13~3<;`H~bT`|Jk~EYL8p=R5T$J;zFR$!ta%feg0w^SFx7B`qt- zepI9459UwFx_6$V_;SK3_sFily>{^PVFwJ5e%RSnQ?nU7UyXAX;J&aYH~b5{BV%0= zE8WGu_Po$b)UtD)BH$TN(a=OmxVt$x2)6n7`o@bvs0GADOH;GN9~)v5G}GjJ_Z)1A zwWe72t?4WU4CRchDfo88_4F9=tK6@@_T<>pg7-!QDV#ucoa7DG;{zc@8pIhm*hgPf zZe&0wpU-u9umfdbr0B`O4h~z*%PnWF1_uXU@bJJ!4hkQXjYTwWpU*?4|1djS%Ov!Q z>aOg3(ts2;!hUD(aIe^skheTSLa%CTw?pzo@der_DD>};+pS2{xb#vmAgNm_x&^Yy z;V)lMP_JVJ$g;$RCDdeH+p1S1@k$X!yW|C`S}*UNr=wUaYVIgjcj)PFz3loRr_T48s5h#gWL%hHZ|UsW)2na~g!efv#hzDx!H)cjqosXFfb8q7 zc=4_Ji1Cqw2NQLmZR+~;B5J3@W#MgZ&skdH6Z#N%X?@EoD^EH)#-HR=caqwTjHdA# z^ZO|5BS%bxfIL7@LtSUjp0g!v*K1%)U|LHI_AVou@tiIwXM?@fVm{5Aif+b)l`MP; zh+48!NOwivWZNeM5hdP!bT!;YQ}5t%55s0pPfvFwp>w%(+cb?=Gf?v%G`OeI{SLg7 zcUU87!N18Ec+KIv2hnCe@Y2^?I6{$hBJc`$rTYE&pCB1yl?B<}{4&O5kCsZ4UW_7X zqxZr7vE?J|q+1@yE}F-6OUg@My?pteN8F{0Q8(14Y7XS*pLx83M2e7}|K8_LCFa&( zigx_dD$c)=K2{ij^pU6n$A-CjZd;HnnNaIH>|V%8>;tE-U{-v_>l!uw3sU9hg!KPP z=3vYHJ9pNt=@(io|C1I%`32sYF!#@Wcf+Nksc9TE+d3;fhgmV&3Hh6g16OH`T?pSt z0Pwm8_l^VK1p$e$^~H-+wpo*S9)w1>Pc9uU$Q=`tlNU#j<{JQtU?eITyXZ<;(_#;= zrK`dnITp%Hi_a4L70Wb~l$JGBeHi}nYE`5ecScs2CZ@|s(7rL~C6{#L-Z%SBg+wl= z1)ilp{EY0tFER~uxE3UTw7J?G+XRLOey}*_Lthtr>ZU<+pDi3yB-dVaE3KB~Pz}Dd zy@{Qv!jTf_vP%YE6m z8{*kteD(R|jFaVpFBxRBx()>dt=mYfM@+KfpfVj2lmKX+D)E*8&;%uB0knRdy@lG5 zrJE=tO3JtVxO?m3xBzIlgVxpnLODFT)?1Nk18kCng_fgZdX=pB3^oF}Vj&mGEc#{{ z>P?lrx?8C4l}LI+SFag%MoiLTR}k23@XE)(!Sqq$R$X_kpy{5Z^z@MCpuoVe!~;=) zC5vO#xkYYXT;(-in0h&3!0VB3W+I3yU~tw9VEqv0yh|-Zg9FrG%l_GZ@dhyj>H=@|7PFZiFSbQ#C##Z4)q|LK84hlzd&*h+mFa%0mNZ2NQb2~ z(k+^BiTctr8>V0;bJm`a?R{XQ+WL=b&rHvOBPgc$VZma}u?s%4hm50)SOq&=f20H3 zuZcY!okDyIv4O}O)E5F->h~yz;RS18KB1-6vVG~{f|9eB-1$9G z3Iv)~iPLlFM$oSD@K^?$p=X>nMAeo|+pO1?go(P8XxOzFFGrgphrU|d9$bf*S{gN~VmH_@Zq`xtcg-Y>CVgS5h z$l`kI)c=qL@@4F_D^;PQN}ZzgCYTwr8_ICEut1mCzWMo_*d}7teLAo*(=F?bq74wk?Z;(B9pR_ zDTaP@P7P>E8wWKY9dBl8ssMZ)E{%N`bMzdDx+S=I^X1h2 z;rxKyynN`Cid!#Vm|qKI){pdN96&u!hye*fNaNW(?1~orex=8ktq3}fT2TUSI_U~= z;g@2gy-k@7&(fXw3%+f_pvWO@XyMlV`oLhVHdA%j4_6)jp1G;thEUdjP{#57ohEwY zD+rWPc3l~ELQ^kW_6=H^XUlfep{y%?r#!v-Lh;N*!VHlpv2L~wyuH+~`_83MHI_@= zFQMjqc6h-&C$atq1H(f@{_9?17GGF+92WVQ7#C=&!U$DG1*Gl>h$@MlDU*|T+dyC9 zn(&nc+Tra@<(kK1S<`2aZ}m(IscO!Pr)kH*Mx}0#rv;7Z!g_=0XT1aV-DV%$%3}^! zL6fv*l*64bD=Yol%*72tM&H3wR(facPc2W_GgW%71%Cu&dVa6MZs>j3>#XL<5^ugB z8JFsuhW53}(w0%`(Qc1)KmNn61w`?_e3hYdM z2xTx3fOP`4273`jIcZYZUT9w$STGL~Yt(4*{tI#Um@>wp|BJXg5l?Bh@@l;J)Mu%Y zGRI~CyB@{l>eg1p3IE;I&!69pjy}U2TC&q6Spcg%mLXiEZkqEC*k3By$Ni&Pl^LqC z=sHz%mBgfH6J=c0oqF0c=k{f zA5n93@6C*j?IKtrsBiXtav_Z^!0;gh4vwe-i5gDQ1>i6?Mn64IP5=rqkyIN_Ixd*} zT}Tm=KKfO85FMz}%d;D|A2_bq&e+k^guz6}4}#M0t&bnAXlVT4HvB3$GIHSU+kF`q z4LLm$1@^f?5ATkkP!JChQIxgywYLPEmAjeNoz(G=;`f+N+JRDLxVyX77p zxQmHI6RpRWU0Zds_VPfsbMEMj+Il;p!hJ3F`OstjW6=VH>x)0>U^I{;sk((xQ+R zHsI>i*J3;^m~=qFZGu(9P`my9qemPw4}TDe&G!wtYyTX2D$02=nHmEtLaYImTTe|( zYfW3+^ZF0N7Cd6Sl+3*92ul*LFj%)`Z4_YYqNNHZ`(wiQ zo#J#Ro68+Zth+f-Thkqld8g1iQV==aKc8nMY}+wx-LSo8CJi1>%HrdDs~V0zj?y`^ zLB(L-eE-1m`jOl(-iLk=z}$xJKbwO+7u7d6m+`=F?bT(I+F3D^uFXmsCO0b=t`bY;2P;Y_Gdmme ziKKXp{HixqCu@U#p9UKZ)$EHhhnXsaa;+0!!2V%BSs{$Z8Yf41UjOxTOm6q0FE~j> zA*1nGw=%S!*r;LqRz7PjJ-s8GMPdea1?Y+t5-nA}YVevhYp~^!npv2S&f1E!l@Q8* zmtsM@wCy;`15Av^;WLYshD#=zDW0cLoglwlzL+xP_^SC`zqaMpAF7>uUtC=-phts5 z3SOQ-bLI#~0W-bOuKhoTpt|xyyY=XVK=u4C6=mM>lMD6mSe_dm0uCG9T(?R=g}$r_ zs!>M9=p5rpUS1yV%;Aki#l?Yl0~zV83CN!+=84P-ixb{Yb80M%Zv} zkaiX+B-Hfz3c=Vbw48}aQ&n}n6$yV2>&)15tRt6z!w{r>vrTF^^sCc5DkDWXd(Eky zRPgfA?GD%{ob@aDD6_fUbNFgdU>u*%i(a|w0(vj_j+TkQX6Sy(0Q`3Yg5g7C<(op*$8(x)9(|vjl zkip@m8<`fCJEqK z|LJ+lyE|+H65VH}u~(9xDu-!(=z?=c<6~q9&=ZY;8#;(w5I4IAcej?ZZAfBHD&0jO z^OO6=^JXUVAR3&&j&rcCrCQ0D&!(rR12;(knm?7PTa1A^%u5H_b0*;sct1M9q0!y( zYyjzHo`ULCzc`d4!cY*yxQfQ_!#E}Skt=eFir6K5ukjv_Rr?dT5DT+C{aM%?rPlo; zmVYi|54n2vWu)klxC4-R9+&ZDUM`e${TiPihXtJ#DmZXqismX8ER`zQ+RI25b(?kN zN^typK!yXhGd=AVWBkh;GgWhoW!yi&pxj>t8W-!--$&=JRh8=;{)QrGSx`6KvKg+IILajhyf8S;+J`-tU#mXSr1@ljj2y}h z>5Sta`g|WV$`EQFQ`&1IH6MlvAyU7L$K zdQEhySA?CD_Pr|{b0Ya^_>8lL`)Ia~%j^Ck@x)Pa*hl-ZRvi7X%b3Rd+keX$Y zd~x95mE3`=K|vcVRGqQ;JIjHl>C3AKft9Dq&@Yv)UL#~7JhpDahO3;ax`R#_cH*?p zM_yY~-qDp@4nO{vv3}yt@L?F-$*lC5<>q1&`7!|D5!;P@VWX1RO-e6qWd)5LD^}Kk z4cr?7UN|_(yxNaHKlQyV;KR#xyrg8QsgS@C>3D2lyP}-Xedh>s)!J7h(O13!6;;Qy z>3EHKmi}d7;=g*UIdfLOyMLl5V^Ilxy4tph^ds>4OWZfMh;PET9gtYx2s}6^#IJqk z>3O(gB0!^41*QDZCfMS@BT_5XB%q4D_{p&2^wjv0RhvQfmTomJzQR~=Y*cl<>uSH; z#izyx-~M=%#;9Oa$^yFiXW*6Qzq}~@>^|`8Twv(W!ot#hV+0{BaEo!}je+|64VcAA zTB%uBQ%=gP4i+;o@DNyYjeCPy$qSO=+ed8cxT$-2IXFDZLmSr!oGFCA-L3feWYXm% z`6NTv9)+<{zZxOQ?+k92(+(Jxa1j5%Ipx4Qm^N{2)U@^S7c^?Xv~$6LF{{6asez{e z__A@BZb8K>3c^Ep8~E7w@`jDLr_bx5N@b_Kin;c=x_gHdoXRdxu3&MW`U32gMZ~rn zyBq+y5IX^!Sf5$vjE{{ehV$=pl6`{wg&Vs0o3nzPdz&#nAZkF&c;Pwmb!e!+?rzXS zZJOt9PBhgE`xVP>orly1o=q4eGzukVLCk^ufdzmEhTqrkE246PO}4?V;IR)8j=sEH ztMPeLj188YV$2^KlJ|8kTF|zNo<2}yd**tX1;JjZ8k1saN%9$feGjRt^1^#XPxfx8 zy}>!do#SJYJ(GR}_V-Y);5$N1!HS*OseuDPGYwq8P=Lx`y;I8?&UNVR+~MPK???g* z6B84mp}q(qD4ycMfw;0l8j03qLxl;MlVKEfkVMImzj*_E4%_*X;PO79(tK=p#2p-r zUE|$BQXWf1Tqgu9wAh&@XImZZkX`23*W5A`?M;jid^ zgB1mYl#h{d9A?CcI-j_0?DvRBN*jfV%|8ogZ1CHjZHq`qjN%*Yi&oksqU)l+J-Gko zUF-pQ4;n-hIKr-DnAT(I>62F?`D zLkqa<9qu#WG6n=&xk}IV65fb{?pHFN2279em;JuPG-8$Xh zn1sy^%a{auVJ_7Sj3;aas5_OhNz>Z zstLj*#b*)PNW80m#)(2vFZ%PNv|G-|5jZ7SLcUPoVNTB4OTO+M)|!W5`z<3MHdE}E zm8GDd2-{)J!niMWm74elEV=pLZ_0_YTAz3=mx2Z{@NpUH-G&GOP%Y^jNidFfadC0F zN%c*PFMyGphDR`TnyMEzMJ27@phY*xf96ZyRp#N#q`J&RJWFKw8JQo$@e`F+vi07x zBKUVYkqV;aPQgX3yQQ|amRPrFK|?YLh?QGJ1f^)j^z<~4Yt+FTx|XPk7vc-E;0vo& zefUP3(@DZWj+jEiBc0H9c~hq@<~lqd=islx2rv52DD5#+G{c$g7bHtr-}e|Ru@I%* zzZ9)TRa_`UYLbDQ2?YlX-k|n8^hldgP5d~1f&o8~@^3%!;1kLRtf#+{wDUknV#EVO zgjQ$_`s){`WTO6t9XH&}N}*{7U(C;vjO!xUq|p4s2jLz>1Ypw{L_8(A&c5Nf@SX#{ zdyvRza@uLCxv9_C5D$>A|4)n{;aO-%$!OG? z#~2^;?hiF_-VqTkm@h{{$l__;x(0sljkq+4_=TjJao;ukGP%w2@B?b zx_ma3kTVN#>p!M79HpY91kB`@xLl5rS!QPz-uSx@A4E-SZV@Cg?60>*)2OcAh=J=z z^cC*Pq*ZGI`AHZ&1w;mCU*)=Eq$KKBj@GVHd-fFY>6v}eJPV|V^8}<8%nP`N5wM9B z{^sWaYjqHNVx@hSEL{qM=+uXVJV-mR==u#V{)!cLBmEjS$|O1KHj$pODdCWz{@2&R zj5!HL0pBJ^B^=(bZ1K3Y)b|#D7BoCCtd;g<#@{Q;Vq|QLoff5qgM>Ui5ix9_N ziZ6&>Is0Y~2F7yy>p#B;^suO1r;@>m0c)WtebPVpsZE_s16mHb;@b%cus<^I3jy_= zSoMirz*eswG~qBlV`ZUIVUjH)(Pe<J834|GdgaywR>%Uy3kP!Rbni@aCW2s7}Kb z$LS^ZixGuyG4dcG2gN~0EC&4(If+(`bochz!{QPcEB0?^FPa&wuA68u@rBdhHQXTn z`hI2|bdDJ24nvCk_{1ChU(b{<#zWnAJv)06YvR%JSQA67#fd9szi(t|(%yf41YVrG z1eh^l_yM%u$Y(EQAiuD0e6<6R0o-zjf#zXUGe*}iCJVTBZRd&CyWv@ci#pJj9ok0{ zO+9;k)NBvN9APHu+MP=_KX8$F@77poxE0{tx^=qPzYYeLeoOFr+@KRz9sx~;*Rygs z|62rIU3dUMWs4)$g2owk&Olti2}u?s>7G49C)i~){`C<;un%Flj5`5?VK?wuEVSf^ z_cSKmfPV@^;Drkp3R$(5q_<%cZw$z~uy{mP-VPTtuuumUtUGsWDM|6uQ0BOQ{R$T7 z(KkRr3)~*S9NxZu#K0MxRJCi>X}BI30}{*Dk)SMET#-}OKgFVYu^l@yjvRAEr!kBH zw2|ln;yD6>IYci1+dbaR2+wkp`g`>VCl8ayRN2@KPh3CX`v@5iYmtc3SR=U`=$A!G z3AWIu0b@X$+yvl*jZGi2!}s5wHqE}PV1AJ$|Mn>PF#v{Fz=xli`H91a!|6&J@FUDR z(nqYUK4N=!2Y5N~bV^t1L}>}f6qNk%i6O=wBcD1dM@Vj8Al_Asf-O(YR>a=F1q||W z{5$An`aXVSS-txC==$qRiJ!=kZU9#iF#;NI*h<>sWTk6VAWITPmhiB~UIBFb%p$fI z1{PG{8WAy>sQ3SVrhNSa13N!`l7Kv=<}?K-DG~5Gs&Q7+KvkO@AAhKm9b%~lOUHma zckbYy#uvhY!dy9>TzJ7;h$i|V6d&VEe`Jr|4`|Ve42`n{vTtGfRchi&Y>-|(PTyO1 zw-!rnvD>LM{Vpy;K8iWu+a1_!16mw{_vL{FuP)BMq}kg3@9!u_JI7g&pTA~~4u(mv zVT8gmB6RGD{Q&wed@_M5U-I(GJoS~MMLQ5Vks#Wj^y+=}umusteR5z&I=MRjEJW`g zbEeycFh~_Ss887VEvp8XRh@LmFj` zc>-hv7hKr1h8@K*oR)BwS;bF>4J_jD{IB<9MU363sLZh<3=U|GLgc%VdNxH=JD{`y z-5lc&6h^HOHd(&XN5c%|J!gk2cyho;>c3TLNuJtsfQ+Q8>U&}Pm()o@9`SMn8x5SD zoSqdG;k0{OIughAdNQ*P3?`U`Pw2|ZmVh4LBs2itAfzxm?R#G%se(a@!Zz5pp0;fD ze|-f3R5*_M`Zobh!dMYR(Iz7qB8P68tOf?avT~&WCM9qTP4{^Lkh!a~(|M#Hqn?qE z*`GjB75?aV>|EFE#qRxH9{#OJal=w2Qw(8Iq{9-SN$9y0@e85V4qe5|CYDD|OizD+ z=PxSr3FuldMkh!#I2pL8dZK4l*AsdAfBo|;X!+Lg>F!3H0kf+yJ()O0YQC`_AZ)-; z5@`*;uh$~~jv(8-@nl7L2kq?&Iy$;lt1e2sFg`t-OPx2$%+{ZSf+S~(dIfd1?PGob zYP0&HGCGyes3-}?esw_fn3fHG6Fn+h_FDL@corB4bj-}m^z=Q^9Z6_5I`E64j{UN^ zp>XBRL2rP1DkUH z5K~G|9@ErhYKgxOUVwjBq=4xGSQDWRxuY73TH^SHL#H|a^I8;x4q1ms!5{t&k7A*f zNgStb&ArW;cE+C6YcYE~i9HVKFBj|wDHhA1jvPG|hi(x87)uw#?0aePAdCL%K^CFW zN2g0Ut2c(v3QLQ2JMqSr3TJ^d859=Q+tsxl_kbvTnzj+;L3p@`VOcP)IIh#uH9|a_ zHkIyiUr1~4U#IKLV`x1L3~q&nHXw(h#w-$ALrR2PJ(s!UQuDxa%BmTOn72HAaX&P4kt>4<7~HYJ6p8V38)WJAHxL&ekrda}7PfP< zIqgLu3iTWmNCYJSrMnp*D`E$)<1%UnzGxJwsPVv?z~fC~4RO<>b!Y$U@yL*I zSj101M!x`^9xhmsPy}v@ul<~dHAxh z3_u+7JZ!&u_WXH7XM-Jp=S%=tNUs+>JyGyBzkEr|D$z)qg3XM1byNF(R9*kGO4Anu z8ci(qgee2mcpz*y8r2e!Dyh78Ck7)+vQ=ADHC~SnB-O%j71I1oxRqH2EEgrHmE+8di-f4fy zGJO&81wZ)AenGAD@`i?!I3)CA-`ddR5kwjQ z;7y!i{~5y;3RyH(;SPZikBAs)nL~J-|qMaxbf6o42Pa7Ws6H3G=Tm!qcwXM}{dB6qdF|?aPLXM4zdcYNwt_eUf z^S&*66xHp!%BVcOLb94Sc!2)evN`bM-^=G`_5_gt2p*mYD~SruSSyOob^>3oJi-m! zHQH*2|7Zms+hXK^*0wq6xD5QXf;Xv=(XdQmH_t0z4^t92Q~;0QEG&Wj%m6IkPQHng zEsOR>9+=^<1-=<+n~S_+u$UN`ywe7HUsN2}_~cZI(++A@ah~=ToSWq5q;L2BOFxt{ zf!J0=6P|p*bg>jLHAa4eOL=+j2Mz=tl2BJ(Oa!kKpGR1%fRB%BwiYW&EbTZ@NL4`D zR#Jk60b%@xOGMTa$W!a%B$yrnlQ$4AY}90BFMZ}o!jjv@oby+6E6m^EaD5<&6Fxb>AJ9bN{}7 z+k{F(Xm1TgB@IoXyS*35Xhp>OXJiki@d_-hl$RnoFO@@pk+{uHM zc#w5|WHS*F&oI-4PI2rtU?Ru7!{E7gRQS!Htp-S<2E!R}46uG154JTS5<-;bkFSo= zmQ!z&fxi%K6RC>#fys`$0PPSS+9(joQEve|sK31Q?s2@PX^N;d6}jz zotj~SxlwMK5Ni%>Ss0f?l7<=fp1aV$+enQ8mijnT*!mbH>l@GZGk6Vh%l0qvo0;0A za0k!clA7D_&h%0x!~(ic(Ir-IXa%!{tZR$TUtNjQiyNzDp969dw8B0oIDTv`5+7KN zNxq^qDXFR9ImE32QrN6;Xz%~HhTwLQJcco%_9CuAiOsb^Vjs0(rJ9O)tQ`6 z*oTclftKoEMBq@K3)uScfRA)zaW3vWhsYA9nYa7yT-O-59cX2>Agbty?L`ZqBn91v zL+{{yq&A93XEVggWT`2|O7-GDId!kUfO zBA2YwghA)~&Q6Bas{s{n*U;4kMUKAg%WYU%oaazzX>1%mCw_bFBk=&Ug~Y85znBF$ z1}CYxq2VLG&LztLi~Rj7N~~_~P&qYy;3=XQE}6CtgepdAYHBEe5#KeUXnH%XaD(f% zQQ5H_o!}n`Dz9j(hk%y8EA%eS#56vMrAA{H5itHEk5V^a#0QWTS9-(F^p9%;F z@(X={F-u~PLziiCAn$tmg5VvDf{(E9s25P_3x#kDT65)g8`iAJa*l``>^P<LDsrjmH()UbL`5OZC zrnCD=q>Nwv-1RpJ1MLG<&^Q_ibT2gs-#j(ah?E#X%ckt)J-oGP@O{eV%sC3I*?@d9Hk4J%?W^Uw;MC_%;vioT-}Ni0b(Y=5J7P;)r;NaeEaCI?dNSzPKiwqbW~iK zRw+O}6E5!qPTZLlyzoBJb#*EC`cmsuq4U{FgLid|&r>{l5P7=*KTKwwD&Xef<~|`N z6Ds3&H|S~w`&vT8I5G70!t`mj0+?d#X@GD^hpq=O9%a#3NiWO0st2x!uGcE0UlzOU zE0yRW$eMs4!$-O2MJqbs$>!5>bQE2#qjWG-23-s1$Dco#=-HwZeh3Y;_-anZ@hdZv zfyb=qR!byf%dHQEIrkt}bHhrW*Uj~P|12F(yw2?zm)o@CA_;QT?|{cuA5@~(&H#`V zp6w)&4#O+j9MKdUrw>dsB`h%TQ1M@QGycvV5D7jG3}}m;aKli5ijRYXicmd6w3qU{ z?#FsA!E4lpn22L1Y1dW$_0?f_cLm?^{3E=*0pxnVrFfwO#kRw{Q%+V^7Ci1OZ*2^P z5wlvpYW;Ds{VPzRBxUS0LJaSF&+;_i-q59SsrW6f%^4#o#CU0SP;D;B7Q0%(y~4|IZXfT+#9)7m;gOxj$w4B9&uz{%x6M@4^(KF9Lfe3Kpc8M)1@Y=vB>Z7=I@tdy zrTa&hab$Ef7&OhGAbVtixXRG=Hy_hGKxCS!upa{v0K<0Abwm1n zHNsK46~tU*?Mf)Y0FR>(dC;IZAzHEz`c-gWyU^o!K z;EP|K^xX>@6u$1nsuNW6!Z~bQnEce(XgKz4<2BUAXkWq#8{0Bx`u?sUq7YnPY7KbA z7t4#hmTyxQH1gYuJy#%e*V5G7cZEdpNBJBK2(%0MFlLI+;|81@bl1z2|};80fYnYntzn&2j&L1T^b9DT&m z;o%I!RN8M>e6$Ng1~8i&#k9>86NYBK2?*_dCqLJGr+YDNIk9ZpX`kiyt4#OLQx2`1 z{X)8UmBIfinnRMgfM0iDij9@1c!HlYGcs;Dy+J;A4r!S!#9TxVeciG}`}4%Fw%tGl~>G&4lOh{SDIv82m^o zQF$Th^*w#!iwwDK75Ux-KAr$1s?K&Fo@U-6#nFRl1hN#k&kd+iJbNRFbef5ox%yQl zssCyO8)`xqlrz{wfC%6Wf5wz+dyIg?z%T%u=n8SJSg`@`4<2IxRZJ^aUa#W5Juz4Y zUd#N23kO?^bZ@aQkRXvZWd=x-n9_AjrGDVUy-O%dNiy7-{ELYDQ`1|C-gI;|nv##d zfAB_G3>-$uPPF7v_oC=T4h%g_Tv?en_Gbq2rLAgeH?TW`f<3^1JMGFLaYQEJi+Qcv zE^;`P&B(g04VgnKwqKV&=c@Wd{`R0Br$TqFCF#x*`*pI!<&fFNLQt_pL67l~2}^=0 z-!#BVBxs7b->7YP`S_CYl;W;BnwhPtOD6se7;)f3;ptzq@j&dR=_9w)i^W!@#>3=xwvj)8?AgO7?21m@!{ z9$iAZs^w4z6f5}NhSHouJFVJhBm=NT6xr(ZS2FhC;@}yDm=$I;ZxOPegIJF`1vloI z5SY}j@Oq;Z&FNZonM7{nGY^l@W+)1&BC878$MboHbv6rT@z-~X?k}I(dvs^zyQ+vS4s|mi3G%;gz9T(=Aski@6ql2j_W!n8%NED1 zQC|6C^f=vi*9Zy&f~!29#B{`7%nh?_<$eDm^FwE+>UiFk)uI>p_J^gAb1&(3-aWxr z9j?}Zzl<+`WeZ6!S|Hbxv)Nf#Xnn+VsL7Q}>$YtT zF7;Thq`z2C;y!MPEgOiWC-fGMFLhBV9m$yF7^tu>ntPNI2y z!?J7?*r83$1~V3c?N8jDxqYOO{;HaVChd=Fiz%gD$|(!=z`1;VFO?+1LEG{N8TfoIAc2OPxq-!{V|&&ECaxdop*H zQOhX0)T}VSQ+ksZN4_rq1b=tCdn)M!i=w;GXQ-Q8I7dtU_mfI5@aUOT{1hrNM}K|p znbLKn;wy*lSH*iNXCpI=4)#B-5_!^^L`f~CJ8Gg{ zL(gzxxv&e;X{00QkD&G`G0C(*UO&y5Rl({Ua-CO1Bm<=ya+VurH#-@1H-83#gZ^7i zyv7?~0=QSBm(A8I{=TLwB2-dR`XaCECv8K#MZ~-7LCumf-!WQJTXA)+gZG_4UfKH2 zGyZd%SBG3yW!T`!AjnAa&ZT0SHE!hy9413u%OFkzg$;LOpS)1`qmohOU8h}>zn`_N zzO$k~gRoxdD#I2!`#B8@b0fFCh^1|C=kZ)syOk$&UHc$v)M*Q*Z?d{~)ee%qW5w|qL3n&fcnB+DjK6}k% zIxbOdn(83(xp5>}Ld<)8#24M+I_Qdo}VIr8vTsh*a3 z?i(V+zaMfJZBy%*@8nnFkVn5_mE`eh(@QyZ=KSjI2bV67lRn=uwy{0;(3VO@-4_un zS+@w@l0Q~?1iu`w37=(MQslg0Zr09gJkrtxR}EYfJOG2harOrWa;R+z+q)YtRdQAu zCdDBHpaR=cv~-UBQA4FOVP0%?RqQ~j;=`M=iDi!$7 z5C--ZsoHVdIM6RJJHm7Cu?!sE@NZXI1YtNPv^JK#WL-@amAh#6;ELB7qD+&7&1+%> zb?J%3zm_*V7$!sHX-GC%Vo!BPUcP)I%!AyBg7g3?wsJ4`u&13}U7W%?AB6jM2|Z%& z`8Kmp7PNxrAp;Q|1xzNfuLylpztN6n1wkioNDz0$o$Xvm8=sNZ-5Cj zuE0p5qj1!tm-!V2v0E&co&FKo{y1%|v`!W3!TU7MTpE~L>$JyfZ~l?4xUP=D7uoWS z;hQn_?Xja?D3B=QG(Bz%s&-nNGGfb_PG6g+2!IYfFAOL@28~Vr7MNr75fYiUy>4B2 zk^l^>qYBEy?6|)f{~O?0mJFPZcVoIMRt?0%w-~#L79z6y#z3@h@_W!8L29N!a~_n; zEc3k6&s1@OI=NoGdeyx&R|zPp;Ka7~G|imr^OYV0*3K|W=keLUMCgvX4NT)15(O33 zfu@E#dLM~be0ca4ooX0oX!>xkXZqJ&mXR}T7$q3{B9dCJE>psd&^KYY%$q_kjM-+KbsR2sV_|8c#;1EaQAUUH6R=F6AIX@uo-#4)VS_Gr3gwXF??!EVDKweh&FAMXS?# z&7FnJ`ocws(&R#`64z>hI)CAB77CBZ!$Lz65xoBuA`%XM%FjN&Zy2I?~p$qw? zyQf2YXq4#IYNj_`#j=%oeYp;eHAcN|OBsXL=))S%GaY?NpYt$5VjbcG*N&Fre0<`O`67?Z^T{?& zy5meIq`D08lFa}2OTx6Xo=+!bj-%cRitCQjLcwko`(VbQ0fklo$8chBKj+S3eE zaTmW#2XE>o#+X2vmG6y2D+R->yHz56G85h&`}I^Pj01vgwpj_ASYNq}Ky<9o$6=HeIouY0f`&&^)HVwkhIG)+5$+&80?dk_W5X z(0o9Ye1@HU@-9LDKf2pzVxVZ`BZEuTYRGudI#rzL&%;x@g!#-9!@j)j z&#V?N+xmNEG~Xs9-9|FPFR&d+kq! z3bo=L!DE3;sD9x$(2I6qz9MRR>V;bbQIU8a=(ZcO9RSpUGl(|4tWesi3!MoF{5*5W zZ10>;XWaTTPStZ6KCoR&5s1v6KvJp%SqGnFn2&a>`e^D=6QTCjh{nrOUA!|V<-kzl z4DMcgj+d6k+D+UX4FcN&&^P)(SJ{(~ z>Iqr38a1-L-;39VsA~VnYk;^tyYA$W(!@1m!m)GsmEej;zU>(%85W7E0T%8Ko*z0C z_8jJE%(PUOC-PU7cO8J&(OTn($quhiM7oL~o1_hm2NoNzDTsIqF`2SZu8pTWiC!?W~ZDA)Z*l6RnXSp#Rbli`oiB#lwm`-W(5SSAIGFl--ISHI>KiW#oc0*@T;rrlihu(Mlj)99?0LF$W2)4q`pWl(` zD<3D0m&6ZsZjazq_?h27f(sv^aq9OR zf=``Cpf8%w#y-X5+x9R;@|1cfN#j3$1@8pLdQP{OO`P@5pll78thiAiKH|Fv7>pwq z=}5@$A0mSfdA7%iZj4}2v$^PT$i+pi>O`iXw?oO|h`j&I_}bA%W7(Uq)=NgT-q-2^Z5%_>W?R!Lgx10?r<5Q*(< z|CE&E0|HAdVhdvY_@0Kl>4qtW$sDKoj|=fy{q1^yQ^)Tdw_lo+ykOx}(fc0vo9FBn zEm#nmkS0ayPyGF}nDAN5zkilafPhQbRdTFAoki^3KBcfu^0n;@i`ItzNBEF!sn#DE8pvL@x}XrZi~4y$Da6+CVmHi{sn1N6Tz7A8u>Dx zLs%}kQ=l)7&n2w>C!E6PLX!UuD4lUA<#{k$v)byLnH7VJ2OI|WdW0MZdp4E%@!pm_^n86@M0xF8_W`=tvKLFIrcV zj>rAIaC1pIzt{DPNVdOUkY%Jh+JE1MIV8c~&&WJd-am*8@x%jkO!@QNslT$kb>y=f ziIjR1Is9y%&U0^72`lORMZTTC2W1jTk?qge%Bea3_YZCS>L~8qwTSYpg z`a5PrTEFz)pLFp5ua)0$6<~0J&jcheVNRs*dyyMyXBShVzlEdx!4E{H&iu>Zg%1mC zNVBP?;q3*v%^x4GES}fJK#Dm1=Rpwepl;nAvP7zV`Fk{(p>i1}Kzp5FVz51=Tfi!J ze2b4k#dbO%;CZ%H1!0JA;5pIeEn&YI->Df?v_r+|@~Uw4~VEuya@suQu`u z5CKjOBwN}CZ^b{~#RUNEXPqU~F*jx+D?mQyHOMreVZd}TRh_>T?IM`Kpf0@`AK~&* zT5Qg7ZSOzQ!bs;np7oWVR`Qd3$7+)asL)DWzRc|8HuuOKXM>spi)*pD8 z)sAnUpPzsE@?{|V!K)=xU~=H7Bp=~A<9}*HTMdCQ|6HPY6UpvSAh#Bhk=Vz`}i^Z#3Qq_vq7#vpRp;c zIyt+tsI_=LDdMjk@a=#n6&v40M*NMLp${G3MazV-}rM?9j=Fjp8&dmW`V{i zY5VXhJBJs2yLw6(W_f2Kg$Qa(CWm9@`I7-vWjRAa^9Kp7iOCB<vIH;D9rj#+R)q&2s^Q;tv@v&+|%=wW!ztBh34R6v|b)QB#L3}p?9>t>hEgc zy_%($SP4alPj~GK>Nju?lGvemQ4fT=t!HHtE8&NSWe!z@^B0;r0*z>#^_-mtwz#de zHKEAWBE}>jr7HtLVSGI-bVkwT_5pXdZUnGRl69$8%9r244{PV@GG72G=r&6`yg2Vs zC}@PsWBt{nPdVZ-)_&|U)*YQfp2Jh9LZ6tpx~hvb*WNlyFpq0@fgT{yDzwwQ%gQ__ za5i5M${Zjw7C8=@{M>*P0F=+OEaRl%^Y;9PdAPs=iuE4DXz3=V!LvHm%IjG9X;^SF;0A!-(!lWE;cvW*nNZ&(SJ%EnNW7J!ZO$*eqr` z%LXfJV-HFQd)j&*jMLfiajlIOMZ*Ju)_MX8b;mH%yZo=q=Kq}}8VYH$NMs1i+X&)B zvsi*24PD*kA;dm3r!h{w3D6FVjbkn*((B6g-P*}^6jLLt&yA%%gXf`6T<<-QD9&+) z*^5jmUTbu?j&p0RiTme8+GLW1g(fMqe{RdatB#b||oaqheFT&|Sa`(Aoup!q1VPUIdEu#Zf2 zU>_q{YaOfF;}#|cnkT9*z+?$rqH}SF%9pv9D=+)?Ox4ddZ`9uA6~{dIaI{TY|Ks`y zVe`Hg4zUwCTRSvKKl*IHL7N)prRu4b5l2+Xz=L(74d3)H{enFHs15qQTVs@b>!U?G}6%trms)vE7tzv7-1_Xrnpw3PcRR%lCh7sC$dn+ z0PSLowYDGE(%ETFnWrzy`qte>e`tDE);t=a#@F1W44FXI;X!vn$S{f?M=i14zc*jWj zeA1sON_qt495rwwio^J2uMtD3fv{nCc$w-k(*@taTk5wlkls&y& zBfN({QZ?#S?OS$-mx;9S$#>;@IyZCWY75Kzf7qJ7C_>@6MK;TsU&V}uIhR9eU0Per zK#9|}SE29qZsg?XHL22e{Diu>#ZG7__o+1JTg^S>`d=%Pc|?rR17RU#a1taX52J%_ z-9=bGKnje^g&>P0Cu6!P_1kA)dC&+EER0XD?;_~F$S}RAQ&v|MN+?X zX!#3zPdqoZ3N4XuwrjcW#-(AmzT$Yd`_7h$9-;1J1>elg#14cK%u7G2VtBXsz z*-f4pJx~^c4(e)a!>5#AvKm6ha3Rrn&X3J`sc=V1Or7d>S=4nS`_iH9 z>D%%}uREkpC3Fka5Xaoy^6AxxXLMm6D@9gv?vQG-1--NWdva*dG(knt3?Xk8a)x{$ z_q<&=oXe0@23N}j&7>B`@VRAHc}evYYOgO1d)3-y^oN=kl^L8G^*hQ)z|1{%45 zvV6zf93fp+M_13SeUHt?1~Z=-I)v9he(iDdJ!}o7PhD3+)8EI+`^a#%j)#6|KsO3ix#bE@vv=XD@Dh!*D$EukExG zv1F^NZTt+1IKf>5qfF`8q)h8V{=1O{!n4&!Wy`Lh^FHT`y*1x>ng2pJYno}S+fF=S z7n@@i^k>HFT1c%{Ilq}*P~HTM7)N6nLYaL<%vwc4LocrIbQanvzVsJ}EVJXp zdHF*n_xMR7e`ObsO-f0mru?X%NOeX8;YDJzaQ1oepZou^3f3zn9cQG@CKWgY$IW4P zF$?3&BOPk|GhgESC zmIF_(Rd4F>xp&ZAarVvxAnkiv_7+*sed&m~RF@c`JO!b*GWs35Urba=dfpl&oMQNO ziS)Q6H4aDR_`ILLeeI(V$;It-cN6m#M6O<1bKc!_4GHzz4FZ`x+v^# zK)@y1bimr17v4jk-MPfApLA zfUyyF^UwKi3YrDIqC#Je<{ztQoHhcBeVhpK5Wj_cSa@#H8ZA+;u}Ob8TJ=~mNljrQ zqll)z;eqWp+daPy=?zmZPFYuLFl}@dzA(j5G5&Bp4^JlwA4fqOwrq7-9(UJ|TIRWj zmK#fJ9DZ$a#ogW{`I#sJ?x(SS&F4fh*$!*u0NRT{~|`s#KeR^xkq|KVapjF zo`)b3*?gYu9CI!4aHC?5 zq1stn!{QLtcm2zkFCRSkZX)q=FSVRHem25i*!*_<)2I=qAoH@*ohd>(_Ov@c9DWqG zW8liV-v3-4YLpnXf+(x;Xl9}=LSPrrxvXB)NG9gG5oNm}%J$|}?CkByWX7Q!EXYqz z!~PzE1V1+kRSHHTRE&T9D6aJ#Fi2xaCCc=pk{9mZy2q1{1hOi0O%=!jvE1>{1PpLZ zP^}d=LAyP4t(#Iu3u$TKL6*7Hz3J!@V}z}>MFq-PB_*YykV)No;lw=Zw5F~FIOw%~ z%n9o9AwulUIyx*%%A7kCTaw*q-J3V?TaRm=Bs>C~){fp;eanxQQnU89l<*?;lsqKZ zVnW*B*1f`iAruenkG2tJ51mTgI#ty&6La~#tSMSDFwk2+Wf6egJC*wH=zdzG?co$3 zO2al~^g06sK2N8$ZBi#_7QMdN|G*0!QAUHN8a=S=D)w8fUgMFn%3P`i5Co{hwRaUE zLx74!D}$P_)>0sDG|$?QLolE0;g-IP+dEkE$hG=cEiqA#h8|V^0y)jHl?R_B`j2gL zg~!QkkM65RpP0&oNO_19ZMd9`?z#H-8c~}C_gXeatQts9n13NAx+*$qz3agOyF!>r znxe^J8>})~V_Q?3D4*`erP{;r=k*Ybq}ptKF*E-m=XBGEB7rKm`gEYMfs5H^l&?MA z-JoTJ@tiuCIy?^(frhG)D%7g&!OUk{T1dgVng=p-x@6 zY?X2myn92rprC13w{4SfwJe~g02=0qV-aL~19!}c9lAldXZ7_=~}rOZ?OsO%6!KDm$Weeu4^X2y_sK5zAuWYf3D&T5acX)HP|Q(QmiHl)DT z^<~gSxegISAqB7agzZv!^EO#yGmp2$_$=Z@>hP!M5Ok& z&FXY-Kq>ioP%H=pCOdwdI32;?4~O*I8_5!<`ent&)gsFanxmp9+V>}ILqTKx&PtT& z#PJYlwcj+Sjs;4it5%xC!PsMXjN6{go?pbndRO^4rfoZVoM&63-KRWQp<4GR${lXdr+OeVRmtz@ z$hdB*wHE(Oc(zSO6alfw-UYjPm!)}pcpw?=+&Qnap%f|7C}RCWU>DJ<8c zs;bn6)+;Dj9x+Qdpy2z(E!#xyO$3?FWC;-+mWM@0 zWJL|!J-7E$+kqa(L|_+{7w3X_tu)@71bv%9^U=6ozBINoITW=&%U*K2+vh7^b&k9* zw%?KR)bEGW=Vl7mccjRvSV>6+luTdsz>#}AuvFyTfuN=S0qtOV1_lG%XZW&Sag&ev zuvn!^a!I6&k7OTWG3FL1!8h1?uG+h@hk^QMtYYu8aQ34IT)XnKt~((*m3|rsas5gq zK1t!oDVEYDf)})^>b87tI8b++W{HDHAFGn6~V!!@D2Kx%Dmn>(-@oUoT2?o$-3t2UsiTC)sZ*ztNC4HAg76(kb$(M)#*dxSXilNP%krSs!uAZ7m zpiXHJI23(Ia6r4rhU(gDx>38hJ}X#x=thV!c9@54WAxZ%<0iD6`;9}h-IC1iApXHj zg`>?LN?aFqH#x5qn$4MmC7Eie1qyqzlPAQ9ja6S0NRFrGL{Q^v)NBHxsY_BtJ#z9> z#~-hf+z|A1dSvse%|$J;JI3C{IoE1;VFG#g2e4FbA*M+`k1q<^mg1J(AMFG7_jg~&2p5Z71UEV z3cE=8&b<$s=&4$;k$`Q3%m`6S@AHhP;))Rpg^}G>Q7tYSWHRGXt2L*l^OMH*eU98k zsXDyYmu6Vcx2FFqB12eu^4Ov1Ag(;6hbt-Nk(bE%JT@nZn@C-{fo@>)O{#zH_M`D4 zpLHjNZX)vj>k4vA=cmeeZnwEV>EOkgaxsyi=*bnfV}N8!h8H(5#70krmODT353@XE zP-+!%xl#ajm# zNsVnf$242{)OanB_$JLFXGm@6W*XIaE0#ETKXg$q_2QT&Z=BK)) z)efGoPsms%OOZ^Gy6hO1B(`F}`7CkaPV_f`Np>kD1dOrINSdB@bQuv>PTiPRt;vAr z&)#;jQR$J#N4HGo5tR9Wf#k{NHPUrjYr%g7u!>yBE9d1*3r0jAnfn>CFPgkX<6Xxp z8)BP{y6DlRUbcL>jWks+zqAQYVLP(7b@540E@oa;>g4maAD1fyeRw0}-*3Xljm`SYf_`<~H5|Mfd}Ng`mj!0Wh)$I&B=H}N zbT&>QzrC%Zq_S2~ao7H{XU<$LOLnU;kfoz;QI;!IA}$V#6<4J9?IY)?Hl6aC!d+_L zuT5Ngjd3TDEKvkC(#dZR8R?v)h6-CQh^u_E_g4iWYQp8YcAHW|IL{R1EI-&y&RiOv zOTMt|?OdO3*q6Vy{b-f%vRx+YZ&+>#YL1!Tw2bQoYb;B@M>FU@Zd2~a%uP?hPaAjo&D_cG&~4p*jz;*H zM`-&c1MU~sr>veCXk>16IA?G`)9=MK58-udw2ja3KiAmUt#45vct$VsTG&iZ7!K{e)7UIm0#`2Oy7or zPpof~VqZ7gU4hr1<@L5JG%PF-(P>{>m!6;wuw6srS`-FO$FzXxvjaBw!fOZ%JZPQ( z50cY3VEdzeF};(lsmZ7+RLuzA>o2K9eH9)z%zLN!i-ka651+p!xSyxhrLL4 znhh{wcT^1ANF)QPd(Wu?q&jzGN6$x#yNIEk#LVpIx|W#g!u4$?Zc zxSNaz4P^qU`OX05j zkeCrD*%}M`MQP_wix+BYbP!@wus6?Ymt*+XvK} z4ZJ$McEdzCS5j_|M$~2M>O7&HI?@5*DMLreUkxc4B)Yq{o(0N;Qz*~YvxHIbefmUw zo1W_J0E$&F*HGo2E3^6gnsO~SwvZi6Xe)&p;{4~Tk|KdX?Z;$U@5=^+;fQUIqn z`*9VUUbt15mE|+=z=GuSmoMu~ZV>d?2YJVeWT?nn` z)-ZaF@fSeLm(kIszRq_6s8IFM!H?g`@ReU5`5c1B@>8k8AFsL58siupmInm6qYwM}^cTa$$sPUKv^ILj-us50kpy8(6eHxE-l5;m4D4?AbZj zq6X@mxUlKNbZ1M9IxqPeQp6&G&0k;zt=(s^q-TE{4C%DtSCylg`~4U-b<@u2Giy?a zWa7ObbWGNlK4Q&&f^#k9{AzQSslBd|qCloyU5ZzH+D=Q2sF0K{gO(it1yaN!@9E1f z(b#@{NJw3L9h|`7Yd} zAT#8VA1WTpS8d^WXM1?9{kh`y$9($@+Yd)->WrRmju01&Ya@pbo>w+Box^c*>iNla zN)ii_m&4SAOX_<6Et%N*6HVj~YOJIow@8s((eG~0+YDk#kBh(?XRh(LKw9=r`OOf) zHlC_rfC7_-laq7Qoso-Q(UiDMfR?JQ9(2Xz>k#_5&2m{{lmdnIbkv&+-qf4px>q+} zZtbzTF>pdrE-Xou-DSOsG>t*3x3a6}f|b`-=Ii9o;nFoN;d#J7SX}Ss)3V&z0e&LD zoV!I{3GmR~AR!?kEBg(n99-&k#@AtSF#p4QD&+xq$QUGoQL4DQs^9b;GgA)XITjiC^m)&BeMny>U5LN!i?`#!D>(TSy_P89PI5 zf(Qrs^$aOuyO{|O9k>$V5}aicGC;fj%$db~;&gNU4}UTH{Zp=z`qVd!eZC?Hpt&~* zIv?taMU2)YZ>|!5(M(1sQf;GgR&A~t;cvHUi6IN=lk)F>nskSty^r@ol;&1-cm8UU z@}~c%f5>5v)qxrK72He(UufDPyIf!}Z0ff6ps|J#&t?KZN#LX^pb9mL=!~cqY)-P9I3YBy6;G{k7ZXb`1enOV()=T_Eh`gh|V57Uf z@Bw&96P_x_oS5Nj3DXm}cqNt{Z@tf<@j3qdz(T`oYC({Y_ai6oP*=6F}LM+2!&~CTVl4~1JH3mVM5m*hS7w3G@^$Cl(0uwh+I-f{HrAQr81=B{bV<7T~JYY5fFt3s!^V*N`K zzV$wgW+!IfytfA&yhR^jL`*A`=ctN1m(P#grrG>8H@x2=G?;Q@sQJWmpw0h0N(PMG zkkCg78JKIH1eR;46yR&Ao05gEHvo6&ZQSGk%Zy)n-y_e7WRXLN=e}=c9!|$C>nwGm9H_NTRJ7m&^{qLx;BAY_T&7=`M9UHMiGLAS%L#Gk&!ktD|J|VND44 zhA|&WbB)HsbxJlbXkT2L4N&Pf1~O&n4G+6m)wj=i5a_6LX{K~v5<`);#6ds!dP?nt z=hnwxn`f}=Y7Kt05D+eKh2WqqwDE>T!C9x_rYSYKO9QUW4YW6C9lWnzgcLw?JDX`7 zSL6N8*L*xY*FbITzv)(GvgVT0^&k5-BC%l11$-`D54mNpPyY4PQPLmWPi}wv?zY_i z4`q!EJiRj`(H3JD919^Zfr)lC>r%$^F!%QQKJH?j zL9#k**Ay1dHyW8;T$2xWVh<%rJSRlzv*=3 zt7>e>ZxLA2-pTptbi;#(eZt*?8pGb?sISYk+EjU2i~448hhbfiSgg5fo$-CU$b3o! z3m*To@Wcls_J)6MB(`8>UcKES6KDaRY$wFzyulxILtr?P4p!j@>AEwS5~8icgVA*@ z5ging5-p`~{qd!LMK7eo#~v(P-X?L(wo_}AQz2#Lv82ES2M-*${v;PI3X{xShiL7E z(G2_=dYZPjDcV`rO|D0-#+}f=unV~uFyj>1H~^DsD>75>f^Vk9{yk;F)68E`F6D`h zjv&5u5;w1~=j!7Gg^5q>)7b&Lwi-r(0RzL`bd+dFWo*hZHs`8BYHorDq(cr!i#tu9 z-lg7B^|;bk42fsoiLt2V14kpD@My~McIqsSpY!IXlm%>;3am=qf*e>5KhRx$L;d&E zHDg>~++~oXVBa=>W8M;{@5|a+te2VmRH~gvLM%PEmSrzdsn#(U-^iyNh;;Xb z@`-%0{_*3&I^*ZDw=-R8g4rt{z!qW!Bcr5sZ3u>J!2C)7R=L{&zI8XMGZd*;lwEWO zWY=<^aeRP%B-|xUf(!Nk>cT znawYKpP$4lq-}Z9WEpGz7t1~GRWGIobo9P?DTNG0XaDL=2iY=ABqb#^Bi0i5&ROXh zy3q$-l}a&t;pp`g=7lax_e5@rBN6`R8z0AQx>$bhh~_BsIiR`)b=7tq!Ii#AM#yZM z_C+o^K9)YNLe@NF4=2SOiolNPKAPprDerH=aBJ=heLq#sHaL>PJxyKr*p=>#t{x+Oq3WwQu!I^6q+1PV!89!p)!^HtOA_ zMnCVP(e0N{9}|%{su#9C& zUZ)<9c(}Oge_AwY!5Q7^Zwi42y`3#o=TBYX(44WQlZ3ZAl$Gc-M$XVwH5VHC)>W1bF0`rJN&r<^Is5EnM7@+Vz8k4f8c9 zS@4TS5|je>Xc*bGK%WMT+g$r{bhM1$^dw3=y-8q0#y8ADBU^Gm2QFJ}0IL9)jnmvl zl8PG+C&-iT=~|@XRN+PZ>+YIA05J>37M^e+lM{pU9XMh%te0h6I_m_lh#DlH83SFd zYZ-=dL95h}Z_miSVn8yUbB`{j5`cD|^2Ioa#!u;v?bq|_qitbeYJVAMjZ!c<%JOw0 z;_lhsYpe3!eI1wLzWVvm^tO-5zFKM(^{5@GNF=v@3q?Xvgo69M`+?Q2YnBv+Gt(NMlkUd+`rqMGQ#%Bx&v@J62KU}4&{?0jMu^8S9~NG7C^{YI^_|I- z5^Xi=uw1h!-LRLL=~+#p6#K$MDu1QC)MwR~l)Td`4pcSfl|Gq?e7CM}@=G*Kj0}w} z@Ops@sGm4lbuU|)4=H1!tTHM|~6_s0;UNGXpBMz;BrzvM z(O7P+y-&j=C|j=8CcNcZ zzNU?j33*5E(Gx9@7bDdk92l?!PIndt*-YHA)MFCrHFBjipZ-b-VME=I2ONy%{qu3| zhLBXB62FsQccDr6Uat1Hc8W`gT(hCh2_H6LTqo0{KVwk3mgPtcoV`A|5AVJR7?|32 z+PUB!TDfVr3A4cteR{>2$-{E=lha&g0kf3^+McQN7&iI4E!(~DR~58grI6D=kaXy; z1g0icj3|@AT!0TZsN`^!w*W2C_e=RA4NXk~kHkcxhAT=9U!fN4u7h0k^^T>g5cwM! zF?GQ@=<&E-D#_+MpoT}V1%mifr+M`gY-wg}9LVb&9D zr8N&Cgm@=oR+A2`nJxJqd@fMnJGdcvA8GhkZR)=yS0O}hj`F1!LDHn|K4DX9^Y11T z=ex(AEg;=-{ns}mkuHM?_D{yA6*7n9*7zsFw%&aXi7t6I=|s6jx&aZ@|Ne(WrQG2T z@7$X*hNgT;O+puD^Y{%Eylmg!b(-xz=}33JRbU0nyxsZ-cUCjMzL5Rr;b4CDY%AqiQ;{>L zd%&qvhX#a|crc*yA&B6hL>l2Cf(5EaA2nbwe)}#*&d74%L*UH&ph5*>wKCxtoFt*) zL5t``(vCVk;Z0zH92;ztja*#Xa9YrZZMXaEb7Fep#z6Y{ItzT`hY@I9AsWGysLjD$ zulZh0?o5FRx#p5$-D{oS-jISNt}q2gPE{Wzu6sBGUkH|%a(Mh(w*?rO`Bv3Y)Pfiw zRBf*CQ>qAM+Z4y`T78^*XZMq5CCxp(xyF|tRUh=x{_Cik#+8P^l?hksBjWL9pRt@` z%bhwwoS^zf!8HL9hVTp1)+PoD!o2Qfq0^4f4g<-#raFg*-)Y|#>LBFJY5KfxgqTBr zR^s~^k80TT?z5L;HS)?`H2BqJap1y1wb`w5EhtdP42n}AY@s0UfDgz(R~HH+*3U~9 zXvpecs^?I=G?iVTAy-&W-WKNW{c8)0pUwXU6+JBU6HAQIb4M8m`S=Ffj1QneWXpNwut1>rb6yThqbUdF)Ek0~41lk1mJn zFaBB)TwWtOOyxT%d=W$elz=XXtDS51Vz3SReQS}AKnDP-a!6!kb<33_5%dF)48WE5 zA#_2oCVX|Yhdr@d-{x6PxeSMlmXGj&xpkw1sIXM=sd=`h`mKq zygVQ9b!Oy-Vu@ez;BG@DwMreB>NV8S-+`GpGZrN z!w4LW6!5Ak`=R8<7$V!&Gr|3SH@7vnSx34#Muwl~`!M?3*-c*}@hEd``Pms`J(LZY z-VBLEvtcv0rAM1>t4Mj7RIsB)=R%^)`2khzTQdM7Vl#PE&Jy6m#mPUWFWIXs{n>ov z$*Cyyl8&DJho1{Sevb3}Joe8(l`P@je0fsogve>djd_wtmWJEumb1x(ynjjfAu9TM zp>YD=x?6f%Zhd{_O|Vo{-+++?#){E7Sh?q!68#rjBJ&pU2|IQiQ`5oS?;THF#^3!v)pJ$njA-7$s4CAE36skG^J3 z)Oy69Z!asR`DuAFHyW3o^3b;P|AugwUW5;JlTO=~oV2exf5Mk7zsPNWzAv8czVhA> z`|SOtkEIuWpvt|4@_4wnxYP&~4w=FS&dpa*o1_=H78?wTHB~)Q5P)=@-)2s|C@Oto zvk3_n3ig{>{F;~0`Z&#g#-KFukHWv}d*RQkAopXt!*9hqBv|j5c241~E8X<#dE9At z^5Hv^{F^c|L1)guNJzq4l${!R-zn~W*)yRQ z-WtQ=Eko#N3~t(DJs}{r(3h-^_`=)B-T4kA7!@1tsp7~R z2*_0w7CxJR(ThuU&oK#wMMl~*q|?_6H2Y$(q|!#X4+gQO!+`PJ6jP*te!eMn*gpL7 zeEYI~c^cM38vxZJaL>$4f1FAA_8x4z>7J+AFFh+RZaJ?*O!7d}O;@rA7W#`r|44c_ z26ojyp7Im*ym%(g;HV0x{h-(<>}$%5;VCo%&RX#-s}#Pc$gYm8vdWSGE4n69+JqUjG%qY(PezDQcL{q@2DftJ$~3fT}t9JuAy7gntQ{-#aZ z_kFsuqCoEvjOdo_k=*cgLMD0t*A$(24Z$}{07J>8p2Z*s{L*4DvIN^ z+w-V-dxkIq833@ry4oA{S5)mX~i$(d&e1*y%M(l}4-;_w3>$mOu9Pn!ND>+e zGYQWlf37(#*ibPHfihg1h~@52U6re}*;r!}mD6Xj^+lc7xEo=?PA_EZ=JJ_)LP9+Y zo@s?Nw`s_6XjH`NuDW1+|Nl_;=FwcYYuotOEK?~;=9DsIDuqmuh{{kTvj#=UltPF? zWKM<#5;8VPgCRqdgvwYEGG{1bWaf8#B6Z(;?|1$Fde?fN^*n3sXYIZ3ug`T|=X9LM zd7P(QznHjd3O%o1Kw+Ly+adh{J7pe+sWyjVqRr`&)qMI40{jZX+&AdPrZ`uxy4Pkr z_y{P;2a8CF>z_#r<>&mIqo>Gwx5{7I9kp^^K^4>i~Ej9(52STP0=&S?CEGpojsMZ<@ROP;}4uBQjk z9pw-cguu6)j2ygciUh9mts8)3q#BOtj*dj@af(YSU2-vV0Cf5AbNrXKMy}a+8+!^G zPW!wP;j*GKjw(y9$afb&;rI(}kzJPPm@snRU~6{5ipPhyMKTIE=%sI1t^Tp^uO`g4 z6-Spx4xr} z7@H?SYuCLIj^@DS>46=$A1r_=y0L_s4nKbtgW9-DGxAQW&1s(KksaiJgs2X#fn9+i zH%9YV8SYxWvhW=rf-o_pVH)OpT-6HN1~OO#1=Y5FpHRM_7^^|M3;`TU&50m^-^*9u zvj>yX3K6%S=%aO$hWRd6`X19O|0I>{ncNV=V|4hlt`^lQ6|3fXfaLYFLqx@qX=~Q1 z*K5Y8H8-cUPFB{)*(}j1T%IEu9lz`TavmOY1l#v%R(*+5cV&0S{?xrR!jcz1Sj7+n zxh{@qyPtHuyVOQ-bEa^4)5~Xj&mB^-t#34GxootpnqY{$oSkQgOb|I*zRoHOo~`eN z6FH1#D=v4Fda?vQW2mBM&_JN4O0biNB|X^J6241cv%cD_i!L*2buVIDkEa68?A zNkU8WZ~xGj#_&D#IfU(1=YF5k!G(M zc@&~g_#jDscJfnjTI2@q^QXz7Q@kW%3W+|EvI9c*8ED&p`x+e{ju&dZJT2C9zB57} z{&mgBCP}H=ra#{;ZOiZyR!V8?X)aLIz}4&51#?w;xK247-?3!xpm$0Ch<)9#B6F)m7USR68FEiC z=W&0Alpq1c>=txd<=hq-{Dj;J2I_&%D|`n*#c||?Ke-$j$nx5y-f>4CX7Di|GxqZ* zWcJ02qc>UjFAI|0mPlmy({=LpK3A=GgpHE^s?Oe1UYGep%Gg2ZU4fKQoc}HC3R90z z`!k?3+0q(<>e1yWfJV@KtH}+Sl2RWjLj4qAWNjn0Xu(&X`TbqA{?{bG>NsTWi=sTe zF5vImz9mw-kJ#jZe4fQ)HwCFqYq8$kXV6eXcG+kJfR4R?YLY_AdZqA{Yx(%b4~!MD z0uo4Rdwcue>7yTu>)+%gCMJp)XQdx44TJD@*HmM078@x*ne{mJzrED| zz;YnMynOLy=Mfx|9n+sYL0su$kmi}|n=HH)AJdVzcm12a;^5XxPBNES1R{ubEs3NF ziRFdJhd+`;%K49Qbq$ktG=HiIoFnOggvYGgd0L8eulbJOf5(3awM%G@4ArxdUbsWc zclYAGAiS(Jc|9G$NNPEZ-3mNd`myv7>1^dMhM3oqO(ai+ZR`I@K&b}R2^;k&-c!;ihBGCJje3uTeHTNAt-|r!lW7jZZs+J=K|9%TLU_J$ zlYR#pFMw)50e8p1svD2=rDF;xSBY&q&1B}-t|h+ofvC6!vTU@k3NtUdJDffZv3WOl zcNAI<17GCv&x9Ex0ByDKOb4A3?n>b+i0M~gM83*Ri+$Tq5>{>|8SRSw}p^SCm zGb;d+V+a@>aA)K*`AY+dWmD+Z=Ci)wUHDKxcv+}#Oo5T$Mq>%>k1FJb;7+zgjgZkr z>XcTcNRu>I0=NKv_2a(wGAt=2mZn9So=XL`1+f&U6i%-sk%A@Cj351CBY8$l19j95 zhoqJ}TE1>PY+WsdUO?7d23yGRxmaKJ>vLZv$DZE?Kq#Np5lQ^ej~_Q>okVAiIkziG z2+6Qx6?rLK#56#)!TZ{FI1r-5L+iS-vJ%Q*%UQ`uY;RH=ihr@YNRd~rU8}=nGOnZE zdMiHk_4%M+TPksKkT+@cSFyz-SZ4V%5E`WzseBAJ2`H;wQ=}Jes{CpRZ6s*}v|lkn z^fL1zJr?2ebk|@jr6JxdvAE2Mf@FDIH~a7}5*LXcgO8ZYI0_O7vXgNIaRTbt=G6Z- zlbnqVY(KBN^qfu@ZSnB%n2wNs2~iU&YHC##l@{Aca_Q^84|MtRVMx3T-*4HpZ{I%D znP2gA@PXLbIoL!Z8M5g;IQR=Ue(?eA2@!E|I}C#3-*26IA&C}7vS1}fP$rm2zSx}N zVt3{Op|c=|*pbf~2v}_k9wDl59y#aG0SZzLTLfp2KSj$PB=QKxg%7`H*7BNnWkE|g-9u1AQsTXc|CJ<-j1-dRie}8tyC@GinD7?+Q zXpesmD<|jl7uSIqG@)Q4*Ivv&*5i|C`~y2H%Di}Y5~vHh+r(~hD8SxHN*czOh8$Tu zSp9G)>O)usSqf6~)&Zea;W(1!NlKom_3K@hPr+dExE>oB z&~S?d+hdH(vno&{ShbkUE(s(}qR(YZ_30;k&^>@B;^LtS&rup&9-t;^A6xv@C_;{b zXs`9w_Mi^O0cWq=cu*XOB8)_0-bh+*W0@sVsGGJ_r@ z`zJ_5p}RJ8-<%334FwE5`5pjuZfs%iIsz4^}uf(?t>szPVn&(co)0`_`Y+v}nci2XTAte8TvDWkF zXGT9cHM?ixfrG`aG(=50yy(>h#0l_x^RYcRCFtBtDA@61{28hExT&i+-Mr)JeumBj zUe}NNEd(pj2qVJSRDsAnSaXoHW5F;b(Izg+JoTIyZhMDSH|WvABDc<(ZX${Q`876d zI>a`hO7t`5uo5kQsj(KKK*4w$eLm~KhqrV9h(8F`o9H$o2i0u7jiylV=TqPhyvkn{ZZw z$Lz#$lm&!|VBtC3`nU~gkZtj6?QUVj4S@;@?rG^mR3VWykB*dJ59$qDs>NTeN7+Wm zWWi?D z*yo}kE$s~1D%{qFW*QRR!l?!m<9HJjL-$);s;jFB2MpnP4C_vt)4k|hy%@SSB4Axd z!vM1zz#}FU(vza2qY3;6!h85U@`caq{`~YCY^($!BBS0KQ(?NH80GavWuMW?|qlFA{ygn_Cgf#YIJf z@pa4#_6Rq*8WIXEMr6ao*!VkznVdXiScqVIckOC{MV2l4Rr5P|8Z^|@#4HX1f*Vg( z0HCHzzP@mAXR$4dh>!R2lgPA`@>%b-Bl_U2Q&2NxIdszD0w;c7AhAwHLE)Aym2)>X zbijYxVo+Mo3y+)F!(Bi{I{3#j0zhr$CnV=L!kxxFA{s@ z5{}KIm`135ejEGPi4?LLlW zVB&yh322~ZuYwZJiw*SZDhN`+MO5#y1Hsl|1&AEr&FIfFw(R zN=WNwun`aIpkdgfkSl!z1{CgJ5!(=(XH^rC%porKS`j1z&Jqmo#vDEe7fk& zw};>WGQppQ55sJ{8;>)!kR9|Ih=t?%6fO1(NymB2fEngGOElB<^I?lQ{BiX{r-57GhW|=GJvl&0DFaiWsHiBINAdj_ne+06-{h5(b3?3f6ZSj{ zk7@#6hc=9<`{)OZd*k642QE5sNsKSr;#C1QiHM1LH+G>*2FgGtOA&h8Wl6dVNk9w| z{hHMM8}eBjtMEr+hX5}1eAj!f{G~58FT`X@oazkH3|vMYJbWh7CPHWb#D^0YKpKCX zPZIs($Irqb&UeK)fmZ*-X}~mpsoX(i23YHgfd(x0`c+RR!+RjgMcPtHMMOmGj2*`! zPQTb67msh6cREV|Mk3l4Ws*x<@Km-ez+46?^ogam>>A>#t2kppAic&X9?N@H;0fRXra_b)($a1`o*WBxvNeiZco5-cI`e!~b5lq*h|N=YM)==yCkoF$iTNN8 zs#SV=`fs2s9y_+andbI)To-EHZSIqj&1Ad_&XxNvQc=iywiy-f#{;y*H6Uw7diC<* z(+kfRo~$)q*EW~obtnlp>Y5-Sf)ejj)Ni7q{fH^R1kBkNL*?{C#2DmeTcF@t#soWK zLd0W}I8510_xm?%Esh?oy>GP2V;7q=GS&g)xlkDxJnry9Wc9BC);tZ_5x&2*JhPA$ z+n4XcTLYy5wO|sf+TeY}FD%~Z>=-pRGqys~)V3)H31M9qC=0}bo?pI(v}?h?<{9OlqO*f zOJXEl+VmUvaDIaKk=cA+cHO!Tz-oXOB$4TVBp|2*q$TrjNc$5~Iid1J@L4m$1RMZ$^dk^A68E4G#^RR-^=WjCfwC zc2Z5AZ#79AUvEd+yck8~bdDW62EGAujO*dyug1uv3FnMQ?k4=_w}A0s%{2uwuJ`zJ zshK$I?ioA=MSaMfbl}K*DUb@n$0Km>QDaA7S2j_D!%VQ&5L1ckaHve;i-#JCTSt9M zthoo3eSGgx@kR&^Gl=Jz3F0^`D0#+(rMUGF`>_BF-fI#dY9cU&7&pM6Bj4Kd5 zfkl7A+8MaR={QbO!k;hOWoT#!2Se;IhOXqGJBiu_=oR*slw^|oExea7uy-Y)gNw_H z{{Htowm|-t7>^l};i3}KfZ(AXSgI_hi zHD3aJjdLM-k3(EL&3A&rcM8r7u*-5Tt{L1sASH92-?r#EC5s(VC~!@&hZIW$V2qS- zd|w_N@f{pNjTEm*!c%2_AZm`xMrii>8_1$U1rbex!B`QJlJ#0+*);Fun~ zoBwVKViI|J1QdLbecK{2vC#b7Nvn~(rHt^;5OM|e5VKn?QvM{z#oIl|{UH^H-fr|` z1|JEfC?ymN2(-XeY9KX&|CXsUv0OV~8yQ}*N>+|%>6I@Z1;WBa$><7Yg=1?N09VM4j*zI?d6w~2k9HN#s)d6bpP7gT3jGpjuZA@ z!Eegq-Tg_mBQwDVM`Ag6e?sw`Gf>-9_AHkl@R;UF^RdBuhT7un*=JZRTR`Q!b>6zo zaiRJNs*J5sv5*QL1$OBt1x%#{dD$xw(%Bp!FK}yK7cXMM`eeSCSV)&f=Wz=HBdr91- zzh9O4DY#9dUK~3$y!EDtoLnv*GoFwlT7>IGMwsVCq7lJr1 zN|TKn1GyXXTnWGfzj34wNC~%$Lk9{l?t1p^33&flDu4^UHg)QpP48Egnz5CFp;qoZ6~tq&6ZZblm;V!cM5a_tLv zwdd2(o|+BP(gzze;M#BBzK!NFfhV?|CGF>5zn++6L{IH|PqW8d-@rg@WaLNiCNciH z5VR=q08=23jr$!#ga+|%vzSMf#eD1Bg)0i$Agh_f@)aYryCtmz|3^}#X@+w z2b#`}U*I+nR=^1rxJJ#V0l2nkb2`UtFWbO@kFwMP&5BE%hEF_7bB>0o~reTiitig)(_sRpzFE`!%3D_teJ$cV?Cm_%IFh2BWdT5lhO-{|7Qsj$&uISdSkuwssUs3ga%_P~W zAux2;Brny=g||KI5tWSY1jbTtZ=)=CZF#hq2u3=NbnBqj)TsON;D-$1O-uxl z=x9HL5U}4{EHlOKg}-iJ)q7jY z7RQBi>_@OjIdGqS_ax>ba?a0eE1>e6(ok1lt>Bi0j0XW5%ici(R!g+S(|nXmbL)>g zkw+4Vj4|QKJ0X3II-J3^O%`SPX6_L;Zuk#$Q0m*k=8<~qJutp*lISM2c#N1ddez(< zI}A~LIa%P2PAS$_U4N}xa=;6J>PG9QXkU0BFXVj#%asyk=g3K23yCEI{%v=B zv*q{IbOZ_R_4>HI5*LF&=(^`|i&fJC?5 zY)OkT{mPBzbLU{66$_Qo#lS!YTiXFp6J8e=BPUV4efXw^jZm(S*qRO2dRp3WyQubt z9#Yzg&KIC>3CWPt6}NBm=2N_AvN(QRO;r`t8E7*87EqF`= zBylq0%=RmBb8*Q-%l?+UD}H%$d|aEgqpxo-l^l+3!|!AJeo}^55$Z(BdWec3h*Ks5 zr_t6d+*av+p;LZP;CBhR6JC_({CF!so8x3zVPHlL?(Me(CO9o`wVs`m*vC9T$#xX= zpxcTp`m!*bV0yjv^xi}bwSCm-SA*};^T%>z^u~OU`nSihku_W}*yw z_$|C(4t%S$KNHtMA?{T}C(~Hea$U0N@Vp>}oiDj3s}=hZt_w=bUvS^BQRi9^PPxU$ z@Q_5cyXHk7Ey9;H?Mc^`ZJ-bdOpxBTJW*!K6n9>~H}l#&E1)rsWWMvp>w{|Mp_J*q zNk;qB79=f_-^gG3bnp8;k!EYIZC~%dKD5_u+6_xryXVAwws1-G_r*Lv3#vC?gdJ+EtcYMo(9e<9av3+Hvay@nL;-@r@ zGCk!B6e9hsk^FVoUfB#OHIBP`1s3L8Sh5QTa}G5`1>L~b`D(ktSBL1OL<}BpI8lE2 z;jigq_T1WZ`^W3e+-F$lHjzHvwrV-+?R&4U>YZk$T+{e4h4R%)lE#&{3k$Gn9F&+( zaq~A$oy_WBV@JO`&f2SF@qX;fWo!M#(@2)_^LNDYb(1;G-po6}3lb1oR}y_caY)%R ztlm;vaQ;PY1hXWs(2QCh*(gPccSvbj(L>7%&Krj&Vci+J&e|ul}~h{?IFSNQ|22MFGcG4j{CF;be>Ga#W;`iUe0EyQ?C(8 zO<0in*nhOCbrd;9pIKjJ+Wv21=l!oR`89ex*?U*>R8HPUuJ*NA?0YFP*EYJI3b8qr zQ`oaL({;P$UJ6>qwQjs5i+>%!$2^}z?PnKe{@g~-{B2BH;&HW>dac6&DE{LB&iH;> zli*wRCQHWZxuZb%Ovp3qrqsRT&s*JiJ;@V^!*_kyS9O1{R8|sR!ZLQ%@$ICte?5YG zuEe=hOj+eDSX)*N*NL5MdZdvmJc6RDH0p0HUY!5OvkqW-_{gky^3zg3g~4$%mt}Km z4K!P5gF`~PUS4=iEU$FD40z+An=efbar{9z{-h)$qY}^UFKHRqyGe)mPU$XLJbalI z9J@TG`lRw-wuSQEi9YbgU}R-vhGqTNj+^XbH@4S^B>hrFDLK`zE$lF(Q(Q{n*DB7J zEwT5=y|r>@Lmg+b1Jx;5UNgE&Hid2bJw?0o0H-N1fziW{UssC>2JiLfP?+gEq40rz zm7wvHgH^p}PL6LGd1%zEpUaq+<`VFg<-$@Sdn7!7#vpx_3IG+sp|3iTKIY*0wX)YF zHBJ4AO<~)6d^r7qq)UZKIa;?K8KDrsMu^+{-M*hn|qN z5{v7>XZr+Ip+lb^p@gsJ&eKxD)`gh&@qhX4y@@PGZfz*f>Z|QV+n(NenS7`!`Ic=AFAqCkk5y{2 zhP}~Nrc=2PZ&2t?_}_9QA_XyABSB%Wb5J-nFbYvxSvP@ZiKG~t4@zyjjG1n&&YW;? z`(+7dUev^?FO>`eRRun|xSwl#|Qz1Bvk}HduP}7-r5gT?J z^H#k^MgZzvt5jKX>Y&}xCsFPqbTUz$Pn6&LXQqd*DBHTbu@*D&+a-?uG2yYS9rxcX zNhl+Trs0A+t`?%Q2C$8%0gUR+{EX^!(!`x30glVkY0d{yXx@gm@jlKJrg^QLrIzHw zBYa)uA0}ViI@)JHz;InUkYl*0OY6>&hx;CDbU2+fDDSoXBsb=^x~E0jy4r7SeO?KT zyDr$RiHcdr*K%=;dV3t$$W4h!IAe$cK`H}@(IKEd)?OR9i`lKjA#Le~ek!mM!Js^iLhA{*zDP)n}%ba+r5@B3c6LQW!HNWqd5SxkbUSlw*r&He6JMPC__Js zlu9o(0Z{Xp`Q-5^M_f?w@-q)Y2I8mVMgSwnLz);Ct-Z8OH5VOU_Dm~XmYi1~!prRT znn>PEOg)2K&djAV0z88a!!;K)ZrpaURZ&qvWg~baDk@5x_A%v}Wd+N8qUjwB*Bmc4 zI#{;E;wHb%3A*6JZ#DnJIBqZirMx^hs{Z#J)uWwfNrxKBzf@(|ht3pQ|8nYId3(IG z_b4%Hk3R}i|F;9Vd1;FY+hcEz;a=aZw~xfKZqaI#?#_!78*}z)2s3R+(-T%md4tXz zF<(B*{3yKIu^)B+NE%YDJ9qA&Md^fk%-XBF+wyY@dURdGk6xqZixM%4d?o`X7c4)u z&hRh!6G+Es_-Ov6e?phgupqm_eh{)NJ9cseHMO?RjU^v2SO((Jx$RRsT!p{%Vd`ZJ zki_tZf97N{_Xl(~jor%uKx)64JF_zkYp&={A|#-9g_|eJt6txLO~a zbaj-KmF6W3k=4GO?9kh55|V{0&d2!w>;g(+lt)>%&>`NRui!ouHh0~iL|vul@m-_hSHD{n8-CSI%D zC&VL^;I>EEyxDl-$q85ybEev|d)$F*=lJhjA%n`up&Q>!^SH#!>lC0%G>?$3Fq zmigF=f*jVT&78@(4DGU6jK3>wKpZ*sYleq2{9GNF(R*SQVz_gEem;q&o{&!bD?ovJ z!~_rAs{^1cock&UW6Q?AztZ`QL*klqwkX%pJS#RSYDwK>oSd9oQ@NoZPJ)G_FQQsS zRaF&G3OMFqO!K~DQC>?Yv#Mjk#nxNge78+%i@${IpJbr~$-=P^A&skr#P}0JV$R-8 z&r%q8d!3$0>hMi@)k_9F3Lbo`RQ)}BPa%_b%F(yCd;Y2rGTH_wl{;76@iH&=(2GA3 zve*A=@TEqN5yRH8RYwIGg9Bkx$gtqqT)$pFj+HR0Sy_u`9$VP=yllgiqM>CymS;Wn z^N1aRa`wFdd2IKM9~WfR`u_OXPVOCRd7q*sM0Ya=zOz+!+KfK07rg?at)#Hh-m2$HwBUSRB|k3Y;El`Z zpM`Pj-a80b_zL;H%PS$4bcREiuW9KYCwO=*H%A-X1`8*r+xI#N`zUeeG=@)-)MaN= zH&X1vh|@8;IOe~6-MmeFzI6Dl!asdoeS&}WQSHfu(}%3D1XCB0;?Jw?UcsNCcx`VD z3bG2$b?ZRn@rZk`^;E3Rc1i51oAA&2MKZ_x9d0?IH>FP8ga zcGz1!&f7!p)Z>Q&Pf~9&s`)DqDe3g6KQ)JR7D{BRMlEbp%h{+x6h=-a4G9hPg=7~l zu_&bY88Oiw#Z^NU3LXA7aJI@KMaoqvRO?LTzXL8#*+}qiu^4dgipLmAeF)g7f98Jo zpDZCD$k}l{q0aIG>MVof@p%3uQSBwtMJFvY^>#WCX!^2nGzuefGaU$kK ztoxjgb2G$x$@R^rR9_=hgH=rjd7!&gBUGHv|P%8~Zes}!=a9$$>+kIk} z&B$Vmq`))syan0RIm(+yvpR$}v|6E0b9p&GH8 zw;~12woblK9g1vE3W`ND1t0$pq1)>>ZfNY!!k*pq3tvHN!dQJzRYD2mDu81sx3A)$ zT(M#WI+~RlYzFMPfAgyKXz zS>$Uy|7R#(ka0ZH&bY3evss|S*cUmsejfa%=USl} zfw%FOw(WD*e~ma17yT;foZ9a8T}DXQ4lX2Y6Ava%Unl3h&8EBQb@jh&uL-32T{Ww+ z3$M%u?Dcn@@~S#>(ak?fz!V*W4A!!|>CeI^f2!Eu^x3*Jk=9Ln3Hu7Hq0sukz$hVE zeWvg88K7hLAh38!G9ckxqQT>1l3O1sg{nRR89n*dxinOTlHxjg>%4DlJCha#L0i!$ z{3o-a_yr|As^p-PwJDDv7jWo^P1aE@3y*Lu$WFC=`(}jAshEbr_F6N)wOpqYMZVJ? zwftOqE6q24N0L|kjt9D_)nF5N^J>t$D+Z~j0tdm{jkBhu+bD{~UzIHt-}4Gsx&Bm^f)A1V5pw=Lt;wQ&H8?*?1n-E@j*O?~)2I z`#U4=y(X*IaPja=HT%YjT4LsJ+)UVOTViX&nc8~>oB8-I+CF9ayNc}j82M!&WG3Vi zGy5KKUQc3K=sdhtu{kbu^UZ~aDA2H7coEVe>OtBB|BXjI(yt~-d}O{Qv+J-Zg`w5o z=-#AfMwDZh%P0H8E)*9)4 zc<>@geX4udEAZTTca-UulL&ia)Kl&r5Zzq)R~!u*xMI+3yn?QBcm zZ29}sNuMx%F!wDYs-k)1nD~-Qa}CoTv!~t^pdI2qduf?q`OY}bgFAQnOeJr0C=;;X zpcB&d)7$$QWtMlg;^3CKb!T>wUy*FHrL8<-v$Xz@y_3%HmOU&EJ_nvCix#ZmRH?r- z9;p2GupNU%m8QFYr5xYgaq-Eu>k~L{s_f7V%Z*ZUQ(a@F^T4}or|jE4t4^sr?rn~i z<6Bc=~j1{AF&)m+{Osb5l1?KDd%M%}93U*I!Z4^>f`5{ulgj`Rlw^zZlaB zyL5+1op&82+o9io2APlc|NI+BX9FFqmov(!51UdCt@gRIGkdwvsy^||~w@#YLUq zz3~?|sDCNvU7ry8L_lA;GoI_~&nLY~=Ll(aXtTQ&`mAdFQJK;cFni=<+NX7E@`q;| zyPDmG^40nWoOBco%A;7;KK}KmoVU@^S)xR4R%90Dd52t`Hf-fOnO**&DoVrc+* zvgQSN1K7BMra7 zdsYggY!jzb4{+eu75#k3Mk`>1u2v-BRSe~6*X_#xya(nY%WJ>iArmtlZwPV!>(qIf z{yzL&54SgM(r8o{&!k!R>i_=FugfEbvD(RMeK3$!ic=j*R-CzPPIFKF$)TOgxh5FWjNa zPP@Kg3V0q6wp747p4GuyoPGUoPqD+B{LNYzC8hduzn6dc2a#%F?M&jok1JWS=x;og z1q|1y(Iy<)L?;nYC=tF>Rz<*5Zqu(@y&xT^Tpe$`BqHGKwT2qLJn}Q;_>{uN|Hprx zwFbN+k^1q1*>45Y!rG34ru6?btxX(7C!%Mjn&uILG_q%N*{QIY=J>`Se^$+uGy zPLFGS>073R9;T?CwmTnK|9*YF;(6qD3@e}6sFV)(<^K=3aMOiqE2(ru>e zyiW*3gR?C!E}-+;1V$=Icpeq54=^jabs3w+03qY zHGD;(J3$WTWTjR}lLZV=1xf^{FXsU*XsAtdd=TH3+hX7^mSx-je({1XYIKgDLI$3BtD=Molp-h0N^<+$N?2?1LF5`fXpi3VRZ{CWv%M-4uH6TwTBC z+U>0ZGB*qb){fuuO8tfs5LN{Y)!4Kz zCbIHJQn#sqGFtv#n_YUnPm9pGi(G5iarR)NNx0kgH7xf-ce53pkTiz8c6Qe-;e?-r zCK?8Yn+=_GK{B&Zk>|bJpVbb|rhi7prqw5ozrCijZ@;Zd?V6k+eLY@LgAA~)!lqfM z74kQWpZvH{Fb@+)Ef3lljG_M{6b%jhe5Om={Dd{U0+Ky5qi1Q{3S)3vxOF;~N0K}8GGndFxBkwTaSw}UB ze6U&~Z);CgP=LCmsZmZD)I}tj2k=%dYO^uITx<9>0N3CTYDm%Y5U%2!v zDg#q!Y_dBeVJ>NU1nV;;MSJwp119^CcH4B8EBY1Ahg!ZRMcID9sFkSu1h{xjdeN=Y z$LmUdht_UB7E;Drn0(ysutN6rPXaHqNqVilXTx@ePmRY+wtnu8vVLfaR?yK^%?>@g zK}@V|r*^H*sQAkSL`=?6X>+Pxmc8tkoo5*32R@TVZ!+YNUuQPzYo#RbBYX2kXenmD zUnWQ?_8y__1bg1{^OGK=S6!l4m(3uYtHfClW(cZky`# z_4HCZ52K9-&howxy|w+(k^6t_m&=&3FX0*^e2G(|y)Wl|Lz~a<(Nh7-DT%w{nnVKV z9nEe(f}STvuWWJ&I3EWdU)k!xTl^OALe=+J1oAuSKE*HlR21-!97e{3mZtn!%kr)_ zmfaj}T8cA{19<*HDKz=h!{y*5xafnMu`gmp&NdaP*>jmgqHmoK-4?EnP7s!uD8LM3 zSM=#%C)VQ!FP~q-^ZU^!1Zb1qY(g~f7FDMXh-?Y-Q>t0QpvC;sa-@3&=hsaN#=UgQ zo03(*)d=l`t9K%&skhTK{P}mXl(_pL$)8BQuGraV^-`;gefaPpzcWW`H9^n>LvV$r zw9;$h#Z8?5^u@>{rR-(HFu+rb%VQ2 z?Ah}RpK^tDCPfT;uK@pf9uzQ zuHiC?NWx3~w-X^Asx`f+eQ@BVsvWtqX{xmpg@wBJ{ja&u^|#SQ@@bgTQSf}o_`H+p zc}9i!j`jc^+v;syZNa1ZV;EF^5u473*vUa_%izH z-PY>FsagT)%o6o--oJyYV-M?gdp7?5b^e<(!Ojf}TN}&EDQ#ztVM?q8#6~S1Ny|_t z*P4ktEy-;8$!S+$*2inAh*2Hub=^xn#=YQRA6dydgl>qoE5e8p&h7)2p^iCyJ|Q9< zZ?>zXTUI7}JQz^y_!o)|Kr=Y$gX3Cm~d?YOLjGM z8PNQgii*DkPs!KXc&mTa7YuBzwK|S*gWevH>vogJ@}`K{>MGhlhJeKK3NcriEd{eY z(-*0lqg1kw)~oZFDGX z+UN8o-b|nf#f+T!3sST48Re{%KKUybGxOr8=feV{qO~qDk>^7EQ!Ra>MZLW&jO;F- z?pOzleQB~>;+0x0MX%A#+`dMau9)88p5A3m>Gp8QhdZ);O{rmu~yVQ+d4h zzS7p4t7V%KgubR<>%T&g^dB#0{`|VdyCQ~KtG~swqr{1Mu5zOnDHW>T`?nmbH zp}nJZ;i-<_Nk7K8N60}(4&ui%uQ_ZXx0JwOj?kWsfwj(zNh$v|Yh&CoCuY$&8Z6A* zYtVes0y)nv>CCR$S}l01bD$pQd8C|0$VFlS-rXqhZsc@ziMv;w`HXgq48rS@FNh3~ z;W4H@a)v@zU%#As6A6~tz?H2Q$W{f{4zj;SIrN!JeV7`#K*JsS^6Evc znI03F_gHJ}y>%GOG}AL5^nL}l^$(?OzvLn`^$}J)yg4Cnf{yax&G}yD+71g zhl*%_jF4^peDWc9uO>JUEtyW1>;yPwA{Xu9)|)<5Ra*DY2N3;6X|uFk&n2A=4kJTP zugJn|8-;X0TxgJJ*iF(MO?A8Twswqxz;o_o2>B4T2n+^^i$pZWIO zL&uY_z{56T;}r!uK>%wNhu^Fv5~{{5dsq%Pi1Sa4A6Vn?@8sm5rEf8=n>+)ietyeE z`e4ObXP2u;Wq1T-8_#l|>yAVA&vW{%L`I?^-v&(4>QpCL6Nw{`>l}`$*Urrrqw+Bz zc^Vv#`GCm{blH$t)Z57Bs}kFBny0@?DbDn0bzb}6n%-dZ{M{7y#$&Sn(JN&f3}!Jg zmqVXt)cgMCk#S|wB|#iESxPs;l+`pIpe{ioY0iiYi{eggH}R{4=yU|gsO51h#p{Z>Sb?l({LyQ)ZXY0gK>bT zxLY#(Wnac)m3)=2X>M);Ox<1VItLanr*{*Br<@V;(;jk~Q%&NbXEg z+qoYQ+#%Yj_adRIeq&A>4tcM12@QHv5mzcFdE{>2nTKrFCGMARqcc`AF`1>zsn>no z>G0Bk)p8Cm`~Z{j9SWmlr~Nyq^HqO~-dpZ58^tX0+RWwWNW)iKrip#8K)!{RNOzSQ z4v(`Ve+$AW2av|S9;mwD)~=b>w#N@+X*@F zyHCCf?c+MN_Vt*NO?Dzmyb~Wl*$@&E(w(_|SD15eVUMK-y@}om<55uc?kY;RJ}BF@ zD%$ysp`Bi&tF9yaV83#@qt}1i(Ph6%2Br+=37Kne&#abhW8KkEWwB;-ji+Rr zkpip~<7lZRg&+6Hq~Tk9Z@Fyvl78*oTADzjhT{ucM~eEVQEWTe)NpEc#J0d>WXkvM z>o3_yt-BQGgbrTPVAOFK8F)>dhefrZ59uqGfV0V~7vc|I4R{!BAez@_+QzaZz%sDw?yD z3>7?YIWe_DX}J4a3g3IT=tB}W)tJ~MetD{OB(c9u!LjFQ!~TNFcSWux_c@bi?;X~(~C)PT~l6NzSjWc_umF9{-w%;t$*@M9a z0r*73xg4w-8rYv2vUXdW%`;#dYaiZD6kZlFefBKaCK-c2Dip^=M^YcUhaCF_1ufm> zH=i>{B!pGSY`Ueow7%bxLn5E%uG&+f!|Z}t0m26jRrWXBeZLiv?RRld-=iG8?OiEe zO46^4@xtW0|8}U?&Nl^e4fz+IPm5*IIJelW{^afIDb zrZ*MO7VpqI(!@UUC?X`2Q?af<=N(T2CW`x^LX0$rhLOFacG~I*VVcN0?x&?;4R1S| zyLW|H4fu=WS$ObJ8=s!k2T7+^Y**^JZZI9|9iJeA+>I4GJ@>{SonfC_Ecvd-{le5s zE1JGImTedp^ct{IQM(wVB0gza#(C!Bl$Y(c(We7d|AJi|bcbcsUf00Jvv>1d`tCPm zq8Czlc9#2^s>3%rlfoX#6JCa?eVv;iqHW+G-IDg*agAoo*N(JbP8jia`^>T5z@8)X zjY6fZe2TIcj&fglwANIjPLq>+x5GIUTR7*F(+veW%BdY3N0vCDt!>Z zFocMR2q8__lw{oN+6tQFcLm0ot=xKP53u=0K1SL;evFlMY_Q|ei}l2)|3u$+2y!%v-3!qco8o@=3uwL-Qe3P|Q8JI;m+6#t zajI8sKK9lwN`;}Gx&8U%u&^yABwdoXX_}bC2}{SMSMwRZ+J5z^=&O4*4z&sKf`)67 z>02)ewjEHBKk}a^*5d!Bj`?9X<>$+1br?s368t5uy6O7XAkQDLSv+P{S6?to80Pf!)toV)X&YwJS(?=qDK)DN@CyA1@lyaTGsE@iWk z3LF_DLM8$Kf11Y5zF~0gwqT|`aP#|6MkIph&Op~z-98&i!B)LEA4!tIOCnyCLnTPX3C-!(N^V3 z2$s4UJP#aVgfAizTLV{4pRDeW?6tBhE4loAm$?1IS~sibC>M@ET@bUu;QZ~Axdl`U z+ZZNMX`FFrFtGoir=My|Z_jSpoUj^&cvwZ>&Jj(`;-{ZX8=%PJlHgn>n7qrgd}`$Y zH31f*-Q@Jq;P@8XFUDUg-pD4J&GhO!^c}XjZTeZw{b!fS2P{4Fn27S2=uQY}JhoQF zk%qQ-;jZ;dllP6JCg0kIO{%LiFqqv_UA=F0R^G|HC31(|2uzqLPOa4FC=B>5E)nF(B*CZ}S%hKG+fZ1qAuBvN9m+1c~N^m-)$5BCpZEdzfi4 zvBBdwLU$=FU=#J|<-da_bI<5RNVD9LGRBgSDYLxU;pgULLWFcAy=YboW=f+dKO_H_ z8j?o>PvDFqB7M+I%N-IOs=bYEH<1|$>jw2blJ{Kav(j})Ia&?(%0&aRFPyVVy?XXsN`Y{T34dl8p85A#!Ewu+ewOQv zS7&#=5n71a`5Fol@fM9yQCIB?5Qe~@8M!~Ye$a1d21PCSlCCKC%FD{A(Sv||`Iz*M zZ**#AcH0gm?i@5XR=wMsPCxWbGC}W5UBY1@!!@gzi|i@ILX}ygDD{k)*?u=O{b=8{ z@N!&<^(th&@`!6jn7Uz!=+I=xRV^r$VF#y?%pIgk00*n5dfe=qb%QmWzP2w7(0m=t zDQ*#dT!YU7dNf<`rEr|Tr;Kb!=+t4$NzPy0`Fr}42`aC9oNawCP3Aq zcYTj4T@2)I$ty~=#P`#wjv>9#Ble;Joa)UTX*db9(<`)V3NEbgB&8q?nq zeIxU1X4Bc5wE@HZCqWcKoZ2We+%J4MV*ii5hpWRS1>S*}{JAgYToXp3Mj&tY5p9!C z?jlDy=evf&X8dL=yjJ!{NOC-Mv@g7O}@38oT=F> z_0*~cgKsi$WtgoUJumjo_WX~VD3pnG6fnB)<#;r zP?~3mWWB0-#iD0y$Es)i@%NMGGC>zJay1ftNA*nypHN0ghf8e1hmrr+56jq`IR>c5 z2GG9ZY`dcFkj^*i_gA7KJD&CUX(>#oocjL25KLmMV@rI6kpTV1B)+UB9g~y?56^Jk`jqoO39lJM(#hk!ch>`bGw+*kh zC46LTEQu?4(Q0(&+x<+eI4{L?u=KgR%ZADYZBvuWR5GLe501W<9mpzc3i``vEkxw&b<>#tjR_@S);gq*T-tB;z*$u1R=vDjA5lnA%F0(>BPXQ`|*LL z|4RM0z4ec~0Nc;(4&X1n zq9$xyJ{pEHCw}{B*S2_eW{-SlfFyGxT5}!3_PJ{ge51~ZVtNpkmVyaqcnLXtR)26W zJ)@hMmmNlI4NT~t9uD2R^R2MYxz_@Z*5_oA zND}SpDoVQZJ*jwpyi8vTi$Ggei#=cd)e(^ZFl&-l0d@EPue~o1r+R(YU+vwfVk4O{ zBqEYcgiNK7S*8^kN|YgFo?^8#D`Qw?NHPyCB`lU{lUXTq<`QLI*ydq5&qqj|@Av$! z>vx?$&bhARFD=XxAqm34?BD|5RmRFcI^T_*1}#aV5T0`lCa*w< zf+^H}08H@U@}H-tBi2*kwFTyuCeV|Om=WYA=ozKqz#8_LH33HAo>Vodx4;!71NSm= z2IuhmY!gCdt56j9_GtAkTS8bss3q4U-*_4Zr=U9N%(H|qtS3r>NZh8;w?|S+ToRV-19tqLWCvNr!(K;>%;kz2?SSgm_f1%a&)7#VeuU{oVQ{X-R!w4 z75b_~3tPV0$1~u)(FY(GU_Zl+(beh$Rz7E)C!clYK1M}CcHU@!*gxJAJgIsw1B zhdzAu!AzLFsD0nt!;r?3Yum(o>zST_Gn-HsA5c%VEuDQ#XMBUqGVpvGKT-EiYVN51 zOQuTuKV|g4BMyL##y_+XevqogrY#!I?{f2JAiN6PPQDE(#WO1gwt^8)?Fq0%0}o%c zn8GySOORONLWrO}0G$W}J21r1@=ge%=%W;bi4|vtvJ5_PS|kq`uJsZ<=EeF9C~D@^Y0 zVAw}QkkOM*V4`86^~Dr$&pTE5{3LK$gCLFQv7_PFt?8nnzkvh+aCAxIXv+PhWH1!_ z>}k4|s>G}&gbc83zS|_v36?zPE$?V@2HU@G!=f-Q6<@Mf_TJQlBA>X zQz%x)P6b}lKm^YALm~LkZHW__F!#W4MY^g%*P6K!%F_7gF3(VKg1X}F;HFl=-9oWR zf|ZE4$@q2jVPc*g>+U(Rc$X1uNEOLMXAfQ~Gw1FXalpQBFL6yLp9SwT+tbieC8KN6 zS5mzErhbj6)T*}s^wk=U1J^}DlXT%lc{lGVs46^%xxPM2Q1mZ3d}MbA!>n^iV24nj z8lz28KL$m$^!efNwE%(F5ynAN1v4jFCiv&4Ex%H~E-j-@ z5{HUMYOz-JzOqZ26a`P^BkO|YZ`WgwEraw(i>WkRt+($B+;w7okA1T;fLi-{gr94G zLMSHYEnp0p8Y6;<6xA3?G)N)~N@=G5x(0s!^KXe|0_f*Bk1q*iC?oo*6<3Pr476k%D zc7eHOs-{t)-FO)pXknm8I4PIpan-Q;J1h}PA-Qm__Zv9a>R5>vc*BOCCXJEGr@c z)^^kYC2~P3hM!64G8#!%DdnloQsydDa1TWNoEM$F)jU0?s<&Dw%tD8so~qVf84Q;) zq}BCFx9M4aBvKYN_5$Clo&k|G36W}uJ5Pej2&Q~InGg1cZkHxYx$)K_AI*L0mM8TI zEj`mv&MnVoVO}uTGtSo4Da?L!@A0cb=x7Siunph>USp}3uZB6SI-qx54WW`-O7*y@ zGtZ5r$nHt0)4W&(#Ynf(LD3mv7Qw=uw@?m8BFnHg6s02GjE|jm1!I>%*EAODf1Xko zI0|>)xqytH!CPaxEb+xoGb~Nb4$4z`UnC<8F4bPK9Vqrizl^pad@bR80z-bpL4W&X zS<}@O`oCR{X=-b0YiT7#KG@2e1M@jDv3egMV&{UfBlzWjb74YPcJO!LSWNx2{L|2` zs}p-%qB(ap!>Mnf|MMLVDxtIMpKaHtxgGx(_HIew;2P9$1Wa%RT3P1Et%|{a@`%nV zm9Qlo#$HuR{`24>@j+YHX86&>Pbm7e{+L*40~u1ojCzr3U7! z%d*@Xl8mvbJhE|H3GDuR|K)96YCf^nXMMO=%xX|%)_Nsi*gd&#qK_*xe_xw1SO!kx z!UE)Eom|xP^~WcKFr>S9rrakp(gBswKKC|Sm|%G;#Qz2T{)b!Eb_4v%+eLjmyK2zymcoRilq*|$T+XH+_>!H zI0EE5AQ^^`Mg@sYjuGA%PRREKK=GX)?yPH!`_;IgIQ)| z*EL{Y;DnrZ7xThLAJzwV%;5R78BOm9SB=EfhV-mC?db83ufEjqEYyCMnE7zQmP$dq zkG>zF=C4_8VbC(Qu>B^&)NGbUCCT&J{#FFwzbZW(p;S#wlJx9}-1w*fkp{o|ZxVFX zcHH+1^QBd>s*VW5{X0|<8~W}>87|M0p0_D?cP!}J`F8s8n9S_(n|MPXr@Kd^h35Z> zI!|dm(hXu6+qeUS`Hzq#+Rc--J)1Bvf-Z7sBU975A5O0B+VGhF22{9^Jx;`3a+nV= z)myy_do8uHqh6niTLt4DTwEk&n4C~@?R-!*UVLHK{<1Hs8M_ZUDjWevB5;Ye)Y6KG zX}T5X-qx;@`#=zc0_fTZbwm2k9)1aQ?wl!0(K#a=0}tN;hYL33u*|_2ecFmRo~++~ zS5@m6VwsLe|v4+##-UhI^8HRg9*$hB@W_j z4bS$A96J@4MTxgM;Bj}DOhO-*i2!fAM}#*+7zn0z>+J4eJCHq9_?7uwMTEdAihbq{ zJ^F3gA&1I;gHXpQF@IfM%1dq zYiOm&A4ViikGp=S+7Q8Bo^B;z3)wYeNN2CN`bpQ)c7Gha3I_%yRuwHQdzbUp&~V*t zB!E2gIK3&^ChRo{F$tNq{OTUn&&v4PqBmaKDM?8RW#h8#Kp?R1`}-Fy3{&ZJ0bti_ zj*UbX90Si<+)RbqDAAiDl5cte<`hd#RZv4~BN`}BIFuop=V!Fs+)&{rsq29CHzGv< zTyUO)G>0!`g1Q=XC{rGWMf16A3~P(;F(fdGik`?-|0i%?J(D<;J$e+^t29YQUG9yOD#uc@9j(5|yAD%qSWH`J)Kv8$QT-*(+O}_CGnCS@`GupJ_;14#SvYwt!cUR}a3B zJ)%%j6X==27Np^{Xz!4q@y~GjAzSrQc?)>WC`osMIrogcNnS{^_n&H|o1GVc+z8YN z)a(|vi%S-%sTzyI=lb!`to{B+kMHSZ&l4j7z_SA!y~FvJg4(xKO#E{(z5a0uYtqMO zr&D@GteX|q4ht2TL^{d85b6LcK`St4KOqTN_Xe8k6w#?<){+{k$p{CpC-GJSfY!gI z;foZDvS=C?pile4s~iMymqq zc($Z4%>d9tjl*C87-LZ?K3z=T5bBQDwo1A$UD|bm<})bQB;0(92=jv=eH4KiG-+=V zrvMx)=qo37y>(AN%MpRgIZnR& zcD0AJO2H(}pdVPiNXB)mLeN_ZnCwe2cao~1Z;N9(bKQ`ix9ZNNW zT`n}ok=SJxol)A53vqnMeA=BAO6c5n`8uHABKvbMM;vv5%^j@@8(F=Q4}{B+EYMRO zD#ttwJ~L3lCcQ(ZNL%tcBl(>CUX7ag_|TF1O_1c_t&qT1=s&v(jpo|-)ps4pR*1p5 zTz!zQt};e(&Yq>=F?n(-4}eGhQ{nvQENwOCytqw~&Z@xnmS^-%on|TWLc@j(Zy@j= zH}S=z(l5Y-k!<^l<=lO3_q`c_pN3uy;`UyTkv}*LC6I2el%ogOjW_u)TLwrfB@bkq znj&eVsB+l3(CtenqHqQo<1Gc-8IC9rBrFGOCg0sZ(BmX>KBTvE6XA-sak^BPfV`y>1S9(2Z~F9)h>zX39)Wy|bpW`;hsE zmH*VplflBZm<^P%-h?#WCGX7xyB66QK1Lxj7j8f`RHGlZbHrYIpuW`)pJKLy+M z*0Lbz!P&YVerhNeV|W2p`QL1|f2z%%rfr&n&0eg%*9Da}F+bnEyF%m;$S;ij58waB zw~r7nR(T?j1oU0?5xa)~5-#r=G|wtsTP2cccJ$77o$eF%yN|ND7&b~!2V6BRka#-%z=Zn@1hOTB*0wm9WvmfBph<= zVuf?q7df~98~t7bl)3}w^UhD*WE{|(zFvMRIpCSqn>IMFL&fC}ONTvDHA>qP#u>Sn zQk1j5>h#Z&{+<%|Ld`e;iU$D60}0a!#W`Xh9|g4LiLE7v-p51FbcRVSs6xMWj9`W& zVM*Om1&tT9r=*;51Hb_U8#5xl@%!_1#i+!;J|0NyftUfW1OsBtHi0^0QlQaGNtAH_ z0*8{`jqAu2d;57^b6=@}UcB#pbB3XclDSxQ0|QCuoB*$vWnqC^PJb$dxyOH(HqrXc zDw{CX9A-1>URt;;xOqbnk&{u#EcpcxR)e8634+Cnm{;1ZIP^lcGPgieuIcR9*(#Rf z0eVD#s5%WGfd(&JK%M+!6fT#Useh&P#RmVOlI@FR zU-Kxq%nZ^1u3@)EcA>0m317Nu37XNQzgK}Tlwf2QQgLHhn+nE=L$=fNj@=8S3<&4v zKlap4kF;HmJ5~5aj(MxwC_ryItypqt=$MPfy7%sTaXYX-m9t)^ko}U@ zShnCbp?DOl1}%bKN5^j1x6AA;PBWLG@%_;&TE3UJf_0S1rwz<;YdNrha(9$oIJdf7 zRF1V&4-LgF(z>*ij?!TsbJ-T-0jUlMAQNo`h66aC?@B-PcUW~aVSd5)llN&?eKeq2 zIXI;CkXQ|xG}X~5@K|-t zP4N1_0?L zT0f}d-LPIw2UmIr{{`0cX?T83#QfW_#Itdr)dVEH58QBb6T$kTtl}GQNzbt)N zL#Tnyn|Flm3K%bF++Z0;=}w$URS3KhERhFR@?ls|mK|-Ed0Mxo9-hyLSU5RiWfRk& z!UcqGVhrY;3RDGw6o)7TY)_!v<0HKxqYv4cbpk3s0{B~S&`t8_A z6$oDHPmDk+l+y;~EuhS)mO&#`p+Raj96&LFBybP$Y)anqdbZ~YjEMoByEZd@K(5vd z&2gW-4&F~bI?Q++gpHi4z}z#socvP$Ggg=)>0$7>{!IJ@W0k_M6I7aOxCCnJ$9H~X zI-t*7nj%@|s;ZKE=vA-byAJ4wf-g)gS+<%L{D}2?>7djgZ_1}MdKT)ji{#JZ5j8E45uo0PIP$ua^`lce;`(EO zK_IPw(2wB6yQ~$t2vb%PPxPqn98!;O+|doFm~B;yf5c}!@=tu2#RvHF1!S;61YXuU zgvM~8FJ{NPc4iq$29$4+^~79wTrNW~VwQL|Jt6S4 z(#1?$EaR+ZW2@VUrXp<-;{%wF;yBVGFF`)X!FKyg+#^H?Iaj_FTgsZRjQ$tPi7>M? z5QXJoW?AWyDaGWQXRh?wG);auFzSm45x9rlj(PJ(EzQB1RK# zMke<{gEFek-JBM-;bOQ3kS`}rVA(l_)p=<*WSOp+3^vWLurUK0sF=X|VQW?Ihv@u( z&41UCQ#2k&!ZVIdUx{20PXAoEWMf5>Fd5wZY&@Yj;kzO za+W<(TDWtTW;5$}k2c+ft$>c5cbhpQp&VrOJN;TBirt0e$+#wL2eyU=YYGIJV+w0}+WuK-OBpl2$=Iv8lVV+L5o^tx) z5*1~h?6-^U`_XR+4M={Y5cc*a{RJZ%5I}J{8lBKxHT#)0aeN}aBD|l-gtv`Z61J^P z_>Q}sWGJ4>WQJ+3^@R#n?*50j18=p#pqX)OSGcAJeOD8aWpjhCDqf3Et{T5X05zk# zw~G08?84Tgp!;*Z`KufnG>BLi_joQv_Loq9UnUYq2xIEkSAJI;-=ms2?_1%Hy#c3N zZ;Gu$i+*D7?_9t3fO*(DQ%KB&#CTD?!_xhYpxD4-j7pBDLIL90^DLW_|kC`*l7u+?D(NSV%Q@GtIS*R`SP1sbfzRZ!-2C?32u9rS8b+BxBO zm>(q*bI#DI+w%Z4hmHGDc*mrH3@gp+Pc6Nnn~mrHBA9HJAnN`f?Dyy(c%@slp7mem zThdVDdV{iJLv95&+mS;IpA7Q&5i$lrYZaNn7X0pT|3;R#2M(%8T!R|2## z4BP4sXvBNRQrI7#{>sXg2|umMTTL-%edustuX9^v9^nNfQeP(qi(e24qo-WD7yNFR z=QH}|WqFvEFOL%%8tsUbclXc}^cbG}q%rOJn>L^+Gy_LS2VQaYY02`@Afp+cx1eLU z=?Zp1@izzP4tDjpr!zpR=yZl@9N3{U*&;whFwn~c7B^Z1DdUnW8ecFowyPz?Sc2l76)OYMgFIF{w*umAmbBV!bwCYo#9NJV)?~tt{RBlOB<(f8x zFHTrii%qCng_|;Jf|c>e?9KO2d!UtSws8dNZosyrAc=x$k(WBxAkxJyEx35|bq)E{ zh&%F1f8TO!_J)1akJqWGa~@mYV%Vd8*nb|9?e zBMdzUqzH@}6;-mA?RJ2V#}v%L3hG^9!MJK3qyXWW#(qwfm?1H|isc?w&NB<6f2YKG z5L`10kCdd?PQo4pW4|KZ32JeKvG{@e6+*?Xy?Sn^5mMI_%?4UUhUsDNDFswAguQ9z1$`3fqSn$uzT+8c3rm}krt`Thgr=BHbl6!Cpk>Z zpENkg{z{}W{nz`5K2y}}*e^xe*-pet^e(Mos#dASz>{K z8$>QtX*ykhJLxat(PF(xJxjLMbX9UM-hUIxlh190YKlFl-!s%wlo4L0S*2#S(K3%# z_IC7=J{7+ige#_wMQ`8I{j8%_bI@`#4&W6K=wQ|$F`D^$X`VR!a2&zk4r}0 zEB)-l$etjt9^%Xl%qRdCt=z*2#^-8x(Hc0%8$S<=vNN(rL9Ta1$UI!|6f$1m-KwNJ z=N&3G^>~=j5D-oRt5FLm&ttCOV?R9!2e9!C0uh7Z!MB#3%N@*a3W3dzt!e>jwl7bZW$;*Z!3QG z{IKife;Ebd`7XemE*L)Mn&SviQPFLnLOIJNu!-nwI3X$T<=H7uqhbbt9x#2*Kzu;$_6zydls>yo{Kd*S(BVBh0qB(I8e<)X)L|n3yU`%^pU6%vBp7mA9pn z@+ewkMYYJv)?(J?F<7H|7R~>kFMvX+X&$KKIx=wzg}U3saHQFM4+{0{ToX5X-3 zwTL&`4%EHpMryL3?>Oy1eR|aP>9MvL3WeGgrd<$*I4%8-LdjGDh(4r>g6DLw6kheCU$ypaNo@MFGFlcnXmD7Vbx( z;&OIZ=XCBsp}0bF>LL&$FlP9jd$-9Uawl38O496LkXbIgpBk%K1kbvQ-2d1wE*M@= z48`#!F~mGO3%+q>F0`o7heNyCsNoKF+1fqG)kvcCJc&Zpr}b$qzh3I ztx)r7pBllX6R|12l&1ay_nK!HN zvIIlHtw&gM&C>4Yt*@Pp$3i-DG|zXfFSdR033Ybe|cz7m^KrJm-(``16A2)WlvWCLDsR4RCU=?mXH}MuAyFiyo ztxS4iyyJ6{Yo)ttm%5*(f*Apf)dv5uRoI9dKOuS0n+Y9ROp;trx2CUjJA>-9+W}Z?zs{HecfS`s=SprHzNwAGHbU{Iaa%Euv2TvaS+^ z;4A#Ru$rQd@Beva37IKB^8R^gMg8ypSY$$Y{LOa^X15ln2T3$rSNz;6gsdi*0|G8j zOK3W>*gT$=?p~N3l^BbtcS?WTdS+^=4>^;rw)Wf`3aN$7Xa4Keqt=IDfS{X#F}^T~ zcJ6)56F0uwow$2;Zb;S#ayiAVm%Zl`pOa$`YfOr?kbwF6R&OXrf5*4E3ZREdq0LL^ zGDNG5pOzb-0a7Mu#o*@4lgG)#kYi`#=Wpqu9H#976Oe0#T!&bU zl{IAi*^OYl>0bXMLL7PrJfEV10+3>(`a^N+ht%yERkP=( cKP{~7ID4F9A$?BwIr0>F8I_AT>1+4@1H=oFkpKVy literal 0 HcmV?d00001 diff --git a/vertical-slice-architecture/etc/vertical-slice-architecture.urm.puml b/vertical-slice-architecture/etc/vertical-slice-architecture.urm.puml new file mode 100644 index 000000000000..9fcc14b64417 --- /dev/null +++ b/vertical-slice-architecture/etc/vertical-slice-architecture.urm.puml @@ -0,0 +1,125 @@ +@startuml +package com.iluwatar.vertical-slice-architecture { + + !define ENTITY class + !define SERVICE class + !define REPOSITORY class + !define VIEW class + + package Customer { + ENTITY Customer { + +id: int + name: String + email: String + +getId(): int + +getName(): String + +getEmail(): String + +builder(): Builder + } + + SERVICE CustomerService { + +createCustomer(name: String, email: String): Customer + +getCustomerById(id: int): Customer + +getAllCustomers(): List + } + + REPOSITORY CustomerRepository { + +save(customer: Customer): Customer + +findById(id: int): Optional + +findAll(): List + } + + + VIEW CustomerView { + -customerService: CustomerService + -LOGGER: logger + +render(): void + } + } + + package Product { + ENTITY Product { + +id: int + name: String + price: double + +getId(): int + +getName(): String + +getPrice(): Double + +builder(): Builder + } + + SERVICE ProductService { + +createProduct(name: String, price: double): Product + +getProductById(id: int): Product + +getAllProducts(): List + } + + REPOSITORY ProductRepository { + +save(product: Product): Product + +findById(id: int): Optional + +findAll(): List + } + + + VIEW ProductView { + -productService: ProductService + -LOGGER: logger + +render(): void + } + } + + package Order { + ENTITY Orders { + +id: int + customer: Customer + product: Product + +getId(): int + +getCustomer(): Customer + +getProduct(): Product + +builder(): Builder + } + + SERVICE OrderService { + +createOrder(customer: Customer, product: Product): void + +getOrderById(id: int): Orders + +getOrdersByCustomer(customer: Customer): List + } + + REPOSITORY OrderRepository { + +save(order: Orders): Orders + +findById(id: int): Optional + +findByCustomer(customer: Customer): List + } + + + VIEW OrderView { + -orderService: OrderService + -LOGGER: logger + +render(customer: Customer): void + +showAllOrders(orders: List): void + } + } + + class App { + +initializeData(): void + +run(): void + } + + Customer.Customer --> Customer.CustomerService + Customer.CustomerService --> Customer.CustomerRepository + Customer.CustomerService --> Customer.CustomerView + + Product.Product --> Product.ProductService + Product.ProductService --> Product.ProductRepository + Product.ProductService --> Product.ProductView + + Order.Orders --> Order.OrderService + Order.OrderService --> Order.OrderRepository + Order.OrderService --> Order.OrderView + + App --> Customer.CustomerService + App --> Product.ProductService + App --> Order.OrderService + +} +@enduml \ No newline at end of file diff --git a/vertical-slice-architecture/pom.xml b/vertical-slice-architecture/pom.xml new file mode 100644 index 000000000000..1a9d15591dd9 --- /dev/null +++ b/vertical-slice-architecture/pom.xml @@ -0,0 +1,90 @@ + + + + 4.0.0 + vertical-slice-architecture + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + runtime + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.vertical.slice.architecture.App + + + + + + + + + + diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/App.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/App.java new file mode 100644 index 000000000000..b42f0bc4a2fd --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/App.java @@ -0,0 +1,41 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * main application. + */ + +@SpringBootApplication +public class App { + + public static void main(String[] args) { + SpringApplication.run(App.class, args); + } + +} diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/Runner.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/Runner.java new file mode 100644 index 000000000000..12a42ee31b6d --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/Runner.java @@ -0,0 +1,83 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture; + +import com.iluwatar.verticalslicearchitecture.customer.Customer; +import com.iluwatar.verticalslicearchitecture.customer.CustomerService; +import com.iluwatar.verticalslicearchitecture.customer.CustomerView; +import com.iluwatar.verticalslicearchitecture.order.OrderService; +import com.iluwatar.verticalslicearchitecture.order.OrderView; +import com.iluwatar.verticalslicearchitecture.product.Product; +import com.iluwatar.verticalslicearchitecture.product.ProductService; +import com.iluwatar.verticalslicearchitecture.product.ProductView; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +/** + * Seeding test data. + */ + +@Component +@AllArgsConstructor +@Slf4j +public class Runner implements CommandLineRunner { + + CustomerService customerService; + OrderService orderService; + ProductService productService; + + @Override + public void run(String... args) { + initializeData(); + new OrderView(orderService).render(customerService.getCustomerById(1)); + new CustomerView(customerService).render(); + new ProductView(productService).render(); + } + + /** + * method for data seeds. + */ + + public void initializeData() { + + Customer customer = Customer.builder().id(1).name("sugan0tech").email("sugan@gmail.com").build(); + customerService.createCustomer(customer); + + Product oreo = Product.builder().id(1).price(2.00).name("Oreo").build(); + Product cone = Product.builder().id(3).price(1.15).name("Ice Cream Cone").build(); + Product apple = Product.builder().id(4).price(2.00).name("Apple").build(); + Product sandwich = Product.builder().id(2).price(6.00).name("Sandwich").build(); + productService.createProduct(oreo); + productService.createProduct(cone); + productService.createProduct(apple); + productService.createProduct(sandwich); + + orderService.createOrder(1, customer, oreo); + orderService.createOrder(2, customer, sandwich); + orderService.createOrder(3, customer, apple); + } +} diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/Customer.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/Customer.java new file mode 100644 index 000000000000..47e6d7ac2ed0 --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/Customer.java @@ -0,0 +1,49 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture.customer; + +import javax.persistence.Entity; +import javax.persistence.Id; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * Customer Entity. + */ + +@Entity +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +public class Customer { + + @Id + Integer id; + String name; + String email; +} diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/CustomerRepository.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/CustomerRepository.java new file mode 100644 index 000000000000..3ba569cb4b91 --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/CustomerRepository.java @@ -0,0 +1,36 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture.customer; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +/** + * Customer Repository. + */ + +@Repository +public interface CustomerRepository extends JpaRepository { +} diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/CustomerService.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/CustomerService.java new file mode 100644 index 000000000000..6d9422d39157 --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/CustomerService.java @@ -0,0 +1,51 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture.customer; + +import java.util.List; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +/** + * Customer Service. + */ + +@Service +@AllArgsConstructor +public class CustomerService { + private CustomerRepository customerRepository; + + public void createCustomer(Customer customer) { + customerRepository.save(customer); + } + + public Customer getCustomerById(int id) { + return customerRepository.findById(id).orElse(null); + } + + public List getAllCustomers() { + return customerRepository.findAll(); + } +} diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/CustomerView.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/CustomerView.java new file mode 100644 index 000000000000..ff6f30ea592c --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/customer/CustomerView.java @@ -0,0 +1,42 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture.customer; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * View for Customer. + */ + +@AllArgsConstructor +@Slf4j +public class CustomerView { + CustomerService customerService; + + public void render() { + customerService.getAllCustomers().forEach(customer -> LOGGER.info(customer.getName())); + } +} diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/OrderRepository.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/OrderRepository.java new file mode 100644 index 000000000000..7621eb1e07e7 --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/OrderRepository.java @@ -0,0 +1,39 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture.order; + +import com.iluwatar.verticalslicearchitecture.customer.Customer; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +/** + * Orders repository. + */ + +@Repository +public interface OrderRepository extends JpaRepository { + List findByCustomer(Customer customer); +} diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/OrderService.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/OrderService.java new file mode 100644 index 000000000000..062c935e63f7 --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/OrderService.java @@ -0,0 +1,54 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture.order; + +import com.iluwatar.verticalslicearchitecture.customer.Customer; +import com.iluwatar.verticalslicearchitecture.product.Product; +import java.util.List; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +/** + * Order Service. + */ + +@Service +@AllArgsConstructor +public class OrderService { + private OrderRepository orderRepository; + + + public void createOrder(int id, Customer customer, Product product) { + orderRepository.save(new Orders(id, customer, product)); + } + + public Orders getOrderById(int id) { + return orderRepository.findById(id).orElse(null); + } + + public List getOrdersByCustomer(Customer customer) { + return orderRepository.findByCustomer(customer); + } +} diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/OrderView.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/OrderView.java new file mode 100644 index 000000000000..0906aef530da --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/OrderView.java @@ -0,0 +1,43 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture.order; + +import com.iluwatar.verticalslicearchitecture.customer.Customer; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * View for orders. + */ + +@AllArgsConstructor +@Slf4j +public class OrderView { + OrderService orderService; + + public void render(Customer customer) { + orderService.getOrdersByCustomer(customer).forEach(order -> LOGGER.info(order.getId().toString())); + } +} diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/Orders.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/Orders.java new file mode 100644 index 000000000000..479cd37e066d --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/order/Orders.java @@ -0,0 +1,56 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture.order; + +import com.iluwatar.verticalslicearchitecture.customer.Customer; +import com.iluwatar.verticalslicearchitecture.product.Product; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * Customer Entity. + */ + +@Entity +@AllArgsConstructor +@NoArgsConstructor +@Getter +public class Orders { + @Id + private Integer id; + + @ManyToOne + @JoinColumn(name = "customer_id") + private Customer customer; + + @ManyToOne + @JoinColumn(name = "product_id") + private Product product; +} diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/Product.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/Product.java new file mode 100644 index 000000000000..45374d71f4a0 --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/Product.java @@ -0,0 +1,48 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture.product; + +import javax.persistence.Entity; +import javax.persistence.Id; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * Customer Entity. + */ + +@Entity +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +public class Product { + @Id + Integer id; + Double price; + String name; +} diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/ProductRepository.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/ProductRepository.java new file mode 100644 index 000000000000..e0deb6445e8f --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/ProductRepository.java @@ -0,0 +1,36 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture.product; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +/** + * Product Repository. + */ + +@Repository +public interface ProductRepository extends JpaRepository { +} diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/ProductService.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/ProductService.java new file mode 100644 index 000000000000..ca54ce3fa004 --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/ProductService.java @@ -0,0 +1,50 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture.product; + +import java.util.List; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +/** + * Products service. + */ +@Service +@AllArgsConstructor +public class ProductService { + private ProductRepository productRepository; + + public void createProduct(Product product) { + productRepository.save(product); + } + + public Product getProductById(int id) { + return productRepository.findById(id).orElse(null); + } + + public List getAllProducts() { + return productRepository.findAll(); + } +} diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/ProductView.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/ProductView.java new file mode 100644 index 000000000000..4d0eee480750 --- /dev/null +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/product/ProductView.java @@ -0,0 +1,42 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.verticalslicearchitecture.product; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * View for Products. + */ + +@AllArgsConstructor +@Slf4j +public class ProductView { + ProductService productService; + + public void render() { + productService.getAllProducts().forEach(product -> LOGGER.info(product.getName())); + } +} diff --git a/vertical-slice-architecture/src/main/resources/application.properties b/vertical-slice-architecture/src/main/resources/application.properties new file mode 100644 index 000000000000..64f39530555c --- /dev/null +++ b/vertical-slice-architecture/src/main/resources/application.properties @@ -0,0 +1,6 @@ +spring.main.web-application-type=none +#datasource settings +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=sa \ No newline at end of file diff --git a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/AppTests.java b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/AppTests.java new file mode 100644 index 000000000000..7dbbaf03bee9 --- /dev/null +++ b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/AppTests.java @@ -0,0 +1,21 @@ +package com.iluwatar.verticalslicearchitecture; + +import lombok.AllArgsConstructor; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@SpringBootTest +@AllArgsConstructor +class AppTests { + + private final ApplicationContext applicationContext; + + @Test + void contextLoads() { + assertNotNull(applicationContext); + } + +} diff --git a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerServiceTest.java b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerServiceTest.java new file mode 100644 index 000000000000..5dca86f9a8b7 --- /dev/null +++ b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerServiceTest.java @@ -0,0 +1,74 @@ +package com.iluwatar.verticalslicearchitecture.customer; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.*; + + +class CustomerServiceTest { + @Mock + private CustomerRepository customerRepository; + + @InjectMocks + private CustomerService customerService; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + } + + + @Test + void testCreateCustomer() { + + Customer newCustomer = Customer.builder().build(); + + when(customerRepository.save(any(Customer.class))).thenReturn(newCustomer); + customerService.createCustomer(newCustomer); + verify(customerRepository, times(1)).save(newCustomer); + } + + @Test + void testGetCustomerById() { + int customerId = 1; + Customer existingCustomer = new Customer(customerId, "John Doe", "john.doe@example.com"); + + /* + * Mocking the behavior of customerRepository.findById + */ + when(customerRepository.findById(customerId)).thenReturn(Optional.of(existingCustomer)); + + Customer retrievedCustomer = customerService.getCustomerById(customerId); + + assertNotNull(retrievedCustomer); + assertEquals(existingCustomer, retrievedCustomer); + } + + @Test + void testGetAllCustomers() { + List customers = new ArrayList<>(); + customers.add(new Customer(1, "John Doe", "john.doe@example.com")); + customers.add(new Customer(2, "Jane Smith", "jane.smith@example.com")); + + /* + * Mocking the behavior of customerRepository.findAll + */ + when(customerRepository.findAll()).thenReturn(customers); + + List retrievedCustomers = customerService.getAllCustomers(); + + assertNotNull(retrievedCustomers); + assertEquals(customers.size(), retrievedCustomers.size()); + assertEquals(customers, retrievedCustomers); + } +} \ No newline at end of file diff --git a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerTest.java b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerTest.java new file mode 100644 index 000000000000..ce173daab0ff --- /dev/null +++ b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerTest.java @@ -0,0 +1,28 @@ +package com.iluwatar.verticalslicearchitecture.customer; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CustomerTest { + + @Test + public void testCustomerEntity() { + // Arrange + Integer id = 1; + String name = "John Doe"; + String email = "john.doe@example.com"; + + // Act + Customer customer = Customer.builder() + .id(id) + .name(name) + .email(email) + .build(); + + // Assert + assertEquals(id, customer.getId()); + assertEquals(name, customer.getName()); + assertEquals(email, customer.getEmail()); + } +} \ No newline at end of file diff --git a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerViewTest.java b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerViewTest.java new file mode 100644 index 000000000000..a7107161cdc7 --- /dev/null +++ b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerViewTest.java @@ -0,0 +1,36 @@ +package com.iluwatar.verticalslicearchitecture.customer; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +import static org.mockito.Mockito.*; + +class CustomerViewTest { + + @Mock + private CustomerService customerService; + + private CustomerView customerView; + + @BeforeEach + public void setup() { + MockitoAnnotations.openMocks(this); + customerView = new CustomerView(customerService); + } + + @Test + void testRender() { + when(customerService.getAllCustomers()).thenReturn(List.of( + Customer.builder().id(1).name("John Doe").email("john.doe@example.com").build(), + Customer.builder().id(2).name("Jone Doe").email("jone.doe@example.com").build() + )); + + customerView.render(); + + verify(customerService, times(1)).getAllCustomers(); + } +} \ No newline at end of file diff --git a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/order/OrderServiceTest.java b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/order/OrderServiceTest.java new file mode 100644 index 000000000000..028c6d0b7b3f --- /dev/null +++ b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/order/OrderServiceTest.java @@ -0,0 +1,74 @@ +package com.iluwatar.verticalslicearchitecture.order; + +import com.iluwatar.verticalslicearchitecture.customer.Customer; +import com.iluwatar.verticalslicearchitecture.product.Product; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +class OrderServiceTest { + + @Mock + private OrderRepository orderRepository; + + @InjectMocks + private OrderService orderService; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void testCreateOrder() { + Customer customer = Customer.builder().id(1).name("John Doe").email("john.doe@example.com").build(); + Product product = Product.builder().id(1).name("Sample Product").price(100.0).build(); + Orders order = new Orders(1, customer, product); + + when(orderRepository.save(any(Orders.class))).thenReturn(order); + + orderService.createOrder(1, customer, product); + + Mockito.verify(orderRepository).save(any(Orders.class)); + } + + @Test + void testGetOrderById() { + Customer customer = Customer.builder().id(1).name("John Doe").email("john.doe@example.com").build(); + Product product = Product.builder().id(1).name("Sample Product").price(100.0).build(); + Orders order = new Orders(1, customer, product); + + when(orderRepository.findById(1)).thenReturn(Optional.of(order)); + + Orders result = orderService.getOrderById(1); + + assertEquals(order, result); + } + + @Test + void testGetOrdersByCustomer() { + Customer customer = Customer.builder().id(1).name("John Doe").email("john.doe@example.com").build(); + Product product = Product.builder().id(1).name("Sample Product").price(100.0).build(); + Orders order = new Orders(1, customer, product); + + List ordersList = new ArrayList<>(); + ordersList.add(order); + + when(orderRepository.findByCustomer(customer)).thenReturn(ordersList); + + List result = orderService.getOrdersByCustomer(customer); + + assertEquals(ordersList, result); + } +} diff --git a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/order/OrderViewTest.java b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/order/OrderViewTest.java new file mode 100644 index 000000000000..98274babdb20 --- /dev/null +++ b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/order/OrderViewTest.java @@ -0,0 +1,40 @@ +package com.iluwatar.verticalslicearchitecture.order; + +import com.iluwatar.verticalslicearchitecture.customer.Customer; +import com.iluwatar.verticalslicearchitecture.product.Product; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.List; + +import static org.mockito.Mockito.*; + +class OrderViewTest { + + private OrderService orderService; + private OrderView orderView; + + @BeforeEach + void setUp() { + orderService = Mockito.mock(OrderService.class); + orderView = new OrderView(orderService); + } + + @Test + void testRender() { + Customer customer = Customer.builder().id(1).name("John Doe").email("john.doe@example.com").build(); + Product product = Product.builder().id(1).name("Sample Product").price(100.0).build(); + Orders order = new Orders(1, customer, product); + + List ordersList = new ArrayList<>(); + ordersList.add(order); + + when(orderService.getOrdersByCustomer(customer)).thenReturn(ordersList); + + orderView.render(customer); + + verify(orderService, times(1)).getOrdersByCustomer(any()); + } +} diff --git a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/order/OrdersTest.java b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/order/OrdersTest.java new file mode 100644 index 000000000000..767da0bbf919 --- /dev/null +++ b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/order/OrdersTest.java @@ -0,0 +1,27 @@ +package com.iluwatar.verticalslicearchitecture.order; + +import com.iluwatar.verticalslicearchitecture.customer.Customer; +import com.iluwatar.verticalslicearchitecture.product.Product; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class OrdersTest { + + @BeforeEach + void setUp() { + } + + @Test + void testOrdersEntity() { + Customer customer = Customer.builder().id(1).name("John Doe").email("john.doe@example.com").build(); + Product product = Product.builder().id(1).name("Sample Product").price(100.0).build(); + + Orders orders = new Orders(1, customer, product); + + assertEquals(1, orders.getId()); + assertEquals(customer, orders.getCustomer()); + assertEquals(product, orders.getProduct()); + } +} diff --git a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/product/ProductServiceTest.java b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/product/ProductServiceTest.java new file mode 100644 index 000000000000..8a53db6a1ab2 --- /dev/null +++ b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/product/ProductServiceTest.java @@ -0,0 +1,58 @@ +package com.iluwatar.verticalslicearchitecture.product; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +class ProductServiceTest { + + private ProductRepository productRepository; + private ProductService productService; + + @BeforeEach + void setUp() { + productRepository = Mockito.mock(ProductRepository.class); + productService = new ProductService(productRepository); + } + + @Test + void testCreateProduct() { + Product product = Product.builder().id(1).name("Sample Product").price(100.0).build(); + + productService.createProduct(product); + + Mockito.verify(productRepository, Mockito.times(1)).save(product); + } + + @Test + void testGetProductById() { + int productId = 1; + Product product = Product.builder().id(1).name("Sample Product").price(100.0).build(); + + when(productRepository.findById(productId)).thenReturn(Optional.of(product)); + + Product retrievedProduct = productService.getProductById(productId); + + assertEquals(product, retrievedProduct); + } + + @Test + void testGetAllProducts() { + List productList = new ArrayList<>(); + productList.add(Product.builder().id(1).name("Product 1").price(100.0).build()); + productList.add(Product.builder().id(2).name("Product 2").price(50.0).build()); + + when(productRepository.findAll()).thenReturn(productList); + + List retrievedList = productService.getAllProducts(); + + assertEquals(productList, retrievedList); + } +} diff --git a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/product/ProductTest.java b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/product/ProductTest.java new file mode 100644 index 000000000000..f257c3de0939 --- /dev/null +++ b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/product/ProductTest.java @@ -0,0 +1,21 @@ +package com.iluwatar.verticalslicearchitecture.product; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ProductTest { + + @Test + void testProductConstructorAndGetters() { + Integer id = 1; + Double price = 100.0; + String name = "Sample Product"; + + Product product = Product.builder().id(id).price(price).name(name).build(); + + assertEquals(id, product.getId()); + assertEquals(price, product.getPrice()); + assertEquals(name, product.getName()); + } +} diff --git a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/product/ProductViewTest.java b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/product/ProductViewTest.java new file mode 100644 index 000000000000..6e0422b98740 --- /dev/null +++ b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/product/ProductViewTest.java @@ -0,0 +1,40 @@ +package com.iluwatar.verticalslicearchitecture.product; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +import static org.mockito.Mockito.times; + +class ProductViewTest { + + @Mock + ProductService productService; + + ProductView productView; + + @BeforeEach + public void setup() { + MockitoAnnotations.openMocks(this); + productView = new ProductView(productService); + } + + @Test + void testRender() { + + List productList = new ArrayList<>(); + productList.add(Product.builder().id(1).price(100.0).name("Sample Product 1").build()); + productList.add(Product.builder().id(2).price(50.0).name("Sample Product 2").build()); + + Mockito.when(productService.getAllProducts()).thenReturn(productList); + + productView.render(); + + Mockito.verify(productService, times(1)).getAllProducts(); + } +} From 3f1828a9c367fb29125fb39c70c9bc2252d0084a Mon Sep 17 00:00:00 2001 From: sugan0tech <71312159+sugan0tech@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:08:50 +0530 Subject: [PATCH 2/8] fixed code smell --- .../verticalslicearchitecture/customer/CustomerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerTest.java b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerTest.java index ce173daab0ff..9530d6ecb7de 100644 --- a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerTest.java +++ b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/customer/CustomerTest.java @@ -7,7 +7,7 @@ class CustomerTest { @Test - public void testCustomerEntity() { + void testCustomerEntity() { // Arrange Integer id = 1; String name = "John Doe"; From 1b130b137d5cee5998121fa07f939645f42c5281 Mon Sep 17 00:00:00 2001 From: sugan0tech <71312159+sugan0tech@users.noreply.github.com> Date: Tue, 3 Oct 2023 19:59:57 +0530 Subject: [PATCH 3/8] App code coverage changes --- .../java/com/iluwatar/verticalslicearchitecture/AppTests.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/AppTests.java b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/AppTests.java index 7dbbaf03bee9..4085b102bbb4 100644 --- a/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/AppTests.java +++ b/vertical-slice-architecture/src/test/java/com/iluwatar/verticalslicearchitecture/AppTests.java @@ -15,6 +15,8 @@ class AppTests { @Test void contextLoads() { + App.main(new String[] {}); + assertNotNull(App.class); assertNotNull(applicationContext); } From 272cb8703199397cc24be64fd76cbd414fbd32da Mon Sep 17 00:00:00 2001 From: sugan0tech <71312159+sugan0tech@users.noreply.github.com> Date: Tue, 3 Oct 2023 20:02:41 +0530 Subject: [PATCH 4/8] local variable in var declaration --- .../iluwatar/verticalslicearchitecture/Runner.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/Runner.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/Runner.java index 12a42ee31b6d..22fe98c1915f 100644 --- a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/Runner.java +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/Runner.java @@ -64,20 +64,20 @@ public void run(String... args) { public void initializeData() { - Customer customer = Customer.builder().id(1).name("sugan0tech").email("sugan@gmail.com").build(); + var customer = Customer.builder().id(1).name("sugan0tech").email("sugan@gmail.com").build(); customerService.createCustomer(customer); - Product oreo = Product.builder().id(1).price(2.00).name("Oreo").build(); - Product cone = Product.builder().id(3).price(1.15).name("Ice Cream Cone").build(); - Product apple = Product.builder().id(4).price(2.00).name("Apple").build(); - Product sandwich = Product.builder().id(2).price(6.00).name("Sandwich").build(); + var oreo = Product.builder().id(1).price(2.00).name("Oreo").build(); + var cone = Product.builder().id(3).price(1.15).name("Ice Cream Cone").build(); + var apple = Product.builder().id(4).price(2.00).name("Apple").build(); + var sandwich = Product.builder().id(2).price(6.00).name("Sandwich").build(); productService.createProduct(oreo); productService.createProduct(cone); productService.createProduct(apple); productService.createProduct(sandwich); orderService.createOrder(1, customer, oreo); - orderService.createOrder(2, customer, sandwich); orderService.createOrder(3, customer, apple); + orderService.createOrder(2, customer, sandwich); } } From c189ae90d4e231c9c5375947eea8bd66079a784d Mon Sep 17 00:00:00 2001 From: sugan0tech <71312159+sugan0tech@users.noreply.github.com> Date: Tue, 3 Oct 2023 20:13:26 +0530 Subject: [PATCH 5/8] added more context with example --- vertical-slice-architecture/README.md | 1 + .../java/com/iluwatar/verticalslicearchitecture/App.java | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/vertical-slice-architecture/README.md b/vertical-slice-architecture/README.md index 9356119f9b2d..44a72ca2ac68 100644 --- a/vertical-slice-architecture/README.md +++ b/vertical-slice-architecture/README.md @@ -42,3 +42,4 @@ Use Vertical Slice Architecture when * [How to Implement Vertical Slice Architecture by Gary Woodfine](https://garywoodfine.com/implementing-vertical-slice-architecture/) * [youtube](https://www.youtube.com/watch?v=B1d95I7-zsw) * [medium](https://medium.com/sahibinden-technology/package-by-layer-vs-package-by-feature-7e89cde2ae3a) +* [A reference application](https://github.com/sugan0tech/Event-Manager) diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/App.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/App.java index b42f0bc4a2fd..19870b1aabf6 100644 --- a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/App.java +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/App.java @@ -28,7 +28,11 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; /** - * main application. + * Main application. + * The main objective of this code sample is for you to have a look at how the view, entity, repository and Service are + * organized. + * No matter what application you are building Layer by Feature will always give the upper hand of better + * maintainability. */ @SpringBootApplication From 24d5063125b237c4df83c0142c20a379760440a9 Mon Sep 17 00:00:00 2001 From: sugan0tech Date: Tue, 17 Oct 2023 20:49:20 +0530 Subject: [PATCH 6/8] Added better explanation and updated README.md --- vertical-slice-architecture/README.md | 43 +++++++++++++------ .../verticalslicearchitecture/App.java | 10 ++--- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/vertical-slice-architecture/README.md b/vertical-slice-architecture/README.md index 44a72ca2ac68..92cf530a72be 100644 --- a/vertical-slice-architecture/README.md +++ b/vertical-slice-architecture/README.md @@ -1,6 +1,6 @@ --- -title: Vertical-Slice-Architecture -aka: Layer-By-Feature +title: Vertical Slice Architecture +aka: Layer By Feature category: Architectural language: en tag: @@ -9,21 +9,38 @@ tag: ## Intent -package the application based on features. Each feature will have its own set of layers ( -Models, Services, Repository and Controllers ). +Organize the application according to its features. +Each feature will comprise its distinct set of layers (Models, Services, Repository, and Controllers). ## Explanation -> With vertical slice architecture we can have high cohesion within package and low coupling -> among the packages. In Conceptual term +Real-World Examples (Consider E-commerce) -> Consider that you are going to make a backend service for a online e-commerce application. -> initially you make it with usual grouping of controllers, models etc. but as the application -> grows more it's requires implementation of new features. Let's say that you thought of having -> orders, customers and products associated layers. But now you need to include another set of -> features with Cart system and wishlists. Now it's really hard to integrate those features it -> requires lot's of dependency modifications and mocking. So if you make the package by feature -> it will be really feasible for future additions. General example. +> In the context of an e-commerce application, the concept of vertical slice architecture becomes clear. +> Imagine you're building a backend service for an online store. +> Initially, you may organize it with the typical grouping of controllers, models, and other components. +> As the application grows, the need arises to implement new features. + +> For instance, you might have distinct layers for orders, customers, and products. However, as the application +> evolves, you realize the necessity of integrating additional features like a Cart system and wishlists. +> At this point, integrating these new features into the existing structure becomes challenging. +> It demands significant dependency modifications and mocking, which can be time-consuming and error-prone. + +> This is where vertical slice architecture proves its value. +> By structuring the application based on features, +> you create self-contained modules that encapsulate all the necessary components +> (Models, Services, Repository, and Controllers) for a particular feature. +> When you need to add new features, you can do so in a more isolated and manageable manner. + +In Plain Words + +> Vertical slice architecture is like organizing your toolbox. +> Instead of having all your tools mixed together, you group them based on the type of task they perform. +> This way, when you need a specific tool for a particular job, +> you can quickly find it without rummaging through a jumble of items. + +> Similarly, in software development, vertical slice architecture involves organizing the codebase based on features. +> Each feature has its own self-contained set of components, making it easier to add, modify, or remove features without disrupting the entire application. ## Class diagram diff --git a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/App.java b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/App.java index 19870b1aabf6..d3b058f8833a 100644 --- a/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/App.java +++ b/vertical-slice-architecture/src/main/java/com/iluwatar/verticalslicearchitecture/App.java @@ -28,11 +28,11 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; /** - * Main application. - * The main objective of this code sample is for you to have a look at how the view, entity, repository and Service are - * organized. - * No matter what application you are building Layer by Feature will always give the upper hand of better - * maintainability. + * This application is designed with a vertical slice architecture, organizing features such as + * customer management, order processing, and product catalog in separate modules. Each feature encapsulates + * its own set of components (Models, Services, Repository, and Controllers), promoting high cohesion + * within each module and low coupling between them. This architecture allows for seamless integration of new + * features and functionalities as the application evolves over time. */ @SpringBootApplication From c52566de5e2f5a6babc4dbb4e6b987a1f7454a0f Mon Sep 17 00:00:00 2001 From: sugavanesh Date: Tue, 2 Apr 2024 09:25:13 +0530 Subject: [PATCH 7/8] correction updated with pattern template. --- vertical-slice-architecture/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/vertical-slice-architecture/README.md b/vertical-slice-architecture/README.md index 92cf530a72be..705b5e80782f 100644 --- a/vertical-slice-architecture/README.md +++ b/vertical-slice-architecture/README.md @@ -1,6 +1,5 @@ --- title: Vertical Slice Architecture -aka: Layer By Feature category: Architectural language: en tag: From 08b77c5053f2ed4d253d4a4036acdbc71e3c4606 Mon Sep 17 00:00:00 2001 From: sugavanesh Date: Wed, 3 Apr 2024 16:50:44 +0530 Subject: [PATCH 8/8] added file structure. --- vertical-slice-architecture/README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/vertical-slice-architecture/README.md b/vertical-slice-architecture/README.md index 705b5e80782f..e5e830f7609b 100644 --- a/vertical-slice-architecture/README.md +++ b/vertical-slice-architecture/README.md @@ -41,6 +41,29 @@ In Plain Words > Similarly, in software development, vertical slice architecture involves organizing the codebase based on features. > Each feature has its own self-contained set of components, making it easier to add, modify, or remove features without disrupting the entire application. +**File structure** +> have a look in the below file structure, as per vertical slice architecture we are grouping model, view and controller per package associated with the feature. + +``` +- ecommerce + ├── customer + │ ├── Customer.java + │ ├── CustomerRepository.java + │ ├── CustomerService.java + │ └── CustomerView.java + ├── order + │ ├── Orders.java + │ ├── OrderRepository.java + │ ├── OrderService.java + │ └── OrderView.java + ├── product + │ ├── Product.java + │ ├── ProductRepository.java + │ ├── ProductService.java + │ └── ProductView.java + └── App.java +``` + ## Class diagram ![Vertical Slice Architecture](./etc/vertical-slice-architecture.urm.png)