From 03a530a752f11426540a1fd3f91e5ce547fb773f Mon Sep 17 00:00:00 2001 From: xiangshuaizhx Date: Tue, 10 Mar 2020 17:20:39 +0800 Subject: [PATCH] package init --- climbing-nemesis.py | 230 ++++++++++++++++++++++++++++++++++++++++++++ sbinary.spec | 93 ++++++++++++++++++ v0.4.2.tar.gz | Bin 0 -> 12502 bytes 3 files changed, 323 insertions(+) create mode 100644 climbing-nemesis.py create mode 100644 sbinary.spec create mode 100644 v0.4.2.tar.gz diff --git a/climbing-nemesis.py b/climbing-nemesis.py new file mode 100644 index 0000000..e78fd0c --- /dev/null +++ b/climbing-nemesis.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python + +import xml.etree.ElementTree as ET +import argparse +import StringIO +import re +import subprocess +import logging + +from os.path import exists as pathexists +from os.path import realpath +from os.path import join as pathjoin +from os import makedirs +from os import symlink +from os import remove as rmfile +from shutil import copyfile + +class Artifact(object): + def __init__(self, a, g, v): + self.artifact = a + self.group = g + self.version = v + + @classmethod + def fromCoords(k, coords): + g,a,v = coords.split(":") + return k(a, g, v) + + @classmethod + def fromSubtree(k, t, ns): + a = t.find("./%sartifactId" % ns).text + g = t.find("./%sgroupId" % ns).text + v = t.find("./%sversion" % ns).text + return k(a, g, v) + + def contains(self, substrings): + for s in substrings: + if s in self.artifact or s in self.group: + cn_debug("ignoring %r because it contains %s" % (self, s)) + return True + if len(substrings) > 0: + cn_debug("not ignoring %r; looked for %r" % (self, substrings)) + return False + + def __repr__(self): + return "%s:%s:%s" % (self.group, self.artifact, self.version) + +class DummyPOM(object): + def __init__(self, groupID=None, artifactID=None, version=None): + self.groupID = groupID + self.artifactID = artifactID + self.version = version + self.deps = [] + +def interestingDep(dt, namespace): + if len(dt.findall("./%soptional" % namespace)) != 0: + cn_debug("ignoring optional dep %r" % Artifact.fromSubtree(dt, namespace)) + return False + if [e for e in dt.findall("./%sscope" % namespace) if e.text == "test"] != []: + cn_debug("ignoring test dep %r" % Artifact.fromSubtree(dt, namespace)) + return False + return True + +class POM(object): + def __init__(self, filename, suppliedGroupID=None, suppliedArtifactID=None, ignored_deps=[], override=None, extra_deps=[]): + self.filename = filename + self.sGroupID = suppliedGroupID + self.sArtifactID = suppliedArtifactID + self.logger = logging.getLogger("com.freevariable.climbing-nemesis") + self.deps = [] + self.ignored_deps = ignored_deps + self.extra_deps = extra_deps + cn_debug("POM: extra_deps is %r" % extra_deps) + self._parsePom() + self.claimedGroup, self.claimedArtifact = override is not None and override or (self.groupID, self.artifactID) + + def _parsePom(self): + tree = ET.parse(self.filename) + project = tree.getroot() + self.logger.info("parsing POM %s", self.filename) + self.logger.debug("project tag is '%s'", project.tag) + tagmatch = re.match("[{](.*)[}].*", project.tag) + namespace = tagmatch and "{%s}" % tagmatch.groups()[0] or "" + self.logger.debug("looking for '%s'", ("./%sgroupId" % namespace)) + groupIDtag = project.find("./%sgroupId" % namespace) + if groupIDtag is None: + groupIDtag = project.find("./%sparent/%sgroupId" % (namespace,namespace)) + + versiontag = project.find("./%sversion" % namespace) + if versiontag is None: + versiontag = project.find("./%sparent/%sversion" % (namespace,namespace)) + self.logger.debug("group ID tag is '%s'", groupIDtag) + self.groupID = groupIDtag.text + self.artifactID = project.find("./%sartifactId" % namespace).text + self.version = versiontag.text + depTrees = project.findall(".//%sdependencies/%sdependency" % (namespace, namespace)) + alldeps = [Artifact.fromSubtree(depTree, namespace) for depTree in depTrees if interestingDep(depTree, namespace)] + alldeps = [dep for dep in alldeps if not (dep.group == self.groupID and dep.artifact == self.artifactID)] + self.deps = [dep for dep in alldeps if not dep.contains(self.ignored_deps)] + [Artifact.fromCoords(xtra) for xtra in self.extra_deps] + jarmatch = re.match(".*JPP-(.*).pom", self.filename) + self.jarname = (jarmatch and jarmatch.groups()[0] or None) + +def cn_debug(*args): + logging.getLogger("com.freevariable.climbing-nemesis").debug(*args) + +def cn_info(*args): + logging.getLogger("com.freevariable.climbing-nemesis").info(*args) + +def resolveArtifact(group, artifact, pomfile=None, kind="jar", ignored_deps=[], override=None, extra_deps=[]): + # XXX: some error checking would be the responsible thing to do here + cn_debug("rA: extra_deps is %r" % extra_deps) + if pomfile is None: + try: + if getFedoraRelease() > 19: + [pom] = subprocess.check_output(["xmvn-resolve", "%s:%s:pom:%s" % (group, artifact, kind)]).split() + else: + [pom] = subprocess.check_output(["xmvn-resolve", "%s:%s:%s" % (group, artifact, kind)]).split() + return POM(pom, ignored_deps=ignored_deps, override=override, extra_deps=extra_deps) + except: + return DummyPOM(group, artifact) + else: + return POM(pomfile, ignored_deps=ignored_deps, override=override, extra_deps=extra_deps) + +def resolveArtifacts(identifiers): + coords = ["%s:%s:jar" % (group, artifact) for (group, artifact) in identifiers] + poms = subprocess.check_output(["xmvn-resolve"] + coords).split() + return [POM(pom) for pom in poms] + +def resolveJar(group, artifact): + [jar] = subprocess.check_output(["xmvn-resolve", "%s:%s:jar:jar" % (group, artifact)]).split() + return jar + +def makeIvyXmlTree(org, module, revision, status="release", meta={}, deps=[]): + ivy_module = ET.Element("ivy-module", {"version":"1.0", "xmlns:e":"http://ant.apache.org/ivy/extra"}) + info = ET.SubElement(ivy_module, "info", dict({"organisation":org, "module":module, "revision":revision, "status":status}.items() + meta.items())) + info.text = " " # ensure a close tag + confs = ET.SubElement(ivy_module, "configurations") + for conf in ["default", "provided", "test"]: + ET.SubElement(confs, "conf", {"name":conf}) + pubs = ET.SubElement(ivy_module, "publications") + ET.SubElement(pubs, "artifact", {"name":module, "type":"jar"}) + if len(deps) > 0: + deptree = ET.SubElement(ivy_module, "dependencies") + for dep in deps: + ET.SubElement(deptree, "dependency", {"org":dep.group, "name":dep.artifact, "rev":dep.version}) + return ET.ElementTree(ivy_module) + +def writeIvyXml(org, module, revision, status="release", fileobj=None, meta={}, deps=[]): + # XXX: handle deps! + if fileobj is None: + fileobj = StringIO.StringIO() + tree = makeIvyXmlTree(org, module, revision, status, meta=meta, deps=deps) + tree.write(fileobj, xml_declaration=True) + return fileobj + +def ivyXmlAsString(org, module, revision, status, meta={}, deps=[]): + return writeIvyXml(org, module, revision, status, meta=meta, deps=deps).getvalue() + +def placeArtifact(artifact_file, repo_dirname, org, module, revision, status="release", meta={}, deps=[], supplied_ivy_file=None, scala=None, override=None, override_dir_only=False): + if scala is not None: + module = module + "_%s" % scala + jarmodule = module + if override is not None: + org, module = override + if not override_dir_only: + jarmodule = module + repo_dir = realpath(repo_dirname) + artifact_dir = pathjoin(*[repo_dir] + [org] + [module, revision]) + ivyxml_path = pathjoin(artifact_dir, "ivy.xml") + artifact_repo_path = pathjoin(artifact_dir, "%s-%s.jar" % (jarmodule, revision)) + + if not pathexists(artifact_dir): + makedirs(artifact_dir) + + ivyxml_file = open(ivyxml_path, "w") + if supplied_ivy_file is None: + writeIvyXml(org, module, revision, status, ivyxml_file, meta=meta, deps=deps) + else: + copyfile(supplied_ivy_file, ivyxml_path) + + if pathexists(artifact_repo_path): + rmfile(artifact_repo_path) + + symlink(artifact_file, artifact_repo_path) + +def getFedoraRelease(): + cmd = "rpm -q --qf %{version} fedora-release" + return int(subprocess.check_output(cmd.split())) + +def main(): + parser = argparse.ArgumentParser(description="Place a locally-installed artifact in a custom local Ivy repository; get metadata from Maven") + parser.add_argument("group", metavar="GROUP", type=str, help="name of group") + parser.add_argument("artifact", metavar="ARTIFACT", type=str, help="name of artifact") + parser.add_argument("repodir", metavar="REPO", type=str, help="location for local repo") + parser.add_argument("--version", metavar="VERSION", type=str, help="version to advertise this artifact as, overriding Maven metadata") + parser.add_argument("--meta", metavar="K=V", type=str, help="extra metadata to store in ivy.xml", action='append') + parser.add_argument("--jarfile", metavar="JAR", type=str, help="local jar file (use instead of POM metadata") + parser.add_argument("--pomfile", metavar="POM", type=str, help="local pom file (use instead of xmvn-resolved one") + parser.add_argument("--log", metavar="LEVEL", type=str, help="logging level") + parser.add_argument("--ivyfile", metavar="IVY", type=str, help="supplied Ivy file (use instead of POM metadata)") + parser.add_argument("--scala", metavar="VERSION", type=str, help="encode given scala version in artifact name") + parser.add_argument("--ignore", metavar="STR", type=str, help="ignore dependencies whose artifact or group contains str", action='append') + parser.add_argument("--override", metavar="ORG:NAME", type=str, help="override organization and/or artifact name") + parser.add_argument("--override-dir-only", action='store_true', help="override organization and/or artifact name") + parser.add_argument("--extra-dep", metavar="ORG:NAME:VERSION", action='append', help="add the given dependencya") + args = parser.parse_args() + + if args.log is not None: + logging.basicConfig(level=getattr(logging, args.log.upper())) + + override = args.override and args.override.split(":") or None + cn_debug("cl: args.extra_dep is %r" % args.extra_dep) + extra_deps = args.extra_dep is not None and args.extra_dep or [] + + pom = resolveArtifact(args.group, args.artifact, args.pomfile, "jar", ignored_deps=(args.ignore or []), override=((not args.override_dir_only) and override or None), extra_deps=extra_deps) + + if args.jarfile is None: + jarfile = resolveJar(pom.groupID or args.group, pom.artifactID or args.artifact) + else: + jarfile = args.jarfile + + version = (args.version or pom.version) + + meta = dict([kv.split("=") for kv in (args.meta or [])]) + cn_debug("meta is %r" % meta) + + placeArtifact(jarfile, args.repodir, pom.groupID, pom.artifactID, version, meta=meta, deps=pom.deps, supplied_ivy_file=args.ivyfile, scala=args.scala, override=override, override_dir_only=args.override_dir_only) + +if __name__ == "__main__": + main() diff --git a/sbinary.spec b/sbinary.spec new file mode 100644 index 0000000..901c337 --- /dev/null +++ b/sbinary.spec @@ -0,0 +1,93 @@ +Name: sbinary +Version: 0.4.2 +Release: 10 +Summary: Library for describing binary formats for Scala types +License: MIT +URL: https://github.com/harrah/sbinary +Source0: https://github.com/harrah/sbinary/archive/v0.4.2.tar.gz +Source1: https://raw.github.com/willb/climbing-nemesis/master/climbing-nemesis.py +BuildArch: noarch + +BuildRequires: mvn(org.scala-lang:scala-compiler) mvn(net.sourceforge.fmpp:fmpp) +BuildRequires: mvn(org.beanshell:bsh) mvn(xml-resolver:xml-resolver) java-devel +BuildRequires: mvn(org.freemarker:freemarker) maven-local javapackages-tools +Requires: javapackages-tools scala + +%description +SBinary is a library for describing binary protocols, in the form of +mappings between Scala types and binary formats. It can be used as a +robust serialization mechanism for Scala objects or a way of dealing +with existing binary formats found in the wild. + +It started out life as a loose port of Haskell's Data.Binary. It's +since evolved a bit from there to take advantage of the features Scala +implicits offer over Haskell type classes, but the core idea has +remained the same. + +%package help +Summary: Help document for %{name} +Provides: sbinary-javadoc = %{version}-%{release} +Obsoletes: sbinary-javadoc < %{version}-%{release} + +%description help +This package contains the API documentation for %{name}. + +%prep +%autosetup -n sbinary-%{version} -p1 + +%build +mkdir -p core/target/scala-2.10/src_managed +mkdir -p core/target/scala-2.10/classes +mkdir -p core/target/scala-2.10/api + +java -cp $(build-classpath fmpp freemarker bsh oro) fmpp.tools.CommandLine -S core/src -O core/target/scala-2.10/src_managed + +scalac core/target/scala-2.10/src_managed/*.scala -d core/target/scala-2.10/classes +jar -cvf core/target/scala-2.10/%{name}_2.10-%{version}.jar -C core/target/scala-2.10/classes . + +scaladoc core/target/scala-2.10/src_managed/*.scala -d core/target/scala-2.10/api + +cat << EOF > core/target/scala-2.10/%{name}_2.10-%{version}.pom + + + 4.0.0 + org.scala-tools.sbinary + sbinary_2.10 + jar + SBinary + %{version} + SBinary + + org.scala-tools.sbinary + + + + org.scala-lang + scala-library + 2.10.3 + + + +EOF + +%install +install -d %{buildroot}/%{_javadir} +install -d %{buildroot}/%{_mavenpomdir} +install -d %{buildroot}/%{_javadocdir}/%{name} + +install -pm 644 core/target/scala-2.10/%{name}_2.10-%{version}.jar %{buildroot}/%{_javadir}/%{name}.jar +install -pm 644 core/target/scala-2.10/%{name}_2.10-%{version}.pom %{buildroot}/%{_mavenpomdir}/JPP-%{name}.pom + +cp -rp core/target/scala-2.10/api/* %{buildroot}/%{_javadocdir}/%{name} +%add_maven_depmap JPP-%{name}.pom %{name}.jar + +%files -f .mfiles +%doc LICENSE README + +%files help +%{_javadocdir}/%{name} +%doc LICENSE + +%changelog + * Mon Mar 9 2020 wangzhishun - 0.4.2-10 + - Package init diff --git a/v0.4.2.tar.gz b/v0.4.2.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..be1ae2840947322df14951c07ded43a22636ac77 GIT binary patch literal 12502 zcmV;{Fe%R;iwFP!000001MEC$bKAy}{u=&@UL`L9Z5raC!%wnQMM+f5U0p>|_NH7e z8w7?VY!KiBhB|C%fBSa#3{H}wlqk;IjZiL=nCa8Z{x-9J{(H`c7@V@2symn>D*Sc(qabt9gEU z9`A|zu5X3cFRSL7SzrBgXwZDv++1Hg|M7ca{x@nHjc4nB4m#glh79<>%tADVFg?tY%3Bl zjYJrM6ZpSKz)pebA{3@Im4O|41Biq)OV2@yE4f3BrP7bkx|(>d?Mm+&5!;>>3hsx2 z>xl?11zcLb1Q~$kU0T->QUyN<$Cl@Q6%JUwgEagL5lVbRbO`8M(nZpq>kAOR@UHTI4~pI@+_u1=7Us|q@NgFK8?2~H(l_SIx1p|3W?GaTi>=a)ebu2|^KJEo&1NDrjtPN~J^GkLASJ zRWx`!Yat@6So2g$%xVS3f#VM7Q?O{0Y2S0BQ3V_~(sgnLB5JgSkHbim)gZ*W$nzM5 zi>$M}DT53|bS9)#srAH^FGsD%wKJ^{~_G2VA(tmi7aQ>?$tE4wKZnx+@x4o`;25NvjP>qn4>H7AYhSaPIih zMH5VdkSP{LHHm{aE$E&e_TDu+EogV)taJLdeb739m1Y;;S1RzX-FtI--UEc_G*5cJ z!RaA1Pkw{{YM&gSAzJ@^)@gOSaN2?P@!3(kbx?u!$^Oy#LHp!a*u#M*r#(1oAGdpm zwRg%CHLiB6TOxGFt>!=iaqFaKB3*2Q)?0jm?wjV(5ff{kqW~S|aR2n|w@&-lH@y=l@Qtd2syL>3?bdUu(?f|LS_}DgS?mr@P1Yrz~S(LhOh1 zGQjBWh{(qLM)^{?2u#8N7yW@3RpN|`aAS)2V{0S&A1TzI?8I6J9 zEg4}Hm0(*wE&MUnQtC(IVbDigVB!p2+6hp3c`UG|z}z=xo)p@E6CbA_3ob1#C#VjH zQ#*(&%*`3bHCgM!ybF>AsYQmVaX|$C|WFctaeQ( zhYmytn6kr|E~^r34{IcW>c^^sG0;{FxF|b}kmpd0vCN_(0lOk=OvyJk?VSeW|RihSbeXb91W%aDml`<_LCRB?yOVYv`pUq^9m#fq(o1R?-((shW+IQt1$# z>e#wKE%Clrg+3Cvk4$8RU6GhYw{Zs+)?n=eln_PSo1#;pC|DUP4MbTf5mm%&qet`! z62(HLaFZqP&@Xw0c*#Rp3Z?0;kkd)2)YHg#o`qATMsa1)n5`1wo=zOBs^iM_r5B(& z;1`_DTt8~&dQ`%<)UaO&4`L=qz-i*4XJM%;u!MBPMEH*IZC6ih%uxzCH8hn73T|w7uvU< zHWL2gXTkg*3Ln>D_8*(~@pJe5udOv28^!p)*=W?C=KptiR-ZpF!E;=Pu)QIeh|p3i z7pj$cWszA))6&Mm)ox_spw-fB@W7=Ct(e(uaQWhSg4aRjcq*+vu4uj;;nI9>N(`QGxMbOEVXW0WoJDTfRFG5p|bSSe6Q#K5QeY)m1nV!cjZ-ypE%D z4Y+WvuJ~7x6@wSp&Ye*T2ne;u&5EQq5S~7 zz#obbQcXu?vMGSo$Mq{MYk9u`wHE_us@)1?*+bj+^8CemkKsR%(t$;c+^@ojwxCOsDO;9QO~(tZ=1qr6R?D ztYNhg$2Ab2ABu?YP@((i4M0>L&$(0|L?0)=iV+Ls2V;Oj$6(htw!JQ9Pc z$64%>eAj|c`{aYMVm{I4j~__DoZ@<D{nYz3V?88sx9tevUY7g! zHcgyfGM34jrlsQy?f5xDeMjv;6pRI~6GGBqC?;s6_$Yr?lMF?Hl+~ujpxS!nyfU&= z`woT`f|TF8LNR`4DjCg4Qw9n};)hvzd!c(lXWh9I3KQPxpvWgEe(*AwRG3G;@1QO? zhC)t5I^b7Z>nd93m0?9)9N-BV_@oZaUdB}(rVx2g>5Vyd?P~diW|(YBry8GixR-%4 zaX{xAJWEW-$#NN56I~@BEZUV#T2V7phg*!i*?Ezl6orYf#P*2Q$mZiEmQQ9)*7AW7 z&2#Z1>+3a(gJmX$ay~z@^gK4>5X0ex_O5x`T9`uGFwZ*>rBEj==ywDC_W`qH4X)tv2`6E87eY}72~fvxMoPK zQ^XJ%yN-tvH89v977iZblE9yi`)JDe9DpG-1&ZY8-sPe*W3uTIuiB#(-&{J(iRU?| z?q;L=ADGOlR~>B;$BG4Aw{}0I7R2?$05pgHv6I4L-4upFXsom`WQTONq112ERc(9| z&K9h|3vH7Zuu?(R(AQOKiYBI_CqTh}ZcFzJIM2)uFpjnwPhw~_r1XWqVBd4WDm*r2)3fog~C(6 zPtZ{=!a3y*TnuW-?F2d}4fxzTJ~dTuT_PJz?NPBBI8&$SM1=y+Pv24{+4( zEW}exYQ^PCIuI38#8ROVvosZ7Iihn|P05aFb#UkUb`cljfr)`En$o3PMWU>?<+upp znw{?J48tIbIP>Q>2mR|Dmq`lCw&i1D)4%SB!3T3FBrC9zE$t0iF6WZhd8CRY1^{Ud zF)c|BBuUCrF~UNpqp*(AB%1d5W>uk3v7&Q=pn@P$+(jA1e591o{qVfF;w&XqgC1k5 zEg{(5f%^JJQaKRQ8aKo*7;-2JM$-xH%?f8l`?v5SwfizR8qm~A zE|Bd&!iNlaYry>KPTpY+*2abT)pmC7&SowZK&YJ}LL!pNVSA`poy4>!+%piU4M^BY z=4#BXN!Lq^kLJgk$=+_di6hW*0^y`R$^;QTal5#9GFagiaLd3^o5`b&bu~oSyScYG z_9XBH!E39W1n|WVE`0)5xrwSDeFn!BT_(ib>TeTV$5O?Vh>di~k>|+HeB`DVGNtxi z%NfBk@y$iMk)|_rakACT&DFa3iW48E%D(GinZ89LVP)^o<}_Ag$8Y8#LsTymJluIBgWj2$Lj2E>GqR5=)D`*P&6o)Wa(FZ4vxV;w`>egVg z&Ca=@LKkl%Zsl_&od|WbuBer*{K-QX(_RJ`c$^>*QJ*>cRqR<3ELi}agmfIzXalJ+!%H+Pu=0n26 zi=CKaVeetNCN$ecpt-6g+tO4~Q$yw7cv^8HB#cJ9me$EN+u!s&Ltk)xfJ4uBWMzjr z&YN-EpJ6cA*aN~J)MJ{uNN~v=3h0X%mPHelI^uDnj+)q-!MxYULyGn0 z0><;b#CdG4+pH3m8|G@lq8{(%smMG1fd*C3aSvNDr=36G#98dI+Z5EoX-Fq5Ha*PT z0r?zzO)pT+b5-!2t<Djdx1fH<;CV26dk?vfwvz;MFTZPr-Cl(rS zF4SG8%@2-Q8WHqRdh*F7M~VR~NwFF49bQgg!T4HQe>Mx?z;}IIUv1$J351 zC<7L01E;}!UC=qq{m%;RQB9Z1Sp{t8AnHpY8cQM8?tm~1;sT9PUn6T6L=oR=8~Ux0 z7|I|-_<|D%vdft}EtK1cnr|H<{2=Eg-X1jI!P8^${8;D`M}a?_?-SIs#3?enh}tSe zb0HgqhxAXIzAqj$V(nFN#1B8*3159Eg+~3MBiP*@G@|xkxnV}`r6a2MxtB!HcSIfK zLujTY&ZgkdIQN6A-VY8t&q-phs&za_jJtvVWt*UbzJTM zNiDY*R;9}@a>XzgWoafhXzKGzmAJDsLy~fCpMNwF>1AT7xZa3x9MR9K-y3QX&6Q;( zx80)6o?C;vzDs||hcA*CTv8F{3<~2_wOoO;Q5~mYV{(aORx<-3?UDL{N0hm;pT;(- zp|vb@U}}`XXWPaC!4*^ft8D^LWaT}L~Z z(tZy8&9Hs_RlU{KMol)L0HCP_>S}iO5{4;#B=|ZN`gX&jx-(au} zHtjsu>YH$zJxR4=;8-gpo}F9HF<9K4J1799)576Fj>`g*8NxH176acM45IKrCB(ub z@9ItMrhe17S-V-k*|^!HZO1IkJjQi<=IyqKwN}5WHSWMw&*P$CqxyCeBWVXnY?-RJ zUQ`IYgj#t9p`l<&OZ!;X(w@Q<2E~l8DsARjF-T)Hrgq5TA4|_0$e?N*mUAO!MPIu^ z?#A}Lq^Xx@;Tm(Lp4H<*xo>W?P8u_P<>ES|pd(GHpeUuM>S64URH@flU3q<_-Kb2+ zbCK(=-mTe>q}avQ```Aiy|;~9+24QdPqAl#9_%KvVmq&U?YMxGCg>S}BIV`<)lbA(t!JX_`~uXn{Cda!3w`vwRGPKi(MI%8GB%es?$?aVPEi z({0u5xlw8PxSBT-f?HdGh%2!^iGJm5#lXLy$a{C(|(>fMgG6Qzdwz-M>_iR73MY#793!1uLS{ z-F+oO3r#Rem?mh1{&JhU8XW$xTav!Y>tZbNe=Fid zj7(uqA1B_95euJDzFtI%+W7-TZML>dxERNMyyn!8zLI@o*JF=XZxJT|5)GUQwbNk1 zCSa<4{ike({RciR`+p7x;0ySHt?>Waee!6xvH!RIbdCT1HJ%8DgW1crDj?h0+T-Gy z2f?zhcF8-53Do=A9r6R96}eAqLVe;_geHf7J!%Zlgg4d$W)K5R2#*sEE<6t=J}GEd z$S&oCuE2r_bo!|!F$emmo$NHN={Rc!_+ynXkz&68qN$x^%%R>fC*vXE86yxRkbK_E z!OXrCVsNzCZG*hTX|WqQbk3u$IczPC?4e`7;?DEIP;PHSabFVCQ?wN`895+RQ#s?Z zVy3&|1EsjiczEEUKJ*IY>Kaf@UCHEdv;Y~vl#zmmHWQR*BIf z$l4PSnUFO*INcqZ`#oMu)LrLb<2|$~*}QB>~@x z6@;56{pr)3mhu0K`TpRuV*KBE{4^Z@cb-0eyvBd~8c%chmr1$#8nmNic-rQ8-%a9e z*Wx(@wplR<+W?Q%s2tqsXtM|~Jn+=tmf)C-qBbli8A^(!@T{`J?PRzyq+LVOeve^qZYe?t+ zBFop7{=b&xHyd@G4e$*A{g{nFzYhC z&GVwJdW;x)D@?vI9W$yAC#AzgiJw9Ca5dgjG6)OsHC*`ePTxN!8gr-Lp%eCaep6v@ zSUVYSbs-5J)7(_{v85+WEqeq%7AuxYoYO&3fqD`)Y0bC;2!=~%vRh3MU302%Xx2sK2XwVvW&0?_*XF!chN!l`wVFZ zf_9cPm=fk;01i0TBsU-jY7^(iAsg7)$(!--KTN7IV);0rKfnJl7@uag*)!dajQ1~o z`S~P-X#2SdFPL~RdcCv3UZOj&U*3($xX?lPD#-KrME5rwAP2*->3w)ZigvJs8op8= zVu=A*hR_p~iguuY#V&(SxGgS;CD^xrR->t8-ylft-#>uDHa9kKpCp^s-H%264kT(% z`9BxJe$}U={D_4zyC~`6FLH?Jra7MHM)**~o|24fBpCnBuuL9HjL>I!y)jE$H4%-s zuNpFF^1nnS8pB5mj%ozFBEV5a`TBZiOq0ILD@<7zzv zy}7lmaFBl}KFslC-(^Gl+tM7UvkfFolS*su=jtwNufQ}ODBmm)nL5*F9?(dz+%Co!|5Z0V3-LEcly*iiM_^F8O;g zX!KEex3Ae?O+z~QoY=4X~ zV@gkx$CEy`8p81+#OBdSXBi}&D%j*H^XO~MZ(Jg0u21AfWrmYl<{Xz+NPEc{L*g|9HSVJ9T+k(0EdJEDZr9ab`qgH^6q1%SqWQX*+;=YC$EUTeeE- zHTim3mt-3~L91RdrR!1&NYWxoBvZT#b)?{GnZm$DL9XQp@uU#R3sFH~9#oCW8t=aQ zSo~JuHCI~(Vo)}o?9FQhfdMY08YMwnIQU_xG6AZ7EbvOI+2~gTwT-xi6U*T25_dF4 zQ-ObyzyB&Gh?@B~y6=^TNWz!nG}1IA3}kq?=$Z?+e#eWt2ycpZ+BgB{$&^He(3?0J ztZ;T%8R7bEC+pbbliCWA{h$k4gT}EHNpqa&@E$w7@$Vc`%64Bt7w{d4%5HaeyE_Q` zF`k`&Q~;rzFJFOIs~hl=(5IRv2~^2D*%nwXP1}MCzx|MI-N`T?^Wmz?5Fj@*Vu~LY zjs4Dy5iw6_OF>P2f|LSNei+)PlbLq8(sqGCF|2LeO`c!h*l7Xfz@W%bNg1k>RVEEq zxxK`S#?B8o%7RkQZ)?!lPaIU<3Nyw{cvLwwJ9%q|=)OU9-g^F$<5n~^6KQmFp7Y)2 zhzx>jaryucB4w5{mM?b{aj#Pqh^IFbH z3%213?uiWb3@sRUu0RN+7*v7L$j-|tW*(`9MP)u(T%3(fL%5!VLa`gM0O%QqWv6Zq zqMdDUhj~9*0>(7q6w73tGMs0w$Sr`Nc zWyN!=nz_A><@P${+_BCp>-oj7d;RmLB+)e0m zWrK3N!*S6UmK)mE?LjBrU!ik2Yk^lOG0?bYY@GiViJm=>m+(XSJWqkh{tqxW-TIQ3 z0OEeg9q<2p{N(Y|_5FWe;aS%H9CZw@e{2hI`TpPTqsNaz{J-5D_`Tl$`wCBE|4;f= zdv9{@W7+#v?ehf@s2wWyAEn+CJe-_WQ@l~UTbN%q?gv;t>ASs_Y%K*SLWIiuQcl_&>-jI#F{qhi&0(?=zvcdcd#h0q~ZZ}tA|B-#fZ2b zH94%r@@8~3FJqh!M@ZS5A|P&au_&+5sUsk6`gssIvBt{_9SogAP;@6f zdshu%o>mQMt*V!&91XedCG(nc+)Ea`qy>H@$G`vGl#V2|zXg99ENkP|fC}>iy9XDYjG_7D&nX33S zkDS~&wUZl$vv@_@w%Mq-aHos;0<-^xcL!R*S9sB)6eBVRT+yL9j%=DP*$Ia^AZe4# z1ij5-Hl|M(%*XvCJv^V3WsSi9mW7mrG@cv|hsibXgHXZBvRd8hTnahnLl(fHIiFIA zossHIRtHAK1H86m3+M!^Bq>0W}!Av2hWAH!s| z+~@Avz&^`KiNDN}qXmVddD`P~)H@00_& zFB@FC;?v^w`}XdLQ=jA@(5y_+ zcf7;c6HsYYvf} zC?QoeoIa4?vqrDaJ-LXc)9iW!N#>2429mpX!ge>&Kc#zgS@s%}jr=blJ0iUH2U!8( zP>me1-dMYq7(`t0WDeo;KN;Q8kYstpm&az{*6-hUlAqdrOTOos)c0OpCGaON@FzLO zYu;nF0xHWnnONe?^2O`^3<>j-6S@I?9(6e}&L+;=>%vTbW$8_am`nY&m6P%hpcBB6FInEMf$6W3pLrE>QQb;d`bK8JnPjFm&4F9WjqlLI zS72n)VWGSq5S!`^3eVd=Ka__4>?C(TAd3%U@_-(_AIR_ljO6jLOpSe#b4Kk(ZAM?O zSSl)LOVT-NUVOQ^ZI03xP*;Ge1)l)*@w5wHm&Fh-Z}vA@p7X{bj0=Hs9f7p)c*1~? z^(|FL?#I<(PUTv2ds7yJC{<(=!p4SM5jG;Ctv2p;-BdrD4svwYcW2zOc=_<;hqyiP zZiB?2EH_|dku)SPNbF=?%Cn4a_QMdKm7tgQ0R6VQ)CguS zZ9WB6(afkn@~yrGW{YRlOTG${zWywH8M>Yvefax_I$6dJ7j#zYALS@WDT++DIuWX7 z&JLJPzB2Q}sVTa;B7oRd()&0@yoH@kGK!!a;zNoGlo5ui2stZpoF0p)@-RuBEUI$Y zhw;IF81gL`uA|Z-P}_bMDdtq<xbC4x+xwRqb%B9xkz0r@Gh?iI4 z-l?BMTRM=O*C~eua~Etwsq#F7SF4$(0fib)Qz)}e7{}hUCf^x2!oIYFPSk)5Q$7bFkLJ>&4a|8yQaIXE-@Z-I*TA~_x2%Y>VhL1E7$|(aS(DQgu2KCxh7+T_K zIoc$CXgp=WU?VJ^iWJe1(@Rqy{iUC)O*Fhwj8E05-?Hcxc?C6Yk6e+DkwGMM$;WBU zV$oWAu_1LEIW>Z*P8if)gfhsb&A^s)A|G~&wh6t^mXzX0ovODM%FOjqmR^M|@A<^q z7?rLcZRt;f@V0cGoEu?nsX~dxg4@y>nd#RyT3>3-z$Mbqnh*(H_GzOX%9P=M3|`EV zPYLP5PBofYjA%u^wsl&vRPjn@T0eSgd5hOL62GhqaXvq;^J>dbliVuLl@eV}+7tt= zdQ01>Zn0ZA|@u zH2+IO)%yOw<-CBIa#?>d*Kc}0$NwAtt^L2h!qd|JXVWjJ0-w|VkG7wz+y5&(?d|{k z_=|u){?|(U$A`PSkHhwV@^p8N|MfKoMTTIQz`ZSecXk6l5bD7H8!!vOR*d#OVuA6JW@|qOujSU*-mqS%J}Ft!wL7@OIIFSquc3 zTyJhPj&UBh9N)yF1{)i91Tfp!*l^HfC?N}F-LcuAz0uH-&oIfQah45eZZ?I3<#3qC z_7aN*AEuFvsk058OqI|fTWk=-sU6?0DdSlN=ZcwfpQ^M$Cx@}6@gqnkv(c!W*ha)d z<;Xu@LIvCxlXHiGBJwearew%$1-t^G5uH`6_$6uF?8NuYE_O(pQEOtn$D)xu$nFe6uYJl ziRiH>(lGF>wMtWb=pJC`jJEcWf-r2m7r)9*Y?`2kn&jktc;iVOm)&Mbi*&W?S`QF7oT!2g8>;ClZ56`l<{-JilpYu>&u z7c`kSo5!9yxY;q{0dB%%$094Bkf4Vb!YsvinCuK_r0>E|oYdtMhp0MBirG9%C1<>5 zv&5ZF_9{z?^Ycl04l9EUPo#HfPW_VCrnxE(BXx23Zi}NAT_Oe?$qSdGvQj1J9L<8* z=4u1-6qny-+j=pgUCF-A4)NXfY8{#%MJeG*;1)lRp zAD8M3x5>Yw8kD161uMGyx^y}ao+jUXlce5zlI~#c+w>Es*J;p%wowiOAtd+j!+abB z2%3PuMF8wR3`L8mU6qJee2X#r4B=08%`{YvK_Zwx z6U^QPn)mP?=sZ(hH6`R?dtn%tlaY2t(0fUNS&N6&zo zwIpb_%h}lw(YT;$8Qx?p)pU6z*g7;HbBuE(ezMt%d&b*we>N;%e}~?tFsmL2Sr>b| zDIFWiu+ewuqvZ98QzN`fnp%rr=NChK;~a9HrJ;idOhoV9yO$hu3n72^?mf`@Gq||C zgz6p_^{>#Q{DK-y=rkuVZ-=Nf4`_KCp(a%)*_c#ryA8><1RuPS{>6ASsLn~i_`{Tv ze60GV=F95Tfl8L4^M8(wp~9r?bFGQbK?fq4VX*s1+rAb=*}c_B)$R%YOF^bn937 zNH$oRmAHF*iC4Wm)(uu8L!Dvj z@DoC@P?wP{(TR>2NK9xau|21&fRk%bn~wh04PIPr>)3WG14gB=ggXNUxe{Ykp@0hXA1Nm>kt{A25g{+Ha*QTXtz z9uGlDf57?@$$KK^P3m8*?~5C(Ff#)C)S-B)!KybV{DhWV!k)Z!WH%^|OA~&-z(E>u3F}pY^kT g*3bG`KkH}xte^F>e%8