From 69de852be1721dad0af993ad2a1ca0e2ca29df84 Mon Sep 17 00:00:00 2001
From: Gabriel Studer <gabriel.studer@unibas.ch>
Date: Mon, 6 Mar 2023 14:15:42 +0100
Subject: [PATCH] SCHWED-5802 Allow AFDB mmCIF files to be read in OST

AFDB v4 files are invalid as there is a mismatch between _citation.id
("primary") and _citation_author.citation_id ("1"). This can now be read
by setting fault_tolerant=True. In this case, a warning is logged and
no authors are set.
---
 modules/io/doc/mmcif.rst                         |   6 +++++-
 modules/io/pymod/export_mmcif_io.cc              |   2 +-
 modules/io/src/mol/mmcif_info.cc                 |  11 +++++++++--
 modules/io/src/mol/mmcif_info.hh                 |   3 ++-
 modules/io/src/mol/mmcif_reader.cc               |   3 ++-
 modules/io/tests/test_io_mmcif.py                |  10 ++++++++++
 .../mmcif/AF-A0A024L8A3-F1-model_v4.cif.gz       | Bin 0 -> 7597 bytes
 7 files changed, 29 insertions(+), 6 deletions(-)
 create mode 100755 modules/io/tests/testfiles/mmcif/AF-A0A024L8A3-F1-model_v4.cif.gz

diff --git a/modules/io/doc/mmcif.rst b/modules/io/doc/mmcif.rst
index 63bfd8822..c4c361bda 100644
--- a/modules/io/doc/mmcif.rst
+++ b/modules/io/doc/mmcif.rst
@@ -172,7 +172,7 @@ of the annotation available.
     :type citation: :class:`MMCifInfoCitation`
 
 
-  .. method:: AddAuthorsToCitation(id, authors)
+  .. method:: AddAuthorsToCitation(id, authors, fault_tolerant=False)
 
     Adds a list of authors to a specific citation.
 
@@ -180,6 +180,10 @@ of the annotation available.
     :type id: :class:`str`
     :param authors: List of authors.
     :type authors: :class:`~ost.StringList`
+    :param fault_tolerant: Logs a warning if *id* is not found and proceeds
+                           without setting anything if set to True. Raises
+                           otherwise.
+    :type fault_tolerant: :class:`bool`
 
   .. method:: GetCitations()
 
diff --git a/modules/io/pymod/export_mmcif_io.cc b/modules/io/pymod/export_mmcif_io.cc
index 954240725..ae6e956fa 100644
--- a/modules/io/pymod/export_mmcif_io.cc
+++ b/modules/io/pymod/export_mmcif_io.cc
@@ -403,7 +403,7 @@ void export_mmcif_io()
     .def("GetRFree", &MMCifInfo::GetRFree)
     .def("SetRWork", &MMCifInfo::SetRWork)
     .def("GetRWork", &MMCifInfo::GetRWork)
-    .def("AddAuthorsToCitation", &MMCifInfo::AddAuthorsToCitation)
+    .def("AddAuthorsToCitation", &MMCifInfo::AddAuthorsToCitation, (arg("id"), arg("list"), arg("fault_tolerant")=false))
     .def("AddOperation", &MMCifInfo::AddOperation)
     .def("GetOperations", make_function(&MMCifInfo::GetOperations,
                                    return_value_policy<copy_const_reference>()))
diff --git a/modules/io/src/mol/mmcif_info.cc b/modules/io/src/mol/mmcif_info.cc
index ce93b6778..576e05912 100644
--- a/modules/io/src/mol/mmcif_info.cc
+++ b/modules/io/src/mol/mmcif_info.cc
@@ -19,6 +19,7 @@
 
 #include <ost/io/io_exception.hh>
 #include <ost/io/mol/mmcif_info.hh>
+#include <ost/log.hh>
 
 namespace ost { namespace io {
 
@@ -76,7 +77,8 @@ String MMCifInfo::GetMMCifEntityIdTr(String cif) const
   return tr_it->second;
 }
 
-void MMCifInfo::AddAuthorsToCitation(StringRef id, std::vector<String> list)
+void MMCifInfo::AddAuthorsToCitation(StringRef id, std::vector<String> list,
+                                     bool fault_tolerant)
 {
   // find citation
   std::vector<MMCifInfoCitation>::iterator cit_it;
@@ -88,7 +90,12 @@ void MMCifInfo::AddAuthorsToCitation(StringRef id, std::vector<String> list)
     }
   }
 
-  throw IOException("No citation for identifier '" + id.str() + "' found.");
+  if(fault_tolerant) {
+    LOG_WARNING("No citation for identifier '" + id.str() + "' found. "
+                "Couldn't set author list.");
+  } else {
+    throw IOException("No citation for identifier '" + id.str() + "' found.");
+  }
 }
 
 void MMCifInfo::AddBioUnit(MMCifInfoBioUnit bu)
diff --git a/modules/io/src/mol/mmcif_info.hh b/modules/io/src/mol/mmcif_info.hh
index 916954323..351f27bc0 100644
--- a/modules/io/src/mol/mmcif_info.hh
+++ b/modules/io/src/mol/mmcif_info.hh
@@ -988,7 +988,8 @@ public:
   ///
   /// \param id identifier of the citation to be modified.
   /// \param list list of authors to be added.
-  void AddAuthorsToCitation(StringRef id, std::vector<String> list); //unit test
+  void AddAuthorsToCitation(StringRef id, std::vector<String> list,
+                            bool fault_tolerant=false); //unit test
 
   /// \brief Get the list of citations stored in an info object.
   ///
diff --git a/modules/io/src/mol/mmcif_reader.cc b/modules/io/src/mol/mmcif_reader.cc
index de1dbf8c6..527f68fbe 100644
--- a/modules/io/src/mol/mmcif_reader.cc
+++ b/modules/io/src/mol/mmcif_reader.cc
@@ -1844,7 +1844,8 @@ void MMCifReader::OnEndData()
   for (atm_it = authors_map_.begin(); atm_it != authors_map_.end(); ++atm_it) {
     info_.AddAuthorsToCitation(StringRef(atm_it->first.c_str(),
                                          atm_it->first.length()),
-                               atm_it->second.second);
+                               atm_it->second.second,
+                               profile_.fault_tolerant);
   }
 
   bool found;
diff --git a/modules/io/tests/test_io_mmcif.py b/modules/io/tests/test_io_mmcif.py
index 20162281d..a1b217709 100644
--- a/modules/io/tests/test_io_mmcif.py
+++ b/modules/io/tests/test_io_mmcif.py
@@ -1,3 +1,4 @@
+import os
 import unittest
 import subprocess
 import ost
@@ -312,6 +313,15 @@ class TestMMCifInfo(unittest.TestCase):
     blinks = info.GetEntityBranchByChain('C')
     self.assertEqual(len(blinks), 0)
 
+  def test_mmcif_fault_tolerant_citation(self):
+
+    p = os.path.join("testfiles", "mmcif", "AF-A0A024L8A3-F1-model_v4.cif.gz")
+    with self.assertRaises(Exception):
+      ent, seqres, info = io.LoadMMCIF(p, seqres=True, info=True)
+    ent, seqres, info = io.LoadMMCIF(p, seqres=True, info=True,
+                                     fault_tolerant=True)
+
+
 if __name__== '__main__':
   from ost import testutils
   testutils.RunTests()
diff --git a/modules/io/tests/testfiles/mmcif/AF-A0A024L8A3-F1-model_v4.cif.gz b/modules/io/tests/testfiles/mmcif/AF-A0A024L8A3-F1-model_v4.cif.gz
new file mode 100755
index 0000000000000000000000000000000000000000..b3d49495138579e3828572d2105e83197dcbbca2
GIT binary patch
literal 7597
zcmW+*byyQ#7bZrGoD3<60Rt4IL%O6!ib|-A?(UEp1Az(1fFIqVbayKuAktj|qXg-a
z3BotOf6sZ(dCtA(J@2{CbJ=1@NsT@AtqAUv)cBQzl!QdYv?Y~9`PGE^UEHi~oXvd2
z1gsov@&1Fq@mi9s3;A8G7+~gGZW)Pp)J`q1_}p2?d5G(g*8=^0eqjkc?~^?Y<59K3
z3MCo<Q~b^i)*@iKnpgDOaKbySsIzL)=r;N2x<_`$uG?8Ic!P1Hj|mD~4wdYG&&WI1
zzOsa|OknZL>_6Gy_oHIV+*$d9NrA^M^hdzIr*ZqdzOQ~25VUfT?b0;#M%Ar+r<<<*
zZ`r)<ub5#o-OT2oJJjF0z!lTFZMM<*{;gxVC06-bhuWZ#%kodriebgU9ye}Xw|$d7
zw?<9yt?So=Ps7@SbKDea18N-zg|-Vnr((7mRu6wD)T*lt&1IM%2&PtiGZl8O>4PSR
zq_3-h5f6nFTomehcmFnwgzWnsKQ^o1_;njD_Ws!#x6F1)|E~K_S(R9VI{`y1_4xX^
zr!;fS_A_YF_F-D*))JcxXwkJk63_3RrCEjPtPq|jG=qQ{z<Nd<bi3r!HPl==utosr
zIy7CMu<N&NwkajNa}ZhP<ezm)0|X&w<nNOH7Qo!u0Iq(abOEncp8rQ8mY5lo3zxIG
z4thuEnRL|5xY%=;cme`^?T=q!Dz^0f-qdfA-RT6nM|zWZ|BYBw@2}lfD<NUhqVh(u
z5|>#<ryMk$7Q-%9K6Le9iGV=;^pV2$HR0m-edCS>Z7Oxo4EjupGLnVB2@x2#JJijB
zHH9sA-o0~l$(CO><1h&BOszm><JC3<WFA@&7Hq<jzgo6xa!ZT&oDlRarMmrMUET2V
z*|ZwFJJiD7%(Q-lI55pF^Q$>2^U$l>kO9p?I?2RtI`bK)w2wnw^ObKl5S&uO&Hb)s
z>Ah}kU;HH#&FX(o#cw(Mu9FYb+rM0h+RijdXO8_cwR_w)bY?}^+ndlaMisT+iil#^
z%q)<~&xx{7S54h=y$)_(l`OXmFsbkx-Zw@tcC*I2MTLgkc8uM6o4)6q|GtYpQo1BP
z8GUsqksC8Nk}H_Y=2spREc54-@hgz~?yO9bS;0+W7;|lzWRa`J5bJsl?MxIJCkbNx
z$}$GqGj9zVc>-w-@OpOHFiN2sqi}}Vx+s~W<@*c1`ehj?Sw*)xw-95>Ug-8WUHNF;
zs(mTMnd&VOu}{tG_!V{M@7%~pDP86#VWb)IMf-%IAJjM44NdBYqsoidr-H;7>Y^sD
ze%S~4p$ysT0*_B?1q0Xg*GQjO?4DCC=^d$+5jq9tt_(Oop6_cfLUS@x31p9coe#PE
zPj^aY|I4Cj&2?T#2*U4abeA7>sAAw%z#E0oVsXCQ)pF@IRzLsE+KFD!V!Ulq)Ozz$
z{gq~D{`qgtC?5R4D=XrI^<rdmGj*OEPmn~o|4*I|h_U!ysfMWB--Sb0k3*zF#e!;h
z0b*hG>$Ho#W2Qk2cPdU}V1~Phk)v9<8)i-aH-YZ`HXhJ!uN=R2wwUIrGbW68S2g_d
zb<(Rt-9ag7r_<)@3=oKBBez*DV(o7fH#StpxUc>KbM4SM%QdiY(lADe>~~BU-HvZG
zm%d9G{f=y|S6V6j)t3LtS&Z;aWxq<$*4G@^WpJ~6={&oGT7g!ljUW~iSgXLCsYy~h
zm-5=qg&nQw{pcKfzou(vAH5+;#m(u!Lgm+ab@pXPiP^LjY4$}u#{}gSm#aG#k9{A|
zMH)W;TYSRG!(=BC)z%TU)_7~a;2E$;NRCWjT3`H1HSpH~^@5N~iWn9fAF3Qn{O9yC
zBY2_GDE0LnTR_tjMkIn~4pT}aIAnW~&S6{r{M~?|158Ki7gsT4Qe97}C_WFV!KO--
zAfHIa5iE9J<xezk^trwPXqU6R#G4wfn#bCMbNq*MXz)3B=QQEa9v>&<^x(MAjsn=l
zxDgIoQ#27k76TrCYN=ny$`rFP`P6!dVf4i-oU8t-Mb4Wp`H;PVbo!|SE@;|PP_BWl
zvMOqxw^vr(MQM{~(B*#6yBD2sf>#HhcGdJ>%a{90x9F#bc-*)fVukr;qg+)wt5h-o
z(+@4*<T6&PY;q*BrCej;kU@=Nia#x6qHCTtjf#@S?(>r*7=$c1X9<qUaiM}%?F2!b
zAM8{lco=_<MLX*~h|Y~+amTJmo8`=6m0oPtm<dQoJ*IKV{u0B>UNmX@weC$Q;$T*^
z<};0Y=aYC&w{J8<Bx6_je4*;T?V_YlU-s3^@I4j{zfp);p_5b%iI`^}p}3O`$^Kw_
zhPD52x3;r#CD3`@dKqKW^cQ<MAXh=WlCP0jH+xS&{T1WHD%-6-n6Q#CX!PxTyFoRB
zl;6r}T*18qPa!7vZT=JQA+n}E?7O$|*!bcfRs!qgzXyj2FIc5~OFHAlu*Q6P4Zl4Z
z4UPi%1?klc4js0-3|Z}uo?=<gpskuNk9HD=6L|GrN^K&0Du+F|@WX#t(*`pq8&7ew
zw=bJNA4!oJDnS^S%qGUcwtWJUpC_$bkd%e)QN-T47yX>Aq4|-5b~C$dpUR|_<x@&a
zHTVx;yeoFp<G~0t&B$~bGshpFZp}LS!N71uy*9QZJ@frqB-pmU36W>xkl*6?7s7O(
z7*@2{zU4}pliV#O;;nxdx!A_{)aGKyI7Xpn+p~38xHcbhEvXeoKd~A!Y}FO;h7+rR
z7h~3Ciga_o@>43KU7~kc2q%jdZ@AKn)b}%c%<|5Z-u&7y0eTTv(0h1&qL=5AtkkgQ
zpduOg>L{mPJTQ=fVmx8%*E{o;bO57G`HkC%E?r$?q5KeV-OlDm{l%jJ_<LyW;I5kO
zZn*{ivaD+ZOOx;Hf~a>Yi@ZcOyS>KRhw%U)#W`J==ABn#QR^$kQs;_kZ884BO2qWS
zNl=|AaX;@d8Qq@`14G|xjQh>M6wI$9ohf1rB<UXevOI~f%zbZQ&F!#OoYmv~n%IGt
zsy3;H_d^MIy^oa9Ab8*<v$QEizXw<LLx;DYi+CduRQ+9GcBtC#hS-B=`$Icl6?0Q8
zSl<%@QNjxRobne3Q)&Lm4T9Gx{UKZ|8a|dmiYBy^o-hPv5D0!uRcl;HB~*g~w-_@|
zeE#;1pa{;zVl)XH{qSrL3gu6w&JYVj_wauta%A-X5EDE%tU2Y!!e7J}Zx8%=Yff7t
zj|3P&1}HqYtyE*nx86N)bn3D#TRDhHMKWw}$=~H1ogIkSaXsi3`@#?LLppn;%X|~%
zTCa_n=~$8C`J`Y+NSEVO`_{C?mDxX&KNY(^ZuvDaz<}{9mX){6|5H@|vG3{eH8zB)
zJk;xj`;GUfT`j7Hsab})*eFq#=HVTJvfCcj?%v+;XITzyOWo!<-LIHah(7%Ot*rG@
zAS!ChiE83k;~)Z188a*@XQ9%cZcHz@)bCa0T=IoKq`;yJ-gtU*n?fWBC<<8FFRNzn
z$QtiBVX(k%xF^CR96U3Rh5pd+^sXO_-?9DCw}TE6dXZ8rcY7A{J&~GvI(%+axm^01
z;!!)gSmgSq6aDbxOn&pPjz;y4QL8cXl%;69cL?>)r=RK+1P$)ryv#j)Y-e~-rMW#Q
z(Ea(bo%&_x6}ew^6E>HEZjNH+4hrK&XSpq5fF&$TJLveQpOH46x!ng;{T|JC2<oYz
zq-wHs)l4C^2h*gaRZSoHo`iUScWZ`boi5>lAGBJ(lv-Tr#MZyKBBNzkyxFHs!DQ~=
z`CgZ`s5i~uHta7fJbJgcOThPpB7eZ-ipPY#YWeuv)+dWgrLRUJL-!9g#G_DOH@pW;
z%lZr6gwdA6xl6s;Up{zNdEQ`VW<s?lI!~oCkHG`CjWTxF9wE}?dZWOHKJ~FHKTKC{
zJhq;SGzz3(FVQk-jNY0Pbl=Vvx8zC4{l~&$loxdpF6(Jzf<kVuC`RP#V?sYt>;2wM
z9qL6;P6qrzt?1_5rhPa(+}S_!7dWPtV4%unRo}qRq;@+RNQxR-v6r->E*zK$l5|J>
zqFAuMu@MQ@-ob5VjDs}RM~s1L-agVNY1du8O^0oM!&)fFpCRsO-kQRM>m8Nbl-qp7
z$RW=v-kt4WWH)tjb0K3BYyCu!?}>|q_Zp?Ip-)iyXq8&M*5#5t73I$O4BLLQx3tc{
znZo=gdGIY6^$qH;uR?@+nsT$=)H+35XPWlH&y!t?2tE0n>5;s<_KE6VVOdXUJH&gI
z#+Ttc+H9<O3(Q)@dEbr+RP7sVxlV6F#8_&Iy`}GZEy5@EFWFh-sEY6Q&xz4><yiMv
z#}OVOg2AlrmG9ey*k&v`OsMQHQ4Y)NH3$`nSlaH|+{D2#_&oPV98dkkKA3O<>zy{r
z7PW!pVfyjKTC!a+dTFR-zjhz5h(}B;?$D-r3sKztsW9q%J1l2|qf>{ZcVMD2t959D
zbCk9r;EzOb#`nl$z^Y<gX#*@$0*e<Mm){-}szmG$=jScQ)R@>29a5Rp->p+Wui3U>
z8gJOxT^nyKf9FEq*goX6Z=EZ+YD9j&&w@SAzKs8)jZm#vs-OhT6BhXfj8^Meqaw1t
zG`hU<(mUwmSc{%5-GszO?8VlHtlGNe6j8%2_TB}}mC@+)OOIPDtYEpLVX!1is$aHo
zncw@{V+n(Wa<orcpR^5cW*O~ll26)@w2gdbne1$;Pufo@o9CHj))F|tl(da)W?8Jn
ze?DoaQZ{ch%Nisc=Twb(yp~$x=&iD~-IILV0l%zMhF1((Xp4AfwmRSgugXs0n!!G@
z4>b%XhdX^`;y?19ZH2UFk3CPmJ<VGYFfaWU7BF8${;G_|VlZ%cMX&h#`xnWSXKBgp
z#k%QC#k^eGuy%OQ^JIE*DS<Rr8JoncvQ6V-Lz%D*4pHl^WE<UIiq1$Cs!6mq&2$-Z
zKJrrEuGXN`<gPqEE+)gLc9U>My?;^Acfg43JrleXwq_Gd{7%MxAyHSzKGeX8wEVAc
zGCr`PiWpD9goVm&%i~X*{|`GA8Uu}FWJB?c_V<hT(k-7B(J=guqAkTP)u_9RA8EBs
zi}a$iDS?&;-)5^aTNf97yt;L&``J`{WyH}$Ir_zA;+BSu+!__Kg}QK;gT*S{Yf(nF
z51*&j)MD0H?(H|SC(e4j=xk+^zv)W*AvhV;57u%@HE=t3r1JHzba66p+g|;&(SJit
zB`1_JdszNsdM4}82rgRqacFpIEubdretJHcnuSoNoH*MnI`JIE`d|&zfsD|~N~$g2
zSqku=(H=R=srdsW<40S88rmPMnXtI;<myBkp5*}6T5T5@^t+U+YPbAEsDEZ*YbF2l
z<um!V3*%<4%A>zG)RPC4xueHu$z5gLy1jW=sznBq5qmxst-u49FFF`{EQ8+0I!W;5
ze)7DV6=NzAHb2*V^0Kl&@Z*E*rJ|AIWe0U8GZ*<8mT!mqH(B0u5h~YwY-sIG#~qdm
z4Z*$=cxb_lMzFXFpP?3Ui0ilV_ZJh!ru-b)#9NrDs`1HaUxU`o>8-{WFJrXe0htH!
zOZ{dm1@W#Ep%(=!o&j%r`ChzTrzC!0{ygSJp%~M725Mj@{?mnV{bagi9Q~$0a>Ahs
zdvJPqY{Z%Op-i~bVTK@8mX$8F)Wzs{k`;L2lUvWxDRh0~o-oQ2p9ZcK?j>&&(bwF1
zv?|_CmIXyRZ)i$-ke(~JFO$B2<RzVo9W!lNCke02RD=VoTwe}DNkIVLVb>SnXg*M%
z7sq$bV_D$_g!!2lBnKeu$bkrlXhau>^`H_5i6;wDf=aG!kgg;s8iCJ1eSAKK3g#Oe
z2>=Z~SODB+C`RyTfCb+_0}HeeSx*+i9*Vb$h5@R0#824g$XLdFTr!rkNy6@#i$?x#
zYlpZ}#Jk^@)`x<iz;{G|%v?g$NA9Oned+{Jd<1b2aGd#hMFz!KI5Z;{vZJ$A`&-;`
z?b=h9Lza{N!?7HYBYvP-Uspo-4{$of0D>+u3YjDZa_VKc|HO2jKGb{+QB#;u@;~5l
z0flV?SdXymaMPVG$|60m{xu8?B`zn^NP=?c1dWk-P7z{eLM8#gEJX)QJCf`CK0Wy$
z4%dB|)WnTn1~iv%k+!G#y8LMfPOYH`2^Y}7KwY&V`W!ob^+<}hiam>Z8IXAwn!;St
zXp3W@*<(mAD?0jSbCno$2oO5Mqd^{U=f&5I03{U2Y34?w+r3LWoRztm(W0JF1IU{`
z0}EAC&DKvWa*meXY9-kz5ZFPi3y8Hh;!7Sj|0YrWGe1PlZdx(ojf@qzFO~Huk%%)o
z^GX8EsspIbuC0V|*nfI=M5BRuBi_1;f3H!rNqk+{ArT<txE9-EMTdsva+~53>R6t?
zT#qOUBd4>O*{mYz!-WEA@U_C$m081Ny2b-RONzvD5d8GxaR5!^Ghh(M2Mw?Sg$uXr
zK0Xk*nd7HO!_%kPu>ci6ad-U=`F$fBeSQ@<fsbMlB(8rCx%npL5nL|%BjyYuJTlas
zjt?c3ordPOA|5`j2su5<S=ZdFK|WY0?Wpk8iAj#yq<VR*%q(y-${IGP<udn>CzGL<
zY&J#A;LS!Rq{diPq++cn5&~>SF!a8sDyTfs0Uh>LO+&x-;^C1KKG4YJUSwJ&hH)rC
zm|H;43dX?_=uB3SOPm{0QC0~YX+%w6Lm*pVvLORWlGmAL8l&{0$>T<->NCi$Uf?Kr
zat85?>jo3+1nD{UoO}jE^3{$GWlK_X%w2`Sz+=S^nfpp$5NtD}^>`ud<u#Di_v7g$
zcUZK_sQ`UeqU?|Itb58o#J>%3t0{b0q=8obEdusrKTO%p(%Kxou(HJ${)3`QoDP|s
z1<3FaBCJU*MViCU?J@0*xeZD|=kmtvop_HD6rVOAmd_E#i+YQ_TV=BHh^%{aLw&>|
zyHhGvCw^b0zSxmu?5VPcr!g-n9lllUSZq5s7D`S<JR<X=Kr@(r9_1X=YFsB1o(|7)
zwrmin;8(g?Y+HoLzq_vs13l)etqEhO)FJ^o{&GZqHd(7fv9c+OkU2P-6YWkxD=N!@
z7#R<aLLn-8g!x-bd>nC5|B!1Y08bl$E=7@e1JzuSUQ!DcS_c&5yBo{g7O^P+tjtIw
zD56T#0B;k6a+~BJ*I^5I3NVv$?oZFE!#-#EYD@AK3K=S!(jb)4Ge#MMF$Z%G{k}$U
zQbzdcNIv(%MA7<!H{oa+)I71Jm<5Z9H_jT9!uLDpCQa;~{=d@ter33q!VnW+>ArWA
zKmFETE4jW^yr}|$Nrlwt*;qK_spwT|#-&YgeMMFQQ+w|h1Yd(<Q8ZCGb~Am}J<=NU
z;_H)b7)Z}eUvDWYOR@>cpkqveYBP~c>D}6((W}NswsgeyoN6)PDvKl^5Kkb*2+(tb
z%u5?el9IU^>{}&3g}`4BSSmRmI)Z~^M27%;bT&?g)3TqwtwLdVoXQe<!$R7cfOU~N
z<iGw2&>KQf&ob6-TaQ$#d|J4JGot^QOr>}TjLB<~AJ#fr)(Nom{qnRRIDr^rJzEOK
z)fGx5$SEKg+33}+9!>E3^9HT|Ksp!0f2#xr^VE~_9_)b~-~!xov~gh+>nDiq*oM{Q
zEXoU<ELhA_UT{V0K|md!Q{)(}zyDw33S3L{iUxRUGr;to>T3e*&B${H8o#H(1q9H6
z5h3dfv<E(U3?bj34z<Q4<%MHQ0n{+#bBhN<)i{oA6Hw3g{I1EqBrFVIp_DygEGC>@
zL)C+`0X!Ve7W^bPA9cxw*VtQns{QL1Ll3`hM+_<@wg>;PQgz0C;>ph{{li$Gl?xE#
zqm!mswFec3%IE7BNJL{vpAnw4b8ADgB(sZDya|f<yIIixZ=0459#`H9{^EO@P5ytA
zi>`6%(M%$JMV67g{E`c4O`MK9fR9egH1r&LL}ve+vx;V_iklletAwcnYJo_5PlI6Q
zpD4*~K(ECARh!75ou<XHt|n&Er}s|wNfIPynHA9L#r>TRJujXnRIEDOj}EWqKs(Pg
zho$Kl6Rs13)j({~5k;j9T9BV}DGQ2!#O@J;Q!=g?B2H#L%Guv*H~c3kW9B{2af^;y
z`&!bZ@~hfECGGkW!KI-xT&+i<bd2GuH2@a^ogiUfB3hv|w1(zc1O%v+@iNpzggClJ
ztEH4=nfVmu&LfY7L3qJb&~lPi(TE35TIdq379gOGwF4Z+u8>e#Xh$TRSwl?Y2W%#|
zr|hU4f+?F24L^5C^u`(TOOzi-Udg%elr+h;L7wa=xs&ASv;d(1%tP^e`O7-=wRZUF
z=k|%m0_%nu(40vXcax2kw-bBzI8C5b!DX22^SU2Sn<tPe!!H5yVD0-w<N6WS#|gxQ
zqpRy=L~(=zuY&gEPQj_ESlHUV>ga;^G+6JYUYQ4bo!=OfKI433=may{*T=+99{M}u
z3tyv%X_%BdCsnX8nxU2RJxv%rPALX)xb!ql!}vh`TJ08-2mjdSOnUJ=N%38Bgs!B!
z9Y+H~`;QomBL7EHfNW)~|0g087lKr<*1=M2ohjleW*K<l*|MydF2st@o7-TITZJqU
zeos5~X75kF<=bSGnyhiu4I;wiQeK2?@ubmtD|Z55_JkyJe^g!@fnMSMNGihpSDqau
z4Uja@mc`O4VLlU2mZMfFFP?+LmRjv?@;lD&xsMThPLa@f<I>_!_QU14kN6URsZZRc
zAxWk>J+39cxyseM^JE1Q+u6e0ruyvR(i+p07hUh+3`-X9lP#e7b5jmcL^Lb9<-uO?
zH^$v@d>~P36t%u35#zshJq^xFSv5|tkp*Eag70yDrDR6S(C>vWGP1}0jCcz`O&{W=
z34QYN{*Yp<_&uZ`{MfZb9nBD_QulVTu2%}k`9PzZyWqhd7in>l$QW?E%zSrJ5BVDM
zBp71)WSUb$nJ1LAM=rn+{I*Fd{oE0QyB$D+^Jq8~=eH2f)qkw>LF2Szt1l3x&2keh
zwwB=2@;%>_1lZ2aJek$v==EbD?cFe$pxfH`5ui;CHz3T85dFCbF4D@~z6P#@=)!RV
zO9=}W=wU_;AfJ;zi(<3bKMk%EL{emwROHk{1I;_*I#)Ic@i_YY@6p7uTm_7>h9k?@
z$u|3S*B7^~CyP;QaBvDlUZ3N;9t{loO}wl8Us<3D@pZJeF~G5KiqH-EtBx{t0cWfh
zvAE$i<qZ|Qk8EivkBUl9Sbkq2YkGTI=Ja2Z&UbE##{1D`>F$J30P!v_@$OWxNAo6}
z1yqldXC<2+HJu3UXS+>4)`Yt=(29z3BIVS_4u!*oTD#so&VclDq{;=+{DLvEPsG=v
z3^5%&PiAej#U+9r?yXAy<8s#|h05;$pnj3p=%CZ=d5;AE;p?Xb^8}VTU>0bp;O9LE
zD)yECN5rrong22w?qEB!^yZlv?w()qq9uyg3x1i}qBG?|re=s4rDLZ5w0MTS-H}EH
z!4C$DjKKP42p30=XeH#Mc28XudzPwpdC=)qn0<I39?d;cc$2E#IYFimr3!U)e6K1+
z9X<g#E<5p2)Fw~Wv2(ADHCkF@JPwY^0Gp5{EUSv0SUd~4Qz;qQ*>v95bhJC~aoy(t
zX=tFy@sBi%e6abHefvB(qQ=1i1SfzO{P-0D`BLjMsV35p&Wyg5c~wXYyS5!uPqLY3
zK{k+cu!z3M_TtKk;W?I%%%SB5@e_vN<M;zJ4uz}dxvW(?=W%blO|A)gKkRPQum8gx
z-8LWPtoqt$bAS$X_Qb&(oiWp_6qL@lc9#iod(*D;@BVQKbwC}@1O*d_gc$Q+7;@bB
zvuTX%EqT$DXX|M0{M1rHF<So{M-R0xAAN|jwC6u^t{ETF-6Q>5_s!`)nT=TEH(>x4
zyZ<2ak5LVwx`Dh#w8@;J(E%7Abj?OA4HW$w@`WdQhDZ13qFC#}40KP@3YZ9`HIxi)
zr}P{=z2;#-!vskKZjR2VNJEmi^J|{#cCZ;ol4rhAy!Ab~!^6Y7yCcNA2fLA>bi>2@
E9|GN#YXATM

literal 0
HcmV?d00001

-- 
GitLab