From ff01bf2cef655ee0f0de201904dfa7f383a20abc Mon Sep 17 00:00:00 2001 From: Simon Suo Date: Wed, 24 Jul 2024 12:40:23 -0700 Subject: [PATCH 1/2] wip --- examples/data/resumes/12780508.pdf | Bin 0 -> 25458 bytes examples/data/resumes/14224370.pdf | Bin 0 -> 19460 bytes examples/data/resumes/19545827.pdf | Bin 0 -> 24293 bytes examples/demo_analysis.ipynb | 761 +++++++++++++++++++++++++++++ 4 files changed, 761 insertions(+) create mode 100644 examples/data/resumes/12780508.pdf create mode 100644 examples/data/resumes/14224370.pdf create mode 100644 examples/data/resumes/19545827.pdf create mode 100644 examples/demo_analysis.ipynb diff --git a/examples/data/resumes/12780508.pdf b/examples/data/resumes/12780508.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5f90a79eef23c09425e6c234531a7dc70ca3f672 GIT binary patch literal 25458 zcmd3MWmH|uvMx?=cUx$1cXxMpU${HLU4naX4elYhyL)hV2=4yK-e=!)-ne(X`}eIe zSI@5Ms_yFQH5kqJ6}h6QI2{u`D=ZU$5nyj@1_;UO+p{2c@sFBOZ8lv3HjLb}ooQ#}IY;26otTc>lpII0`Q^E4{!vgJ0|3t*{ zpOJYw009hQ9xf6pE+77|3@SnZ7bn+09XS9aJtH$LgNYG2(+sja*!SPIdqWQJ|Zp2~b%=Snr=0*#27#ibm!iGb$Q6 z0qtA>%pb$bA4}TXxqOJu0FJ+9WuUXYtCI=P8Nl_oLded}{$rSl@o!NMXliLBZ0`Zk z`J-UtVgqopGVA@v*8jNub0{MAHug>`4n`(Gz@IZx6j5;i{E7X~x*y$t2mP09{*OY! z$;k81jQ>vBU+xkrMu0zwRsL)2pPhe9{Kr)MV;_H6iL(RP|I0{I!Pp9D^4GwJ(Z3V; z*KYnqsRQ`0eEmtlKY_~v?aW;)0GxlvDsE}>kz@daxXs7;i2_aRO@V*ra(4Ono!P>A zWS;8jRqy_c_c=G1o&@E!^9@h(2lx-NpaGEJun7%`0(~^2;vu@ZHA#`4?=|R3UDaF{ z8%uB#DhW5RhgQ{P&@(E|xz%3YCI#N_AJ5U*i$_}*_4ePhs^5JY z+YO)HM>h`EoA%DHQw!-B-bgkRg+oIsYq`?YD60lkLJ00xIaErSN{>TEZkQ44dMZda-~FM2WD+n%t1-r++? zY|db1)z84QWDNZ8G?&S60>4fiMfx-dHwQyCnYi9y5PlOPtb|5J1jW(I(YO-L>-?(WJ#00vdo~nXRzcFPiqJ+ zH`vI@h{zm|hR8@@E`uM`3Hf<^={yr8@}+d^$! z!cp$-DH&Z|rEmQjih{C+qK5l^+$6b)2g)+f$h%=zsK4m9D9iAQSwn@M6d4R-tu0E> zdk)Rzj66*X$FOqAvx%bQL2jdh98o7;LM-C2B;>x33*3}RD@ADC2o#Vfd#_y6oOHvr z`#EbwhYpFi*pz`_GwH6kV+1>%`FnV!g}E|oDqlh@-cK=31lB3M;!~f>*C8qpjHus%BkQOh zVD`JZftdo`t44eM;lko+`4j1T#|IrCrsVJh{`@bGe3&)vXl@y57 zAMV}w0Fa=$UG^@D9BD3tF8ad1*UN4Pc5d&(RX4pv+|M~|#{FW#29HT7p+^(aPm8D^ zXkH0`191;$391|p{}L$-_1Xi*k1>!92&5A?aT2u%0IB@Fijkm_JxrC8q>?>CHMy6R zvzPSQX@rGqFVSg4g=?=l^Qu1cN>u(a)TxZ+eh3;~T?}3-#%-j+L4jhP-C%oK9f}UH z6dK3(iBV_TxqM57{3aY*Z!*pRaQQg4TWY2mEhda|VU78%QHvA;y>GctK)Iv6ZzZ$& zbGU#oS;+6)5@85$HC?Wt%6N=8b|B)|y=edj0{c?Y=qLWO)Bv$A zDyJ_15zNzjHkJxoF>lP7EsrpKPqZU`QW=<_$Qj%s7|o6R#6%R%&ADt)sCe=qlAV{5 z8~8T$U2N01*T+710mt_~=^7^##TZ_wG>SUO@hJ(&Oy5=LepMqO|6x-#>ZkLP6hYVs z0C{GbY$^%6^iNHP`G6#&saJIcaa}RQf^g4Aiy(r~dN^y3?WfDpVOQ%1f^;Yc}r@PedMJ;c(;=GdEb$upLfE8o7E)y=sAFwcPh`CCAOU@7K}XnN3B3% z%on+z&s{3CMpQvT2`CCGn+rgDnL9WWly!$F4&4L}{5^z0&))I2txxux19kh#jx+3cr<;L+s0Oq40xc~sDDP^t?qwF2eL6yI{Zuph8WsM2zBDrNv0qde8 z?r$^P-=7fNqM%yI5ZscWc;tiDWP=Fux~qs0LR$yq#A|{^SzXGQ9fBhn$KF7M#BY$o zZnPg;{WeUeox$67AX^|ME45g7%d?Qyji^$a49;1zCl(8A2ef2RzIr+qV zr-q1NX+_EeNj}gZjc${Cf$6VaVcs<#hEGpw^wJ?Dqhu0~|vs4w8lrA4HU zn%!}JIJ@R{b8@->M>C&T%tx@M&}hHT?<+8Vx@XCKUnXlJae9@-QVw^K3n3FN!u}W<^!4JyFg+T%K}Ow%2BbrQeXGVJoBWN>gp@ zhRrTPpO@OZLGn`|ereURQs8FN!dx4$)~9J%T4$w96VQ-kaz| z3Ft(W{m}B4MtKi{RQwK+NK%nVN!#GX4>gM3x#&dN%HD1E+}(D-reWi4#Vro-Tsag| zVK5CBa7v@y`8$rXJ>2&80L8VJf-&n~1ctI=nXxBA*+Yz~Obgf8pEB=xj-wI3K70}U zT-+VkU*4f1(&)3%{v|LHjS)-23?v4f!O&roqI&c{^#XHNR7`H>72pM3XUlmpA(uh8{}qDYoo%`lb`^$ zGSMM)MhVi5M#-`aN={Cm4TG5P?0qP&%})`9+W_AtvSV-`fw;WqfM3w^8_-t{xgr`> zNH@Ken3M&d!3KVHWvKME6Wha=6+`H21Q=lMoY%RRci*D>Ut70yN9cUpqD*<9i%idZ z4UxpTNCQJxEu4lIy}w&<0;cIfFZp~6FnvjiVxd#r*DKLi0D9c)%z(X(iw1n)~cZIokF94WYPr-QTE2Ta}=sZT~ zEaf$(tDNx7&{wt(?Ph`p=h`6# zgJwG=y2C=ivXEtywF$86GCpBpZ9?aR=N~tN>Ey?^{$-lpv#6EouA6ufU zHJ%M(oowSPK6r;J+W3wQA{TKk;@sA-7K34v9AAMfaw&)%xr58H$wA`H-3y`G2g!WX zxN6lQXj^Z5rq(0}ZgKzyXY2n;$ISx2j*8!EP)j|sw@3JzULcRSqN9<*Wjw7qz$76T z=ZehXI?TAL6!BF`W~0er8XKN$eyo9QvEQxThE>4|6Z+$6sO1jFcl-&d@fc zO%$pgso2^o*kRXS@8o39oe<0KZpNokRH0UC7{oM7 z7)aIKO=_I|*%B+Rx)(>;{aDg*B8hB)80R<6gcnEC$DOn>B8hZ?7+yd8gBM4#$DKt+ zKm746Qh8f>W=f`7)c&5j<0Nx!;ZUPXeAd`*NEIjtx$^L(gt^#dDF@l|+UD%js}rJ`gQzm0&ocA^zWRGQ<}pgN?VuB(t6ZWZ=7FVyb46LHG=<{h`xm~=vi`mD5>r1Wr_ z`a6V#8r~i)(IZ3hl0AOMb~~yu0>T~*XPtuLL*BL}8C>bZu}6bhr(o|}=}Y~^|I*cT zP}-UbH^V~d=jZB~9QTs~Pq$zcR~jrANpe@DQR4U!-tCvW(SwA)XCe2rA=u466zczR@jGwovhKE4gm#6e9J0TNEe~h zBTzW{YsDcWd+F|Wx#>GpCNhR4GQiIu>G9{;Rf6f!v-0ClMQMi%yu*7*+?*h0eOCl2 z#-f71{zg_m>Z1K>gp)^_ajlj@;1~6YW%#gouW01tnFB;;# zC$)jE=d4PiBreMp@y*gSkBytHJfcAfEURI z7>a~odC5li3a!$MV* z0%aUWYVb?G{C>)hyAkg?=2~YZPnD+8h{;~n_p9Z&7MABN|0gYX$3$gyqN5wm-Yian zyd4{JtkLgRrE{x-bXE7f6SbVNL5#(=sdn?Pn-ANqNUNch0uoq|Bng!ZP**+d>&?hN z8NB_kSPF7lzkzni-%=RKfqERBohI_zF+xaeLy25OG<7qcEer*KNp9;1{=RVl|w7kBi|?jcaYhtwo_ zZg~$rA}L-xRe&S>9w1%r9g&}W6{I^7h0SyG;w4*7I$kP3(oDl`LCC?aVIFeFp`3I% zbmfVJ^JXMYcEmJ~>*O~laoXz}9Z#Gp<`OC1NE4$t#(A$6^ROVOz6PG4IzR*eI!-uR z0v$&l5>rkHyRN;xqh=hbkP|`2zhN|VZN~Ft8Wo$9Dlu`R z)hlkk|KKeFn1ts30`&6sUXTX4wzCr^#?4Ll4qrvn3M45c-;pKJ(xg20yR%N@Ui*m@ z*j(uhZxR7E8|56gmsueBTS2xNr(IG8f1bVyyM^|QkX)XTMe2LWOci1-7 zQ#!|SZ8E6#;s*X}O}JO|TSa10bzl=EkV)H&X}Pf9;#uj%Kf99&cQB!iBC7+ej)F@L|ynHDkTLKS1#xxXClJ? z-6Xl^C1k-$aVxeA)Fa=7DrSamz&*1ir#QqQ@k@6jNJA6SV3~X=elIIl4pEa^*gj-n0#Fp z`~k({+ks8B5R4q7?4_IUt;4#y`{G5qxMl(}w~^pVn{)6Tq}xKC$vbK*wKnB0`SivDA1%q38Q*6vkG?Q4u_ZCKXAw%2Ifb)4RrA&PI}?6lD~fM}Z( z);eNK)Biy=%NT9blMy_|zOw$bE~Wmgv%wPpzwxwwszyD}Dmuw3nlp#YH;c??5$-#U z%=hukBKs(d+{lXD8`$gPm|vTYkjZ(UR9@EJb@Bp|E**}%}abfHXqrvlTS~QPdlaj=df-Au-OW(*{XH7 zjBZ#>=fA5~LYu9gXY4@$N$G*k@oT{GBFsF)$9E8?tm^iv90KSW_GqLr82uZh3jl=nFqmj#W=nX4HC2I+P3AS}5Yjyc9X*m@JHjF&~7QYKEIx213u+1E5`D_(!@~R*J&sQ`h6L_zw@iox%&^L%QYlfs+4x znoOU_wrokB-C|iu<{dd=sXjY%&ZcE05SUF-sy;tixNj#AOmqYpck4b*e7c25AIFRJ zf*3z>aY;9Ltlrk^!{O5 z{zU@(i}(3M82sT7*qK;3|KVYn{xB{75DTh*kwGFxE=D%?=6|>t^AD!wZz|?L*ops( z*!s)k|4H32{mqIn{F}RB`a}MFuq^+OH-9rC4F4;6^OxU0vHt(d-u&6lpD6!>z4gn>}?X4@tt4vXeZ- zb>=L6TVFD2&-Up@9X`^lM9@rk^Q)0^Q@d=}=;!czdzgIf^xNq4yua*xo*d0N=Ra#{ zU2-q>ySsn)b@$9g`k-&_yAeK`9KSW6CBG$~MIX+W`_Z$lnBo(^_m`Ek@guF)+4$J= zw=WMX?{}|n3}FVHzu(_tdx-?-Qa5rgPVC&S*Ip~L1YTYy_Y@YQXV=j6;KO#ZUOfG- zCR;mSjow%C2-frtTRMoIy0exOUf#~OXL{kV@hY3gwt&4q+kTb53V z-nM&Qr!C(dwzuYX&L>;*I-Tk7h@1A{Q+3bj&wV+cAH14PbM#O8*4ADhhp&;$WruH7 zzTD@y+rQV$NWJc?@UxMx`!2UXUOEgmz28*7T4r|eyj~tHtYISxgl=8D`!2uNo(ya$ zJS%km?sC)a__By+9(V0{p*U_Mlo5yR9Q8w_aZ`BH@yht}j*B}f6=QSIQ za%P52KRLh)&5YEA3z=zRtA34Y7XOD;HVVmh%(gF6z9l9yps>u*`~(9g2cfJi24eLgN4RS&rY_pEg~8KM@Ir$FX4;)Fit6mz7z&7stSvq=!HY5v<`K?HARqv9F$t1 z1CaNE%&$8bRCipauAy~f-oATG^Cuq=ZmLd|2#vG<#+pQ)*p&X|ZWB_v4(Q2lmK`p9Z*KS^TN?`k* zA$SgqZG{}azqV+S*%sn;5lxEy&*)|<6rN=4H(Z+p;V1P#S|$kLA3+a2@%5P@aY0H$ z9)oH)=ai;xq#r%80UiqG_5Vp%n-}HIJL>T~E7?Rp`1>jrrvhGVN9LkUtmDj^juwd= z<#v}O7VJq0vZRrKO$cTeA5%E8D>y%$ckEPw0j;`|U_urLc{9MfAwB?V)3+G5z8vIm zlWIx`5_8tpqffkKGWz$AfJ&O&Z3dKM6YRin`Y;$+__IYN@DZNEKI1MBiSDSpm`pE` zuVTZoBXq>jRUy?bTCNpav;cL7_6xB)Q#f2QgJZ|Jmy4*%O$oL@MPC46Fz!S2q(KHVRSRR+`!kyPGwwt7q@jH>vHN7iJ3?jDZ`Fm$g>OIt zJ(s`#efmeBP)oF-6^mf$*6p>>g_(R&^df@dIw}~+;XDcc7nr1s9;U_7VnQc{02te= zJ1a^X8QLxkIp|qPYq3XH8s%uX-T1~~dqzs1&dVPej;4Ag4$zONtopx2h=V7g&6`i{ zA=&$?k=fCWpgn9HGv| zkV!buY-rGI0|*a(lub|KuIq9zUIqvcLI@9El+8y`{{uYOix(|_jU!b7F9c!+IM1%Ajl?LddYtVl(Zrs=wHNl_nl0c=1JU?PQlqpW7ApZ!35+R=1 z?$7o#Ri%!)C5gH%H>$ugst9BJ#b8vS(4)!FquGf&@C9Yy%O{gp)PX0ms9S_y&3EQ& zNm$xl_-&4mg;J9C>Yf;^5{kenoak!|VXGjkK@iP-iAnOvFPc;AXTw|yU5?5vT!G}} ztq?hOl$x@mB$^i19rP0nKz&FZ+QbnXO*}>LKrnC-GplGalToajz{m@%;rUHZD}3q2 zNci!Ew`1NjvzSS_+nP4w7lTejm;{A5Zl8uaL!V$y*^?v5kn!%a`B;H zq122VnePAvgcF^h1TF!YwvoO)qAfQXXpMNynMR+bgsM{tc{@l1_F#Qjz3{vD-pzs<)Rk9_Ou>85~zW6|R@rYue8Xlo{s4 z-wF6FnRaJc7amb@hY!X^*Cl00YUZdY%O|7L9EV4GtEj1mJkI8X{ftx|j^4~UD z1TBBVi}UUk9cSpW-r6m#^^ziq5$>KK3*MbAi}OYmzJmGak&xw}5sd_)&>Yms7Y<|X*PO3-N=(H2bXH1-wmRq5D> z`Bw@qBqLiD;fKnuq^1o>hJ49p4jYENPxgo6f}YCB+-@%x1MQt=4(vMZ_@h)mjTC9W z#|N5YT5E&j>|)}W01xBbr-&a-dl|#;4e_7L)ZAJoM49Co1Nyt$rd6I%lQS*rXW)l@Ykh3)3*9O81X$+ zEe$1h`&kh>4z>Bx6u%vB`atrty7PC3?b~U8G`(ZZq7G+%#Sc@L|GFjhe2nP+8Af&| zg5Y=IHIc5$nQ2`Z2tz#esF?t-Z*O{HLucFBgZC%M1tkd6gdgHpU{vDNgM?1p2up5a z2;vmqa?2$SH9liw*HbnvLSJ-|nr5uhVNep^XLki)%yhp9zrqeIfv9)MdBzGYg;QG+ z$O$G2SB$N~Rj*WkS=0AeBW$zl^jPD+Y-zt}c`aKw4OuwtKDqn4aEeyF!g15m8?nV!-viNU-D6}!zaQE&tQ!XeGe znfP(v1%yt&@n-?h71WYTS%2z=G}`2SX`8|u@69}AC_hvvKW(;$M8*d+>=#R>2NmOs z&qf!;YC!@pK>`8YIha8LoLjYM*O}2QUv>^}*W?BknG74r^*7(bo zh>Cj81GDLJ>e4B-+$Z(nT;1i-tqfeX$PvzbZ_v|7oxP)NkcEqMYj30Oa#cMgX!K%~ zK)`t~wI>mTCy{>}5}YRy>J|T|EB=avd!e{{(4ps=xO-yaa}kj%{-)2yO2<|h)Qe!X zhi2}%JKZh)7c+~p!~^?A=;kn2jd*R-h((PfBebBj95_BQP+vd~aj1-4;*z(212lJQ zMo6H$NuUkmdwWR2g2fO6#SqJBosemrKrp#zX`LiBccjpoNB)*N6kcYuON#v6 z2V9(p)NbM4>njt}3%o=skMcu~@&g$VppEjA#C`{0zt@aBKzBbt8@}}RJcI>bA|c?s zJD9z2sPLB|2wPBvEcOXgvoo9p6Q94=?OByOPlE_$$32$$AV-& zu^LD0Nm^Gh0tJIxZmdM2R_c&wFf^M#PgSdfOHKlhw|;F|O!-^($WIJsWyQu`e@Iwd z$Zb%qjt91m2W*J|tB!}l)E(W_U6;JI0MJSrx8_LPY9j157;5V7QcZl-;5Afy@mjAP z(x?U|2)U)@kJz2DZ@=~f2e)e2&e4_fCwoUZ;;<9xk{;CpS@=Vfbf1J!p9ElgN4Re= zI6O8mJhoia8(q{Jf`p%5)LSLTHOIDqq*PUe-g)8dFqfP8+mnF;jmMsSoAt;Qa~tA{J0M~FS%x~H;O zscX1ZU0x9KC%#>zg&i0fA*IvUP?i`0z|b+g5TsfoBOoyGaT8*PXpJQ0o;l=?x_&h_ zb;x9Y61&D@HImNoZ)M&+m!9epkXZ02iP`XepV8g9tQ;senUv9_rd&JbNg*=WZu6}z zD@eH+)4v2=bNCM9uDTlwL>l_eCfFaUCxUxdg`|obt}*um+2T zaNgs!Bp7?JAfu5Mg_~2AA8HrjPE|8W9)_hcvX?1eN)X3aH7IifAwdHNuaq&O6&Xrw zWmRI)w*_j4&1E~**@?=XN8SG!-EpeiA@XNM@JGE0#KM7dvHIqyP0QJaelL9fA*xC1 zw{1vWFvVQ_P9uyP@0KZ&Z?*nlkj$0nzRNXqv<6oP_Hw3FW_ds`>ad72_^pnKt&B0F z^;2*VE^_67E3}xhHoC#vi#_<*aRY^g(wfNz7pN|Bzr9=A+d(r>%aE{@pCMB-4!TPPZ!b-np3rek86uUDV+P?8F>bjW{8yn5hQbLb#-U5a56oDG;-VbP;k zmxG>YmV0S!P+kwMza70_RS+h3&s0)c`$(CZxruO$+0NV*~H1x;iKC8?-FErBioN+ZzW}+j}MKi zr7h4|9_X%YZ);?y3^aGOG5TX>V`T39Q3n0DgYaLq)O2i2Ec8sAENomX06Jz4c6v@W zHdb~{023!G2R#!z2Nyeli-nV(m4ls)o%y3=nL+9UK(sUwvNQiEdT0EYO32ydPf<5J zGaEhE-$t+>)zyD1>6o}!={cEMnVC30EJchQB!QOZ7A}AJski`b)d8$5^jxfLEKJO7 z|BC7ZF#|Gxto|2@_#eRJKltXKYVN;5HYNZwGv`O7|HuI5Kj7sD^!UGmZeL(LbmqSu z^4*UlV9}+R()}cV)E`c<(MrMcY~1lkr0ai9;EdTJt0P~Lwi%A!BcllTj=Wr#2v#&z zm;56{7%x}lr`->i^{H?2I^P+KR;Iw{X7j3LjVz#Rst*JX^y%FEk51a|JHDOE;A@$` z-k)Zgz$&39OJ#k>j>N?+uV50rCk%?W-g36^b+nbgPxNbtUhXWQ98AR&4lpcPct?w* zer1iCXXx_x*1m?g$qDkk>`{IRHdVevzIo5ekF#Xr#^cP@^9aq)^knqgQQquho|hm9 zed9W;kMB~JJkWgvyXh2BI>Vz1EfwKV#!)pJIK?6KS0wRfaaVEv0R^1;ku)4 zn&fp&b=-$8I2?$?#y{1se2U)Mob5=r5yZ=k=+lrToRN`H^SmGB8x=jH#A>GQ6t)ZR zKvO^|KVB-ciItzm^GkuH{)F-RjH=!gOKdtRA)nbML8F9Z1UAWmxs-k~m*cRh10fAHZQ3rw2}cv&vib{GJ3^Eg7`>=-=wr*i-6vZ7AwT_q3=T#Yw6!Y$v2WzG(A+Rv4P2gL2$wgOm) z=#>tvZ@3aP9z+ZX@WgnQ`M=D&e_R|*y}|~srN)~(K!f$)UT9){j}yHHl)SQ+4|`@T zpwr(lER+LyDOF9T$}Iui$2HbRpY{)i16JVaVVtQjw{3@rUBWlmgHG!9;V|wqiah zLQWnQ%lo$W7~slyUsBSpnj}yEU%S z-1PzLFee662W3#r@fxrC_H5()Qj<$ngNOTy^@~rxE^MLg+x7lAv#j7}7i`3$@E%;1 zl{nlV`f_1zU_?;e9{rWD!_XBxGCSs+#%H71eO`0~ZI3i!D%$1KgM1h_0*27Ehg)_@UO4 z90S%`zG_Kt=^kL{V%Mg^{|VcESw(l)k-1#?3jV#EzlvSJ&xbkU=o;45^_H^7s(959 zR?Z)eo1DZ!2*F=@cPW>`Y*~=QwoPr_etxuGwrFq9C8m7RO7Kdyey!gza}*zVGmF`- zjWm|5Lvr%YY|FHZi##yh@rd_iYX(1xW(1TGns4ZWSjTw{GTppz2&GexYXveEV}bO{OFq7*e3G;LZ6%}j!_ltUBkO_B^`F8ADz4O6h; zb{5*$KquYKW?5j~Kurx;``}%UCMS0&$ios^)wvsELHlbi(2mP>aJpdh_Lh!9CYIqT zd9?cCk?`peh}P8#YdrB8#QD?3FSG@yDuf98cFL7PeaJ1ey^)#yn^G!S4=dqS(jf(E zXI2lz`Hs~(Y4<%rl_0m4_V(6U6}>{SE82qE_#BM|ogYi6CYOS0YOYvv=0L37#%t&n zxGQI}l$q@Gk&c;6{Gh6g9BbyoJtwk6s-#e`@+$)9*Ka=5^a?skOtlvE+Lf=aqb~$O z6j{Q65#1W!%Vo`4-Sd)pHpRk(nS-R6;CFiyK93`*Vh=* zpOCIHdwM{hZmkzd#9~lIMOAJ=uDSdx^G8A~#E7v|Fq;gb!Dr4W0d7QiZg;=@<~Fz7Y^+EQoom>X zDj%d??o>(z?yb8NLB|LD^4#caWtFc>ajy~ms`GyBnpe*&=vQ_HyV~9RJNYw8*IcKC zJ#*>WV6S{NKD%UU6$(Jb5xyOhbXqSiFfZI z)1hwWUnP|z`l>HX#VXYzPcMWW3O4{(b>BC@YiIRdg8EeZBXyAA-J>d#m}QY=19%E| zDFLHBc_zR~am-*=C1jPr^p(%OnLj5wEg(H?x1$7kAf(HNy^(Y3Y5a$PFZ}j zS}MR_##=Zpl`oksONK)UfW#s%rYNUfC?5`@ncu935sSfx&S!1&+*8PV=eX3YLt@{k zye(Xsf7OrN#~xq|5!cj+sSG)@e4;TbO&{m5C@qZLRcersP^M(!kELWp{ zD*4O01T8UoA}*W)25shKu5?@VGlUVFR5}!in6_tnWmS%ag=h%*b8)si=TkZ-P35dk zWn4g5n4Ru%CC$)yoT)jD8drK~b7^ECm`ifO!Uwppw!_C%&isRw$f|Nt$v|KzyTSzv zgUc!lSqOgOZNg2}*v>6;(|}K1F)f)qd0{~}1lhV7wSo0eW>k+YOCAfgEjqXum zbsd9LMv%PYIPyrqcC~SwjfG&~q*=je15i6_&z?v_ibahYT3M3~S1%>oujGrxkb!*z zv8thq7B9ILq%O+B*t@1BJEg1L_mEkOD;c*7=&23N)Lk<(nIinp!zmfb(I=A?rxv}a zv~*0zC^OV3%vdq2k`l5LB+X#Z5@p%3OvQpJ`c_B{AXh)&JRyURiOHJ+knQT@TVTq* z?=FeGNHu0ZLA4qhXtzUj*R!dBWS^w4Ex-Fr2i?i9 zul~|6Q!GoWdTIWQJIFhKIOWRVcO=R&qNFBuuWHpzb+vI+Rw8Jt)^Qf;6zrz@#II4s z0#N0+?J|dYj&Hq6KPPr~)HoPg?r0zX#Dw#WTLcrIjVI`GnyIiB6TM^}Hd$3z1{i4- z>*ss^tvk{xE89Bxl;!Bw?CYr1b1sN(i&4$I3SP7C57*ZaX)l};YAYM7-wr1~P^k{v zu=+F-gj5wG=KIr)Gy(VYRZC;q|=zBpGO=@LlY$RTXBi39$Xvq4ODGOC9 z>oV46#f=u49II21W3z|zJm4`+6Up>8XP8Q@PkFIPomnv-VF{EIR|D>IX>_?=rHcsH zxL@_$%=DSYC{Qv{OHp&n_^YDr+8MY=F9=>vOelG04~A<*RCz())7MPtnGueMtzd9` zmNxU==;f*={M!e!`^Oh`c|XIaWrZ=Q(N=rUQqTryX#$)0%Z3F`PCsrfj5D9nAZ8$x9!}qns&PM~?;wpS)Zi1rnow>fa)cCkebR*T)e&O|EP6cd zp%N5Td|wcjYp=WV+L8Lr3GK?W%FD{>TvD6~y=--WVbg*N0$wMTtzCvy@67MN1=hV~ zG&r8Ru?%!OpGm8(9u@Ke&8xHAwQ!%#I-n2w+6BYpIH^c*KF@yEqHqkyr@M)uq!tAY zOR2rR;D~v7Ye9>t+gJDVVA5787&Sq_jjk`};N{&uX}7t1TOgZUb*p-KO3Zauucx3E*$4kIkt$>t_Cp71 z0LUKO8H>Q!8bAD-wmxm#BkyPpt&hwJ11lY33QQ}`6L;6Bb&4o>77n62U9=An_SW~v zukaxa?%=xAO z0f$lS1v;VGjYHr;#p=+|Oyw*z@z_suDdx=zY@*{kC-o#5t3Zu!*2Ll~!Ps=WEcgYG zo#-a4brI8=K~+PILIk<5zf`!%#+CM3;_IZx_pb#SuLZ_uEo94J!`mn|OpHe#p>Af= zg*{V9M8I|>RYOkk=x!3{xwE8GVCtH!uhq~)v1wKtZDtdHQqV;T69H|M3{BGdXr2=Tr;Au7Y6ltW;--aBi11GmNP z0pkb@=UIY{IS1zt8H<}p)y+@Gos+cu+G)H7$Z5HIE7gVLkim-f{GL|pN!?yX~e~uJXy&QVaF(o>75Y~V~7@~_boim z0AODIC zv-wqzF3oLQySNjr8R*R}?R8RMk0hlD4Z#+nW%0}|X`KmIR+3gpyIXFpN3<;8{S2T% zBoI`4&@ROXT%I%S8RFQ)9ItsXC&s79Tp%LQTWD74u%*MjqKC9|+b4ZG`=A<%N zj4BauTU9US5U1{#Co%2A!^;Nw_~{n^<;o1)9L4k zzM#BJ%9twWz`_|7rVyLks|DrNZDZywV%qMZJZp0JLAs?T>i- zZWp=I)4hpp(r6l7B(Pcp#qy?JBw^g*$GNN9?7sL6^z8fY1qWVN*Ot2LDn7^&IGfEF z9+&v5a$q)a+)k_Zaen&&Cq$TC#W<+Wg;|R_`WaMx24P^^GqXFiMYhGA>Cu8(4ue#Gn*=#Q ztB=S%wI_-4Q!S8&a`zb3OW>Vih)d!0amzb-WqwiF+ry`@ZPh5Wpd|Z*!JJTe@#-ct zGJ$G1x$PSr-`IKf7{iR!LlH_e1rIcp+QdM?%Z4*|Q9o-xdIct?^Gim+wsB?P>i+Ge zW6Q^ts%G>A!f%}1970Q5O|nt1;XE>1-{p4x9sTyvhW%^&PCD+Rf@W(mgWqm^aopCt zhWV*&SnR6TIjO>$tEE9sBi8R@y_yQDiyAPeLE=M3N3II_d&UO-%Cg{3L1Uk*-ln?2 z4}Sw2pWSW|kgKUFmD=>wl~mMtW>&x_rg^kZ>GO!1>@6=(Iv*tQG0^9jywKKvplq?( zwHs}8K%cMHuatliW_1-vZ7S(}4zAKQRN$qK%p38Xp9}Nys_Hlv8_UDc%2l?uNqXs7 zZ+{=_Me_UlPFG{GhQsfDw$32nx925ceTnd{Gp=`D-!gJ5g0WBi1_z>EpSR4Jn<$&&xE&RKMEB`dR%zJOR1r8IH8#3QzQ)Fq%vp|0l$z7+XnfD?s<52pVXHcfxQ%4$pkGyA zXhiDX){3>~xwx!~0@*Vxv#QQ4-^Rm>bh9CeX=!8%$_3Y6PDmdi4cGCDM}B>Ky~$Xp zrG;U9pbPGVWZtJqg2|y^`DA74mDIbU}mn!qT5-$vn7d zr(Z8(n#*l0E|Z%UaBEPF{Q0>?>zV8sXP(a{|0@5ZA7xD*7qlFG#gM(hA9Bqny5T}H zaRPED9U3qgTW$;XExnK>hVpRsC!@Pp4yehYiPA;8c|xlBpdQUrO8-`;B>ohQg6jI> z?2+|%_Ug+Q$DcmwxgH;G*FT@DsuHX{FT4}Mw%69vG%r*9)^F_=eH&>|ca3|W)pr*B zZk2AS^DIq9>&bn|gdzF4ij2Xi4{vM-mW$~)6`O}B!hlhW)%I5hqGMnnI(dmm^7S%C zutC0VA+t}duHiGoN2O~5quC$J0@QPLKEI4#usnajId>73dZCw7k@)>0DiQpLh z4B?b)i{TrjCRndwF=7_C4kMonEnJkp8%lXPNOf=Mk@G3LJ4^X(&sfH+l~u$(SRWnb z&t-MQ47$Y{*YPk)$>+@oTpy6pak#wb#Hiz3k7mW4nBhynrEra3)o9S|v{`%7FrBE; z&zc)oyefBmCM)7{o}>#GvNx0dl$LJT)zU-vhMhF9e%hux?bYKAB5IAk5UgaC1l^F# zdn?Z0f*6PCY}3X*c-HSmvC!+$jna2iQaGJ2%C#_l;HGvzU*^~Kmu+_gxzSm{dOoR` zPQ6KFrwdx2-4Ieg_Q>zlEpXep%d;HR*V6R^lK#y$cH;Ivlj+-v?EQomeq6zxG2Etl z?6YSF0AlO1vp87J=+rvr;QU_fQ|TJB_JZ+?*2Vz+dj>0^svDllo5Km@QxLiJ%EE7T znMZ)!&$NbJ63eT8xkArX*!5gnajvGl!WHtZNX?g{A$&)_*l)5Pm^>|^`=E`P>6$X6 zr|KigX{nK!j%A3X;2>D~&Nl{^)St!&wo5J_V7U&{SM&Oudk1n{l<-K6_Un8fek#;T z3y68G`hzEC@${{osmhDyB>k$g5xU29tuM-%SBYjfV0Zf;H}1Jd(m8y*YH%SmFCH~P zUotP!_KlsXZqbewMwbaYm+@E=%Hl#3-4SFb8Cjb zQpD#%BxWs!7_K!dEi={IJLT06f@|+DY?4~yx&Pd#Uk#`a)I9BF`4afF|7aT$?`dl% z6Y#VtZ{=zFOz4yb4Vc^EXST4}PmM<-9S6{$tr>jcT^At9O#Ly3RX>f&du@(lNX)qn zSy=?s&Lz%Bkh8wSG~Z0^puQR!y!qZW>thnHyT@(Mik^r3U0+1zr1>)n&e`>1#ZdaQX`A`T9thlzj&M* zqtQn96c!%FGrD?26k4v&%xO-LU(dOXBPy-;8qQDRG&&U2q zvN3t}(*TfU`lP{mQJ8XwQ}{65h?Q`}J|SXe_a*exB8F;!o`?R9#qu>Ahw5@_>Ztiv zop8rH(WFO`B%vfhzHu&uL2|7vbqyu@xow^|`CEGZpU~yT_RPiSmF`p0mb`ScpiU~r zR^#b;_v)*IZ0=x>#CpR~nElNwfe#s`hsP_t=7IJ5qcCQ}x;HiJ87iha!{C*@tslap zQhgZ}4}w4?w6mEhlQ_QucqAPJRTA^N13i|BbPGQI`qIT$U)i_7BcRmq(|@gbh7woi z)i`N|<>O}!ZKOnt7OV#=B!#+iIZ8ihN!e0E#_ABi3Jw`8S+ZtZ*yk*%`zwLriefKXPAW}u1{%-uw`ERudRcwNXB!}3 z!@JvicQ5+ihxy#r8k=8s_{f}H6#XNw@}WK#z7~8b_qC$E=fb906U zou+}yBWt|ifc@P*uIA`#(l<*xUy4C>*=q`BX2d6Iu(l@Z9Pg)S1a|V4be@|gpWN7j zwGElR3s|kG@FNS@7KFU%(9nd)di9jXXcvst^#vU`siu>wQ5A%n_i16JPNrb$+38J> zYKsOl6_JYtd{0YwxAtn%)z#)S7ZcvPDwHu^kJNHzFic5Iu?e;H_kQqLA z*ydrk*{Ra^R+l-FADGN9rXF|^wQMr%)8y)Wb2r}i@i`(l^cM)ilS{j*xkYkn)O`MC zWrgN(=SLd4eKjFL&jJJML;ltCQ5H#H?@hUzPKq3%^w<0H&W~_zI79R|;(hP&8YMM9 z31t4J#B@F4S3!CC7hkCh)eoFH(Iw0;o9v6&4?xLau7GtHTUTaY^0~Vmao3}lL86t3 zs$4@nPtLqE?_ZoxJ5RNg)gK==KxZd28wT-kb>K3+Cha&bPG{$9uV}2m_0Cya!a^!c z()aG&ev8EXStfFpgaPwiHh91*jeEpBe2=h82y!+hO5zzK9a%3!vvSR#Hz6E9VZw zy}scwy1aH>;}{&0a$W{mx}jtZ*4F5$(uepzXyum9wb*;XX;DNTz;eeT#9ho&U-~}Y zSehGmzUB7`|EI4CRgOkK$>klk)iN$O?L5bV)331^V4vNX;Et+rJOax%(3&K5C z(&x)wmwD8y4Vb}^8yuncjSh_21@V)ejU~a8T6(puJgmQDR0tht$gxlJHkciXPfBMx zWxf`>Fic~0fNm6(v<#H?H}jqBGIFh$4=hQwq)C6H{Nci15}UCY)yrmG{G;|q{EzKa zm*T^MtPg^{Z$2KZ1e(0jjvD=05LC8n?>yRAl3$%WRdCp? zaG(0%coD1oh<(?muTng6Cv4}#1>yUuefwyCw)Tf>hX_R_KJMrd^`*zgC z+YfuiZE5uu1nM~6(=nYQjd6;I9}i>zvJ+s{e#Mz%-6FDGp*ekAoo{uTo+rq@)WW`{ zHDboSB>)`N<)NJpC5os4!g2&ZXxnOzjN^l-rvApciXaKCvnJK2ChhiD%%^&%)l9Mw zTUWQ-EnI|Nz42$UbI5tadl$IXSbcB}bA@7L{B^=ga+6`Q7pw7}`iR8qH@q4Sw8;lQ z6Kj&IahUnlo|g1z<;sZ>r$e3YWX*pIlw=67rfQyX?xQLGXLbFFdV8dR0SN5r?3Uok`vk90vy4qU9+vlMdN;!Xq){jUwL) z%oAfU6T#E2v6ar?G~oa`tBU29G?KUlqC^(py8&yN?3Lz)H&zE*iI|DW)E&R+1XEH= zSreogWIX3QU7TfXl_l|mTUk-x!io861h~2So)m1c7T(j0pXhXTl7)?5ag<`dBZ(ww zu0&18Qc$zY&>XwZMXIokip5)&L_geOg;33c@wTQFsU~r3V|@D*C!2c7oKLoA;!x9! z*^`Upna!Fr0Ruvj_V9XJT`ucUX11tQjyJ^ewBs&>^%&APJ{j~_YD*WqfeQRr*x-)C z3Tz5medI6S)U|wI5W16Dx#?VaC|Qz#u`+SEGS4kArGVq#6@AJMOeWi;*y+O02k_Ob z%2);588wp2fv9=Jzp0|X@rZdR_$p`2mKF7?5!Wr&iEhRadhSD6b;l%53L|z2o(V1J z8eYtpK-&Pt5o^0&v^EXLMw)Vv8~LOPewKB6Sowon;Yrz&^5(*ng2HV@l9}%tZ19-~ zPUf8Z+}xt(jVrFIEGI#0lg?6vO?jSMkC3)A3z(*_8cKQ*c$=z2r={>I9j@K@3f5%n z_v_iL{a}~Tk*!SOM4{u>u$kL|IUap8ybW(8;G`+%D)=EjgfuR^K_7d< zeoW|PCWalJvUIHomgCQG-6R6h7yYhjWgKG8p-cENd#o?VFybu;`rpTP+{wq^o3AO+ z60Yx6gK=Kxa~>uxIdr^TZXfQOKCk$S+wO<$w`=dP&?n8 z+y%U!m|Nx^ryv%=F--}OWAO=h4I}x%cQ$BuN25RoGb0_Q(s^hWrI*0OSY^gHY$Bat zzOM^vBf6OSMdy>ugXb)(Y`i%b3ru~20$s=1tHo6q0qXmS`nXo=DkfA;ufPgRCmU() z#x9yT*i%B9$vTg%GCKv`mKB-hFqmVSEh>d8j+=6yI+%E9eh57IuB>Yu{%-eqHow91 zSB+e$F%;K461`bCjh2(nw4X%G*K*q0;$-K8O5_iSayU6`ipKJUKEY$M-)rbB@pov_ zB!f9leTxOpe(7Ex+`&v=%d{!J{+h$>*$1~Z;ZZmn!~D7wn+8{kio)a5E=fIiDI$KG zPwuLxSc?^8zrw=9l)4;dDLSz*L^aq3{9dSrPYEYl>;6!;s!WL=f%lG^@^jq6uYW@R zD{%W6gEvb;SJIcVXlmh)s)j1ZGdkz@-W1{D zVF;e(Y5f^f#e^|^bKc@u^qhHwS!-mHU3W^sDx4LbVJfd9x3(}mvm-;a(S?6b(q1LM z1zgC%TgEYK49AS06#T(g0`HmYxhiI)n$aA1r0zDRU^UM^n)mfH&fI%>smQsjRZAQ& zqP79&_BB9amSGCra?Oi<-8%$N*4e(87h2MJ!2B>|o75*0lIAc4bM1y|dYwZ*zP?3p z>KWbA5dAe$?dFgQ?OFn*>4I^3L7z^0w^s>e2St;W0p5bQfE}w$hcC`L+Oqt~6}gWb#STI=4QK3E5&qvifq$S|-jOjLsa@TIwdFyQt z@c|)~mG@PfjvhXOkw41;{;5%Km&$NyrRk0Cn3)HJd~ozQ#E<_TE2LyJXYYywr@xC| zRvx$Jy8KeKMhsd7$RZY~WK%Js#L3&#@DP_^2ra8S+LagRC{+o~0Wfs?A9YWj?>O>Q zQrKG{AG)U6le?`?1N1BFIi3a9S4xzy{uAh)un3NP5XNksvB}$si zd@WR`=qW7`5*ChBV7@=B_ND)Zis58_D}4iDQVg7F-a>-e`W`$-9{SZXY$4TpC@zjz zDRk3afT*gf92<+Iq`WU@LRXR*&sEGp>70PK+X6F%S`)l1f=heObz38;iZKq?@ZORT zjS20h=Yk9Y_5!}2KP$B1vC5>IJpIFuLZ!GByj%s3RA@d=jJRfIZ&iQ8SO_bij>pmz zqq!Z^E$XLJ&B5rz4<%moU+ zIK^{QmNVOB7g&C;Gfxo5=G=WHh*`2$Ud&!s)_FMmUoA9Iei?4C@Urq5FvlvR*LaS0ymL>b+`Fxn}}PZ zO_=jAT0_#>$-Q1al1q!oZ1{N8P* z_pP{%xu&wKULMCMXG_UKHQjQu(H4goLnL0caE~u@ZyQ?RDNM66*P!5Koc$RLuOYb! zF+!t8tl2g?N_be!g7ic@1fzMJ2&dfdx3>J@s zycYI?aZ+)UG~u{kF*87gS}KR{b;zqlY}^yevCCke__Y{U`8r%CH(!Z}G`N+m-B#qQVUPH+v zX@srcG>V7Ry_7-fA$|U)|1KwvjN`W)VnoJ?y#Du?k+y%!A^E@KkpzpQA_LDouC8lx)T-wH62i2(2azbdb?Ga{vtRrNnrQBdvoCJieKXAfl6 zz7I4JMd9uvws`2f7&zM@p8_DN7U=%94dYKh85E8Tp|GZ%)qNnL2_YK&MHIag17Qm0 z;)z83M}6l2RVff34p34-OvlyL^HT6o>$b0f-KW5s2yQ%JStQ?`UW2Vr23!7lkh&0T9dA z5a8>>{-1yrcDBL>&R_Qs=44`EVq^d?02o%H4H0%Fz_^bP?b~Led{orPr1L-S`;Xs$>L_GqZRe^}xEM+1+)A^&@w|8W;nG9dU{i+`s1UyJn>_^(v- zYbO7wMA-<~{!64TXJ~0+^v}ST=)c$epXvO~Qj6ffmiX@y{3mf~6I(N9a{`Wk`!*+q&wI68wdQ<1?kwFNad$K9+`TK4bCJdVQq(f?ec*Yx<68l?uIR(o{q>K_ zU9lCDyYTMa_Wh`5Z{kWjKMzBkzVDUTtkip+K1TjI!8NJX9SYNVFpd3c*o-=?D2C=E z(HL|=7u4tC{gJ7nUAmj>_HEmQ@qJuF!Qc0jqJLvKUF{fROR`!$Df$Ug2L#Gps(B>CfC-YBHd6gQ!P*( zIk`&YIakzb-)h13l(#S71eMK7V4;QPn2mX@$QQkbAX6VAX#(V{8d=_eq1lKNt;OgN z-E?ehJeQV6OXr}t(CJ=_eB|BaKgM!lbJ%c%VvteDYzJf~*6+9rQ!S>_EzaGhW*drL zNVV@OJT8mh{XIC}S+B0(x$yKR)&~v|r{=jkt~)X4AIFOy`FOQE=3%&QEXgx? zKRlm*zdOsNO*Xb~5Q8@edia0f>{8158ps^5AH-u*}GR|wj( zeWJH|Jc8BjEO_}k4NZyRU;;s(MBEN4X`e*=PN9T7GzkC-ITJg6=UzIHg#yWf*2uiU(23{= z58CV+v0E*aWphj#kae>PBm5-w${eFA%<$7S*`&XKm2~WH%3&UcB6P*Mu04L^OF6#M}z#BBhmM_+)q5d482UVqbt{mi)uZj78C?#GK8+|1Ecu5U%;_KxoEpy@< zhDx>SG8FWT}z7cNtclq#>=)kXooA zy+%{4kDkB~A(1wO${Hb&K2$hq2yMy;)sTvvKIF_6A=CKt24}}*5HAzV+qY|=C0d(e zuXmt1HcPnE#z5R3mv5`cq&YJXm;xF!HV9aJ00>nd2$=zh64O7Q0Z0PVp9Pj5_!|K* zsJsxSf3b7nM*21@jm5-%RCfy@UQH!$xTX(D74MuXK6ph;(4yGbX+i0t*xV_x&4WVi zi@3Va!pteLU)spF9CrXKM{Op3rDvWRlDXUH%&?$_rZ5lTNbh;{j`)+ zdr-*EfS%GoX?bG-XHSb@dH34 zQ-vM2GWf*cN*y0sZNY)20O-luAX9ZAW}I9s^ch%c^PdGXuu|qfSy={v(+z+p?S;&L zPUnG=*%1==vW!G2@@Le!GQvL$v=%kJ5Fq5cnVwm>40Jo~X{i~KBEOlNPOqkVpD?zR zBMs-VKFZlI?2oEMy4JMxBPW(z&%Fg!`hoNCrf=b zf@8>2p-F)zAdF+t#=Nw(AVE8Ns_K{B{lFP|*Vy~0bnt_3<%8MCLA#t**vKKhoW_1U z_J3{YeQzVYoSrv%n_784UywuY{Q=f&y|e`hYi@T(sngl<1`nSjGkRA+oB}P)55hH= z9`=6uQpsW&XR_5nsUyF|lGSj_eSOEBI%v)oVO3~b^LvIw?d;yFI=hF})lhjc3)6_c zJA`?q{L%cfy5>yYNT&_F4u1Mad(sGf8=25hSZeX1Gz$Sax#?D-N}Ec*RpBYLY;VQ1 za#m)IsP4iYgoko|2sw`&4rI@~lU7~A!h?UfqEMx!YrOY*5wU5VGjH|x#d86AH+Fdc zpU^sLy#g$kFCLnhx*=!J)?8iceD8#i!FrViykKQB5f9GZmxJTBtM?xxA!j#3u9}_g z+p6Qm#|1JiPxrge6uNjO^Js829|UkbdMusxrtk-&9BAIP;|5(ri74$6Vdxn`?oUV5 zGoO}C!60q%E5j2v?7ee>e=tmK4Bm@jPin-;G9;u10-B*}ix`cWq4g8RTZSauUNGK@ z!N&18f7OT34c9}EtN+zNTL}cD>Rgj~P&VoKYMGow%!?A$@44Fss#Lt-P-Pbfs=ERsCimkR&!!(KfO$-FDOa#k{fn&&uT4N&V;vM_0y<-n zSxo&D2+m5xpRA(7B}H6GRre?V_=o&7J~%VYEKM|6Cc(in5{(c7XS%hlKL@bX>iJ*w$r zSisLHug5{?y{gB1&`|JNQB+kkjMxoXR-JMOe+NNa&alCX@gy^jBM|r76RNNh4f-;5 zb^kHbL0uZbc^*9>L>_vglPgGeE^;3lgM2Qc7cQz7Zo#=r;r%J6O(LSWq{%7+Xp zq(K>Kj>h4{P;fg#eI-U3lwk0ZV}1uoFMO?4#ryY35n@JrDq;pF;UIj9U?^@5*G;_^ z8*Wf)3^XHsaO$$)1O(wxFyh@s(8_|1ZYWy7qXQp-SbdE?1xbh(w0>fyT+w^uwo-N0&BUxg-C(tY*nK5HInL%vCl?@5(?O1z!9o;2S z=L3J`{$1|nGiI5(#X4`4ECU6JxQP#4QV)b=GRtyXnfldHKKfc?~oPI z3N6YU8J0Tcs&i%!ExLDfvm;A(yp>Jg&Ne)1xe9*n>Pb9$-2L}9yz{!%8GOq&rT@DP z?_U4C4cCrZdbIQHyV`=^ppgz9X%J*X=VYerW=u1@DnN-+4 zKFGbuy72ZPPlPJ<=MH-sRyzh6VP!hF#?MaD4WF2jV{Yy$GPLhIk?XpS7so`}x-yEg zy9LhT(t#In@!}7S7g)D56=X~|sk2U*`>=?DFI1>Ph*Tn_;~F@}_N_tny>gbsL;sPh zd3+-Ugp?1S8P>vA>j=KzRG~LY0Ie|<{(f1R1G}#lE*!Ek?053Fz#K{5m+JZ6OJ<-} z9a2p@n`BRjItQx$8yII1RQ(jV@&O3m69|UKKMAi_fyciPk6#lZHy5II2DCK~?^>~8 zZGl}pAhY&JgNXAo&hbva2H}rpd{^@5Iim_iq*DI=c@OYZ6m z;>rub%1iFb3!=$cm+@Jb>6wrI*$@3QA)#j9YP&4N`%d17ve3R|QzMMg4RK6f*wS$z z2&X_0ri};E%2SZ@!jg=-1c|x?$}w58U$SJAvcHS zTxr<#3BQRn8`DZzPQ+wGIjH0zcnmPUyJnn%^wjT4lZs4mFEgc4Cb>}{pjU5MaV4TvtRmZ zJ%O6-B4mDl0X55+dOB}M2mE3h(Uu*BWK*vo)EXGJKNpAESulh@qh7%@VmD%dYHfp( z9~SdMr|6R>>e$T-r+!hd2~RQT)qSS)S&;i(lrv|=SA^gzN&lAk|1fpu<;>~*QL+`e zlLq)H*}+loz?=tx$wC271a%r|>i`OJB{BwULCnJUkQtzAZ-|eDql+Y`BoZn?`MB{R z?8~xkS1W&@h%0iO>3=;$8W4XUqO;tGcE<yAIg+KKo_udtnbyp=f{m$AP z|Csh$M4d)Uc~|nW9cI8AHu++~KCfLHuEbS=y`fTGD+!j2+T)SSL%MP$m0oHRMV5*; zPuWn7u{uJps4_3{6+|KL9@Z+`febd{(GDt>!bgYjl#>0#e{HBekOZK>W8e+6d8p(= z?$R8iUUpNu>ngawuVFkNfUii?HezQwQa=oK7oDfi)1q#o?nsId~U9IsAt|AfJ&(4EAs;tUoaPMM!x8gYS=XpzhPh@WMlWPm zkc9N8+3IMWtV;cUd>8AYOT!)3ohTPuVr+nvs==xIZEk=;*sorMGvEUp_MvvAr*e^> z9By=6cBfk=#tVZWR4)2S+G`);aac?GJC@F_AUK{y)uipE%uXm)jDW4!lOc`k z${j!`tCkhcq%ew?GJj||M%xVMI$n|b*fBvS#bBzb~2F`7PV%#R8d4nNOO3)bbPVd07PMw$~88qXPv{&?>=GvX+(1OrdIsOFel z7ULidRnkU0iLaMmzs90xB7*S|8hD8>((yvPdv^$v%0I^5-c~(T>oKKaA2Xuv?~V!@ z#%}o?LW@zqby%kn|6FV-doWYKn|M8Q28M}YmliqDT$kCk2zDU<_@b$~ls!xXN>qat z-5A*KqRki_!-Q>Kw;ZxK}F&8Wa$uY4pST zsP%BM@GKYK?Ssd4J$P-FMVd1NvNpznUjM*@^>h!(Y-k`eEJVI`@o_q z=HJNSAtVO{yQ<46qT-m+fi2J>u4Kw`eRT`?OErV8oHZ)TaBjR6Rx9V)J#j>xralJC zfwG%x=_7~kuo0Lw(^N67k5cM3GWGn-sny{6D^*K`))k`o{$fdnFa<$QHPL-h2$ZAt zhsnJ?>}Ttxj*a3!7t>==dbYZ|7oVtcs{&i3qt180+FH8J?fTU%4+yrACR%)-RF0gf zANZJ5>G%}RO92<3>porOgc^&M3WfLOTMrhGzkh$CNrssHC9(e|e*fmef9c>~V93hA z!TKLg%lMbW{)-|K&@2A~i~o{IVG}1KM+^Hej{PrEDQjT!g^?9x1ioI>$`&>zPO>I$ zigq>zwu&ZZF4hKrW!45}PG7Y2Uk-x*FjrbuMrJxj05dBGGXX6VI~yHguU~Be;(;2=(2{;-3rN3-UtaKdz5JkH_Bi2rv^1CvBxwYSZ&d?n zBp4)e#pL$~f;$6Zh8?g5ftrC8k3?i1W_Bg}0|;}Ivu3Z`XLUv9a%I{tyoqP2m{&6^ z`_AsVUwk=k*b;r#*;=QUZuXt-eY#Bz#{K-y;p^7x+SQ$YUc<+$>r@|VJ_S_>rxYV9 zE2n~vS>zQT6ft}6@k#&O%NuzSpM&6Q3+iF34I?tN*b9Uz#h3^BFgAt(zk~QI*nLir z@9Li8Ez`^67{R?>K812CY7PwU3iN>Ha*tu^c;2{bslX|wNZT}jPE>F*vFGC{MxGyr zh=*MsW-;)lphOwY?<_@pehQ54wAWG(&4@x4TBAZ_%1Low36GX;AsseQdBoM$7RT^Cmds)tU&8P^gB*B~+O*3Q5b9PQfHaw%nkE@%v!W9}3f7dx@2e5TD7|^8p@WfWgRnRoFt} zhQ;qNc6L3IuKpx~x5X>A1uP;$UgKaDV+MB{YK|jy}a6r(jtN zSII7)-5oAB-?LdaITK<+WoCAj8VAiaO`B|w{pl1a52+nKtRTM(gfpspq1JfK+E!Pc z+t0(ix~(m5_o>c`p39!Vl-K>`HstvjuN@>W>_*Gh_h3V8oK-|qsQUozbD!pCJlxbyBF*Bh~(;7OX8-_6bj+R6F389q;)qp9re*fQSn z_JN+)E#>{OoBNlN&yEBtAnOoRJuqSLl*CtsC z7HhCNB4$-VzJL;fo~wgoO`O4RAh>Td@nqZ-he%Y5b9Fua5PIUYYqZzu(`NWfP`D> zjO~k?NHZ|IXRBjlW9;UWSAtD$e2!yGJ?DbD;+(o7y@x5WBwv>yCB*rtm4^G{Cj;NM zau$P{y>^pFT-wRZS)(JEqvf{%veL%thW1X36Q3(th+G5J4kDOb~WHeEnmmp)#mVE9MxKg$*!XK{^+fWKB}Eume%MY78Gy9l+saPn$OeC=}qNY3i6aQ-7XtZY|6qT`!(NCrK(f zVAK<)G!*4mH)Eio#W34=Z%r0u3g#UVVZ@_TPq?^}&4#Ha=oayB98JfYm=x#h-V5p} zAVsM_;BUz*?M zrGtW3TiQL?OC?;&tEt(w)HExHptg}IG56$JG@jm)6xZ*jr?26qPfb$Oo$et#qGKFN zRZexcp9+}yb}MX;Pq$#gL4(JSCs7&I$vi~=_&5hZ5Dt;lE%TPNlcek76_n)?NF;4@&p<9YSm=ON>5GTD~;ixnui6g zvl>rnwAKNO3z3pz2veOq_OQ+NY?^kptM{HPY@XweenJib%JC^BipN$NM`q>W5wlIv zzSI#oXx+UgPL@VmXS09Gb)uq(&wpFmS(FuQ*)U*7UFKcVDcf4OXb<;z*0++ds}-A9 zcAyh3dBRy*ef{#w#bDVN7SrA-*i z?{$l#<}D+}+-^c<5yr=09B+*gaY#I%Bg#GY(;jqi)dQy-6MzY`pb4dZWowvH zJ?fE)`Z~V5EbBb(J%Om1=@`St!T=g8?%v3InjTJCN+M>fT5PR1Jn`~~B3sOTS!KGg_6;h`@&IK5s~0!-k3xjL z5Fm6hVTDlGlvp8oQ`S9XkZL^o=sMwoF-pepWNBB0lDBpa>zuI+*brhAaNvxa{(SJO z3xktZRMD*6vZ3_LF$nz=oYPY2hAr+lx zNl7`h%L44ZstQqKh3C#)k|(hs9CM7ft1+ZUMa?JUZSsTjl?GpJ4;rCpdI9^9pvDTW zY_uFfRaL8cfkL?nvL>0@(n}!B>vWXz;whYV$D9AEeyuu>ttZeTJKZ+-++{_~Cd*d$ zjiF0$#6u!m3(ISlXO{3cO)H41P4Xmpv{n!a5mXw8*evriHXOPZ6KKYsh&_Lx+gTl2 zo6Q_Zv6-+ZBPmeFQ6x{L;Js~a!FGnW+mD@Ov21f?u`pLPSS@!5JE5Xu5S0#-`SH=lLfwdZtW&_z^^x=A|6u|m`(X*+uK!2>7YGvXgGD3$+xVd zW;9D!IL3Oq{_G)BF$*a$XMLd)p6?wzJ2NiUm?a8Y%8)dR*QwtC$3FDzB_g44TnRe_sg5Ihr-ID~Ddf!j$7O;ii_`-ibk0Q#4+KK zTloEqq@uAsk+6u0Vzn7sa-x%jB)8mN%StO}+Kj6As1V{bzg@L}FeN~;v9Ym!Olv*r z*2&?JWqZ`}?hcW$TrlM}M)B7X=(sgyVh63;Eqzpa)N{U0*^9y|`G)Neyg3hiJ_=Rw z^o{&{q!+)UelYu6BFH~y@p=lRxi^kE1Op3u7I>m|S4K|J( z&F1vo=`SF3xklV;*|EP*MSHXEoZqcYJm-2G-13>ti&ar8t<{Wpc`b3{z%89~TI48! z$@}Pbm&sA9nu?=Nh5E>;DJ$DOhu6~xt~l#`MhW1TpkpE!5o>>g6aa3ln7epnUx=D~ z{B}=OS`VAL=UZFrNGY=zVHQy=-51@pNlv!HN$4CdMxhA9KeP0DegB$LH9WX1;r!?P<)Agb6D;rE9pmfey3s1ar@o(Ic&?z2e-cdd4#O@?B2u!lqQL zW21?bEJ0I6t$@}aa8dOk+mSO^sFwDfKz1cKUAENELBDh~91Rg?@Kh$Enyy|5XU^x5 z%adeW4Z}UITyy~ahF;~GkAA^&@{}qRs+8Z#l=_+M{;nNaq*{>**pcKkzIu}F<*doG zOEViZRfZtN3h0h5kfTZ@FH#&W!7$@ zB1E2zdjP=qYeUhlb9vVmGsuhZi(p>;!|kb7(*+_%S0rdxsi=W~pUq~WB8k(w@+^15 z7x6oaW!w_Y^ZmdGgM2|W3capUSgr9sBSlE0wS3((L(d3408Ujwrx*03fic1Hmw;f7 z1p80xtAt-ghSn%>DBtP3OwMlI9&*w$`Ec6`T8b;7508^jA8v_<*Xjd1xjmvam8^~9 z2*niCxZHC&LWi})cx;n>ZFarJvn5g6&)5Cje30`5i>!=t`a+FBtEO48O)(Ggx`2sb z6)SJ~pi|fYwXFDW{VhkYu;43nyBK$f!rk!JDKb%p&&@KILBXPm$joW}w_BxZ?=73p zj)inPGkf|nI_r1SSM*f}u(aN=#@fwkH53bvH_Ta;Y;sU4;a{gZmC{dwBjriUI0(kos@Mdd>267ZL(vsGsrTw!KsN>8lq z$Uqy%A15ALKXgC9PCj%>-AsY37=LM#%J&2uPED|--a;J`E;&o$@D$QJ1nyM*dK{6ZEX!$&4IqoVAMTh#YDhy zzt8sZlF`hKE21d-HpTM(6s;(n)s8}pVJb|LmO)@UB0k{t=VTVET_n!RL0NU~IZ5SE zHMWyzWbazp_9M@6#*{z94}23k2BKYv?FZ5F`5-k2#Qd=Fv8IA*;X2tArT?-`h`W-T3uB61O38h{Zk0%?B4y5_>)^X7Cs zpjvROv1>WUnORaeeQYqc(lCn*UYrZp(wd$}Iwj?*P&j|RhpXisSHx5t%)~w)x(`TWhSXUEsH&!*RH%HXdQ`$V310l;byu&>X zHz0y$)dyFf+D~H*P6)i6tSxHw}C;+DntMiMiKNBsTED+x}R@5qWB86q|+;|)|M%ASmx99c73tKrV-Ws7IT6ftnz^HkjgJ{r_BTg{p{B_N`a z${g4u?eHXJTC-HCmk4{!vcFX{^suwD7urIcDw-MW?UrdBDKm!33faOd+kNzL^;^i8 z0Moxr{Sb?O>X_Ns$WePf)vBN#lZ1cxL!fMFWrJUNS>kr%Mmh=LdXYzzPd5kSl<@-p~$6DD=u)h`52KlKI}V*zS` zA%Jh*M5vfLVm;@06;n8GQcC*cV@>nY7mc$ve=X87Kg3PFS5@tfZd?0~a~aPUr&S>U!xHa2yw60y!#uuS{JrAbrhlz^GSP~kh#M_ ztFLvK$7DGRDGXw*z0iQnNXgE$g~n2fals>{WqZO7#^E0JGwhzjU7$(hk6ZofMcNM9 zM2dm<&YM`Dy?u>8F0}3R({0yulog*RF~*&o6tXqVP6YLC9GYa^Vn4Y3RzZ`JkfX;_ ztY8{Bf2_r%KbK&$$Xi*!SZE)l;!HU-2ASI3DEDcI=QF3CXT4RF)_#*^)ofxThj5;z zfNQQFSdofo){QfO8RP)Cc$kX)wyYpLOP-92rh`jq_e$W=v1v*+$9=;Xe_DQ8*7#sk z>uyf065C#0P7lwr`zW1IG*>o{{3gTU8TODCS-t!@l&AdrJSyJIzU$~v);5v(G-{jK zE@x()1)RTFKyNI2WkU#oCerI1TSNe!ZXfn%{psKl_dEYa!LsF{Bz!9*KU~}Q)=~0R z-9P@EHAr2Mi z8+nQLU|8Dz=G$0-M0}~}V!a%%xy0GvX+l2{1M;q{_<&p@anGj#Vk#}7ust4^JM~1( zb8g&Zi#g%DM(bxr^hlhg;&`=X`SAh56J5M%R1{pA3e(QMO_tE9M6~YC_AWXQt%7RN zv?0oVM|-Q@cr$*lyxDQ3KSr>?CU%+a!` zOlwsS)I9DAd)Y+LL2jg7kLnb_F?ZIzD61!pQsU=27p` z{%|&dMR4E;ISME!VrqaZjxR#M`_Zm>@V#r4&HyVxY~?q`5WG&GJDYZsOIKeU9-rh- zvQrHcDt2EP{LM~;`v5(d5q&d`FY40vjcO7sQ?mgc`Fa2fA$?+{TZaC$^@VDIoxx3? zzlA(O+uKhEpwX%rXb zk@zKG-A+dakd=|s>iwupGIzO!+j$v{LJdg;6AI^vSSwKvozxYwK#y;aU&w46twZ8# zpPvR8>NgSfw}QGqhaI;KmS+WDt-^$^TEl{nM}C01bn@^as1l` zI?Ga#+Arg^Ava(0#qL+lYp0wuQG{Ek(f*#ufXuQ*L6(v?G3^l zgdmk(3zjF7@u|gTH7|vfoX@)X(<^98RL8V&7 zCp+ds7r*2{E*uEy3MF&Vw+q56k+QhUn7sbt*P5$XwJVVB=W!ru@5mygAVGDYimFu0eH1jJ2{8yrW2=OXwtjSmGp@a7&oRT##22rWjoLrY-FXcC3x5cx2%c&hZ z+6tl{)g=2dWfiT7Yo|kZ2w+?HTmmoefs6;oX|OzRNKrMIdfT$+r`I+3yn)pKr`hAO z#^vSA1Xt9_;}pl^RtRV*R_R~ z?*YBAvs*rTzUEhnaU0lzuKJPE-%U{K!S=w68rTH_lEz@#JTlOnIX++CNsj`Filrs_ zx}V)fy;e-;sqZ|p3qFAlDJ3gBKf=}<2Uf={c%>zFwV#&fdcd9;6T`|2+shnwjr(j~ zVc>62DOybMu_TfOf0qo{P)F^JExeW;G(|ZXO{7Idq&)tCg~LCyvujC7N^)^^W!Cl5 z$V;Es+^|L~ZH{m2oZq%+Ap~1(?kE6NUFG6zk1bg^Z1&7-9vf5qMSayt#+rZqw)l9y zd2A0KgTukZcI5no{k_NA#7!scn+gP;d*OD+vkAZ-HU_8D&vEV$bBo8z-Fa}gwCtkO z-A|3R{Osj?pi4LQ)VGxLqF?WvfP-8PKV?u*iH3iuglbo~(CFOfjn>Q8ZQlf5&B}|R z9kr%n9;05gYH4#G;c%D#Gsy{|htA_D8e-g*^Zj`yJ1m(^3%8u&F&)|kk|?^#)0zc~ z&$F?QQtZ>8I)p%ZoS1}*-;^PoJXIQG9A{VF=%p?$2wYm(+=kcjz0pCXLJQeSZW` zi$}7C^z~8f==*nwKz5(k74f`iWIO$K0j4Lk>CtnF?t8StHS|wIL3>PzG}d;;%<_8k z<;sCP)w0{DpGx!W&5iu^sj)YDhu%k}@^TL1YUa%}cGhs|FiwsS!EkVx)XzBFtal4Y zF0c64_{5iQA#^!$1ib)C$&zzN2HE1QCTYyl$>hXIb?dx5#b(Eg}i*lUf2efymti%h5T}xbFK_4zq@P{j0=6 z62|JTe(BNno$)Tc^swA z+>NTY_}d!g#d79y{8HRg-3OIZ3}|fV>Yq6y(AkT%=_4%kR+JZse=KpU&K5T-UkPW` z{lf)?ky&4|{i^O;D7;62KTiyq`eTz+=LT%j6=x?6GxGk-`xt7)H;GE7op=p4N7m2A zMA&e+#QQ2(AIq}>a$;TS9vDr9t*KRzkDgI&#LGMstcfM7-pT7^lpHTU(br)QXS=DJ zNj0nr69tbE*O?>>?!s(17K_i&);SU-?qKS&q#jOqiJFrfH6MBWVOa@w6jA+h8jEJ= zC_bPp#z&v%CA4IR{iN173cCc>+W1SGgbAC$v7l`PehO;E=FKD2Erc(MM9q}1Hkqx^A47X|=n?^!{h@UJvoybxv(a`vS{PS{vuw~woewl=2 zTzKyz16qmUwM5`&b!;5o32APWUx+@pq^i5YupDh40?Y??5xTx#ye4TEq_>#e^)RPQu$UGzM6!ss;0 zWC}axVUa&WNt*8{dcz_z>%qpcC#H~m9qjP*a{{}dnCib(^b0%EM3&qmfu+|v=Ns!q zjy6Y~$Hbx`Sz_56N`(BfQ!S)uN+#W}UHiC@zHiNKu$MwMUdgjUD^Rb^5i66_Sz zI}WJSA&Vb;(E-v-f!yS}D0<*qnY>(?7R+LnK9T87Pn6bP;3W!KWT}$j$5^ua)(*r4 z>Jga^B%bg|=qo@?NMvL^Yd|C*J?@ZS_00F{`&I{&(Q23R1*Q6T(5bqM=>a+A#vfEq z(umI^{A5Tgq&qT*l8nmMv#+Bsg{5_bf_AAVm|AAEiy*%8Zcq}2TpFO9s-Y^7e;DO* z$-=tiP%@0ez?Q<`pxF|nUj-~#rD_|%e1op>2or;UwWH1IaSJyy2ATz56P#zEs|MneD*`m%un?o4DqtS^uQ3JR_ zx${_Xb8&&78$!r9Quq_rbyzMtAfBx);t@vE@~%Kln16Q6ffG#C~Gg*71{`!=?e;t=c?DF8)S zgu_dsTWSb#VgPxU4h6Vbt0}~sOnA*;7Je%O*wr&I!B}v@j5>3!{8wbk4nTI#JII_B z%t&1jrk03Rjkce=p17h__-ax(VzF^hap7(I;NsIb+jx>oAGS!pHo1`%{|BRh9A!mV z?2DnqL=D#2NA5;W{n+F5r@E7o#k9uc7=K_lICW@fD|#sHh;Ww|h*iXc` zp4{U^To~6TB2x}vA)H)j4?uErB4SdRpX+eLCq%or6os(+h+{-}9WTwxDGt9Lx(`VL zutxlBvT%k&vAMV3rXt|Xrox|py_yCqSRz?t4c%;Od>^8hc$QuAPm!t~XS;{1a7*I3 z+odj1l87_JHf1~0qQ$TkQyN8)5JK3aL!b%oW{j~0WVBY`PgP(|vH@u2X=F_z!(vUT zGbXNNNX|-h)^5p8V@esJv6`0kIX~U{dCa!twmfw*ivPc|spJATTCZO6pBf`Ig z>nR`;wlU2_=|=R2v{f&~efhc3iTqOSW5?X9*7MyV35F#G+wMJtOWzeW$cS^4$;L-1 zxQeZ}n(>J8(`uFUir7eU!4TRbVlw?)1x1C6!^7Kz z**2=R4cvJ|$p*I+gGBIQpua{YK-HhnjZ-tgmHNoRHu!c1InNHphgJP1{0%fHJ@UVP#bckVP;D6UsEO0UxLPlUhKDC+Itk3e68)bA*8sKH3h4TdiCZ zZkRRKRhhWw3910To~MowaofauFq`|>Es|NZ?1#{H9CGjTK~51GMt;?2s1XzknBT-p z)bcs?vcMze=%gULmFw1;imH>o{xOj9ig#WjGCgW^>ZiU$DALQq*mti2e|RUB78ls+ z5+aaX0eBJQ%W6c{a@=*uazXL4?i1rLDak80C;f(wNw_hUqR8aL2J{um@WQ4jaZ2YW zk|b9XHcCXLpxU9*5DtOx3&9uMM)yA1gIGi)3_nCn>Rz4 zT(#)BL#bpK1r_ItY?;sQffvzJbRx%sQk9`dOM}3a9oTwO6CyiSydG4Ep|w_Z_9T5| zjQD*Lt`wXYVO64QD~sYmQ8d${{k!6+I>@4{_Qo!BNIHG6$T+*=OsG1V53-^u#1-d| z`dBgaA%^>L!A(W-M5HN8xbu~OY0i)Wr!YYAU=w}3`jC7^Co8KlMH#Bu3~AT7vv-sZd{u)LK^n;tFrI0GgDV{p6e%$t z8;*_+aF_dvJk3NkNj?J?#MggyW~e%lC1}JFB!JjEWDj!U9g)fSHNupQ@Qki^?DC6P zIH<$i-EHW88`Qb<=^|_;2qH$+m7o_mMQ9{uffUZJY|Lq5W*COQxLaFfxrpinHa8@L z1|j6DGQiVJ3LCSg0ks8mGDBYfVX0&z0yaafB_SSH=Ln7)eRq8w3(o z@LE}&p_;*tDZ(Wv0y{QjYMay4!430}6NwR1Bic0|{VqqNysyhz$xYNA4znONVTgwE zvrl`ih5j(XkGdMOpV~Kk$eRY9+hA5$Ry4U+FRZo2ix2&f?Ng0vq}EY23>0{qAQ19g zQ#^>D$pC>X2T1SRS(+9sDZ0NIjZrL`IcjsmjmGsZCc0$kU`}Gz`*B+@Sg@+vzSAsX zbBw*Wtqm3nGIGDLGZe}GAYzNdxNIo!NeP{x0ssW4AP|qPEt&^ShHh_{#_2Bf=x3Rn z482I7Ecgbdsvu;ae*ggKXl8(JWMJ0g4VMr^Lj&}uDn{4<$jK_}d1r;Yd?WHsEjFfJ z6u&eCr22AxBArC}&b7ayJ+{JJP^ePG%^|`LQb(UA(YHZiNPl}A5Z1gybz{0TrrJo{ zA2%TdgEyMsC*y>oH~Y?<)`~5)|Z- z05v-&_#{B*cA&tnhK+WPV|;k}KTytBo=&>;?Q&CGp2%~ru4|S0eg({SCD2r2KE_DP zHWc_&`WdI=!babFuJnG?-SiHEadA$43mN$t2#g66eGhwa0T+GWuvu$oj5?=+$c^ML z8(oi?2T6sQ+S~gRbe{)w=D`gjBrswA|5S4AF>O_096G?|21oP{b-2OV76hk+`@XkX zp@SAinFGT^medUjEu;}za$AzI)qo}jqXZ+4m_;VpA2X3Gf%uqFGBQPnE|I^?*i7a$ z3fTgGkimG&$^6daQra#t-sJN2eCKSxJ7`eqb(pIDKVd_ucnC zZ$33ORhDb%nRxngf6AfzSCS7m>b!U-^#Xq-ZKb&P>@$lQk3Uhnap~Yc`nl28aN9}S zbvyslj=mlD(i+DOB%NL#@3mO=H;%Oan7wOd?9zs(ySry0Gd1r|@0s$OzZ~pIPcE`Q zn2~nw+Wl?Ya$o;T{f?P!ul84c@>OMOt|jZ5J!|N)<<7I&sf$O4#+pwjz47|KEjD;RpeDx*6lGq{^A#%2B`QeiLXx4gUEot2s@!i0{bnobk*%O~d)~?=dSQyNipWEX! zoFflkxb3@D;kA4Op~HtTo^0}f>qnBnKltHY__d6(*UW_*%T%v)DD*u zS5f17YLP1_@q~N??g4N@9#uIF(luQns91IdT7rNHfdJN`)ep7XT_~>@5Iua)qk<~K z>ofd;R+Q)RLPfMc+y%^<&W?^YUpual=8*|15iQ+Dq_`VnSGb(D!9yat5yxEvIf`~l;Y2%4OF)3NS1YkWhD44nr-OAZQO@nQIuobvX$5nftoUyO3*fK zY~^D)lW+Pq;~+M$Z;&x#)MaJUE-oU+apJyso2rJ(+i`T{1q*m2*pr|NL>iAmlfeQT zi2@@##>D`HM3G65Sq!erWWHH>J)U1zz#m2!$)&l*7e+1qfY)HqB&Z1%Gr+-Gc>RFv zL0jZ+bGxU5EYAN}{W?cY;=&`ZuLTUj^3pnevT5?oh0X_^s069;hgd*Epuu2xkPyZ^ zF+2f4T(R-+6d_v~JOolEu3w~DO)atFOp6d=LjW5*FUv*9jVWtNlv_rKqR>_;ZGk9A zDpW+HeX5f%RjRIuq@}@sFPLp0DwEWxB();qAwVBBrc!?@b)-=djVVxLs!kLn>PVvM z8dFzEpT-E4)R>17>c~Ne$ik&@%2ZOO0V-??s9UL+C@9p5NCT9qog;! zaG!!~>dmd#+-YF=9>j;1EGQg9kg&fA^sM?#`ft!(rCi-`V@dxpB|m z+Y$X%RaRzJR@NKcPt=o?ieeIstV|qmtRyTXKqD(SettM+RZC|ZQxcl@4_Y{8QAbll zXQ1QX5r`XzHHZa>Gl(sS&F2#cVh>^hVg^D2!UDns!V1Fn`Q-StP;>;ExEP!MYohe2 zNCLv~ImPq&<^GRDOQ4;Yq4Vb&Vti~YY^*FiEIh279K39t^emjz>@3u@Z~_8wrgkQO zBVzxbk$Kpgk}!+AJ4>oKf7-(_s|b@gJG%Vs$dRxxv9Q508yk|aGO>IHF8psRETuwX zW@zK|kB*^}H3_pk(9ZO~-E;hxdu?V#LuY4GM>`T`F;iDdV^d{G5#9g9!1;f~plE3R z=~2|{Y}7s0+%(lGk3Ni;rTaK2}_&LB$F^p*nFO!n5i+)#PqK( zC+E-i%off)>q1wz7QY46r>93`3Uc=xJ5?)>24zhuKmY^AC=Xej7!KMNWnMU%|L(W? z>}bNT##!7LUY*M>ZYZOzu34s3f=PstK4Sg+e4ibco``zkEx|SZ-x(Rh6EFtK6B2xTlW|IDaS_x)5)TP`mRg*0vY}-#5vt>hU-mpmjgYn zw=~`9AJ11OmVS>dYd()255s$v@0JfcOQnAv$8MA5?Td43otNmry@&eDhvt$`JVA+l zf6Hw7@l<85INzn7T(K0qok;t2v1Btno`wA0g$M4{(p+9&Ivcj?xdXoh|BwS^Bhgkm+YZs{kod}P;DJcpJJ4R=TSsdKMDZIDv z;b&?8bs^9V?e|8TGpE6{+HwuaXMEA2(QI^Lz10|^Wf{1t3Ac9m9^7ke5Nc1~CnS_) zI4V?foD|TEUUh(6|0kfs6>y2%eNf$uKfEyESk`Im~P$1%dFo=`8-%WF5-KzIT}j?#71g3R*UdGde=5Y2$v zD?&K#VxyQ2c(D*V&Hxd#V`5MB<)2_72ta5(M4MfL4m>V&x9lBT_G6^W{=&FEYN24E zwi{#3*XE6!Q|I+Ek}!MF5(G|F2GPI?L@>hw7|s~xtb9lj@Enp>xD)UZ!ygdvlRj7h zGl#y&YN$Ma9ua!%-Tjjzju5`0@R@`8Kv#GaRA_Do+%yJ=j6>LcH#izR)G+`v)H1|6 zS+jqM(F)3(c|wmR6J}w#Bq*?OJYqre38$P{uFYifB@~l~w1x@;naxJtuh`rgUU~)Y=W2YpTOw8KQdHHY+dFdj|f~Sjc zdI9T<5)3KSUA~9JeUYhQ;%*ZUt>0>=N)Y>acAI&VTDTY2%4lEYKkRRt2Lo^SK>&>{ zH0n+fG4;ha5D62qF*+m?dadmhzVpYU$W&JfL0J}w0Q4NfLtajd!KT-=?)=eVsh@Zi z^dGMn_Iu6rwf-jCrA=-p=3Ra}{+$01zex!P)yi1l8BB zR_E$QR)NKFIX#Sf(sC@2U@U6epmZs#nLTB|(HfVtFoSxJary0O7#mh-W7cs>1BCR< zFs3Z#7sylZJe-&1@INa23UBiFPm5{j;j|l+ zUv9$>Nlwaes0mF&>5guZer40GeRZf(PG|rr05w)vQhH>=LYQUvK~WPYR0&=IhC+Mp zXh#eByAUd)k{D7U2RaNgLY037$`wK1RyaopsX_!w9*z4K*f~}b;SoH1CqagHGay*a zKxYT1*H|{s#ZnKahAB+vG@A`HTwW6c?4$4(N9yP@jT6z{S+C(2>7T9K7eh?zkacQV z`7HQ#zn;wdLcm{Se56!=VQ4P$K%JLi7tQ z9K|IHlF2unojY9d6>}UC;GfBr6h{Dy3?@%LVKdeDjB#ak3^~XvMaq^XRT+t2bPI7G z7XZ>K6F-i)h5_0koZn%iiW$wY0`4YB{98m$D~^zexgg92(k>7|t7ZV>nvA9hRS>dV zQ}w--4fUt@6IAhJ2nkLFuaZ`l2}IGY3thDdFVjssU0Lk$2p6<0AXsTbSHmt)R`${j zHazykMQ7S%yWxg}S`rkawsaX5?pwJcPf4S>j@(@JFHBOvAN5m${o4NVVNehqd%QRm zi)Xs@)ZyY&nTG3(_dfw@ip*;UNY5?xA-f!q-7VHSFRojddavYDEq=vDky2qh-pK~M zTz!DDgvb@{Ib+(2z(|jM$`qaUZse+MJk@d1^^LVWBcep1$eOu6=JtC49Iwv_>KcKP zzIZmh@H{uTt#F^PJ7lpw-yeN?T{0OX8nd=Q)%!Yh8M3gUqhaewUUebdiZHW)~C zxYa8f?{s?<^UAa&H-@BuI3jI;>gx1Q06gm1ZU%FpR-5T=zjq3)2ln6=g;(Ix&z*4< zI+3gse<6V*+1rdo@5Qrz#Dv)rpE!_A&)6{WA4oJe3XQl4yPQmVd&yStd=2z?k1SJSef+ znWbrWHzi$B_SK4!{}y>GN1NjrgRY=^0RDZW>6-q=0#G5I_v^PljWqn!gmN&qq;roS zvQc$w6iC%K?AfL}dZ9r696FfFfw6syD+}d!4HX~KH&d)r2O1+;%H_LIQh@t!V13-3I!6SKs9EqyZ5GcDd@%YOHC2>J`?b`-Eq? zn8~>{4gnxtvxK6h+)s!L0j zQ?+wC`lZBfqFdb#6W2W(rB6qf6TVxILBH+>p7dV^77Ujjj*z)Zi3N#FF67qaH{Q43 zvwXLp^zDE^pU11~qr=ybjSKY-+SdD>;ek>hk$Y*;5282tTheHzG9D@xqHHL4l1i8coQ zNdIGz7?UtuK!Ia?-XRaCI?h;OS0@iY`SDddKv@ClR`mivRCD@BUjQi(iS;;W5rA9> zDG-D8$g8y-WDyWs0O`xB#S%Ib$Qpz7-RVa!^bD9ji`I5!6xRNg?bAss^p$^*kU8ff z<#%17y9fuQWdRK`Y1BYaO3Geg52?Ilysv=%U3N>b00)Fg=x@|7x8V1;n{6%Yp|y3) zDkl0R;xB9=e@r7U#yHkeY5yZ?K)x6gXl8y{>6Q)fNrziaJ&E!uFNH`cxaLlM%Lip< z8MXt7vQCVQ(+gHm(vaQeO*zry@J}0jToj??y}K!=JYrl@3&oGA;@2}v(EDz)>s*lI z?>)$E-d=ySh(sA{ey_Y9rELcp3I3-}4?_}F;0S|Az*!#eM7zR$4qlSpK88U&*OtG8 zsDNHmhh{01DaktZvxQ=szaH)l;d|>w>|Wp8eBKvna~%nBl-m{|^h3}ooBKVyJ!b4~ zZHztIgpCb{fK3L_p`PPMi$1DF-A6dD&5wQ%kR-OwS3hFG2Kz|!?177)DLSRoYS-LX zqaAgZx(Tp6AqRDE$UeX>0y-chrWUYX3vmb604hV-(yzl)kFY#EnD!6a(o&Di^m5?c zJ(zY6+QdJ5pW?%Vw)E5^Fuff5Ut><#dYdWAbaJblG}7N}OD$JJwGh*sb$0i*_nC;e zzAg3A8)B}}w&a%~wgPJNtmrdM*-Dt$O6+FR+Naanm($u;(%O5|+JB|BiyQL=4>^ZN zpRnMoVB@H$e@-LfsR&0!wnU_<62mN+2Ol! zfI#IPqdWT!!t*Oh#)lSe3l(9*5AYU~Pk<@bs4m!c#G_O_fS#u2;<(#4eVdg^c`9o% zy#|Ab8GIT;>9wa&3{Aatt?wQSRe{UJ1TKkp(zX1mbR?}E9qgpzzOB&dt#m}K9c8?! z(D@Xz){ahe(qUg!=m_g2cidFez3Rp2uuSvfSZ~^yElKl^Ywq4Z>WHhEiKA8|6Bzn( zsB@^7xvoM&Mmrh!@`}VvNr%dk^@zh5cjCo^*zT+&2pc0@tzv%t$|f5QwSAQA%syX= z@~GX4L?Zf#inm$G&^XUC=-N45%yAy)96|wd!#jfND&g5l4$VcGXH&YD`#{HaAR#vt z9>~I^j4~7#$TEZx>`+4T9Td{=I}OYp8KfZsEsU|OFpfD~KaL{GP#{L|wTSR^vNd`c zwccCc9t3Wu3wgg+6C{dbtKR(ntuuFkqw04Iy{#g4p%@Z|&;bnH@UkW>)j(!t`n;4B zkw8@nIu(EKG_ht|jhPG%Rig8dmP+nyMp0{AVRRBmSn9W4@CceIDM2&o&LG*OMhywXUdtMJA^j4^HX>ju7cfMZtO4U5EV$9^wA`+Tq% zv0zwgp#i_*QDAK~sXoZ*Me#C8D{zty5j<0XO@kcKB>gF++ez4gGXLdL$WZerDt;rLc|Bt=91Kxo^G<rc{ekHH4w250t{@RH=1 zcyO4?NULzNbYfBNKcDnC_UNY&1uBepvCq;T>tZ5eKby9g2;|eW$Fi6R{VL<#0X`~$ z8spug&!)_H7k-iT8rwi`dJXF*z`o&I%MUO%)FZh8p0ao`LW*)GsN{Ti)LaM6LhtG_ zNudsXh*ck$A1^o-5A4&I;CUPWFCuJ+)wd>SWQ!+Ky~H~(eRt%z=trU;<9@Kiqh`wu zbr_kXu~Td(O`o)}(>)!4;8DXfN$P@RTa_OxpsmB6Iwy%SR83x3K@j1#nh)vv$@qdM%4{pvOVU-$&WUB#0_OhHy_WTF|dBKO%#9v_;6GdgTe zL2RmQ!q)4{PW2Nw@>vJ4hu?0%)(-dvo|(?q+}0(Z{5DFkwyu|}E|Txpt$ zyjiIe9Sf9G)+?&_1bQw8ro|`+>Y*uwCBO2tRKhKllgSmGD$^?Ri{kjqpi}BCSBUFl zJzzRBd@|ceLFU^q?&vT!8c`<3PIB5<%jb`S$ocPFm1d`7F98+{!Sxy`TpVXlsNTgV z`b8ECVgF}{Ao=^gyxLi^Fk$$}F@zxbS{4g51TFgjGaTntFob8J$kPB}8K%F&Qf&}Yi_?C2HWjUCxOhi~?3M;o-#eI%5|6KaI_;vS2*SZV0z+ggwG zLA2{^2hwMxd`MYR%FxoTH~_h`{S;AMOUC3-L{`~HS!{$h_%~wM)%}_rcFXT#xIS0d zGov~0L_rMr-KbCp zEo09xbs|Q?q`s4M0mxPADz%mZn2HsyOJAfl*92FVS!MVQ*HeBL;@mhV%+=!Id{ zBH=;S^w+}YGFaE4KXqi3^+L_k$qRAMi#z25Eu`pLbnQBkV1|=w$uCM)np5nHAmYdH z9w7J%W;J4r#X~R)KpeW%@yZXig*k1Z)h$${gbSRhywMeXQl=)AsiuxD*-jo4O1&}` z=ZhLCa|4H(GctoO*b~JUYz=2TcqIizPvQ&E&?3oB3f`;Z@vKsH9xr($jfS!BF7GW$ z%K~Ye38^9feDTD*in|pxwW5}jWID;q7LnGPI+sKHagt#i^3%j{Lp3}22CAT#k{H1ZLRCk@_E9b z2v;-Vxg-|y#y=HZIz2z$QJ<|)GsfbR7{0B)2)HiHMqp@Ar74g?qw=IlEJ5b638%%6 zHv314hSiMTt=K(mHg^GHz~D@fG?h%0=gz(Lu+`#_VHO0wXqBrAH=);|(}J0cM0zh) zS32JDX)^*7j4`HfgF@LcZAiqmZ`o{P>q2C3tA1?0-xRN^nq3WZZL}!kO|5}A)T-Jt zL^+N;e>FLmak*HH`-Y{5NRWQaGup~ur04OQK45I^qE4aG7GV3+ zpQU`M;1?RIEXWkv&Z0lP?j{oiMdLTHoV?w6g0ptS*cx_GUY;ag&y9lBo%ZY(tt3=6 znP|359wrkDX?!`&muPimOkGzURdLZHEihbf=+fccv0!A#7xshCQY9q#Ip_Ke4JP+LZ%8M!;>DrIMSlSucAvwOb-?;_t}aFO2@ zfBTS9!t*JO%p^q&pFPU9jaDk5cVbI1hPy#^N)qQ`PNGDK!-i%Xw%$)c-h-Kc5^ zgsJ#k)ZC=Rh%T`nXbBJXu_QHn1x20fJ$(=A3nA->{vNcGRIBb>E)VNf$&_qepv%$A z^xWr-FeA@&wYc#J*7Y)uDW#vSSFfP0ctSM`^_RQ)FIwfln6$qX%wJZ9i-Vi%Kg<^EU+(HZRE_FC^qQ!lv!M;p{4cv@ z{>feaOK$xSzUTiz75-!K|4D|i{>w8l|2G@P`j<}oL5?i zg~o^7PrbQ)q}05Yf1DUUodMrckvqop1+G*XE*!5Nt=H}Z-+dknIbAv|)Lj?u_l7>M z4+i`&d%V?sPY+n4CUK7F)K`R4W~S7kQ~#hV!bSHuzv#=C@4Bk!^Z;c#=(zoog1prS zQYTbq?zbL{QZkVb9^QUzeJI)qU{$7W*+QRBxEiz(;|LgDoQ0n>lP|oJTYqF|1AE&p zgc^x8o>M#5kmg@Nj}TjvnPK>c);$yYK=j!7TM$ux{>YiE*h%P+`)v*z4e(>lU=N}i zKe1ey%%xslAQsX^j6IRpMpXq*)sShj^l9uj9$)RDYU{7Yt@NgL9i`Ud_BFc5BoBhA zjE7OXfQH_xoZdu%+eQy`2b;{?+|*56+uYDtu~TgRszJvQDRR}XRs$1XCt?lL*`3@M zTw}T;!Gilyf&%T@@lAwYjjBaobx1q78>?bN;P?-DkR5V!(4BI-gEvP^%_(oyl4@J^ z62q_pe*l$o+unC0Ap)mGL2$+C@IX_a9&Oij(>dB=}qoHn-1F zdDi6DlS_5pDUYBwOU&Gc1+JlD=C^4m2DxO?5W?Xa!GR^+RsiRoof;`>6=cWdF0@KI z7mKyf**~0Fq6|Xp{k#6@1D;@S(k;K^IB_ZOR+9bD{XoXg2WQP(L0W8vR)+}#plGz8qWHZf zw~Od&G-6OsCciu7qkvL|sN$$n_2Qz`3yY2nDCjb>d+F=OzP<6c#kOnE%?FdC2cDd5giN5nirUZzg*IHUzU2cA%xNr;D7W&S(AW~ztMFY z?IOc%s0g!B!ox}gUb21pO$n~_%Herlu~V^kkGHlsn^8*Y8=2Y8;dOiBfMMTrBQ#PNa(<3@ib}>}VPp8Idqz=h+fd zkHBs|)`0cRanlb>5KQ|$VUQo(FcLlzvqKNTt(=%4q``nN^p`QvI(?lPp+1)1<|@EXBXR4>db29vvZs6d#;EL; zfPNGVt>Aup+?3ugYYuPiaf*z!^8>Ne`ox%i4+xe7w?j|{R!4)EY=BC7d<%@!&Iw$E z6T~kPqTWgZu6+>_$GC%Q@1fBa1PWj@AW+gGB7oQhgI>D9!3DhtJ~I^^3nUyaI8Km$ z%~RpL{fdqqpEQBN9bu#|+@&0^(|@zz+-M{q;??hwTb-AwW@wPpaQ!&3kva!oYNCL6 zz7Anfl3qr#B^s-8)pS?IA%d?ZgEs#ile%zDQNcV=JD@9I1%Rkhkta$bQ5035NJ(1R zdJ<<|kf`$WnEZe@P4>|e_Ggs$8$4TjRMe`99wZWoHtD%FYb&2GUwBkb$??RR7f&`m zdD_4^hqEjX17_7ib_cPLl}5&^Sn}?=a?-RceF*AACLZGjvb9x%bq0*Yh+}_{I0l>W z%sAO`L>G*;&@S)=Yh61h2FN4>v`mDov@)j|MRiZ@)Uv zU| z3l)JC)ky>e^RB)if@?;tka_;a5hX+ref@WLm+Vr3Gn>icTr6JXLN(7Hk;7eDcq?1MYXz zr4_IvTO+y$TVgXHXaj0{BttM4K!;siA57n*2VBL~TyCnNbit)Bi0&RD{qe_yo8tZp zn43bWPR#P(>$RMookbHeaK#KhXu}ma`@jJd2v@0?_S7*-6=DY93!PUPxE$qIPU8Gx z*T%@VT*$%G^{f_(MITQ#Y&dJM8!pO$W#l*wO$-%`#!pg(J&BV&Z&C5l? z%g)2}i6uF?*gi{tn58~pqouL1o%v_+7|W+CVJG9i#Zg>roJ_p`D#3kLDg7&CWaZ^x z;$h=pW99kO6g9N}W@>3};rx%CinFOLfP{mciI;HC@hM6$he%+9=si`S3>TZJU{#V_F><`rWY~q_~_1dvZE1GQiXC! zKvSCUwHI$9Z9jtfz7Demej7D>C|zTl6Y>X0J6fy*6J|D$9WW*8ML2YdWgsL_{6r<5 zyd>0PVMyy6V%l;;cK4u&QK9pFGMI^D9k+z$q15obrg$2YejcSsS_xBp+B`*6#xUFI zUS=8?#@V7wro`BuoS=xC&_O}uuQ>h@d0BjDftWD;LzMzm#v=YPHOcE%^E49HKLJ+X zs;D+PUyH`fN!O8lDS)31%cmh9u`%8H&<;xGevw>)y#(-+bJCMu$KkPF1z zYI89rss_ei)YAtyFvL})BNLW?)~bXgVbU0yD(lt=1E=eoTsHZbZ%BM9)c5Se#R`OL zEL!VG{Ib5xSlcfZO5)y8#?Gw_q=P?sl+nBnq|Q8!dd{#=ufYmaw*w|5; zfTB4~0%Krd3lC>r!77(NdM@Pn!Su}PIZ}rlT_W7$eU6oog@29cd7anAbonhs=-?ie z%G+!I3cV=%{e4qY7?Pgf;AYoY$;h6%z`P{C$NP&uzi;Q@(RJ3G&iRSxaTB!u$Li5!bWC1~PSZ?C@eCNp+n4DgFb~DD)jah% zp}8%@7L@dVrmisG7{GJewe=G=gFYXQs~ zM~k3bn6Mxu&gzybtha}$WKZUm83^-)W5ss|6S-#S+V?LTjtX{ngTiv2-(N-2+v2V} zEM3I)^Fe7b0hP6;A2Z-DHh?7a+bCj_mFyB;rlXUUwi>(r-x~O@kk7*d;((tG$>*;_ znc0bnM6t=@O`LuCN7LGshiD|WxB6Uu^sJ!S)2Q_{;uwo*tD*CGoUzadAr{|khl{>^ zFUx$_&1o8oAY#I&88==0NS#?#8;a(I#$l|WrzxW^Llx{H%Foqi#RhlX=bGyI=n)rO zQzYVA(QNMjL4s$uXvxV2;aCA3We4$U)34?4u*OxTA#zo3Id}kP?HaS9J97(T;B42a zzKDzi#AmE9&`ejO_04%vL)K1AZ4t=%d6y@mtA;72aj`9$B!<|^S1*YI08PyUEg-4_ z1;R0R*cSZ(pE{maa}MI4JEx&9Y#bYnV$@vumSgDJI?A<4dscrsGo&xNbm=JEvQ&|3 zo*{iDojPVWI$8o0e|gZnS7OT4mmdVQg!XbTRkGin8fqYBZ= z@Iq19rF|;4S15^GC=V?wcYK?ViSWNtkCYssxSy?&ZvuuM*d}>xSlf7 zrBnh=Cg%xXMd{GUDX^s2&!dQbn7{rxOhF4#E_Obc_^K;-UM>P{=Xt?gVSG@R{`uq29@ykedW)e3g?X&6nE-yS(G$}Uc zP+6Fb>c;DBmRXJ4+Xbr-X}XePHt}R?mYySLKaXVjsmr(v&Xaqys4*$G{EYTu?PoW4 zs}vy8rG{T|zusso+!_9jec};e9C&~@DxYR6)QnX zOL z?loMS+%9G~vP=ibMa!+h*SDv{hEpUP-lO&(3&T&NuOHZ_!AmFzws~>P;x|}09bn1m znIAn)qCwL+={mI+VdPK7SeS-s7mvn`h!3m_>T7F`tP0UkUYjf?9k0?_98e{p@B9KX}cIR1g>~xvv4t+92?}cN$%C4KK9fX%T zZksY1|3-=hf*4J2p|i&`k%+1e>hf5wjtZ{fRN36`<5zd~1k!JX?#{{;GhH3e)=66; zd~O^JINCA1zVD$W>Z@9cdU|r7Osa)#BdDE zb!CP28ko7+0IpFZY(O>N%-~#gwJFmNgq|mgPp<$WG*P6zT*%B$e9eYS6G7JO-~ z7!lDzKgt4U!~0-kMx!bpcEe#|BMiBAet|Qcflzm*R?n%T@@ytI7YDpegu9z_>Tu<#zUo>xBa}O8{FqkJ+_+23 zJ*QUQNv8Ml-uPvHWyPvEkSo(NyXFt? zCGuDbn+FvJSb931F0a+mCf?{+nCwVH1w%Hk(8mr{X#AMk_63K_)FD0%nCAgKC#es` zt(J>cx4%F_l2)&YY>IMR%8E{)7nTg{i9Z|qo;=Q0nzSsB3K$#R; zqkTrLya|o+56aUFw;l%gIXt(vZsv(Viw?cE~%dOwm!tCsRnwRC4Rdv{yvP~_d zsus5EGb%GuzxM@*xeawa;gBNl6a(r3t`-(2ljUzDeJQf_5H4Ld2}5LF0fZaWXlzcvnrvO8I?>1O_W{x+GGyaz{C?L1GzX5B!X`96Z|^5yNqy zFhEsn)}Xe=O48#=SP4DVMTS)7rys3dbMJbMu7h*yOqt3kYRC1QyHY%BEn(Mse5#}< zObPcEbOlv!|Bcjva6t}}(qc(^tYr0K=>d?%&!l@dRN;IpY%-^{va+KTxgl0MRlmx; z}HJuyl+d)_gR?l^m!l06`Z?%O2*@O*)6JE<^o!f76eVh&3d4F#$ zu8(wIY#T`IhBUD9?Ux9vZ>QfRx=c=ldaM!Uh}$el(PH&^xLESIc}{N@jHF1T=sLJY{1dm8uYMDyvp?;p%}VGih|mn83@ zvdS%WON0eUl@U(v;(o__C%^RB7*>Ou=Zrx2@Gj*~_2o==KZU}8VtZhmTQ|-A(8Y7* zXpk9*Q5>ftUwJr==o$`lJ*VM3xXkW+j|mDx(b9X}P4DuW9&($JikQ_ntT|tq5sS*n ziA_pnw5~x4+pFAqyPhGpFuL)c0MUkwSzQixc;VVYQv@%W$KCkws_SvdI%5345piC8RJcM+kaNCP0)Fejkp=NmE{UTOgnqj%Mi4vTFShXu{bL7p1k!zjDn2SjTa~=;V~4R zpFN=(+VU59G~XbWxr<|B!`moy<84AJzS2_1kN)gA%sCXXOVr6%6}hvm4L)A8Ug(Ef zj_$r*pNBZ6p7z1!Zm;xkeRJZ46CWbq^CGFKS~$;ln}!kitg98N8(Ck&j)0WZxa_7U zEY`e(iB{B~iq}xbhA@naf^&_|g_H}er|ODe`&z9tCAXv(h?;e2YUxD#`{?X(ozcbn z8EPVk?%^;A&`SS|*ST7rlJW3X{V=aK4TUUE$)+?tY*uRogQ-bM$LS+)D#MaQMCttZfI(Wq73)kMF(@kT`$gT@D0c`Cx* zI4My$lWKYt1LGo~d{kFqmqr5=^C(u+8IEHW#Fv$1V*d48^ozhnoyqMG_yV%dT$z~*8iEhbeY`n!xYh5;d(gq545wDQa{wd;kYO%~#Z#a?EfDd8x6 z{}FM^@2(p7hL9HDJI9CMXYyzVC zHBD9BR+8Ca2Fj`&L?q&j(^F-WX|l%h^7=hRedbxmVtfU>4)Cb#>gqp6!6=MS9UGwW z*LuHPT)krw!{wX2tMxN;&So1M?WM_VG)QrL9L+^l&PvS(j_vR22bmHczPmp8rQFc2 zYGmBUsAK>glfOV`hM@+Ro@~!Esr2m(#0q*2+Y;u=?DyO^H;UxE<9S+?mhuTAqaD6e z=kT*cKXy?NLeskhox5~e!l{9=4%%k20of3DeD+=)F}1@DqSSx!NOM@pS*B~*v2xmb zW#E1d#w+KLG-aR}_15Qj9cNDwk&K@SPZNpu366TP9U|c5QK?B#f}F0=9)D8gKuOHw zMs^BQ3eHlT*ZC71$c&q?BHrWE7!^xL@QBbaEKjzJ?lpz9H*Pwuop0>K}LqaO0E12VezdgYJjnjcO$B zk0VQtbI;1-%zby8x73mH(}%4AC2Fr*L@8GN7fY#Yq%XMDDKyc{hxrZDR%cd;3tt-| z#JId4cYjHsC(|XLUJuhbi?_KP%UTCOnZ7RQTX3A>QQ$J{`f9%pY-zU%V&UALiOE%I z?Gj2fvgRf3@)?XDFry|Jl7Uh;j>Bup@?bX@m!tab_QiUrO0L)v5x(PBrE5VgV?)6+J|N+>8WmpXm%CyCTSm8|qBtcK`y zg=DiJ~(=VZt+20TutTW%gDxkGt;-{+hJF(J-)o66v~Fr^#|Piy$8I{lUF%NrHovy5<~BOXYTMbld3W2> zua=?P8QYfX+AUYCe12J0n?x}M&`m4Hn?T58R3tQlW@JG;xvbp+di@K=X1Y8WHEV|P zN%aF)4`5ij+jUt2ZSS6jW{*PKUDAExu*r!ICE=arbcDyfH4aWVz`27D&&W*wg`iib)-JowHn>{{Ca%kTu_JKU+Ru#9`B4NIGvK4 zI3Xw57L98yYp!q+@8)IPHdi*nrzaHbncvM`s+iH?99l`-Mz3h5HxNW`F47S3zq}J; z-`tGk<1330;uZsY77dl@;v%x>K~u^6k?u19WiCPmfz>Osu397Hg+Bx0?J?BHsPBC^ zgM!r87kl>dlZPZYyq>!%bq@Hl#eu3GXUF@rT?6YY3xjpha)sP-5qe)Y zH(m3bj#ao*krA12SJdJncycfpi5Y$ddx;J;yX z!9dr@KwSe7F44-f!GNl?%<1wvqJy;ZR%Ew?;MxB4+*QiQH-pIiYW$;e%&ZYdvpGNK zrK-v2G-H_94-0qG-FRrz`)WD_K333cYT@hGcX|JFh+kAh4b3Tnc;ldX{qYs{7{{Hy zyNTI^+&Uk0q1NJ9;MSG3*dP6y0v^xx!`%~aP$1fF;z)X(S3escbRhk|uuPmzEKwqq z!v!2N(&lr;&!eCjwG;ySe>5ZyuH%d?V9_ElXve-A&!_zsyAO9b#6C|liOMy{EV+qz z@S`>h<$$zG4mM?X<|}#amEe5q3YqmTWQCupGJxy=0fNWq*tlrzH`Mnt$Im>iu%XZ~h*3DnGzB4smmW4!m9DE@mgWeb8Os6=iV0wn%Sqz&PEwP;Vr z37n+mUW||ltCnu{m?;8YbYnF;8_)cLhtc5<_uy1+kB0N@HMEH60HWNYl?k&ezLOz5 zW1=P<6!h*4IJA|F$uaR&w>UHd&R`{qxGvA4&($9?wHT}W@*qMH0{UQ4HV_vmyu>k= zXDU07GnZAbTsqE7*~3}o#1$L5gKiZt!!Z-404BCfu>oS=woshTN!T-k{KnvU813hz zG`{91aw+B!Fa&%5O7YqwQTMvh$i6pzt!z1Hs1UXN`f~B%95aet8*%c7TPRbmc^#v8 z)s$+7NYgVvUW!w~=b<~{OW^cpK_xseQjopwxTf#4Psg?^9GSRYusy^gTNywOaaJWVN-Q9RB06-oz zXvl>V>8M$#7d95k<~6Oc}}!(AUZkw%vLCsiC;B@9I-0(NKsk}oJL#r3-`y^ z&P=g?XS#EVc%>X5ZZ^l|0IJ``x!@%J$xqU%=$~Lbk&%>yPUZW|Gfd^6t27Qt|Am z_VgZ6bHz{GJmT$|Rz(1n*@{g%m1N;UrFU75S3973MuVe`gDEmPCV@mtY_6q!G~Wo@ z`d(s<=@KzX8}@}RS~@Wvbdf^&xLW+BE?NOt6RAaksfw!>HAUOBpCie*KIduum2Z|> zNg>-_gas81e4$^wN?1F!HP=Np)ugFK_d!Ja!2YUc$e;RyE7Qn)Os&VxcBSQ`Z)m3G z@@tuC!FY%?A$zo~_`+lGrj|3hqyB+);#>tf^s0Hmfbhgsofy-tBXDc=RK>CB;qFdC z;e4(3`>;4K-Iq78_Oy$dV+&i0J6oRp_Wq315((f0M~`u$bKqioi&b%UKt>2OosbCEv158M%UE|(EN-tYR6*LbU<}S z2tC$Lzvjd|i|oi4Mpzsd%fSnkO;w7vF-5qd)sJ;LA93b&8JczSfq<3n=;WBkH#yG4 z@_Y1+?CLPc#uBYZepm5k0#~5XOQlx7NN=h)AVF%~4K~%SbsdwLUDovXZ0Z(2*V1Nl zCkD`ZWg!@YPQ?)9ZG1YuRud*H)+yKTCiFexrN*maK^wbfai3!9pPhM?K<^7;Aob*cMq?B%lchaZTkDfSUr5kL*(0QA|^3Y|th z&?Q1S>`FQPIE5}-={Ex{jnFgQvuP5c3kSx2eqbQm8Rxp+F1J(b7X#oepJ_j5QZNmN z$1MzN;34inEjY<^9$%Qbk_-mDqXGj_`}=989j}AquId!qrvKM#oQK82RFw8p2)8Y4 zbA_y|w#Tb})_DLsTLlFA7+ciFWq#jCMoE1l^#_<`&MV#X=~64V-`iE{PkQSXCuRr1 zt_Q2&8i6Q=kE<26TI?5j496tsU29S`@h4>!FTfx-soHija@V|X29C;}5YLAV9f zFA4TsS{HfwoE}?8pxT1&gZnG{+=Cw6ec>}-Qb(|;x7^0Qswg@eo^H$39Tq0(R!#az ziG<1hOgwo&%{#eq2Pz&;#;u!cXpEceq>rN!8e^>RDgL8;S$DpZzAmBAah1I~UoC%A zWvQ3V#8w2zqk+tXZ&vjS_ZCJpnlFDu27;gaEh>^lu$){r^fiA`%z;69*;8cBrjUXu zrPstsWhvG4{7$L-cOS^6=Fi*AD0!!E(P{lyZrXmg^2^6n%LJ6W`t@+uN_k%1|ErR# zfQo7h*EC2epmYo+DNHgTB`|;kC<@Zj3^-eAj@4wDI`}~KsJm0r!bnCtIR_=P9ysE!If$W(3=+&|!hnWv1 z-iZ-yirM2KJiP)|YBmpS^bg)4QR9SCo-u4&i8#>WH**@A%I(P31si)VP85Tod<-FN-Jh&l!%T6He1)BZ*&Vct< z^_OdJ@0@s!t7T8Vy%i+j94ejQ@htUI*P~Cy#}~FYHaVkDr}eG*F{fSH3-@>3mL*>eMt;oW<{kN3`k0@u4io6Bjg5J` zccnf^=0Z1E6mk1@y|>xpGsg;!`Fx{&cB9NJYjm-Grgrz+=^Kv=g6zzpDNIv$L`9>YzlGLPGH&Ii`!Dd-Nb?oNWG*Xh{GW(sliYM3c|;^TPt- z@&WcqN`vkq!fGpXy*G>cj7+7exoLkE3w=Y5Wik5P!q%1~JyM$(G~!y<{d}O7tS|&J z;n`TU+wg3+ho>}cKV^`NCug(~4R$(<`cv>hI4(=}xFWhU@VKiPa)!*$w2m z=*r(k{9LV`VBMYlIP0(xqsXD(*QU+}Yqb z$wIHM>bn}FC|EVVxx~SL%XyQmk$rWHEw{9EiGFOaJZ!(toVUEwB5yzk=fX4iL#**< zmym_!O}_a}9Caq#eekDP1Lw_NWMOEIirIos`C7xe;v%fB_t}1%Y zkJV+lEPid=IA|H+zI5f0`|{e2z-y}_JMlYR&$hy>6#^O2qJCWB8mWoaJX(7``O~Tt zyGDwiTV&N;52N&_iu*z|K{}bd;Z7oOAI`5{ALqNy>Fn@^q#QgoS))dw8&VARSO=M3 zscbo-8?p|C5-x1^J6_3r%r<_`Z%Qi4TiGA65%E-+#~sTq((j4{;?Dv(%!`p$;R_L4P|=l$&J}lz3Dx^C#z-G zA4zL|y7EcGY}MhpQxJ4lpn4+h*4%@+iHm1XJd3T4PC-oLyzhgl|_H^(yXKNz&B62_JMm96B3x zx78}LSWPdkh6N+2JXRthYAIWz33|nxf9kx2aDMy-M|f>Y)qpkI2y~HdKeoS@?9hmQ zMQ_otATYoDLae4LxzP#x?j92=Msa?vecRr1vAMWDb8(Qp)%p_@FH)RgH!I3XWbYu#TZa)EJ-OzeUPfoA8_cGA zGj$I`70Y^!3))04Y#JzqW-8fgUU$DQM4|sA^tjgjXQ*7;hk+q!pfXFLJFjEzc&Yf>UzpHrqxe=RM<(|Oku7enWLfqBAK=n#{H=FFY`-cDD{ zDOtO4u}VeeN?BUJqOMnbd3EenGS!Do@gkKuW#oKPuO)qV(}ge0y#Cw~a}J84=!j-o zlVj80QL{s6RKTbL({cPKQ{LUVAr<=SMYMC;k=zrll!wdlWTI;B(alzZ=2oFb?$D^b z%#&Us%R%+0IwHh;`(guZ9Avt}q=xmk2WX3{)px3KjHyp_aZ>s2*#5Pc&?M#8rU1VMC8nS!&L4!eTjlIudrqS~ zVd&i^UfLte0!5_~?`XhcO0w>uvQr8W*6Rr@yD_0DspxQ~0PzP6D-pG(Cj=x4Tdi}Y znr_?wh&@&Zd8U2mb9-BhlzZToIL{nxtm=No@s02(6qQ8BS(%m$kWlCFxiw3nNE?3k zBR-GlDh3~0qF{mpxhIw=qPLyH8@;GA+}U`e&SoEFE045c)V;!QEHW=i zmA?BNbI+jVmf?FlghVA3;t=V#tKV}s9?KK|nToMJyJkKN+`c4Xi?B7YmZslEV8#XR z?XnqfPi+faa{+%24W%W^ui zgpOm>5B>SA&YSB*>kO)n&I}(?T8fAs7izGt(+oFNmD*ZlJY&u3FLIBZ>&|<2>MRL# z|JKyYVz*DD2IL{Nx*r_ix>Y^Xsq*V;{HhfEF-lgR;#EJ zq3tFyY0@XLXSX(uEp|Q>XXZ}%$$WslGtN4Xo)%A@8OVFofs$(;T(1IUxN%cg&&sxE z-04;`h1^Y5oEBh7-0oD>l|Spy(0=No64kLnk?G5Us;xtTG17PM=nLH~c1YnjtW|lY zV@Lh86dSVI{bj5_>Iyt{Hqhvy_{{4djw95*D$0e2b?ixZP)T0w-Y^kPPRW~}&@k{qP2Ra)0O(%|4 z;Hm?!9&MSTz0&4@NoxKU_TFl1lVJ(Rb{$;Bv-4scT>wgaDv&$vV?r({ww996EPr>_ zP0ENo6ryG(un|i3N;iFze3>jH>TAcA;@Nstv{TfXM~R(u8tvfG-~y|Gw!-=;pJShx z*!EOfVfxoqr}8Q1{jB!FDdLAu;od&A?>sc=>9gUp-MKk+clxciL%-%jbk|d+K-v%w z##d~P+GisS^NPxr_el(gNRXd-D7L@$ ztxJ5*1LN-i*6`JJlm}%|$F;)S8(Ps%aAmsvm?T^!-x6mfO4V#mnD?mIsiH7bS^a?4 z(|){^*c9AWh06yl+7z+QqSC5??pbAr@2l0>Jlc)c16#JCdjx2P_rZpiW^))V_EtS> zF9mMZT2{xAg35bWq>m?}(#GRm-II@K&2vnb>VX@$6Znqwz2u50kW%7f5WvtFw{{C} zWqj_hTrkfzi|^HTOwU+&Tge$1*)l1m9M5;?YpDmWc~RBu6_M&x0E@DzQG8j^<5m9d ziJhJ>L$Z-0gs=B9yuC)NghLpXuc_5ccdZ~e#q9QzH;%117>6o%Y(&PhxnZ~X7<&~8 zVLexelMM~rE_TLkwkI3le7QMHebBf)aTt$PPK>58IE<>pS)M;u`pHXeA>ApX5`hY; zLf!m18{fd|kmI_Y#qOhU;U1W1KyrrZaYKXC+zI7&53PJKqGrscUDGX7P01^Llv08x z`5E3trm0tI=y`o>8%*LAX?01ANYG0Ck`Yp;Fc~f36giVW_XY>?m18G2dzt>eQ;(N( ziRq1FTeo}3;}*jlkvnFV7G`Gg!AkQ5-R?*jzomVudPh1UNso7l>?rKJIE;-UYTA|q z#$#ql-uNQDe@(iYHLiJ?QMx5qqqIjyzV>)b2l?0rMCdR)Wd=wb*TF>-|wA>r2&G&O}?Dfz^DMQ{P z9>KVaAJ^JLin$n`w%db{Nj~)Cfl5b8W6s_ep)j4E5-rO%rK;%FN|ce+(x|p5=9t!` z);h9`B0sTb8TT~Uy)P1y<@-+E*Bw)eYMDw+JknjMP6q095`^-RXO7cT*Cy31OxvY! z27|70!1&Cm%?rEHv}eWh9R&HUv1JeGWa|^Pm^F=CtCN!yxwD=&H`1HdS-agcxF8FO zGt%Rv@${Q$%GN)~sVLxhx&>ihZxP3ZYqF`ZT2TdwPJdq9H%+nFv(D#y{nkvBnaV$m zt`+yuUz+Mp#tn!k1c#}}&4{?*%W{($i0m|0NV4&MT^m{E15*hE{rz(hunZOj;`zjx*&)ACim?9Jy1XSHr_!_LpM z_AnXdrCY@Z=d8VelyM4#l2f`1_2kEy#rA5=<6P6}9576r=9VC4hWihOD%PJ&tF`C^ zx6#}9BN!okAR9{tgO}2e8rmpzK4YoSY(fb#s5F&O?PZ#4l^D=TJ+dAx!3%8W%#lvh zM<{iNA)JTK;qq3(uG9Hn7n0q~`9l_>EF=5Fa-2mm60IK>)#+YjGP`~syTDxti4QzM zfl;E6r1&z&w_ivVykFkk$9U8$K7Kni@Fcj0k%m@_a^=9geTpZtsqIZXwbn}-??iBg z(87`cmlMrtPU}PY4{QsrK9B?DFttM*7*&HLxpUC{SHg6rdjSUrEJ&LONV_UMpW}<}p;6rn+uoF$YUAZ6s3VFHy*Z33q9CP_zYd%rMYIR-QQ>N=e2a$Ck?pIx|@psCtw-E_1km#WZxc zK5AdWd}P1LDi{$jaNc@3Qb%0J+eok~FRLU$ka}64x%FTk>EL=VT{rt_-`bb?f_hY9 zOq1XayMG?LvhdB>!*xqj_U%A_fgh@KD$6q#_Yz%=RGN&oSKUfmwR;m?jSrkYm*GZs zx4h?OMuABal_tw!{&%WPwg9N_PEv2jb7_HzDu4g(wTb0a(Un<2ln1KdP->w#Pbd6& zwldCjrMOR{Sg1C-^tJNz`S0hqMk}ZXph^=*mlBe=a}zNP3m3ieqJ=64X{GEP@)+e0 zjPy82bK=@o94>o`R*WV14R5%)Ib*Klu?1id00bcLmHrKS073Au2;ggfAi*V9Z8YkfEkKX@ z%b#A>1W&hWA*X-@0XSHIb(JXb=Y%myLg5M^I9#4^;Lq^~3@;S`9sU63@aIq{{I|_7 zJ$?>Gvcbz==XhH}J|HJv{*D2}#ltD^`G4mGYzbphoL_ppL;!Y#-1z*!@vH8C+TiPz zL*lW!gsSl)Qgpn;9}qdnZ{06Xc>ryJuT~z8AXGxIm4^W6j(^h90?>-TcLE7wAuq3h zzZWFHF@EjQE?6%Ro(im+AP6xaKnyS#uC4;Iz)R8)M$~E%1Oh=EX%a_p z;z*t#weu|N&tHK+k20&ViI-2-6t2~WZAy=#BN z15YwdcvJ{G8oyJqE|}j>lbfp>zDE;||2FeqXmoso{Tn0pkFJeZ0({y3SG(490d_sU z75{Ffr_TPub2-?$c;Q>UC&&VVe@hquXs}DJMlM+Vg90M73j?4zkZ1_-P3adFo>&oq zXnPBe+mxJ*IIt=q5h2m}lPas>UY11iS \u001b[0m\u001b[32;49m24.1.2\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", + "Note: you may need to restart the kernel to use updated packages.\n" + ] + } + ], + "source": [ + "%pip install llama-extract > /dev/null" + ] + }, + { + "cell_type": "markdown", + "id": "5d878aaa-a660-458b-ab6d-68dd617b69c5", + "metadata": {}, + "source": [ + "Follow [instruction](https://docs.cloud.llamaindex.ai/llamacloud/getting_started/api_key) to get an API key from https://cloud.llamaindex.ai/" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "7dfa9b26-0c0a-4a86-a022-05241efc552c", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"llx-...\"" + ] + }, + { + "cell_type": "markdown", + "id": "494763a0-2dc4-4262-996b-54a1b2ae677d", + "metadata": {}, + "source": [ + "## Load data" + ] + }, + { + "cell_type": "markdown", + "id": "07a33607-3f7e-434c-9231-2e3e9480dece", + "metadata": {}, + "source": [ + "For this demo, We use 3 sample resumes from [Resume Dataset](https://www.kaggle.com/datasets/gauravduttakiit/resume-dataset) from Kaggle (data is included in this repo)." + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "a7c4326d-6dcc-438c-ae35-921b564fc25e", + "metadata": {}, + "outputs": [], + "source": [ + "DATA_DIR = 'data/resumes'" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "id": "7726f057-73ff-48fe-ac63-97f7ce08a01f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['data/resumes/14224370.pdf',\n", + " 'data/resumes/12780508.pdf',\n", + " 'data/resumes/19545827.pdf']" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fnames = os.listdir(DATA_DIR)\n", + "fnames = [fname for fname in fnames if fname.endswith('.pdf')]\n", + "fpaths = [os.path.join(DATA_DIR, fname) for fname in fnames]\n", + "fpaths" + ] + }, + { + "cell_type": "markdown", + "id": "5d52e245-3890-4293-9326-6b48b5593015", + "metadata": {}, + "source": [ + "### Infer schema" + ] + }, + { + "cell_type": "markdown", + "id": "29247b6c-8fd7-4804-a188-d759e5ac7d62", + "metadata": {}, + "source": [ + "First, let's infer a JSON schema that represent the inherent structure of our documents with `LlamaExtract`." + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "6742d69f-1df6-490c-9c2a-59c02eb55453", + "metadata": {}, + "outputs": [], + "source": [ + "from llama_extract import LlamaExtract\n", + "\n", + "extractor = LlamaExtract()" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "id": "d7d39f86-e3a4-43d1-b7a4-4a49ee6dbfe5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['data/resumes/14224370.pdf']" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fpaths_for_infer_schema = fpaths[:1]\n", + "fpaths_for_infer_schema" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "id": "505787a3-5ce3-4f07-af2f-6a05fbcd5b2c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'52a70985-2aa3-4b87-a0ed-3f93c9f793cd'" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "extraction_schema = await extractor.ainfer_schema(\"Resume Schema 07_24\", fpaths_for_infer_schema)\n", + "extraction_schema.id" + ] + }, + { + "cell_type": "markdown", + "id": "fc85e412-8586-4246-8d8a-7c98c812f1db", + "metadata": {}, + "source": [ + "Let's preview the inferred schema." + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "id": "f32ff304-a04c-413c-bda3-10a38875e318", + "metadata": {}, + "outputs": [ + { + "data": { + "application/json": { + "properties": { + "Accountant": { + "properties": { + "education": { + "properties": { + "degree": { + "type": "string" + }, + "fieldOfStudy": { + "type": "string" + }, + "graduationYear": { + "type": "integer" + }, + "honors": { + "type": "string" + }, + "institution": { + "type": "string" + } + }, + "type": "object" + }, + "experience": { + "type": "string" + }, + "highlights": { + "properties": { + "analyticalSkills": { + "type": "integer" + }, + "communicationSkills": { + "type": "integer" + }, + "deadlinesFocused": { + "type": "integer" + }, + "detailOriented": { + "type": "integer" + }, + "managementSkills": { + "type": "integer" + }, + "multiTaskingAbility": { + "type": "integer" + }, + "presentationSkills": { + "type": "integer" + }, + "quickLearner": { + "type": "integer" + }, + "teamOriented": { + "type": "integer" + } + }, + "type": "object" + }, + "skills": { + "type": "string" + }, + "summary": { + "properties": { + "location": { + "type": "string" + }, + "yearsOfExperience": { + "type": "integer" + } + }, + "type": "object" + }, + "technicalSkills": { + "properties": { + "accountingSoftware": { + "type": "string" + }, + "microsoftOffice": { + "type": "string" + }, + "operatingSystems": { + "type": "string" + }, + "pdfSoftware": { + "type": "string" + }, + "taxSoftware": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "text/plain": [ + "" + ] + }, + "execution_count": 70, + "metadata": { + "application/json": { + "expanded": false, + "root": "root" + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import JSON\n", + "JSON(extraction_schema.data_schema)" + ] + }, + { + "cell_type": "markdown", + "id": "d0eff355-7cbb-4d49-8881-27120f737498", + "metadata": {}, + "source": [ + "### (Optional) Update schema" + ] + }, + { + "cell_type": "markdown", + "id": "fb247b22-8485-44ff-8699-3e71d5d4bf8b", + "metadata": {}, + "source": [ + "Let's modify the schema to remove the `skills` field." + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "20e3b2aa-6f9d-405d-8775-babf37988afd", + "metadata": {}, + "outputs": [], + "source": [ + "new_schema = extraction_schema.data_schema.copy()\n", + "\n", + "del new_schema['properties']['Accountant']['properties']['skills']" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "id": "7334157b-8080-4967-b783-99070381c650", + "metadata": {}, + "outputs": [ + { + "data": { + "application/json": { + "properties": { + "Accountant": { + "properties": { + "education": { + "properties": { + "degree": { + "type": "string" + }, + "fieldOfStudy": { + "type": "string" + }, + "graduationYear": { + "type": "integer" + }, + "honors": { + "type": "string" + }, + "institution": { + "type": "string" + } + }, + "type": "object" + }, + "experience": { + "type": "string" + }, + "highlights": { + "properties": { + "abilityToManageMultiTasks": { + "type": "integer" + }, + "deadlinesFocused": { + "type": "integer" + }, + "detailOriented": { + "type": "integer" + }, + "excellentCommunicationSkills": { + "type": "integer" + }, + "goodAnalyticalSkills": { + "type": "integer" + }, + "quickLearner": { + "type": "integer" + }, + "strongManagementSkills": { + "type": "integer" + }, + "teamOriented": { + "type": "integer" + } + }, + "type": "object" + }, + "summary": { + "properties": { + "location": { + "type": "string" + }, + "yearsOfExperience": { + "type": "integer" + } + }, + "type": "object" + }, + "technicalSkills": { + "properties": { + "accountingSoftware": { + "type": "string" + }, + "microsoftOffice": { + "type": "string" + }, + "operatingSystems": { + "type": "string" + }, + "pdfSoftware": { + "type": "string" + }, + "taxSoftware": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "text/plain": [ + "" + ] + }, + "execution_count": 90, + "metadata": { + "application/json": { + "expanded": false, + "root": "root" + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import JSON\n", + "JSON(new_schema)" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "id": "027db07c-bb0c-47e0-a5d6-f3dc21d56190", + "metadata": {}, + "outputs": [], + "source": [ + "update_response = await extractor.aupdate_schema(extraction_schema.id, new_schema)" + ] + }, + { + "cell_type": "code", + "execution_count": 105, + "id": "5e455f75-17c2-4b83-b330-b5b86ac36b5f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Updated at 2024-07-24 19:20:02.615311+00:00\n" + ] + } + ], + "source": [ + "print('Updated at', update_response.updated_at)" + ] + }, + { + "cell_type": "markdown", + "id": "0eb551c5-d179-4551-9c92-11fd0c2f23ee", + "metadata": {}, + "source": [ + "### Run extraction" + ] + }, + { + "cell_type": "markdown", + "id": "0021b05f-18a9-41aa-b95f-38ae3c4ff7d7", + "metadata": {}, + "source": [ + "Now that we have the schema, we can extract structured representation of our resume files." + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "id": "e2238eff-bce7-4d52-9df5-602309d2a99f", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n", + "\n", + "Extracting files: 0%| | 0/3 [00:00 \u001b[0m\u001b[32;49m24.1.2\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", + "Note: you may need to restart the kernel to use updated packages.\n" + ] + } + ], + "source": [ + "%pip install jsonpath_ng > /dev/null\n", + "%pip install sqlite-utils > /dev/null" + ] + }, + { + "cell_type": "code", + "execution_count": 137, + "id": "dc7dff67-4496-4ef1-b48b-71be040b1eea", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "from llama_index.core.query_engine import JSONalyzeQueryEngine\n", + "from llama_index.llms.openai import OpenAI\n", + "\n", + "os.environ['OPENAI_API_KEY'] = 'sk-...'" + ] + }, + { + "cell_type": "code", + "execution_count": 141, + "id": "1e2a3210-660a-4953-937b-48d7fcdf2737", + "metadata": {}, + "outputs": [], + "source": [ + "llm = OpenAI(model='gpt-4')\n", + "query_engine = JSONalyzeQueryEngine(list_of_dict=resume_jsons, llm=llm)" + ] + }, + { + "cell_type": "code", + "execution_count": 142, + "id": "c4dcaede-acb0-4fa6-b3ae-ac67bc45db18", + "metadata": {}, + "outputs": [], + "source": [ + "response = query_engine.query('Tell me about candidates from University of Houston')" + ] + }, + { + "cell_type": "code", + "execution_count": 143, + "id": "11a977c2-1a5e-454b-9afc-5476e9d6fc53", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"The candidate from University of Houston has a Bachelor's degree in accounting and graduated Cum Laude in 2005. They have 10 years of experience, with roles including Accountant, Tax Accountant, and Accounting Manager. They have worked in various locations, including Houston. They have strong technical skills, including proficiency in Adobe Reader, Drake, Ultra Tax, TurboTax, Microsoft Office, XP Windows Professional, Windows 7, Windows 8, PeopleSoft, and QuickBooks. They are a quick learner, team-oriented, detail-oriented, focused on deadlines, have good analytical and strong management skills, and have the ability to manage multiple tasks. They also have excellent communication skills.\"" + ] + }, + "execution_count": 143, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "response.response" + ] + }, + { + "cell_type": "code", + "execution_count": 146, + "id": "d21b86f5-494b-48bc-af0c-d61e9ff560fd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"SELECT * FROM items WHERE education LIKE '%University of Houston%';\"" + ] + }, + "execution_count": 146, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "response.metadata['sql_query']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37cd9877-f2d0-46e3-af47-38a08e5d3144", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 08bfe5784fc53b2da4185f07b9a72c644aa8d60c Mon Sep 17 00:00:00 2001 From: Jerry Liu Date: Wed, 24 Jul 2024 15:20:15 -0700 Subject: [PATCH 2/2] cr --- examples/rag/rag_metadata.ipynb | 617 ++++++++++++++++++++++++++++++++ 1 file changed, 617 insertions(+) create mode 100644 examples/rag/rag_metadata.ipynb diff --git a/examples/rag/rag_metadata.ipynb b/examples/rag/rag_metadata.ipynb new file mode 100644 index 0000000..c09d63e --- /dev/null +++ b/examples/rag/rag_metadata.ipynb @@ -0,0 +1,617 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f6a96911-1bb5-4106-815f-c422e4da2557", + "metadata": {}, + "source": [ + "# Building a RAG Pipeline with Metadata Extraction\n", + "\n", + "\"Open\n", + "\n", + "This cookbook shows you how to build an e2e RAG pipeline with automatic metadata extraction to increase retrieval/synthesis on top of unstructured text data. The core tools we use are LlamaIndex, LlamaExtract, and LlamaParse." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16310f58-9dfe-4ccd-bdcd-0da2c2628341", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install llama-extract llama-parse llama-index\n", + "!pip install llama-index-llms-openai llama-index-embeddings-openai" + ] + }, + { + "cell_type": "markdown", + "id": "6d4c2deb-53e7-4e4a-b870-d93af208d17c", + "metadata": {}, + "source": [ + "## Setup\n", + "\n", + "Create a [LlamaCloud account](https://cloud.llamaindex.ai/) if you haven't already done so. Setup the LlamaCloud API Key here." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "bee4bd31-6128-4d56-8f63-dcf2ba142d5c", + "metadata": {}, + "outputs": [], + "source": [ + "# llama-extract is async-first, running the sync code in a notebook requires the use of nest_asyncio\n", + "import nest_asyncio\n", + "\n", + "nest_asyncio.apply()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5ed9a368-c17d-4c1f-9266-60d8e4ecac5d", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"llx-...\"" + ] + }, + { + "cell_type": "markdown", + "id": "1940bd1f-92ac-4b27-8231-07cdfc8d7857", + "metadata": {}, + "source": [ + "#### Load Data" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "dbb782f4-bc76-459a-9dfa-273fbc241a67", + "metadata": {}, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "folder = \"../data/resumes\"\n", + "files = [\n", + " \"12780508.pdf\",\n", + " \"14224370.pdf\",\n", + " \"19545827.pdf\"\n", + "]\n", + "full_files = [str(Path(folder) / f) for f in files]" + ] + }, + { + "cell_type": "markdown", + "id": "b1516b88-772d-4817-a214-4fcc27875570", + "metadata": {}, + "source": [ + "## Load Documents and attach Metadata\n", + "\n", + "We extract the metadata from each document and attach it on top of the parsed text.\n", + "\n", + "There are two options for defining the schema:\n", + "1. **Use a pre-defined schema**: We use a pre-defined `ResumeMetadata` class to extract metadata values into. This is the most reliable way to generate metadata.\n", + "2. **Infer metadata using LlamaExtract**: We can use LlamaExtract's schema inference capabilities to infer a metadata schema from an existing set of documents.\n", + "\n", + "**NOTE**: If you are using (2), you need to make sure you edit the schema afterwards to make it concise and non-nested. LlamaExtract's schema inference is currently in beta and may extract complicated schemas from existing documents. Simple, concise metadata typically works much better for RAG setups! " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "b4cbc3e7-522f-449d-9a77-d3bb155cc3dc", + "metadata": {}, + "outputs": [], + "source": [ + "from llama_extract import LlamaExtract\n", + "\n", + "SCHEMA_NAME = \"TEST_SCHEMA_2\"\n", + "extractor = LlamaExtract()" + ] + }, + { + "cell_type": "markdown", + "id": "74d3396b-ec21-4617-8fad-ab379176c225", + "metadata": {}, + "source": [ + "### Option 1: Define the Schema Manually" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "4042d405-5269-4788-9999-a20f07ab13f1", + "metadata": {}, + "outputs": [], + "source": [ + "from pydantic import BaseModel, Field\n", + "\n", + "class ResumeMetadata(BaseModel):\n", + " \"\"\"Resume metadata.\"\"\"\n", + "\n", + " years_of_experience: int = Field(..., description=\"Number of years of work experience.\")\n", + " highest_degree: str = Field(..., description=\"Highest degree earned (options: High School, Bachelor's, Master's, Doctoral, Professional\")\n", + " professional_summary: str = Field(..., description=\"A general summary of the candidate's experience\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "93fcd07a-9827-47dc-b987-f322da90bf9f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'description': 'Resume metadata.',\n", + " 'properties': {'years_of_experience': {'description': 'Number of years of work experience.',\n", + " 'title': 'Years Of Experience',\n", + " 'type': 'integer'},\n", + " 'highest_degree': {'description': \"Highest degree earned (options: High School, Bachelor's, Master's, Doctoral, Professional\",\n", + " 'title': 'Highest Degree',\n", + " 'type': 'string'},\n", + " 'professional_summary': {'description': \"A general summary of the candidate's experience\",\n", + " 'title': 'Professional Summary',\n", + " 'type': 'string'}},\n", + " 'required': ['years_of_experience', 'highest_degree', 'professional_summary'],\n", + " 'title': 'ResumeMetadata',\n", + " 'type': 'object'}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ResumeMetadata.schema()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "3f26d9ed-53a8-4a15-bc71-1f807216cc2b", + "metadata": {}, + "outputs": [], + "source": [ + "extraction_schema = await extractor.acreate_schema(\"TEST_SCHEMA_3\", ResumeMetadata.schema())" + ] + }, + { + "cell_type": "markdown", + "id": "ba5007aa-a451-4a38-94c8-519bcb70745e", + "metadata": {}, + "source": [ + "### Option 2: Schema Inference\n", + "\n", + "We first use LlamaExtract to infer the schema from a subset of these files.\n", + "\n", + "Make sure you specify a schema name - this will be visible in the UI! " + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "2794910f-8140-49cc-ad9e-b14057c80375", + "metadata": {}, + "outputs": [], + "source": [ + "extraction_schema = await extractor.ainfer_schema(SCHEMA_NAME, [full_files[0]])" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "31bcceec-2536-4ab3-8d79-7ad2a9947336", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'type': 'object',\n", + " 'properties': {'Skills': {'type': 'array', 'items': {'type': 'string'}},\n", + " 'Education': {'type': 'object',\n", + " 'properties': {'degree': {'type': 'string'},\n", + " 'institution': {'type': 'string'},\n", + " 'fieldOfStudy': {'type': 'string'},\n", + " 'graduationDate': {'type': 'string'}}},\n", + " 'Supervision': {'type': 'object',\n", + " 'properties': {'teamSize': {'type': 'integer'}}},\n", + " 'WorkHistory': {'type': 'array',\n", + " 'items': {'type': 'object',\n", + " 'properties': {'endDate': {'type': 'string'},\n", + " 'jobTitle': {'type': 'string'},\n", + " 'location': {'type': 'string'},\n", + " 'startDate': {'type': 'string'},\n", + " 'companyName': {'type': 'string'},\n", + " 'responsibilities': {'type': 'array', 'items': {'type': 'string'}}}}},\n", + " 'Accomplishments': {'type': 'array', 'items': {'type': 'string'}},\n", + " 'AccountingSupport': {'type': 'object',\n", + " 'properties': {'hours': {'type': 'integer'}, 'tasks': {'type': 'string'}}},\n", + " 'ProfessionalSummary': {'type': 'string'},\n", + " 'FinancialServiceRepresentative': {'type': 'object',\n", + " 'properties': {'hours': {'type': 'integer'}, 'tasks': {'type': 'string'}}}}}" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "extraction_schema.data_schema" + ] + }, + { + "cell_type": "markdown", + "id": "ea56699f-a3b2-4923-87bc-874685580947", + "metadata": {}, + "source": [ + "#### Adjust the Schema\n", + "\n", + "Make any modifications to the schema as necessary. (**note**: This may depend on the output of your specific extraction)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "0270c28e-31e8-4500-80f4-0a53d3cd37de", + "metadata": {}, + "outputs": [], + "source": [ + "new_schema = extraction_schema.data_schema.copy()\n", + "del new_schema[\"properties\"][\"AccountingSupport\"]\n", + "del new_schema[\"properties\"][\"FinancialServiceRepresentative\"]\n", + "\n", + "# TODO: make further modifications yourself to make sure the extracted metadata is flat/concises" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "b554eebe-fbf6-4071-ae31-a0fd30839e01", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'type': 'object',\n", + " 'properties': {'Skills': {'type': 'array', 'items': {'type': 'string'}},\n", + " 'Education': {'type': 'object',\n", + " 'properties': {'degree': {'type': 'string'},\n", + " 'institution': {'type': 'string'},\n", + " 'fieldOfStudy': {'type': 'string'},\n", + " 'graduationDate': {'type': 'string'}}},\n", + " 'Supervision': {'type': 'object',\n", + " 'properties': {'teamSize': {'type': 'integer'}}},\n", + " 'WorkHistory': {'type': 'array',\n", + " 'items': {'type': 'object',\n", + " 'properties': {'endDate': {'type': 'string'},\n", + " 'jobTitle': {'type': 'string'},\n", + " 'location': {'type': 'string'},\n", + " 'startDate': {'type': 'string'},\n", + " 'companyName': {'type': 'string'},\n", + " 'responsibilities': {'type': 'array', 'items': {'type': 'string'}}}}},\n", + " 'Accomplishments': {'type': 'array', 'items': {'type': 'string'}},\n", + " 'ProfessionalSummary': {'type': 'string'}}}" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "new_schema" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "a6de62eb-ca88-4453-8b5c-3e0182b9e457", + "metadata": {}, + "outputs": [], + "source": [ + "update_response = await extractor.aupdate_schema(extraction_schema.id, new_schema)" + ] + }, + { + "cell_type": "markdown", + "id": "bf4a037e-9d46-4a35-b0a9-cdfda4ec1e7d", + "metadata": {}, + "source": [ + "### Run Extraction\n", + "\n", + "We now run extraction for each document, and maintain a list of the JSON dictionaries." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "125408a8-6722-49b8-a992-21127e3180c9", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Extracting files: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 3/3 [00:04<00:00, 1.41s/it]\n" + ] + } + ], + "source": [ + "extraction_results = await extractor.aextract(extraction_schema.id, full_files)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "75eeae65-65c1-43cb-bb8c-d919b52a8f1e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[ExtractionResult(id='c339f6cf-4a8b-4705-b9ca-74c4c8946803', created_at=datetime.datetime(2024, 7, 24, 22, 14, 28, 731534, tzinfo=datetime.timezone.utc), updated_at=datetime.datetime(2024, 7, 24, 22, 14, 28, 731534, tzinfo=datetime.timezone.utc), schema_id='446278bf-ba61-4e2c-bfcb-37645e86126b', data={'highest_degree': \"Bachelor's\", 'years_of_experience': '2', 'professional_summary': 'Experienced financial service representative with a background in accounting support, customer service, and team supervision. Skilled in maintaining financial records, processing accounts payable, and ensuring compliance with procedural standards.'}, file=File(id='857ee650-0177-45d3-a39c-edf769deb86d', created_at=datetime.datetime(2024, 7, 24, 21, 47, 29, 573597, tzinfo=datetime.timezone.utc), updated_at=datetime.datetime(2024, 7, 24, 21, 47, 29, 573597, tzinfo=datetime.timezone.utc), name='12780508.pdf', file_size=25458, file_type='pdf', project_id='41711594-88c8-4ddf-b5bc-9c7a20725158', last_modified_at=datetime.datetime(2024, 7, 24, 22, 14, 28, tzinfo=datetime.timezone.utc), resource_info={'file_size': '25458', 'last_modified_at': '2024-07-24T22:14:28'}, data_source_id=None)),\n", + " ExtractionResult(id='ed65d641-e879-4ef4-8821-9e63d5a1ceb8', created_at=datetime.datetime(2024, 7, 24, 22, 14, 28, 668037, tzinfo=datetime.timezone.utc), updated_at=datetime.datetime(2024, 7, 24, 22, 14, 28, 668037, tzinfo=datetime.timezone.utc), schema_id='446278bf-ba61-4e2c-bfcb-37645e86126b', data={'highest_degree': \"Bachelor's\", 'years_of_experience': '10', 'professional_summary': 'Degreed accountant with more than 10 years of diversified accounting experience seeking accounting position at a well-established company in Houston.'}, file=File(id='e89fb129-6858-4e8f-9a42-8cfb1b07bdfc', created_at=datetime.datetime(2024, 7, 24, 21, 48, 43, 839717, tzinfo=datetime.timezone.utc), updated_at=datetime.datetime(2024, 7, 24, 21, 48, 43, 839717, tzinfo=datetime.timezone.utc), name='14224370.pdf', file_size=19460, file_type='pdf', project_id='41711594-88c8-4ddf-b5bc-9c7a20725158', last_modified_at=datetime.datetime(2024, 7, 24, 22, 14, 28, tzinfo=datetime.timezone.utc), resource_info={'file_size': '19460', 'last_modified_at': '2024-07-24T22:14:28'}, data_source_id=None)),\n", + " ExtractionResult(id='c2a21cb2-2dd5-4100-ad70-15f09d691151', created_at=datetime.datetime(2024, 7, 24, 22, 14, 28, 453878, tzinfo=datetime.timezone.utc), updated_at=datetime.datetime(2024, 7, 24, 22, 14, 28, 453878, tzinfo=datetime.timezone.utc), schema_id='446278bf-ba61-4e2c-bfcb-37645e86126b', data={'highest_degree': \"Bachelor's\", 'years_of_experience': '0', 'professional_summary': 'Bachelor of Arts in Economics from Marshall University with a strong background in accounting and various skills including sales, inventory, payroll, and customer service.'}, file=File(id='705481bb-e904-4918-b212-85e34f0bf610', created_at=datetime.datetime(2024, 7, 24, 21, 48, 43, 836068, tzinfo=datetime.timezone.utc), updated_at=datetime.datetime(2024, 7, 24, 21, 48, 43, 836068, tzinfo=datetime.timezone.utc), name='19545827.pdf', file_size=24293, file_type='pdf', project_id='41711594-88c8-4ddf-b5bc-9c7a20725158', last_modified_at=datetime.datetime(2024, 7, 24, 22, 14, 27, tzinfo=datetime.timezone.utc), resource_info={'file_size': '24293', 'last_modified_at': '2024-07-24T22:14:27'}, data_source_id=None))]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "extraction_results" + ] + }, + { + "cell_type": "markdown", + "id": "530cecf5-ed00-4851-a8ba-e8a8c31dfa7e", + "metadata": {}, + "source": [ + "If you pre-specified the metadata schema through `ResumeMetadata`, then run the below code block. Otherwise if you're using LlamaExtract's schema inference, run the code that's commented out instead." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "fd15ffb9-5a92-44d7-99c4-8e0ffaadafb8", + "metadata": {}, + "outputs": [], + "source": [ + "# Use this if you pre-specified the metadata schenma\n", + "metadatas = [ResumeMetadata.parse_obj(r.data).dict() for r in extraction_results]\n", + "\n", + "# # Use this if you are using LlamaExtract's schema inference\n", + "# # NOTE: Nested schemas do not work well for metadata filtering. \n", + "# # If LlamaExtract inferred a nested schema, it is your responsibility to simplify and flatten it\n", + "# # so we can easily attach to each document! \n", + "# metadatas = [r.data for r in extract_results]" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "4f5a2b6a-d058-40e9-a753-d7a82b85499b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'years_of_experience': 10,\n", + " 'highest_degree': \"Bachelor's\",\n", + " 'professional_summary': 'Degreed accountant with more than 10 years of diversified accounting experience seeking accounting position at a well-established company in Houston.'}" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "metadatas[1]" + ] + }, + { + "cell_type": "markdown", + "id": "eee251a3-33c6-4b5a-8337-61963ab4282c", + "metadata": {}, + "source": [ + "### Load Documents\n", + "\n", + "We then load these documents (using LlamaParse), and attach the metadata dictionaries to each document." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09c87c5f-9ce5-4f2f-9bca-aeaa7d64fc92", + "metadata": {}, + "outputs": [], + "source": [ + "from llama_parse import LlamaParse\n", + "\n", + "parser = LlamaParse(result_type=\"text\")\n", + "docs = parser.load_data(file_path=full_files)\n", + "# attach metadata\n", + "for metadata, doc in zip(metadatas, docs):\n", + " doc.metadata.update(metadata)" + ] + }, + { + "cell_type": "markdown", + "id": "78a4222e-7b9b-4221-ba75-92d8012aac9c", + "metadata": {}, + "source": [ + "## Build Index and Run\n", + "\n", + "With these documents/metadata attached, we can now build a vector index and run it.\n", + "\n", + "Since we have metadata attached, we can optionally choose to directly specify metadata or [auto-infer it](https://docs.llamaindex.ai/en/stable/examples/vector_stores/pinecone_auto_retriever/) in order to get higher-precision retrieval." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "da02b388-c6c2-4ea1-89df-4cd064986833", + "metadata": {}, + "outputs": [], + "source": [ + "from llama_index.core import VectorStoreIndex, Settings\n", + "from llama_index.llms.openai import OpenAI\n", + "from llama_index.embeddings.openai import OpenAIEmbedding\n", + "\n", + "\n", + "llm = OpenAI(model=\"gpt-4o-mini\")\n", + "embed_model = OpenAIEmbedding(model=\"text-embedding-3-small\")\n", + "\n", + "Settings.llm = llm\n", + "Settings.embed_model = embed_model\n", + "\n", + "index = VectorStoreIndex(docs)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "5c1f6ef2-1de5-4123-abf8-c178fbc0f8dd", + "metadata": {}, + "outputs": [], + "source": [ + "from llama_index.core.vector_stores import MetadataFilters\n", + "from llama_index.core.query_engine import RetrieverQueryEngine\n", + "from typing import Optional\n", + "\n", + "def get_query_engine(filters: Optional[MetadataFilters] = None):\n", + " retriever = index.as_retriever(\n", + " similarity_top_k=2,\n", + " filters=filters\n", + " )\n", + " query_engine = RetrieverQueryEngine.from_args(\n", + " retriever, \n", + " response_mode=\"tree_summarize\"\n", + " )\n", + " return query_engine\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "f0b72f17-5d13-4b75-8c31-b76971bc4ba2", + "metadata": {}, + "outputs": [], + "source": [ + "# Try querying with metadata filters\n", + "filters = MetadataFilters.from_dicts(\n", + " [\n", + " {\"key\": \"years_of_experience\", \"value\": 5, \"operator\": \">\"}\n", + " ]\n", + ")\n", + "query_engine = get_query_engine(filters=filters)\n", + "response = query_engine.query(\"What is the most recent job experience of the most senior candidate?\")" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "fabd3706-e92b-41a8-ac59-ea0820b573df", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "**** RESPONSE ****\n", + "The most recent job experience of the most senior candidate is as an accountant, where they performed a variety of support duties related to the accounting function within a credit union. Their responsibilities included maintaining financial records, processing accounts payable, posting general ledger entries, reconciling accounts, and supervising two accounting clerks. They also prepared daily cash flow reports and ensured staff were adequately trained in their roles.\n", + "**** METADATA ****\n", + "years_of_experience: 10\n", + "highest_degree: Bachelor's\n", + "professional_summary: Degreed accountant with more than 10 years of diversified accounting experience seeking accounting position at a well-established company in Houston.\n", + "\n", + " 40hrs Perform a variety of support duties related to the accounting function within the credit union; assisting the accounting team in\n", + " maintaining the financial, statistical, and accounting records; Accounts Payable processing; posting general ledger entries; reconciling general\n", + " ledger accounts as assigned and miscellaneous filing/scanning of checks, invoices and branch daily work.\n", + " Prepare daily cash flow, examined, and analyzed accounting record, financial statements, ACH, wires, and other financial reports to assess\n", + " accuracy, completeness, and conformation to reporting and procedural standards.\n", + " Responsible and supervised two Accounting Clerks Staff, scheduling shifts, assigning responsibilities, answering questions, solving problems,\n", + " helping with complex transactions and sensitive member relations issues or concerns.\n", + " Articulate policies and procedures to members and department staff Maintains files, including filing of general ledger journal vouchers,\n", + " account payable documentation, and other miscellaneous fillings.\n", + " Print daily account payable checks and inserts checks and invoices into envelopes for mailing.\n", + " Verifies and posts details of business transactions, such as funds received and disbursed, and totals accounts, using calculator or computer.\n", + " Responsible for ensuring staff are adequately trained in all phases of their jobs; and informed regarding all credit union products and services\n", + " Effectively research, track, and resolve or properly refer accounting or documentation problems and discrepancies.\n", + " Maintains regular contact with other departments to obtain and convey information and/or to correct transactions.\n", + " Order cash from the Federal Reserve for the branches and ATMs in a timely manner.\n", + "Financial Service Representative/ Back-up Supervisor , 01/2011 to 08/2013\n", + "Company Name – City\n", + " 40hrs Provided customers with prompt, accurate, courteous and professional banking service.\n", + " Identified and referred sales opportunities to Relationship Bankers about products and services.\n", + " Utilized several mediums such as phone and emails to help customers.\n", + " Assisted customers with opening and closing of accounts.\n", + " Answered and resolved problems that are within my authority.\n", + " Accepted and processed loan applications and conduct loan interviews.\n", + " Assisted members with their financial transactions, involving paying and receiving cash and other negotiable instruments.\n", + " Maintained proper cash levels at the branch.\n", + " Responsible for cash shipments to and from main office to the branch.\n", + " Processed all commercial deposits, balanced vault daily.\n", + " Responsible for equipment maintenance; assisted staff with balancing problems.\n", + " Did random spot check with staff to ensure cash levels are within predetermined branch limits.\n", + "Education\n", + "Bachelor of Science Degree : Finance , May 2010\n", + "University of Maryland - State\n", + "Finance\n", + "Skills\n", + "Accounting, Accounting System, accounts payable, accruals, Articulate, ATM, banking, budget, Business Intelligence, calculator, cash flow,\n", + "cashier, closing, Credit, documentation, equipment maintenance, filing, Finance, Financial, financial reports, financial statements, preparation of\n", + "financial statements, fixed assets, funds, general ledger, general ledger accounts, ledger, mailing, Access, Excel, Microsoft Office, office,\n", + "PowerPoint, Microsoft Word, Works, networks, PeopleSoft, policies, processes, coding, receiving, reconciling, Maintains files, reporting,\n", + "research, sales, scanning, scheduling, phone, year-end\n" + ] + } + ], + "source": [ + "print(\"**** RESPONSE ****\")\n", + "print(str(response))\n", + "\n", + "print(\"**** METADATA ****\")\n", + "print(response.source_nodes[0].get_content(metadata_mode=\"all\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39e29a7a-e217-4f8a-80f9-62db7449c5d1", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "llama_extract", + "language": "python", + "name": "llama_extract" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}