From 4a3a1896d6b50edb150517aca55f3eb20f887008 Mon Sep 17 00:00:00 2001 From: Martin Harris Date: Sun, 4 Aug 2019 20:24:35 +0100 Subject: [PATCH 1/3] Added failing test for tosca-embedded-resources --- .../ToscaTypePlanTransformerIntegrationTest.java | 6 ++++++ .../src/test/resources/templates/csar-cp.zip | Bin 0 -> 823 bytes .../test/resources/templates/csar-link-cp.yaml | 1 + 3 files changed, 7 insertions(+) create mode 100644 brooklyn-tosca-transformer/src/test/resources/templates/csar-cp.zip create mode 100644 brooklyn-tosca-transformer/src/test/resources/templates/csar-link-cp.yaml diff --git a/brooklyn-tosca-transformer/src/test/java/io/cloudsoft/tosca/a4c/brooklyn/plan/ToscaTypePlanTransformerIntegrationTest.java b/brooklyn-tosca-transformer/src/test/java/io/cloudsoft/tosca/a4c/brooklyn/plan/ToscaTypePlanTransformerIntegrationTest.java index 6d1231f..dad1a42 100644 --- a/brooklyn-tosca-transformer/src/test/java/io/cloudsoft/tosca/a4c/brooklyn/plan/ToscaTypePlanTransformerIntegrationTest.java +++ b/brooklyn-tosca-transformer/src/test/java/io/cloudsoft/tosca/a4c/brooklyn/plan/ToscaTypePlanTransformerIntegrationTest.java @@ -520,4 +520,10 @@ public void testCsarLink() throws Exception { assertEquals(app.getChildren().size(), 1); } + @Test + public void testCsarLinkWithEmbeddedResources() throws Exception { + EntitySpec app = create("classpath://templates/csar-link-cp.yaml"); + assertNotNull(app); + assertEquals(app.getChildren().size(), 1); + } } diff --git a/brooklyn-tosca-transformer/src/test/resources/templates/csar-cp.zip b/brooklyn-tosca-transformer/src/test/resources/templates/csar-cp.zip new file mode 100644 index 0000000000000000000000000000000000000000..2b251251f0210348952ec491ee07bc0e24a57273 GIT binary patch literal 823 zcmWIWW@Zs#U|`^2=$^ykpS3CK%ST2A23Hma1_1^chT`O+%z_d_-Q?oLBE8DooX`+X z2Ii%z?y+KO?y;p6+zgB?UxCWOCbS0o=Fc$@*!x-A?Nw=F`PEhId4YPCrV~%BT{Yo4 zPr}s-nd%c=|9pVpqYZ;j80n7?2XKd>iqrHPb{ec1PM1qXJmK!w=N3NRYW(1I1`}UUr?gf3Jf-Oh;v3HFp3tF8@b6xcYZs5b;jdM!AJgyxvw+5D`D4^m;3(W#Lx%-m7hGt`#NQ|q*4 z@Wwf(7pNXO<<`XQq|6z)Xt`=zd-=tAmD~Qj`_s9M+vHd1f~;9p(tGZ;-QCjtsryfg zYR&!L7Wvu1DZTqXYTo}UZhdymy=6UVH}eC4NrwxVbQl;UGh6+@3@E_?Pddf=;3N~| zx;zF;k_qr;WRhdXmHZ^YrU8=|!;(f26EiWgLJ}idLWG!#%ViK#LCO2Aqcs!ERFFG? Yrh(jvVHztN$aW?mTmqzPfqEDi0K6D8XaE2J literal 0 HcmV?d00001 diff --git a/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-cp.yaml b/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-cp.yaml new file mode 100644 index 0000000..eeb6bb4 --- /dev/null +++ b/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-cp.yaml @@ -0,0 +1 @@ +csar_link: classpath://templates/csar-cp.zip From 979238ad37617cd65d95631d283d96d2b0ce7994 Mon Sep 17 00:00:00 2001 From: Alex Heneveld Date: Thu, 22 Aug 2019 09:00:47 +0100 Subject: [PATCH 2/3] mark non-eclipse goal as ignored by eclipse --- brooklyn-tosca-transformer/pom.xml | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/brooklyn-tosca-transformer/pom.xml b/brooklyn-tosca-transformer/pom.xml index b707df5..ef9242f 100644 --- a/brooklyn-tosca-transformer/pom.xml +++ b/brooklyn-tosca-transformer/pom.xml @@ -164,4 +164,35 @@ ${spring.version} + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + [2.17,) + + check + + + + + + + + + + + + + From 39bf8bdfad6ee9ded016d8882b87774b8418a495 Mon Sep 17 00:00:00 2001 From: Alex Heneveld Date: Thu, 22 Aug 2019 13:45:01 +0100 Subject: [PATCH 3/3] fix script resolution for artifacts in a csar --- .../a4c/brooklyn/Alien4CloudApplication.java | 11 ++++- .../tosca/a4c/brooklyn/Alien4CloudFacade.java | 44 ++++++++++++++++-- .../tosca/a4c/brooklyn/ToscaParser.java | 2 + .../brooklyn/Alien4CloudApplicationTest.java | 2 +- ...scaTypePlanTransformerIntegrationTest.java | 15 ++++-- .../templates/csar-classpath-url.zip | Bin 0 -> 2023 bytes .../src/test/resources/templates/csar-cp.zip | Bin 823 -> 0 bytes .../{csar1.zip => csar-external-url.zip} | Bin .../test/resources/templates/csar-link-1.yaml | 1 - .../templates/csar-link-classpath-url.yaml | 1 + .../resources/templates/csar-link-cp.yaml | 1 - .../templates/csar-link-external-url.yaml | 1 + .../resources/templates/csar-link-path.yaml | 1 + .../test/resources/templates/csar-path.zip | Bin 0 -> 2014 bytes 14 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 brooklyn-tosca-transformer/src/test/resources/templates/csar-classpath-url.zip delete mode 100644 brooklyn-tosca-transformer/src/test/resources/templates/csar-cp.zip rename brooklyn-tosca-transformer/src/test/resources/templates/{csar1.zip => csar-external-url.zip} (100%) delete mode 100644 brooklyn-tosca-transformer/src/test/resources/templates/csar-link-1.yaml create mode 100644 brooklyn-tosca-transformer/src/test/resources/templates/csar-link-classpath-url.yaml delete mode 100644 brooklyn-tosca-transformer/src/test/resources/templates/csar-link-cp.yaml create mode 100644 brooklyn-tosca-transformer/src/test/resources/templates/csar-link-external-url.yaml create mode 100644 brooklyn-tosca-transformer/src/test/resources/templates/csar-link-path.yaml create mode 100644 brooklyn-tosca-transformer/src/test/resources/templates/csar-path.zip diff --git a/brooklyn-tosca-transformer/src/main/java/io/cloudsoft/tosca/a4c/brooklyn/Alien4CloudApplication.java b/brooklyn-tosca-transformer/src/main/java/io/cloudsoft/tosca/a4c/brooklyn/Alien4CloudApplication.java index d7f6af3..2bd5037 100644 --- a/brooklyn-tosca-transformer/src/main/java/io/cloudsoft/tosca/a4c/brooklyn/Alien4CloudApplication.java +++ b/brooklyn-tosca-transformer/src/main/java/io/cloudsoft/tosca/a4c/brooklyn/Alien4CloudApplication.java @@ -18,6 +18,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Sets; +import alien4cloud.model.components.Csar; import alien4cloud.model.topology.AbstractPolicy; import alien4cloud.model.topology.GenericPolicy; import alien4cloud.model.topology.NodeGroup; @@ -31,11 +32,15 @@ public class Alien4CloudApplication implements ToscaApplication { private final String name; private final Topology deploymentTopology; private final String deploymentId; + // the class ArchivePostProcessor does not correctly set impl artifact on things in topologies (eg interfaces); + // so let's _us_ maintain it as well + private final Csar archive; - public Alien4CloudApplication(String name, Topology deploymentTopology, String deploymentId) { + public Alien4CloudApplication(String name, Topology deploymentTopology, String deploymentId, Csar archive) { this.name = name; this.deploymentTopology = deploymentTopology; this.deploymentId = deploymentId; + this.archive = archive; } @Override @@ -62,6 +67,10 @@ public Topology getTopology() { return deploymentTopology; } + public Csar getArchive() { + return archive; + } + private Map getNodeTemplates(){ return ImmutableMap.copyOf(getTopology().getNodeTemplates()); } diff --git a/brooklyn-tosca-transformer/src/main/java/io/cloudsoft/tosca/a4c/brooklyn/Alien4CloudFacade.java b/brooklyn-tosca-transformer/src/main/java/io/cloudsoft/tosca/a4c/brooklyn/Alien4CloudFacade.java index 7521f3f..543078e 100644 --- a/brooklyn-tosca-transformer/src/main/java/io/cloudsoft/tosca/a4c/brooklyn/Alien4CloudFacade.java +++ b/brooklyn-tosca-transformer/src/main/java/io/cloudsoft/tosca/a4c/brooklyn/Alien4CloudFacade.java @@ -18,6 +18,7 @@ import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.collections.MutableSet; import org.apache.brooklyn.util.core.ResourceUtils; +import org.apache.brooklyn.util.net.Urls; import org.apache.brooklyn.util.os.Os; import org.apache.brooklyn.util.text.Strings; import org.slf4j.Logger; @@ -547,14 +548,15 @@ public Optional getArtifactPath(String nodeId, Alien4CloudApplication tosc } private Alien4CloudApplication newToscaApplication(Csar csar) { - return new Alien4CloudApplication(csar.getName(), getTopologyOfCsar(csar), ""); + return new Alien4CloudApplication(csar.getName(), getTopologyOfCsar(csar), "", csar); } @Override public Alien4CloudApplication newToscaApplication(String id) { DeploymentTopology deploymentTopology = deploymentTopologyService.getOrFail(id); Application application = applicationService.getOrFail(deploymentTopology.getDelegateId()); - return new Alien4CloudApplication(application.getName(), deploymentTopology, id); + return new Alien4CloudApplication(application.getName(), deploymentTopology, id, + null /* TODO is there a way to find the containing CSAR; will things in topologies in here break without it? */); } @Override @@ -616,11 +618,43 @@ protected String getScript(ImplementationArtifact artifact) { // Trying to get the CSAR file based on the artifact reference. If it fails, then we try to get the // content of the script from any resources String artifactRef = artifact.getArtifactRef(); - Optional csarPath = getCsarPath(artifact.getArchiveName(), artifact.getArchiveVersion()); - if(!csarPath.isPresent()) { + String proto = Urls.getProtocol(artifactRef); + if ("classpath".equals(proto)) { + proto = null; + artifactRef = Strings.removeAllFromStart(artifactRef, "classpath:", "/"); + // recast classpath URLs as things within the CSAR + } + Optional csarPath = Optional.absent(); + + if (proto==null) { + // not a URL; look in archive + + csarPath = getCsarPath(artifact.getArchiveName(), artifact.getArchiveVersion()); + if (!csarPath.isPresent() && toscaApplication.getArchive()!=null) { + // archive name / version are null in some cases, because the ArchivePostProcessor doesn't + // properly initialize ImplArts _inside_ topologies. we record the archive on the app + // but in _some_ call paths only + csarPath = getCsarPath(toscaApplication.getArchive().getName(), toscaApplication.getArchive().getVersion()); + } + if (csarPath.isPresent()) { + if (new File(csarPath.get().getParent().toString() + expandedFolder + artifactRef).exists()) { + return new ResourceUtils(this).getResourceAsString(csarPath.get().getParent().toString() + expandedFolder + artifactRef); + } + } + } + // the brooklyn entity's bundle may also be a valid search path; + // ideally build up a search path including the folder above if found + // (if reading a tosca yaml then it would be valid not to have one however, + // so could remove the above error eg if it's a tosca yaml in a brooklyn bundle), + // and in the call below use that search sequence + try { return new ResourceUtils(this).getResourceAsString(artifactRef); + } catch (RuntimeException e) { + LOG.warn("Could not find "+artifactRef+" (rethrowing); "+ + (csarPath.isPresent() ? "csar found as "+csarPath : proto==null ? "csar not found" : "context not set") + +": "+e); + throw e; } - return new ResourceUtils(this).getResourceAsString(csarPath.get().getParent().toString() + expandedFolder + artifactRef); } protected Optional buildExportStatements(Operation op, String script) { diff --git a/brooklyn-tosca-transformer/src/main/java/io/cloudsoft/tosca/a4c/brooklyn/ToscaParser.java b/brooklyn-tosca-transformer/src/main/java/io/cloudsoft/tosca/a4c/brooklyn/ToscaParser.java index e5c3482..ecddf6c 100644 --- a/brooklyn-tosca-transformer/src/main/java/io/cloudsoft/tosca/a4c/brooklyn/ToscaParser.java +++ b/brooklyn-tosca-transformer/src/main/java/io/cloudsoft/tosca/a4c/brooklyn/ToscaParser.java @@ -93,6 +93,8 @@ public ParsingResult parse(String plan, BrooklynClassLoadingContext contex throw Exceptions.propagate(e); } } + // TODO either we need to be able to look up the CSAR ZIP after upload, or + // we have to annotate it with context and csarLink of this file tp = uploader.uploadArchive(resourceFromUrl, "submitted-tosca-archive"); } else { diff --git a/brooklyn-tosca-transformer/src/test/java/io/cloudsoft/tosca/a4c/brooklyn/Alien4CloudApplicationTest.java b/brooklyn-tosca-transformer/src/test/java/io/cloudsoft/tosca/a4c/brooklyn/Alien4CloudApplicationTest.java index bc2fd6c..733ec17 100644 --- a/brooklyn-tosca-transformer/src/test/java/io/cloudsoft/tosca/a4c/brooklyn/Alien4CloudApplicationTest.java +++ b/brooklyn-tosca-transformer/src/test/java/io/cloudsoft/tosca/a4c/brooklyn/Alien4CloudApplicationTest.java @@ -27,7 +27,7 @@ public class Alien4CloudApplicationTest { @BeforeMethod(alwaysRun = true) public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - alien4CloudApplication = new Alien4CloudApplication("TestApplication", deploymentTopology, "testDeployment"); + alien4CloudApplication = new Alien4CloudApplication("TestApplication", deploymentTopology, "testDeployment", null); } @Test diff --git a/brooklyn-tosca-transformer/src/test/java/io/cloudsoft/tosca/a4c/brooklyn/plan/ToscaTypePlanTransformerIntegrationTest.java b/brooklyn-tosca-transformer/src/test/java/io/cloudsoft/tosca/a4c/brooklyn/plan/ToscaTypePlanTransformerIntegrationTest.java index dad1a42..939fda0 100644 --- a/brooklyn-tosca-transformer/src/test/java/io/cloudsoft/tosca/a4c/brooklyn/plan/ToscaTypePlanTransformerIntegrationTest.java +++ b/brooklyn-tosca-transformer/src/test/java/io/cloudsoft/tosca/a4c/brooklyn/plan/ToscaTypePlanTransformerIntegrationTest.java @@ -17,7 +17,6 @@ import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.location.LocationSpec; -import org.apache.brooklyn.api.location.PortRange; import org.apache.brooklyn.api.policy.PolicySpec; import org.apache.brooklyn.camp.brooklyn.spi.dsl.BrooklynDslDeferredSupplier; import org.apache.brooklyn.core.config.ConfigKeys; @@ -515,15 +514,23 @@ public void testChainedRelations() throws Exception { @Test public void testCsarLink() throws Exception { - EntitySpec app = create("classpath://templates/csar-link-1.yaml"); + EntitySpec app = create("classpath://templates/csar-link-external-url.yaml"); assertNotNull(app); assertEquals(app.getChildren().size(), 1); } @Test - public void testCsarLinkWithEmbeddedResources() throws Exception { - EntitySpec app = create("classpath://templates/csar-link-cp.yaml"); + public void testCsarLinkWithEmbeddedResourcesUsingClasspathUrl() throws Exception { + EntitySpec app = create("classpath://templates/csar-link-classpath-url.yaml"); assertNotNull(app); assertEquals(app.getChildren().size(), 1); } + + @Test + public void testCsarLinkWithEmbeddedResourcesAsPaths() throws Exception { + EntitySpec app = create("classpath://templates/csar-link-path.yaml"); + assertNotNull(app); + assertEquals(app.getChildren().size(), 1); + } + } diff --git a/brooklyn-tosca-transformer/src/test/resources/templates/csar-classpath-url.zip b/brooklyn-tosca-transformer/src/test/resources/templates/csar-classpath-url.zip new file mode 100644 index 0000000000000000000000000000000000000000..eed1131696bd31e7603ac3efe178687ce0602fca GIT binary patch literal 2023 zcmWIWW@Zs#U|`^2XwMPz&(JEI@`jOtL6e1nL4ZMqp*XoHv!KLKH@P^mNUt(CCp3hU zf!VevF4i81ODnh;7+Jmom4i(v4ff5yZNRhlceua}(=wrw8wa;9nm+FuoyI2Rh_jNZ224KT}gOd zTs!IctvPa=d`^j2Op|oj*Ym9J(1II#lFv;(9x<586eekvS*DoAQB?23cHuy&sgaW9BpxO<88AEsrkoo+j{j%&*6d}o{P@a43ho@k2w zWlPQ;)wMwq4jWSrN6%_F+rU1PLH|=j)C0N1(}x}Z&E)vx9cs(wseIZpc;lSY3sje# za%J?|ejp_v&hnDby0~i=nThHuyH0j73nbxLL zlY0Kxw4O0(-SbDNwQ13nM_2X;>1|MI{nT^j3D1nKSyHVMD|R$FZFNd=?98jm>U7F< z^h)wv)ig^ghUIKZc5770-ldi-**IaC!i+4z&_A=&0XHh=G|6`3Ub+2Ne)Wi}I? ztxB6+4hp0&h>J6zdSp&!nqN226Ze2v1lc3`d1;yHr9~)y(Zmdv)V_mU%?1K4@9T~_ zysvW*T-UNEzGRe{K!SdW!mb)^TT?~8qB zh!kl1cQf{YbY%VykJ4&i)=9>0Q{PlLbUjJCDvuh+QqM!%Re+uXVSXf!6_?}}Ajgje zrk}Dib8-}PEfo@y6H63SsslV-;@v!bT&;8qGE?+QDoSb-xVTV5(OT8?83V9fX#iqG zF;uKyT#{H+f@~X>5X_x$*Xyu@K6(^=HJ9Ghu3h?6M*T?d)u!tSoyRh~Ub6)W z&Y!24`+b(t%HkszS=<&0h<^Q6rW+T<`Zd$*m$h0|K9edOtDL3oh1<+lUsx~M z(d2~b?K!Z!@q7!z`W;Q0op*&^JZTT8e_T87`R$)3v+P>-AFsQ> zb@qI(4)2!Ky#M7Fa#{~w*xLHy>psQ+Z$>6LW?V(O1Tgv-Ktao}q!GlzEZ|uo1w2|F zgP4jd%R@{B#noF!GbWg+paKAB8mIukY8tNWkL<<@B-4-z1LBND&5X##Ix-_1nT(P( z@tKV9K5A}2HdzW-b3y_Ylw6^C1D~OYP(V%f$cDC~7z)b+xJ+eb1H~*G5HbKm?;$Ljz9 literal 0 HcmV?d00001 diff --git a/brooklyn-tosca-transformer/src/test/resources/templates/csar-cp.zip b/brooklyn-tosca-transformer/src/test/resources/templates/csar-cp.zip deleted file mode 100644 index 2b251251f0210348952ec491ee07bc0e24a57273..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 823 zcmWIWW@Zs#U|`^2=$^ykpS3CK%ST2A23Hma1_1^chT`O+%z_d_-Q?oLBE8DooX`+X z2Ii%z?y+KO?y;p6+zgB?UxCWOCbS0o=Fc$@*!x-A?Nw=F`PEhId4YPCrV~%BT{Yo4 zPr}s-nd%c=|9pVpqYZ;j80n7?2XKd>iqrHPb{ec1PM1qXJmK!w=N3NRYW(1I1`}UUr?gf3Jf-Oh;v3HFp3tF8@b6xcYZs5b;jdM!AJgyxvw+5D`D4^m;3(W#Lx%-m7hGt`#NQ|q*4 z@Wwf(7pNXO<<`XQq|6z)Xt`=zd-=tAmD~Qj`_s9M+vHd1f~;9p(tGZ;-QCjtsryfg zYR&!L7Wvu1DZTqXYTo}UZhdymy=6UVH}eC4NrwxVbQl;UGh6+@3@E_?Pddf=;3N~| zx;zF;k_qr;WRhdXmHZ^YrU8=|!;(f26EiWgLJ}idLWG!#%ViK#LCO2Aqcs!ERFFG? Yrh(jvVHztN$aW?mTmqzPfqEDi0K6D8XaE2J diff --git a/brooklyn-tosca-transformer/src/test/resources/templates/csar1.zip b/brooklyn-tosca-transformer/src/test/resources/templates/csar-external-url.zip similarity index 100% rename from brooklyn-tosca-transformer/src/test/resources/templates/csar1.zip rename to brooklyn-tosca-transformer/src/test/resources/templates/csar-external-url.zip diff --git a/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-1.yaml b/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-1.yaml deleted file mode 100644 index 123956a..0000000 --- a/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-1.yaml +++ /dev/null @@ -1 +0,0 @@ -csar_link: classpath://templates/csar1.zip diff --git a/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-classpath-url.yaml b/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-classpath-url.yaml new file mode 100644 index 0000000..b033f5f --- /dev/null +++ b/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-classpath-url.yaml @@ -0,0 +1 @@ +csar_link: classpath://templates/csar-classpath-url.zip diff --git a/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-cp.yaml b/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-cp.yaml deleted file mode 100644 index eeb6bb4..0000000 --- a/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-cp.yaml +++ /dev/null @@ -1 +0,0 @@ -csar_link: classpath://templates/csar-cp.zip diff --git a/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-external-url.yaml b/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-external-url.yaml new file mode 100644 index 0000000..0a68857 --- /dev/null +++ b/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-external-url.yaml @@ -0,0 +1 @@ +csar_link: classpath://templates/csar-external-url.zip diff --git a/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-path.yaml b/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-path.yaml new file mode 100644 index 0000000..c5e4970 --- /dev/null +++ b/brooklyn-tosca-transformer/src/test/resources/templates/csar-link-path.yaml @@ -0,0 +1 @@ +csar_link: classpath://templates/csar-path.zip diff --git a/brooklyn-tosca-transformer/src/test/resources/templates/csar-path.zip b/brooklyn-tosca-transformer/src/test/resources/templates/csar-path.zip new file mode 100644 index 0000000000000000000000000000000000000000..fef937edc10c04649b0720cfe4014e21dfb1302b GIT binary patch literal 2014 zcmWIWW@Zs#U|`^2xZy44uW>tK&tpaghM&v~3<3-?48_SsnFS?=y2-_fMS7LFIiVq( z49weu;$l;q;$llHxEUB(z5YCuy~a5wj{cH$o-$o%+Tskh{EhRj zB)s;no%a0N9Qn;Y30yL#c@*MT>|AW1VfKE;=O>2Kra#i@zp($w)$PmQU%fv4x=yl) z?a>Hp(*({y_QyXbypPWlBI35sVw#tp!uI2uc zx5OckmDPNY(-DPFmpCdnUGe=|mc8kd{@>XT$PUVpt-% z##txGS4S)B=Q1X{$!E?jd^}b1L#_!UyW^vst-3&Lhx?6h)sysv9qTx+CQm5Yc*j`u^j@B*q~$p(JCsZ| zT~*bKT2#EN`|+C1sd?A^jbayET+bGI`AYQTuh-r@i=7kyv_J4rf9-@1#j`~s7xNdN zD*t~}&v^HC&G5)?>;b^U!Uaq$3=F5z#QebwD8T_wEXDfZM3MtcAZ3_|1Y`mvxq(b* zzs^}+2Q=X|5DOxikX)3SSdyw&oB=l~7t^TV00zd?)-!t^O*%41rnTwRq@F)Et!GSH z_xurRZCZ5Y(Um!ZV|5mQ<_6iXBZ(Tb+^|JM*ftI-N2dy^=gvHO-QW zVL6+U-5OQ0ck0re9={xH4pjwBHvS}fNVfTp&EGp~MJ5SQ4do z2iD#+bGp=$68QVOuZsEf)|sjDhZ!pUW-v`Qa4`<6J9t@LmT%(WLs!owC^>fjTwSqx zYee(1gIo7c&7Wv3{dmK!gpgjx^MaYhs|rN+#Cojksw+JxeP8T5L!?04znifKq$Bfx zc$8NAvQ9E~oBF20q3cQ7Re97nmU;dyCDD z?_181T(CMhWaZN}EeUHby{TQh^r?*ck>0CK*AqIAWq7@23lf|^PcirVETfghM=r9s zEfNs@`mIbiE{gSQrq{_2**Y$3wW@q3RXA2TOWg~%nXSICUb3f2cAepgOyh*;PzmR# z#cM3hqnj`8uy?sXGbqff!d>^`s>LU7*M2Dx|K;^Wc2{vgu%Kql4nNZmqSGR?{$16P zRpZ)oV0YvB7KZgZnlwA_3cYyJ9#H?dcHZ;bKTT%Ywd_A$cY*8d`Cc8~Evb3`%P-`# z9=x!%^~KkHi~-(^OmfV)N^%Kc^f7>fmSIUFh=p0MvqH*sv@#uHDy}RKF%=Y7Zyj}+ zV5Wi!0HA500syONxUxU88}pG&Ln;i2GZr;7A{%P~tkxi2FV;^+$(r~~MtC1JHz1oV q$bv8#o;UCriU9jF!WBaf_MP1(#o6w literal 0 HcmV?d00001