From c68c509450e2d22f788cfd4b2ebff41bc84921c6 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Fri, 3 Apr 2020 14:30:14 +0200 Subject: [PATCH] [Minor] Added example model with test --- .../www.strolch.li/documentation-model.html | 211 ++++++++++++++++++ .../images/strolch-model-example.png | Bin 0 -> 20086 bytes 2 files changed, 211 insertions(+) create mode 100644 li.strolch.website/www.strolch.li/images/strolch-model-example.png diff --git a/li.strolch.website/www.strolch.li/documentation-model.html b/li.strolch.website/www.strolch.li/documentation-model.html index db4c9b881..feac3b550 100644 --- a/li.strolch.website/www.strolch.li/documentation-model.html +++ b/li.strolch.website/www.strolch.li/documentation-model.html @@ -53,6 +53,217 @@
+

Before we dive into the entire model, let's show an example and how it would be modelled in Strolch and use + in Strolch:

+ Strolch model example +

A possible model would look as follows:

+
+<?xml version="1.0" encoding="UTF-8" ?>
+<StrolchModel xmlns="https://strolch.li/xsd/StrolchModel-1.6.xsd">
+
+    <Resource Id="Product" Name="Product Template" Type="Template">
+        <ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
+            <Parameter Id="description" Name="Description" Type="String" Value=""/>
+            <Parameter Id="color" Name="Color" Type="String" Value=""/>
+            <Parameter Id="form" Name="Form" Type="String" Value=""/>
+        </ParameterBag>
+        <ParameterBag Id="relations" Name="Relations" Type="Relations">
+            <Parameter Id="articles" Name="Articles" Type="StringList" Interpretation="Resource-Ref" Uom="Article" Value=""/>
+        </ParameterBag>
+    </Resource>
+
+    <Resource Id="Article" Name="Article Template" Type="Template">
+        <ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
+            <Parameter Id="description" Name="Description" Type="String" Value=""/>
+            <Parameter Id="barcode" Name="Barcode" Type="String" Value=""/>
+        </ParameterBag>
+        <ParameterBag Id="relations" Name="Relations" Type="Relations">
+            <Parameter Id="product" Name="Product" Type="String" Interpretation="Resource-Ref" Uom="Product" Value=""/>
+        </ParameterBag>
+    </Resource>
+
+    <Resource Id="Customer" Name="Customer Template" Type="Template">
+        <ParameterBag Id="address" Name="Address" Type="Address">
+            <Parameter Id="street" Name="Street" Type="String" Value=""/>
+            <Parameter Id="zip" Name="Zip" Type="String" Value=""/>
+            <Parameter Id="city" Name="City" Type="String" Value=""/>
+            <Parameter Id="country" Name="Country" Type="String" Value=""/>
+        </ParameterBag>
+    </Resource>
+
+    <Order Id="Order" Name="Order" Type="Template">
+        <ParameterBag Id="quantities" Name="Quantities per Article Id" Type="Quantities">
+            <Parameter Id="quantity" Name="Quantity" Type="Float" Value="0"/>
+        </ParameterBag>
+        <ParameterBag Id="relations" Name="Relations" Type="Relations">
+            <Parameter Id="articles" Name="Articles" Type="StringList" Interpretation="Resource-Ref" Uom="Article" Value=""/>
+            <Parameter Id="customer" Name="Customer" Type="String" Interpretation="Resource-Ref" Uom="Customer" Value=""/>
+        </ParameterBag>
+    </Order>
+
+</StrolchModel>
+

Let's go through this model:

+ + +

Now that we have a basic understanding of te model, it is of far more interest in how to create and interact + with these elements at runtime. The following listing will perform simple operations:

+
+try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, false)) {
+
+    /*
+     * create a new product
+     */
+    Resource dafalgan = tx.getResourceTemplate("Product", true);
+    dafalgan.setName("Dafalgan 100mg");
+    dafalgan.getParameter("description", true).setValue("Dafalgan is for pain.");
+    dafalgan.getParameter("color", true).setValue("Yellow");
+    dafalgan.getParameter("form", true).setValue("flat");
+
+    StringListParameter articlesP = dafalgan.getRelationsParam("articles", true);
+
+    /*
+     * create articles
+     */
+    Resource dafalgan1 = tx.getResourceTemplate("Article", true);
+    dafalgan1.setName("Dafalgan 100mg 10 pce");
+    dafalgan1.getParameter("description", true).setValue("This is pack with 10 pieces.");
+    dafalgan1.getParameter("barcode", true).setValue("654654");
+
+    Resource dafalgan2 = tx.getResourceTemplate("Article", true);
+    dafalgan2.setName("Dafalgan 100mg 20 pce");
+    dafalgan2.getParameter("description", true).setValue("This is pack with 20 pieces.");
+    dafalgan2.getParameter("barcode", true).setValue("654655");
+
+    /*
+     * add reference to product
+     */
+    dafalgan1.getRelationParam("product").setValue(dafalgan.getId());
+    articlesP.addValue(dafalgan1.getId());
+    dafalgan2.getRelationParam("product").setValue(dafalgan.getId());
+    articlesP.addValue(dafalgan2.getId());
+
+    /*
+     * create a new customer
+     */
+    Resource customer1 = tx.getResourceTemplate("Customer", true);
+    customer1.setName("John Doe");
+
+    // set address
+    ParameterBag addressBag = customer1.getParameterBag("address", true);
+    addressBag.getParameter("street", true).setValue("Main Str. 1");
+    addressBag.getParameter("zip", true).setValue("1234");
+    addressBag.getParameter("city", true).setValue("Hometown");
+    addressBag.getParameter("country", true).setValue("Switzerland");
+
+    /*
+     * create a new order
+     */
+    Order order = tx.getOrderTemplate("Order", true);
+    order.setName("Order for " + customer1.getName());
+    order.setDate(LocalDate.of(2021, 2, 1));
+    order.setState(State.PLANNED);
+
+    // store reference to customer
+    order.getRelationParam("customer", true).setValue(customer1.getId());
+
+    StringListParameter orderArticlesP = order.getRelationsParam("articles", true);
+    ParameterBag quantitiesBag = order.getParameterBag("quantities", true);
+    FloatParameter quantityT = quantitiesBag.removeParameter("quantity");
+
+    // order quantity of 20 for Dafalgan 1
+    FloatParameter q1P = quantityT.getClone();
+    q1P.setId(dafalgan1.getId());
+    q1P.setValue(20);
+    quantitiesBag.addParameter(q1P);
+    orderArticlesP.addValue(dafalgan1.getId());
+
+    // set order quantity of 10 for Dafalgan 2
+    FloatParameter q2P = quantityT.getClone();
+    orderArticlesP.addValue(dafalgan2.getId());
+    q2P.setId(dafalgan2.getId());
+    q2P.setValue(20);
+    quantitiesBag.addParameter(q2P);
+
+    // keep IDs for later use
+    dafalganId = dafalgan.getId();
+    dafalgan1Id = dafalgan1.getId();
+    dafalgan2Id = dafalgan2.getId();
+    customerId = customer1.getId();
+    orderId = order.getId();
+
+    /*
+     * persist
+     */
+    tx.add(dafalgan);
+    tx.add(dafalgan1);
+    tx.add(dafalgan2);
+    tx.add(customer1);
+    tx.add(order);
+
+    // commit
+    tx.commitOnClose();
+}
+
+try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, true)) {
+
+    // get order
+    Order order = tx.getOrderBy("Order", orderId, true);
+    assertNotNull(orderId);
+    assertEquals("Order for John Doe", order.getName());
+
+    // get customer
+    Resource customer = tx.getResourceByRelation(order, "customer", true);
+    assertNotNull(customer);
+    assertEquals("John Doe", customer.getName());
+
+    // get articles
+    List<Resource> articles = tx.getResourcesByRelation(order, "articles", true);
+    assertEquals(2, articles.size());
+
+    // get products
+    List<Resource> products = articles.stream().map(a -> tx.getResourceByRelation(a, "product", true))
+            .distinct().collect(Collectors.toList());
+    assertEquals(1, products.size());
+
+    // search for all orders in state PLANNED and with customer
+    List<Order> orders = new OrderSearch().types("Order").stateIsIn(State.PLANNED)
+            .where(ExpressionsSupport.relationParam("customer").isEqualTo(customerId)).search(tx).toList();
+    assertEquals(1, orders.size());
+}
+ +

Note: Checkout + example-model.xml + and + SimpleModelTest.java + for these examples.

+

There is a XML Schema which defines the model in XML: StrolchModel-1.6.xsd

diff --git a/li.strolch.website/www.strolch.li/images/strolch-model-example.png b/li.strolch.website/www.strolch.li/images/strolch-model-example.png new file mode 100644 index 0000000000000000000000000000000000000000..f88f79bc7a41fc2ce27ff8db06ac5431de7c9bef GIT binary patch literal 20086 zcma*O2RN1u-#>my*_D}$NXRN8DO<7$A$w)-J+q~<$xJp`*;_Ul84(h)ce3~9_dW0X zxu5s_zwh%N$N#vG)^%U5>m1+lS!aN}toUUdavT&2by-qEL;;1m;0}M!#KM5zg@zQk zP$>M3mrAM*3NM^*+SpkenOYd$ba1sXylLoSYJ@_${K}6rkI?vR=Xb78qJ3e4@eXD$ z)_P;te(cSRxV~ts;VY2}599eT!#?G8-}#<+e$=~s_DVdIzFPCcpmy%!JGV94jpmcZ z&BGh+o`RF%BV0PF!Wy5}I zU*dyWVZ+dfa|*HG`rGx%0Aet zFHga^_sNMvK5{$v&jp;;7Q1wOV`ta(7u)v(cY5U?ozo8Q#$NZBygDDd?}e9*b?PBH z-QIQ3do}N9`TXoaV`XjJY5j1;YEJ6or(>%>;#iX`tO*vZb)(F^ZRgF)dr65|#jT=k zTq6m5vAFyqX&z6m@CMs_acxjhy~Ey4MA4wH$zHdAr+j$!7Mh<{uZ=z}*(g0NMNl67 zM5y2p;Y97}w@P33?JJsO=&zW(&bJ&I+_ulRPPo6<`C4J&7=^Ma=ds{iyz?Y(K(62x z&9tY!y0-h|z^Tl#&Q*G@cTHQ(78W)Khh%y&8>AKeUG_88Go{n7WUt^RrLvnUuWMkn^nLBsooAna)FH%3zc$7CSu!VrGU!9Ro4U)8Fh_D_>NUb=3Qt3R z$g|S1EMD+b=eox!#XJ(NU}oAX#g?A=!91tDf;p7@Zuyv0ZvF%Fy35ir`KskcM&n{( z{EuH`3{7ZOP8?sC;ko|OW`8P>-6+9yLCq-9^4E&}ovG3-=G=k`i`@rKW2TB{HERnM ztM%>Jn2d?;ojF-Icu#|Ie_B-^#%NgAI33>*EZzI|N3isoXUAAWulj+}Q?jo0>OGa8 zE;Z%UPcHUJKI{3a+U*nk&=4ggKHshJm7CeVGj9D|n)ivC;WIlY`L?gR0yHrco(pS* z-KV3qpCisyT!Xwi6BPfP334n(Ra-BdJ+N-*_(di6tY13(lRW$GlCZ@?(x*lw7$1mR zO*~52+&Bnixytm}wJ8p%j6#?r=faYiLS1@I^)nZAZ{rIX)m_wEdFf$R!=lx<{%%OK zP1vo1pODSon)i8CPVCe7P2vezlRw8yi0blO>BW}lS-0HZeWZA@%Rc^yTHL8FFExC` z)BMFjnNw1<%xd{C8q1&dFJaD67I)i4SCeE(j60fnjt#u-B$fuvlU;8T#>#sxp*7yC zs@O1JmGt61*Zmat_2U=(Clle#d>PubVX2AldmcTp4gHLN|Cau2Xmrnq)jwBadoHi8 zxqXjS`$fKlk^eC9{naD<^k@w3;(JC$RJXM+GLhzZn%2~T&^Mt(cR&GsS&{E$uS^hTk0()Xs?56tt`tyo1F=NC^6RZD~zLQ zGk-V289hkbMW6I1_NkalKjW3gU)Vwqj|_eEP^1=t1edeRP&UIQX^pH8JoQ`n%}~{= zN}boLe6fvFvJF3le6Vzty&2z&M&NYvRNV-DdiD0LanE>S{RXn01-XkHb=+ZWhd8&7 zf+9?~qA$Ivs>ECKKlUhD)12QHhz6{uF{{pyRh_l#wMub~V$y45+0|M$_r-$4>26kaS~+S@PS4}M&u%2k?i52S zY8Ygus7J5TKESG4czV}S>dHjpy}57v8W-McT=EVi{NeE4TAMa2MiF&tE;p0h(w&>(_5ls^k_Wfo%N+Bu3vYDWFFmzN&eFo*OXjql ze)yD4a#$h*yF~^=Bk_WU#cIXFrmBjm$hQP~HHXAD6N*eB->7Il<+>FN_bm9lVlCe( z5}6;iQE@)ED|~h|FRu0`;_H<^LiUgQ(Eh{>TuGq`d>UWWtT0~f!4`e4D;p)h%$gyX z;@#>=G)k=6gwdMpHFmJ;%`!Z<#MEWtFDuWGS_3?YoZB8N{`O{5=X|mn|`CMrR_ai zc_W72EY(QG(xE>`n~1t|TRt(w(C0oIRcq+882KL`NknHX^x03YU%>Ylo7CMQ*v|Ms z%Gu|r63d$^R(NrV{HQUsE0iAptA9S4_xHn{FY@kKq&{p6lAftQst%m5Un~yAr%%Tq zCb%&25k1`d25WZ|7L7%QLQr(|xM|TLdftivYj7Ed@JVnu~b4|#$zY`f=TGLGxSntt&l4mRRS-Z-;7}s>By3G|! zQ(C}n{YSx{=`E?^$0Zdr?`^BY$yN@0M;p5F{mfRBja6NuG}GT+&qoc-9w``;n!bqi zxaYzYAw?G8>(TfuR#u+Rd-L<`m1f!Qx8BjOWAQlR3Y_2g>DPR(H+{x-J6Dn7x`T{Z z0uh?=jVLtT>GN){kvGBJu%y%Vf8O|NCRx%^io+(N@i&XN=^5ik zj9vft`!?BWV_JC%H?9&^Va-4OGW8@a7E8%DT0+^7tcXdI`*_Pem>{w89uK#77>_KM zFfq$QZynWj;_Am2O^BMfuv|1&+*C?JrU@#RmV)j%5Yj2%5{UN{;tcw^Vp>o4hf*6u zOT@2sq1vE1b!$YJN8&1JiV@uv37QUlsTUjKWY;=}8((2ze)+WaOkP`i%r9i3Ou+CS z3wB0gK;UVkfo7gVBf(9=i$0kP%wGH|!*!Mw$&G`FCAgM%yIxq+aWd+f)Yo35r}S~u zr~7sJ!0+f*R6#i&uKW#`BsxI>lY2J#e&X%23`^fFnY{d^-Vq63B=^KzQXq9`;ZS9E zZX!)srU`Bzw)w0R*0c0Lfkw!#KfLWVQL0S;qo&t57|Vwyqg|1?Ki@ksd%J(w$h7f% zE?F3)(sujmCjHvw$$r~2{az`YMhQz##!7=FD$}*Rm+H&DO-}Ql8?FqGv0T zY8l0O(*8iFlqcfEwY#y~D6kV9x*%~`Nib-Q(2JbZ^8<_RkW7toYH$Y8|C#KgtORSMY9eDGbIhxnuF7k0;aHHqCyqlc^IT{Q17XxX{;bK=0wM zj#WA-&T3qln)hoVJxjSrIicF+>?peW1>fTI*Lo-SUO&pG81j(XaA-WGzewcBJ6EdM zHmu**nDg}~6K(w=9^Qa!F%&^M#iMt9qGQwh3$dQ19uck06j z7FMt5b@R~%e}+uodaQbQkp1QqTik(hhxE63lQZTG9Q`62=H3GR^`*Y;G3+m8#{O4$ zyoIju$f2uliWdbCY`uQ^onTiXk80@V9Gx=%7Z%g9(M3vv5{%=ili3e8YUV!UvUD}7 z{e&jGIZ7yRblf*3{BBAH)O|GBdl52oEu~~P6(~Qwx#X+Q%ylgzuZ19{QTk%y>x&~g zz8~5KZPB_1_^ZMSwO;$E=xNs4+fwUDx#gB>d_qO~RJ@?TpOSH4r{MNJiYa@-T$dd_ z^>E7LOIN$}yBfy^ew7nzDs=l0Igi2EAKnpxa{70gvK$i(D8yIa${Gf?T%j@woD#T; z|J0*_V3X9vnqh%1PGN+^sfX&2K_Dr~<|n-~X?BUPh-`s$w-YlS*)Z)m#UGcSN@JDq5O9~jP*BAi7%R~4Sl&6F1DN?5)N_nFmjd_!UZ5s2>a$rpuXM;{4!I>f!ip==ni*xzt0f80fn6z)Fo&`U`V16=;&D|_Ykm3C37yB8Nk!)3D?)?h=^<%0VF&0Jm@+CB(mwHU- zqDxV?FUq>k{-&>HXj4nRE7OdnWY~pfXo7pYJx{9jXgK3K)zc;R@F)D?v?pRJI+k;) zzv3@fWs(;?=6QN!q483!ScYdkpX45UJZ@hMw~2j68W-bbQQlM$O|>_^HaB-ZpkG$@ zbM}0D=cCZ&1wMUWX20EM&hBE@lW$gTxU9XX6&Ue}t-hj*QSW2-w7u_<6Q!8{-C1!t zKPiXiSOe>84pP#CA`X5nvoC&+4+|`)Js}Ao)C~SfFMgQ!JiWdm&ZS|TX?#db*NlHe z;VaK2tUC7%Kkj=)HNU$QQndW>3bij9W}Z!@ufW#++GhtiGsI z95=GlUZUhN5jY4IHV&OC`2AGoCXdX3mu#Js$K(~gh85CF@4Tzd%Y9E$i)|ga=Bhj? zjFe)21qLKtE6!ASSmM9+U4gc?qexme>Yflv@h$e{`#J%ioOgVmO!lU<++ezrsnutn z)}_kPa&U#*`2=&}J?ATlZr%i;1=9%8pfdb@Rt5#P;~yP2J)ARzldtZFqj8Fn3}}UO z7NUO$rMddpxR~TgCXwomoDTJV%F4x`H75}&UE6zJX@RG_i3wlh`n`R zq8M+4Kh3Fa@%B*@T;$a6WX6qNnfsnA{~-IG@|?)$cl9+Ewa^rb&Q~1T( z!a^UJIv-poqOsn(!W|t_QJlJhC45iFd-?OEwJh(gvhTL-JT`g;W82d#(uHPPyY?%a zQZ?DfY3w8!Z!jZiJKC{APE#j2H^W={uG6^JR<_K?FmtUP-yoqJ+brFxY04;bd|g3; z%^Leb-C^*%dWWpBbaucMnKomR0IT1N?A_k}gfV={{uYXYZ^nA!?AiT|@NO_J*$VCb z3hQ#<+Y=mXTX&j1D+}3RYdXdsf9RrWt}gwNc@}5N#-2xD{Yh3%hsJxJX0bZPQ z;@tx6caJGF;;IU|MR0|)mV=J2Mf~ij8xS*bJ9oY0HL=B;bF!kLc5J1A_u?w*NO-#U zv)ghM%NxFJZ!?@qHWfz)+^1S4HNR=E2U=Y`mX+Qpf0!KigiNrybn?{claf?s%{fM> z(C>_`3%6)M0>RLe78gNvqwr8&-*Ge#;T3Ef2{n5Zij@}mh31kW=malfI!Hbh#hkl{ zj){j)=vumuLfu43iab_w`L#Ok>Mmn^e6ZQuEkYNDbxW_yAwa~*@24z*G>bo-S#DZ? zFg?@LyvgK>vS(2-;-b?1{jCwVd<9aYOjgS)ZvABBF(LH3Mc2J`Oq)0mEE1STH*~za zWw&?#bFX8MrhW2pf=0%`Qn!D*w!3?+l+^T^q^7im^a@UZ7R{L+`aP?$M@#|jKYrvW zX5gQp1z5s=S~SHh7qc_4{P2abXy~Si;CDa#hz)G`T^LL9;IEhc=-mH$S(s4Zua{}C zlaY7(h5N}N@BZiIXSa#!+d?R27Zx&4ay2Sh(a_LD#Ki2Tn_s`(qZzHV4vUYcz`R1~ zk}~?Ox7T=W>@(q|W+^KxR!>jQs?VP{+bFD0(%3Mpz^Jg&Vd9L#KK3Bu(o(8-X>+03m3)g0_jqL?l zK37-kSzF6#Yg4_fODZ=XiinGoR8Z(A+J39k;F-v(Rh=@lOvYj0FXAhor&juAd8iP5 z<8*&AGBWa2WaNNHtI}t?c^fCEOtZmH3Pm%ipI`1Wzj*N?;gRhH@6KqJ$k^ESwegyf zI=6>#Zi}z33WWO-rs35TYE&y`%Dfn_c04(l4RhZcF-EOSHYC%Ehw`y|xxm3>$tFf% z;fvnUsK7&MXlPhX)JodfZF#gu!R4uOTAdlSZix0Jx%$m*y{W$XKs!wq^x`m;}zP&hY!ggT6K5F-8cQ7 zf(D1&S@?Z_!Yyp!Tm0<&yl8vq4Yewp)WJPg%_<=S13I|;oTmML2L}hYjwv76+=Q#I ztdll9JqV|vPpa$ zN&Id_<>mCu%s43$78auwm*FrRcy7GHyxKN7nLIo^tf&8}N~7AiHwoSoc(l7bySON> zs(O92!m?)8n1ei|`@;iiZfotAOBr4c@v>2@v1~fZ1#U#QWm2A{i=j+7$zSfRNET|> zp`y$!Z8wk4j@Qw{6B1uW};QJr+1bHME9J3f2YxQohPZSt1}%gqUr1FlZs4= zC^#4PXW*OGsC)U~q4mVY6r*n+I(LFd*&@Qjy(=pphLAs)fy=YAJQT)Oe{dna@2h<; ze|y}0W0%E5=l5KeA4(?Tt?N5}m7C{ie&)EVQ9&mlkQB)vH?h5VwAIB%Cg{o6aDK*X zIa<*=F_BbQe-wCr+;ILRUwI%$kpZQ|OrlloFrAZ?6k&odwW_`RGk<9?m(;BMLvS$O z-pYug!AJZ3ea z52oaf7|4aC@<_v1^b1MWp~GpQAuOZzcVrr>6%s zR_z!B#XrXG2@QcmJa!kk?27n3$NLAB(?xHX-vL8R+P+gepNJ}WC0^U~LG$l1LP=VR?!T5niR)W+rI z-LbH=#KyzBm|{Lu0GB&4DvEf*^VpK!3C(P%Am3eWBLBb3Lxnbml8YraNhAYB3(8JXSpizLiSC>*QRg~dh1dUw~{Lp3!up(b>Zy}do>U>)gW zMd^^6LU2HNg!MZ+4)bq!;O+&sq|;B=oc`-n3meXU{b{L>Y}N^lF<5ho(ZF;5VEtL1 zq}_mn>C55aVJoZtz3Wl9x>i;NcDBSbPF=BVm{ZV!KMHjw%_g85RH0J~Ye8w)^eBX* zGbE|u;^H#l{J`5*Us`&9d*NH@2V=?Wq9Y5-%Ry2Z%@$mxunumO*T?vMo1C2d!{hdF z)9tu?h=YoZOcJJQ-U3|2<$P)cs!kdVu; zwSMGlsN@V5-Le1kgDIn;r+JHIckHvhP}9J>_AqLd1zuj>*_oLO#AS*;zUmE&Np7KV z;P$Ya=DYe0IMm9`2@D4^q+_F0a}=|#z}@T=l)iIUt9mDNQ|l2L3sWXcCbZ!a!=V1X z-7i-KTZV>WtE#GQb=7?S{KDK^T2}T-XlUrgix+K9j~oTgPwcPU;Gx5motm5bSVkQZ z5@HAg4_X7cW28FnO@SmVsNb-F0yfP*pIx&mtTrEF%{7EMg7$rR7d{0aA74mM?^Z`g zhq9nv;AlPm%%tIVwiBGE+5@>JiQoVd@6i<+1)rlzLSTRq7dcoz}T z4CVW^qhlJDl4wE0>G8fXV3s`Xx)0DrFSz1I%1nuR`L^+_>vm%(v1q9D!&Z{Q>+1Le z0s?l{C#gfkz5oueb#yfB|0vng(!$sUgDC`FLdpjw%hJ#M_^p=rt&KkDFbtcZQXQ9- zku`U#ebtS18-<)l~ zZ}1hLll(IDSbJaJyZuQo9nTc3*U&~V;OICwB6uACgu^WYxMT7on*hf9EY#)6sO7=Y z5r=UPWtsZjN%!r`S#rs@xww9s#laRVwV4+Fz-8GPdV_bk#+faV$8l!4uz_{Yhk&MK z_6Y((XWK#|BV1&jCi0MY9~`(uN41R)EIAmV{tY@?X!HL6q0RpTgl=9h@@de%#Ux@% zTYQ(!={3Hv+23eYil4%}stN(RN=iym#La>?i|@jJEbyLi^1lJ>|M8Lk;93_(i;sT+ zV%tIoo_$uFi#~%Juiw7C|DxGXZxM#*6>Dp2 zCdW;Yh~aC5HGn$CJq9-{$E!)4ot@2oWT(o+v+HA!hloij@%7PFylyGLPvfjEB(H}< z?jIP)&undJx#w}@fa*yWl&iEFw{dpP5)HbxGFmAorOrq2&riH$v^Q3EQlmlovHl~^6d1QJ49et@U9aAj*nUn_K-oMXTS8mA@>blb=U%mXV zv9S<#on08-^6u}qT>%nnnlG0mS{jw(Cl1CwDO-+;n z?p58fb$^o~7dn7G&3)U_4ZywK81%3V@mI_QKQKPe1Gk?K__w*vj0FB(D9} z&k%2IZAr+=V%+57x(4NdN=Qg}&uL1?&dwf8b|1qV?gWr0gx*B&UZs5G4TJy?<@3yp z%uGT`%HW0u!QJH{hC6qHp~^07^odh%?hfgoUmC~bvYyaXTYpRKnF8?o;P8+DhQ5*# zF>s=I4zFfEY=mAdWhM7FczGePxG(Jz!YD>c3=yd4;^sC`s3VxmFmd$;PYX+7tuFv# z7%_A_JRfjLSsAz8_ErMmQ0y0bGJpXfTmdewR5JrGKmY#e-+k$0wXQ@VVo%b=Lh=^) zk5@`XL`C~PN=DX9Ou)st&f~y{U}FHq%;PoAi!cUj&yJQ8_}#9tv9Tq&E|8&MTSd=p z)~wgl^6@3qx$V!)&OU*44PSN{AzZx9J!aH^T-(2Vc~w+&&-47$8E9sEnd!jq@tTJ~ zUl63z5y^mVv$vvlw6pXDsEEmAJ^${XL4EibWb$9f!^mCr-02hlQJ_VEG~!UfsYK_b zn6Nxj16N0>y-v`)p%>;mqmSE1kKwX@c3i$Tn5&WnHvqQi#!L{~%+!=O%uMKsm0#sS zidnJ*#Ka(HIIj%9tDN+t@P;l# zP-k1{4QW_)**XmZuwiH60;1fZ05$7gMgwky1&s0!4yJqXAR4}Vvl*9-adZ`$0Z66m z$9cBD2a(HfW~FRYBMhM`*X_(fzS5CysEIXGw_g5zN@Q07x<fVu3VN52QNAIb%& z_U#7`NW6io7c-p1x8BO{hKTwjfxU4YS) zfJG3pF}JXgrjS!qS&4~r_Kz$vjC>phNf zA}Adnf6#aBZ~|zDmE+%y+SW3$?$&m*xOugrT5JSPu<);lhQl-@eVC9BxBh2tRouDItMScql3RvlCaiN8JEg z;Y`{*&MjeJ8v)qjwEPtXh_lFfT^qni%aD#&NPhlmgZAG3^Dm^Nq~anXe$SiWFkxUm z@;KrI0*KIFZu^Drz-CjX220JSZm=m?f4grk1SwO473E$En$^N`E;H$y2_1#1iLtAxC~9nMB&<<)+aGs! zgf^u@ky8Hl;Q`ujz|il+qh7sw<>M=!Vm)3h3hNOC>;|wi z2BS-Q1(XsE4Gjub4a`L)i#=AqmWuG<=wT9J;;LnhYQPkJZ{A$^UgK(;G6rMEmh zJZI68p9VV>+2Q2$VN1bS#f_F~g`pO>W4Smrg*w@t3xpNrR8mp`WTunXCM5;5utmZd zPYDa$04>li>89OKdiwg3($e}cN*_IXRAj#>%j59drgt<)t@QTV+8StYI-vEv5{O*gr$?XFJM3|VE1=@8|nwpdtuTsBC6Q9chx$5ZdHdy^tj)Doo0l*m$hcS1= zj1CQgGU=UOGnQlPzy%JFs~ls64Y@j6IlI0thuk0jmz)9u0*G>%w5I{GfpURn2OtVW zs(kU~%_DB^>GgFsafN@^m4Ckkf|PA-Z50T^n4~egVKgx_h16uhi}D+vaNrve)JmYM!~j|AM2K8zx6LD z{ez0R{{?#ghsNt)61(v?Xk8cId+YZ%j&0ClWnl@Ln=?Sc7=N9ge;4D`<6DoBOE@kZ zb5}!5RyLIQ1HK{m^k}ssOI%!BSSz(IN8G*mZ{6?NU%_HIU)=(TnWy=g5S6doW!-T4 zCM1L}?+!9`tX_bk2g0#`Nzz7ZYwNqDB&!FjFe)6De_n>gtX^i)1miew!E3XXl+)xp z%FD~^SD9(LL!Ko^oPTI&TUQq@H8nNDJ$e#((Y|(d&3=10*)l$!2rAMC_-cKQxJRyA zbO7p%7P{kpgZ>l^LW<|fra0VD2}#LR*tmdv zlV1K|%D83#A_J%SPdptRoj-%Q?JFat(Y@>Q^Q{cY?!xl&_|Ta1uSvD1Kp7x>oDtko z(c+{QI36Z&gaxo>Y<%3b|06aC4;NCL*Cz}N48CVblftD_)=R*pk+N-8NdQImD#*XU zpxWMCrZ|9cl<(;Z|BCtek*>eL|2n(gMd%rTR*}#UC064+$hrb8pv4cHNVVRb8wH4H zaky9?(TYHViumwB%H5sM$;n9*#BCt1??CN_GR_wW5=(ypqaaVKCWhZ_Z)$2v$im_d zTkXaLp2X0Ul$%_ZzYNNOXI=rQReQWv17jLyK6$2WVke+1G)9#IN@TtOkXjl0Oe8KY zPDn^d=i3QH?isnh^M9IBj3|JO7pJ_=j}f|W7huck$7qN>2}A$8Svd?H1qB6AEZEfZ z5dfGn<)pAaQ3tZ+@aX6O093AbhwSIR5};VMYbBzYpGVCD>G_0bY-so{ zDhhh)?bbRVF#|)x>E-3Fhm-DK032@Y?<2$xu&b6@Z%2pZh-`*bG~gALHZ4ufwF6h& z!o}ae4=OF6m6Vp+IyqH*SXfz+QC5!O&@R?%ZNQPuZ!_VPx)^s(`{8f24; z7#Mo@t^;?<0tSJMblAG^#rdo}U?_x$q1&{R<1?Dn=)H@K)OSo}kp*m>zh^k|W`3xU zv4*Zf)HHZ}cvuzcR<*&C|H_psP%Dv8ti&~m4MFxaXE_@iHkw*m$U+S2)~K|)VO@WC z8|2m)-y=*aRf>A$eDz|34nmpRL@EWE)47H93Jb4azlMv~0?- zL}X+EO}dS3Z5TkbyN&LnfK@Qi(D(p%w6nLzzI^$)Ht(kMH8yP-Pfr1{^mi>SBA{4c z5|^n|yC2%Un;$JVZwDb&4UPf@ng$TI2Ny9hrK6&32}jd7+t%PKHg|Sfnwoq-Z6PEj zecPmaQ&5l^$TINJnVgT0NN2Q3_C*fI>qCV2X8hRL+21ub3gw!@)~16aMCK6u`{mB> z)Uj)3K(zpn!spMfu090~3>yb04YVx;WWlG;EG-29f(ETbkyQ!`vvp{Q6b7EVyF22p zM2WRJ+ozfjWL|b${wbQF!0vhCg3@;16a_&}6uKkNN=GS2;Wf0tZP^6>N6Tj2Z*Ogl{v_B5yvucaf$0IYTuF8|BMRu*bHV~=xvYV>yQJ6t5p<3Z zTFju41N{Aqj(ijjV%8|EYn#>^&U*mrboBNzFf#gsaiL|kboRyNZn;*jnpGk;Y&bvs z^MVGqwA!MGBv#UWxubp(*lI0LcAe#-NR|5s=4Z~LJ3V7VsRdcZm7z2J@a2;Je&^qN zZF87$Y02(i!c7vYmH(Nxs-#?O(6KSC=uL#6dJTXAP=Gh|>3Pt4{c(@knLh#T$M7?n zzajg-Eli2#{i`l6E=9JpV%&r?#UxZzJcqw#*zp} zrTG#k?gMy&Wm3{r(PB?r`G07tLA>w)-V{_-VxS?ybA8V!)^8_*l@bOR`>&f5RIcyM^$7lK&@ro%_5abVGF^}UfW zkO}4F(7=iTOz>8*P)caG|GC8| zC+jVsz4Y6Hn|gb%Ld_z)`!z1<9180hIZ^$LOtL^C6twNe)Z;5ud=h46%m8lY=H~FP zU26lPFAX*fSX(au(X>vq-2m6IzP=vWJU{?IlI{dUg1OsvoaTC*TQ)SmI&BA^RMLY}1qASz_GO#6|e&C#L2_ORWL*xwz z4hTeQ%N-#Q_@k$fx#cP>Mv&!-_+ls+8R;;5g&vcN0I$)T`}!_hi5WO3SdCQ*=Cqwo zE7jH2C3f>to<~az2vvb@k_D(8WRdmpQN0$BW4Pq4O-*Rt4<}q+0bsPCt%kR3V6A=sE}xPTD0u5u^PkoLFqHrlGtI(cx^R=1m%`ZCIM0)5=Kg$d^9Po?Vl z6KMlWN3HGcU2L5U-_dI_mS<-4q7w`a4Q)Y#0-wa{!3`Xg}WfgBWJa)QnKNy#~tRhHr4?eKDXz| zBL=x7187#npJP#;10rh(0~Zma03mXCot@n38h=WufnZ*c&X_ixKz#%inXN;ciG-Tk zi=T!jHE6`*OejNP;xtNmz;ju6fVv%qqWu|JC;r?(d1Z8cO=jLJe5@fEzC1{Ng-3KAv4!>Hg14 z^xP+r;amJe1h#g*x+NWR=NWm23al_#XzcoJcqvn+Q>Fu%#h}e_n;4G4J57I;F@bV} zLS#F*Sg`HQ%0WB-0uV8pn$$UPb~N_#<;#W>wXU7$jsSWMVX-PqWyEvS(7Z?(u~;+a zinqQn3-x&B+(2<$Il1#pd0b`43}&BbW(Z(yfNnGE>tTH+AKmuX@BpuXj0rUj74QOD z0Wt@0drUzmeP?+`waEK#9U1J#nT%NN2nM@W+UJ@U6d_`;>zk&UUUhu^+6btjSKt`W z8ytDiW5PhPMKlQjnjjv(2OP?>Do5So%3;4C^KySJL_I$foN15`gkAajfCRa2e|rdF zhGrAa{_JP80BjjCOM}}BfPg`V&x3S652Fnl6!dX2P80n9w!?dP*Q2ht!%38@JN?Lh zruo_KHK2EWPIAO3hZPWozTpp~K09s1q5^#dT!YnaqtdObMFS?B%Cp{yQW+)apU~#N z8I|7E#f?(QQK~R19ocHQo5J*Bh}2shsreC$`a)i7K+qy0BC6v}VCF#c+QP;H9wrX- z!G57T6>y4Blj0oMTvCzIFmwm1Z1urLfZ6U2+AAbpf@j;q?t|E3HCEN+Jn7L6)UXY_ z^WHAD2E0aCjx8VyAubl&Ut<`=AYtapv;<25(g4SGZpBqbR8$lVpPHI&aB*MgZ~XBW zOQ!k=%Bggk;y19DC8NP5eI8-R6(8Nw#bI@*ldr7tlqD*hgg1Y~AzCWKm9n!5LNn%h z*M=rIL8*j;MhM2I=ecdb5!Gs(?!rJu<~k@s;W05{u%+Wbqz9dBWxOU9mI^`-1x|Mq zo4E}ZGei`UuLT4c`%I$_)F@v z{HK_#7AVg%RAy3Vp9Xn!4$!W59kbuve$E^{$a^1Gj?GAeUY5n^$gy-J0dp=#=@Z}0 zt6xiHSorETIB#lXD2#K)e>;phA2i#28rh-b@*&l)!6Qa0;}aD8_L+>>dMB_gghHYq zMPmfI?C`H&3aP@Ez~jCk1R_rq=0gfjlg3)tZSRJpTa|osKY`(7$|YNsdr04B2U-U9 z@_!e2ynp;q0__dx7+T}EZy|s^A|fKB9Gi{*Mqaj8ap;{$*SY#iWbVhwblOax16Cfa zlFI0W!P{A-p5IeiT-?Fy@LPTYSldQnExLHtz^PzL(&rS^OSIfIr|}wB3g7hfbdEgb z+-M^f=WXK8^A8@AhqRgfTmFGf!niy?KhKmb{dWwF@y-KF02Muk^VXsM{=bd5;u%g4 zE5qa@BvkVUmZ&=FaRo)!rluO9K9|0ye&M&y0vJ?PQ&Z}7e#SvoX~yjco*|Yk1CZyv zXE{m%pL{K>)r5tcqr^X-yLnJFCze@`#=!0VS)he01TnQIZ}6sJ`^EendNYjgF!+Nv z9RF=05e|a?d}$B#*`TqWyORG0;y&bGtyIX60#PIayb6R4z+wl5xOsB2L55QNa|R0n zS9zr*Bo5@W2FUO*zC3YjT7)H)*M^Rc&J7d@1*D5b0k;w`lHmc&lFp6$y?pu))~*SSCI8Z(zLg0j3)Xg9~;u2&R{*-8ax6SE38Du~M#b z2uPSn6bVVHrHKY@?Cc<`4Ja~VRFya^DIih@s5oF9O2)YmRp1+rgws6Hl({{i+<5um zd3s-7gaQG;`!%1jeoNR^P~%_P+utHsY^dNHm`t0yyY&40iC`z$L3jXSgBaeR5F*Qi!bCWgPTeZMkA38^MG#`Wo3(B|d8KP!fe z0g9AWQ~uXUla2>Lpqt#D_g$eIQ+`qzM>=GzL8*Jg|ubRpML;lGThZpnWRgwFR zM^y-jP)5tS>(j44g&)v->#}?5ubwZ<5hs&=CgWLog^WYQ>`jupfOGr`vG$tmmwg`X zelX797+5(p$6gwhs>Q(!=`-Q%ED8zPHLQdk+F8`3EB`YnFfgK`D^2Mah@GG)D@O~3 z{cg{&W0h)lj)kT_cZvfue;@Vmd zmgQH z07Eb)-b8SUiHqMi`JU3Byg`DROR1W=5}(D&-$Ft(3y=6Hl`u^@E$;nV!7FKu({x#7y*}XKR?|EBZC8y$q?7D zwYPs#ICLNGJrb`-Ow<~YK4|%}y||isY&vUT+GUU?AD=n8Fg{Vyp)|&qH_AgYvbMTB zHqq8mVlnMH_H&`5zo)~3D;`G_xAJ@M2e+Lp59*? zWqqc|L+E_?f>vay2$CIQ!Pn6m0VpByBnU()Wy||O$QYl9=m~^+;RO`3zW_s{BccW( z8zIpRr3>HQv!i>%IFiqjy+O`pfh7bX6U4eI(TSFVTvT?%dzfnMM%~xvo4y05LkIaA zoV9|20!UXP!mzf>^d)ex&2wy;T3cTO*bN2}HMO*agqVq(@xYPU8dIUjs);j>bIRIX zGjyx0v^}bEeLc!eQhBnvngkjjTyRL50n4;GW_HA>OeKui!KOLW`u|!)Sa^6!3&|kB z0#1wtwwh7k5~?jPFn~8D^*{ zSNua5md=qK#230FBM8zQD1hf%{wjL`?jPWHfrBY@STh%dAa4M;@>$I3>3&1~8Pb!G zq06g?j*fP0#|Z%GnFBOG`omf+5s`}o1Oy1IC!iI(2QnVSvVB2Vw##(^%gSM?|22Rc z{%8E&lFj>m@{kyA%eh!7_(S3MwJMk9miG4Zf`KJ<^f~|p^dm%RcvUvj7eG1^$xyHb zk{H9LQ!rL%I$r$%yqT$))*wLkn~=I=Tz+6ZkpLUK*lph`$?MD&z7)(}(zU8&pouVB z#36K+4Z&GpUi6^7FAZefciGVWz-ii?^7xgFgTvgvoMVWUdqaX~3#=N*G5Uez33cl= z)2T{W&ycRAi7kB8hKx-|xNmKk3y>XyOCJ|Ao2p9Vkh#7%hkj`XD8t zg0HjtBFY6ovh+Tajg5_)tgNAkgbT6bfjqVQz&N3mf~f`10zQqS%P%?bl=5BPI|vL6 zEOAHsv=%iMHUDv4cAiF#N5HlCE)HU_O63K*8*7*rlJyr++E zyMfeBfB*h={m(i@+Ud8JXD5dd8v$O#HO|XmTe)vEVV?h*Jg`pG7nW#d5McsKS^VY8 z>cKJ}bWFkmNeuxWh3Wd}S1k)L<*@wknE zfFSQk0c#RituL%=renlt@CQcL2B|SouvwxuK}?>WoqYxP2~gMeV(&H#;u4VmLB{?H zn_~_owW9vC>pxn1c60vy={~KH&KC!sF8`gh8Yni@1+2LHUT5wFIt{WQQGD(0hJa); z1oZ7@+b+YP^Z|7oSSVun!HXA)Kw&^4*HA`)BGQ2DSd3M@1KKw5={d`vp~BwOCvQ<- z;UN{^pb)15yeyY2;1Q)_PV5|tjXWhY;{(JQf%1?$fQK*IAjg?m`(nJOCltI?4x1?< zP&6{={QtM8=>m~dcuZm*#to!4d_W&RD-iest%TG!#K;zbf`S-`pb5xghzbdzz*bP& zqw#Bn|A8d^Ft1Y0!9@EAkuYj%of)2?LLFlevk*`VN?b7v=z4e(1~wwF5~V`zL;%D| z5IaF84v2%@p!rM4$z_46T)X$n90eL(DC`1!kh{S(0D6}SA>3eiPyk;14m#=lQV%pW z%V~UOMg~MUF2A`-?b&WGgN4w(eT)B)AsCF7gPC9h$rT*!G1r5Q7hoa*CQ>TUi~}Bq ze(3=+uJqx6QBiCBO)#cnVEgss%L~}13)wJQb}e9*%!$7)So|rko<2rKP@cF zAoQZB0q~AT`3N8K*N~z?G-Y%QJVx7iSSL~q$bpOI4n`y-Xj(9A!cfH{=ah&eB_L>m zWD>&0QI3CpAX+sF*e!&4kS7>8JVC6RM*`MAK6wp*c!`Jc);Ue zilJCTZ^g*akV#PKPO-VQj@?y1kZoZ0+AQ_cBQ*#ub$GJf8>Gd>%RBl>N3p9Y!< z0_LR$^Oa#5zvk4A9`0^zG=c{MN-ooB{Dh|fHqBbtP8m&$RuP>=%*XtVSdD2wk*Pj;KBM-qS9mxyUseAdH%*oca_z(3K*kND?$mZN7NP7gj zs&a9BboA>cU7_?olrE?y2X`s0o&P-CaRRVZ`Iijs<9jBBJZMmJmf$tiU^@M;YjpJ+ z#3Xy+5epj#Kli1HLKA8XS`ZgZn+$#;0m6g?qUYx4i*=hWR6DOUu999z0f~!_ zjt-xa5|8)?)*htOVOD`i_XRo@e3N-dlL2c*j~cel2G#8I=g&ws5o~tgRB?h{0^o5Y zbq62X4|CJ4z=Ji%OL6m{bZ71+($xXaG^xW-00fP`hSPv)4`z9zak7U~`~Q~zZr#3( z;SG;xahQC+i9}Yx0eIZtdHVjo@fGBWkW7fDmsyQ}0Lh%_`t|HFDO@}}gOh_zNa@0y zlok^5?tjAuNls9nN+9(G52DavKGRb{tRC=?{b8s9REG@teb7uGx(yy8XkoZ2Dk@+E zA@<$vNNg{!bKX4)Fpr*tH{Oa|FNhH#Arwf4fgynf)TXl1Ibg9ZG3rM{4*pD2c)de% zxQ=Z9>s{9ZW8!Ha9or;PINgGj8B9;eA$McZ>zt&SQ=uF}C(lPgJXGD;4g6HM1z!|Op zK*I;S6oLpK%h|v_yp=o+>pl%sS{U?wpt{x{E>IXw0EYpCzP-I26TGd3-efj$b*yKf zIvmxoHXFg-f@jr&AP)%)0GY`kbpWluplfX04rf9JZWgE}dLY9>auhiL5Fd=n69J0f z2cGq_P^TAWDhR1BfMY0kY5rfCEhNVQxuIfsR07dL01O^Lys)FID>D7AAEP32?Wz|4 zQ;;htHkK3xnc|NhKkAyB2f;Hf5Nn~QrA0>p!Ux0&4%7DJ8pHn_vTWdul&T|9PX-1C zFxXI#mZ62&2cjknIU8HsX{a$ItqKtiun3AvOaD5M=YQSADeV6%5`hHB0KLN5XMs4? z9slrZWXH!m9oV}yzvKX}!s>#nhGC&e`EwAwn-)P3Z#=mwo@A4$T zUBoD3jt&Irx)cHgFgKjq=PfNQKZ8j1ZV8Ad@}vlCX-Gi1Eaz7uzw%;CM=S0^FbYC9 z*SsN^@CJ{pxmWPK8-~?yAlcBND3_Nn72w$_?tWo^4)KC6VXUCzPt(#eGIuyEVQd28 zOhRNrNJ2w84T5zd;^KfuOK)|(ef=7l5=h<_Hf_`rgg1~kgCvWjAF!|(`;|ZbOJ{_Q z4auih9R|1V+`)r722=p>Boo9hcz_7_K0LlwdlE=29A##wbxk-*