From 17278e019426cb1419f1cb52a81ef027860d841c Mon Sep 17 00:00:00 2001 From: Sujan Adhikari <109404840+Sujanadh@users.noreply.github.com> Date: Thu, 5 Sep 2024 18:50:47 +0545 Subject: [PATCH] build: added packages python-calamine and openpyxl (#291) * feat: added packages python-calamine and xlsxwriter * feat: updated xls form to include building_exists condition * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * build: replace xlsxwriter with openpyxl + relock deps * refactor: replace xlsxwriter usage with openpyxl * test: start simple test to check if adding mandatory fields works * build: tweak mandatory fields + digitization fields forms * fix: apply monkeypatch for usage of calamine xlsx reader * fix: append or overwrite mandatory entities sheet (do not concat) * test: add tests for appending mandatory fields --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: spwoodcock --- osm_fieldwork/update_form.py | 31 +++-- .../xlsforms/fmtm/digitisation_fields.xls | Bin 11776 -> 24064 bytes .../xlsforms/fmtm/mandatory_fields.xls | Bin 18432 -> 26112 bytes pdm.lock | 109 +++++++++++++++++- pyproject.toml | 4 +- tests/test_update_form.py | 102 ++++++++++++++++ .../test_form_for_mandatory_fields.xls | Bin 0 -> 37888 bytes 7 files changed, 235 insertions(+), 11 deletions(-) create mode 100644 tests/test_update_form.py create mode 100644 tests/testdata/test_form_for_mandatory_fields.xls diff --git a/osm_fieldwork/update_form.py b/osm_fieldwork/update_form.py index 72d7fbdc3..75e155747 100644 --- a/osm_fieldwork/update_form.py +++ b/osm_fieldwork/update_form.py @@ -1,9 +1,13 @@ from io import BytesIO import pandas as pd +from python_calamine.pandas import pandas_monkeypatch from osm_fieldwork.xlsforms import xlsforms_path +# Monkeypatch pandas to add calamine driver +pandas_monkeypatch() + def merge_sheets(mandatory_df, custom_df, digitisation_df): # Remove rows with None in 'name' column @@ -29,9 +33,23 @@ def merge_sheets(mandatory_df, custom_df, digitisation_df): mandatory_df_filtered = mandatory_df[~mandatory_df["name"].isin(common_fields)] digitisation_df_filtered = digitisation_df[~digitisation_df["name"].isin(common_fields)] + group_row = pd.DataFrame( + { + "type": ["begin group"], + "name": ["survey_questions"], + "label": ["Survey Form"], + "relevant": [ + "${building_exists} = 'yes'" + ], # Add the relevant condition to display this group only if "Yes" is selected + } + ) + + end_group_row = pd.DataFrame({"type": ["end group"], "name": ["end_survey_questions"], "label": ["End Survey Form"]}) + # Concatenate: mandatory fields at the top, custom common fields, remaining custom fields, and finally append form fields merged_df = pd.concat( - [custom_common_df, mandatory_df_filtered, custom_non_common_df, digitisation_df_filtered], ignore_index=True + [custom_common_df, mandatory_df_filtered, group_row, custom_non_common_df, digitisation_df_filtered, end_group_row], + ignore_index=True, ) return merged_df @@ -54,17 +72,12 @@ def update_xls_form(custom_form: BytesIO) -> BytesIO: mandatory_sheets["choices"], custom_sheets["choices"], digitisation_sheets["choices"] ) - # Handle the 'entities' sheet: append or create if not present in custom form + # Append or overwrite the existing entities sheet if "entities" in mandatory_sheets: - if "entities" in custom_sheets: - custom_sheets["entities"] = pd.concat( - [custom_sheets["entities"], mandatory_sheets["entities"]], ignore_index=True - ).drop_duplicates() - else: - custom_sheets["entities"] = mandatory_sheets["entities"] + custom_sheets["entities"] = mandatory_sheets["entities"] output = BytesIO() - with pd.ExcelWriter(output, engine="xlsxwriter") as writer: + with pd.ExcelWriter(output, engine="openpyxl") as writer: for sheet_name, df in custom_sheets.items(): df.to_excel(writer, sheet_name=sheet_name, index=False) diff --git a/osm_fieldwork/xlsforms/fmtm/digitisation_fields.xls b/osm_fieldwork/xlsforms/fmtm/digitisation_fields.xls index 3f35f3f17122ada10493a1f44cad9f60f86be118..744c431dfb85dd84c0c88e4444fc597805b0b661 100644 GIT binary patch literal 24064 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 literal 18432 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.2.1", "pySmartDL>=1.3.4", "pandas>=1.5.0", + "python-calamine>=0.2.3", + "openpyxl>=3.0.10", "py-cpuinfo>=9.0.0", "requests>=2.26.0", "pmtiles>=3.2.0", + "aiohttp>=3.8.4", "osm-rawdata>=0.1.7", - "aiohttp>=3.9.3", ] requires-python = ">=3.10" readme = "README.md" diff --git a/tests/test_update_form.py b/tests/test_update_form.py new file mode 100644 index 000000000..735420814 --- /dev/null +++ b/tests/test_update_form.py @@ -0,0 +1,102 @@ +# Copyright (c) 2022, 2023 Humanitarian OpenStreetMap Team +# +# This file is part of osm_fieldwork. +# +# osm-fieldwork is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# osm-fieldwork is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with osm_fieldwork. If not, see . +# +"""Test functionalty of update_form.py.""" + +from io import BytesIO +from pathlib import Path + +from openpyxl import load_workbook + +from osm_fieldwork.update_form import update_xls_form + + +def test_merge_mandatory_fields(): + """Merge the mandatory fields XLSForm to a test survey form.""" + test_form = Path(__file__).parent / "testdata" / "test_form_for_mandatory_fields.xls" + with open(test_form, "rb") as xlsform: + form_bytes = BytesIO(xlsform.read()) + + updated_form = update_xls_form(form_bytes) + workbook = load_workbook(filename=BytesIO(updated_form.getvalue())) + + # Check the 'survey' sheet + if "survey" not in workbook.sheetnames: + raise ValueError("The 'survey' sheet was not found in the workbook") + survey_sheet = workbook["survey"] + + # Find the index of the 'name' column + name_col = None + for col in survey_sheet.iter_cols(1, survey_sheet.max_column): + if col[0].value == "name": + name_col = col + break + assert name_col is not None, "The 'name' column was not found." + + # Check if certain fields are present in the 'name' column (skip the header) + existing_field = any(cell.value == "existing" for cell in name_col[1:]) + assert existing_field, "'existing' field not found in the 'name' column." + + status_field = any(cell.value == "status" for cell in name_col[1:]) + assert status_field, "'status' field not found in the 'name' column." + + digitisation_correct_field = any(cell.value == "digitisation_correct" for cell in name_col[1:]) + assert digitisation_correct_field, "'digitisation_correct' field not found in the 'name' column." + + # Check that the 'name' column does not have a duplicate entry for 'username' + username_count = sum(1 for cell in name_col[1:] if cell.value == "username") + assert username_count <= 1, "Duplicate 'username' entry found in the 'name' column." + + # Check the 'choices' sheet + if "choices" not in workbook.sheetnames: + raise ValueError("The 'choices' sheet was not found in the workbook") + choices_sheet = workbook["choices"] + + # Find the index of the 'name' column in the 'choices' sheet + choices_name_col = None + for col in choices_sheet.iter_cols(1, choices_sheet.max_column): + if col[0].value == "name": + choices_name_col = col + break + + assert choices_name_col is not None, "'name' column was not found in the 'choices' sheet." + + # Test: Check that the 'choices' sheet does not have duplicate entries for 'yes' and 'no' + yes_count = sum(1 for cell in choices_name_col[1:] if cell.value == "yes") + no_count = sum(1 for cell in choices_name_col[1:] if cell.value == "no") + assert yes_count <= 1, "Duplicate 'yes' entry found in the 'value' column of 'choices' sheet." + assert no_count <= 1, "Duplicate 'no' entry found in the 'value' column of 'choices' sheet." + + # Check the 'entities' sheet + if "entities" not in workbook.sheetnames: + raise ValueError("The 'entities' sheet was not found in the workbook") + entities_sheet = workbook["entities"] + + # Find the index of the 'label' column in the 'entities' sheet + entities_label_col = None + for col in entities_sheet.iter_cols(1, entities_sheet.max_column): + if col[0].value == "label": + entities_label_col = col + break + + assert entities_label_col is not None, "'label' column was not found in the 'entities' sheet." + + # Check that the 'entities' label value of 'test label' is replaced by required value + test_label_present = any(cell.value == "test label" for cell in entities_label_col[1:]) + assert not test_label_present, "'test label' found in the 'label' column of 'entities' sheet." + + # TODO add test to check that digitisation questions come at end of sheet diff --git a/tests/testdata/test_form_for_mandatory_fields.xls b/tests/testdata/test_form_for_mandatory_fields.xls new file mode 100644 index 0000000000000000000000000000000000000000..407f3aef1e27785dc09f3369e69346d3a10aa413 GIT binary patch literal 37888 zcmeHw31Ae(wsy^An?N85fe;9UCIkpeAneHEgam}JZ=%Q&J4q)QGE0~xEP{Xt2(lxK zg18_8B7z`@>bL!No zQ>S`*hNEAEpMUM$nirVnc$oRIzY2m`pch|<_dOIkjNy7g0g=kNJKlp;e*6bnAlQI` z3=CjT^!qI65Yw|j17jC(-sHa@uZ(?;iPWUhm#BOUg^@jB}aOb4DH z^Jgn?4revEepUEu1b^MgYwzN(ommxDFsWctRPu=E_P}6h{kT4f*PFv%WBF@kyz1Ed zyv;Y9(}Kmbv#4)i^U2|%K!~mjEZ}4|=3oNr%S2|!pN)-S|1;_~W1pZ82DXcgrPr}g zT~{WtQP6V;b3xoKrbW#{G8hZcb%6~`Kr{m{#v2dFLAoK( zz|JzcMA2PC)zN2-vRgg43?o#v)OB^NwcC<^Kk_;jT_+uYVcpo`v_77WXXXZ;LYY?cq}Pjb?1?GSux<>bg2+ES1d~vmA_Adlk15 zW{4+hbj4h8fHq@BjDrQp+tv9{s!^_>A{XxwG5%33fJHDCyDGL`(|Yw1I}T4!-p2UX z#%dnrb#2%{DRYE(g%}nD$5R_OOZ09JD#pJa!c0uz8X6Q{tqp6;5*bS);f)2ZNm_!e zi-&YyjZKKfwX}q!w1gP{rmPWbNDV#JhI_pyexdrESyPz2kRT|aktK6H;*3U*z}Bn@ zYwjgbY3-J;H05Hw+eNcCSR`ZPa12kdScWHLW)2^mlheUs>ELk0`1fI}Ssc?1XSIak zY%o?(JBkZ2aX70jbi`{({6}zIL@~o-`sBe&+^MYf%p{^{%^{qa{j+#A8M<^ z*r|tJW6$^8SNxY3w!g~XSPcKIV)(`3Y$&FFaX4=mQ@=QU-YuqnaX4kwr#SrL^!cC| zeKr-tf3X<;^PFE1!^G!{IxdTg;cqR5FY8kjXKgX{Wqpd)mvKUh=p);+lEQx>JbY=z zr4^a~5{_S4t+Tfd^M9Z7D zPhd4+i&gv7Quvzs0pRnv6dxX*BqRxn{xUxnxlLg{-5MyqKAPva>-$&Y{Zetp7Urus zn)))oIJw|!a8&)3dlde`T&{|*@?(qPH!p@CSq#58{AgZ3NU;yL)bb(wA(7l}KKXSS zJ<*WBCKlq;H9f0@ zbst-P;Nx&77L}1&>Wem@DrIV*FKYu*q)Zb0%i4fkr%V#ar^?iToS{q&Xi&=3fZU`^ z4JfZGQv+If%G7{Xq%t+2rK(H~Xbme<16q7aY|uqBA81wbD}Fxs^NAv5k;^HG_C$jg zgqE;UfRGy&4?^o*DL}|IiwB{_u@oTWuEm2?EgcBCaPc6typ}=}a_izjXf6I*kR!cI z9vxb^O94{y=uogN1xU%GLrZ@tKuR7R$_GjTQu63f@=ywpl1GOYroRPg*{bBxsa-md zl1B&kEJ~wE$)i)JbRZ>^5`I=@B#r*c%_#k8^is&k|tn1T=fhw zVH8Ri6p)ffC$4lLC67-1(t(sbIt@w(Qu63DEFDP6qZ6-!P`!CpL6=SKw}yom;_ zQjJkpR*Diket2h?eZ`@C}lJnizr1rty08uL*w?9jOWcOn#DFj^%C;}ZJyk; ztPK*%+Mrok8{j^syAR3$7IK-QolaC6&`3~vr)i+gV_KkwJljbEww1p9>7!fTPN@ZH zse+JH?gQTAPtHcnlH*RR(ts2gO9p9O8W8RJq;-Tg0P%QEk?s_=dfP$`C=1tET{~gg zp@wG`8;$wCtzK~C#Uc~tzit+5N3lJW^0-2g(4vHlg2_5nsiJxDLxn(AJXVZ96UxhE;*qzL zD@yr_y#IYct`n5`EbhdIa^%rE7Q%x3rL29I?-T^kdu}FHP@nF8keG0-n3hGw#FijN4u4!sfRuIr z`;)%KRMCoQRa8ua62!;>l8XtHviAS{iEl9xS~0DQifLSe7&(M;F+oz+r#J8W7E@I# zrcF^X%}NkMLDoGs1}W?I=eK-|siqavwy2nvC5WNW>=qL&Wqot|sBbZmB&K!Ao>m89 zT9?Apj`W^-bluQvu@Td2r721WUShg&&Z$%pY-gbd#wz? zg9$1qJW2~%R|D$pMT}h?-O@K`oCg&CqXn(60rmD7#%koo`39};0fo0{K^tj6y*-4n z(3S2rT-*Hy9#Hs(7BoQv>g^AVz1n1vZ%rF|K;a2m&=wj{@6l(h@0w=5Kn-{t329lf zn7PpKP~nl+MHl$7WbE`Z)ul0jvM=0rpzMg=)4d7zh=<`(5^N(=M01AAEILg#>q5hn z!hrh7f{J(=k)9jOz!Nd_Jd_j9M%j>pQN~P}1c6dwtO%gZ1s4#=@EH^?(ym5_%HEWr z5EWdATBHxf14-CvrQ}E%xk8F$HZL?x(&$yapaS&DK{A-Za*-OQ;GG$N-dfQ;37!;s zkF=r{TERA(8G;}WvrEgOZ#=5bw?q}hweEe-tWE^Zh80w6L zKhQQs8GRaTw|n`s#L2O71$v7 z=#nQVDzL#w{c)q9yUhmw?^qaHSF^w$kI&lhS9k`{Jq|@h^g+R@jO_((?DdeuOp`TR zz!pT)f4?vcSP!U0Q;O8ehN|+`gL@X{VdeNPG8}n$5HyqH>mq$+*2)_kAyo?=?gLy7 ztHpp97&G@=Mn?#|wKq6Is}{V94{$lW76UG49C{Ak#v2?VRugCZB7A^Tn3WwN$lEM5 z8QM-Zz!5YcdIJY3cGwXC9vM4b8LA4b9h{7%TJv0RQ&-_}*H?v6QZYPvm?z|rp3p@1 zS(K5dn=$`pXbQsvjPS?aCTp&g>5ffW2aiI`?Co}9*||N@$xodrYMfLeBi(!ng!Mz% zL(re~m0V7{h|s55G<3DFX!M0kQcvx0ObUAPHi*Z1+K z?2GAQ=fR7h+(W3tTdW-J=E1B3O}f4|r?k+JUKm4P0h5j}oKOnSnyae<-NRABE!}_d zECMp6gj<El z6`eFXf_Rui*qr18nmZ$YH8=#BTpoXa?pB5Fevsvra3uFvp~%U?@tkxBV~>e;D@8sz z_!|o=s;`K3NKPku?Rd!$#a{AKSN3^ED4DWuO0fn(P*DA9=*{HCKxV9YyGsHPAPr}J6TBItBnZOJ0&~fPKGB}Lx{+fvP75J ziFZ!BDLY%T11S$M774W-9BH)6WS27WsjOX+-=naJOU6NS_^3qUnG!(N<&IFTLFyaIAy#riV1t&E2 zR#=c6_~(@9lNBfOyI8kUTn9-YvkRsy=p)(j#vxFjjG;^y$DTq&qg-FY43zV|iL5T7 zS`DFwfUfnFnhIuE(c~Nh8#WbkMT-aqq+4vGM5Dmi0MZ$<1vBK>EYKE;juRxSAPO$4 zta6I$0@V>v6IIfogTo}`h~rSfW~`;LwKBpTEHJv=Bx0=!#4aHK;YA(&H02teW#HBq zfr;J;V??vrAy`D%4`X3O58|FOiwl>nYf3`-uSP<#NJn;0;cUk7Sj`j}c)p z3=zf!6N-;txS%H8Yq~dQl{j9ojrPE z!b@gHeWaqcF;LSw4p_tyr~@V|?}MVGU~EVOP*=!xkviGpc=%1Wm}kN$I8C{t>`C0S zjrdeD1(r3z?BfJ6fqM&VU^V4SqHC;>DOyQu)$0XvxV;z_s}r72wWv!pA^@QAbWa2$ zW*nlFDcfXoIWR{th4T@3DG=FQc9X+`Nt|uV$Hb<&M3WdT5xd}qS;*VbTCzxX7&T)Y zF6ICPQJ=E;VMX zk7&b`LL7vhXe+8%W*keLar%~1{U4VG3A=@EWuy`5Rr9ZV#|_51Wy6WjF2HY zVS-G%&E!N5o#GPBh^CNkbJ}fG8Cr>UlMT*5UW_3Z5gY7c20Zm9B36co&QUx|qbU~& z{RM2iG9)2SvgJVmGc1i^u1X5$h=>DY&;h()f;nA;ch#XXA>E`&*tX-E7L> zzU&pDXx6(BOY=?8Fc(w8WwD6HMlgz(8$qW`3QTZw0ZW(zC($LyfJRt)Z#M)b)tdyW zPBwR7c8F#n?;Z)Z88OZ&qE)d`Him$lN3hvZDZ`dyGh!*%%4><+}1j z8igD&7dJP!cuWM0wU{RwyC8#yPTYcdl8a0TbrJv4G1pCY3ZZCYg)iIDO~|mhIIkfI zhFmNLM)<+r{w~a9t30c*;@Yg}0LPFW)08O+HdR@1wCg7INf~=5Ef0BiTfT|RfL<9+^DP2r=!SY_t0k4FSTuADi6lL9Dg5@fo ze)YWEgd8N@Zn8o}xfZ;aSF=I14+l{dbz>sPAx4tjd8Cnpj<=E&O1yo-t(M{z3Jk3k z8h6mBbA` zRsS2kF|D|+8Kz&YMz2InP0~WJYV%=BOE=pxax0Mnd=xq9sKHpi3EKe-TD~b8-Yw+A zxg9X`C{rjhd9>jfcm_|(k&}Z%&Pvf(#WtzbF8p-Y44jG8@7V`$m!4_~wsJ)i#E|VT3cM~sG8(#X7>3bkou!^|a*Jh(HkAZey7VDKF=sypp2DV`KZfVZF;-XUr^FpV)RoQL*isXDg%@USsy?#+FsD-Y=o z(8%Z9sVh&au{B9^+Rzr4u#cj92?cBiHkq$rRl&q!A+6CLoEPJaUy@+K2;uoSug5tG zotTc#lYYf{W;@3IiEb>$V_K&g*fGf|0M_{3y=J$&78p`3}zMn7$)Y82c3Gl}?d*|Ek#I5xXwC`fcdm0=%n*{zTwB3{w)x znlp`W-A6PVYcapQ;BemqiDBLD_V{z^4+%Y2Y)&%NzxvF_b3cB4!oE*ljEg+<_2xB? z-oM-X*x=-~LZrFr=~j1FcD!icT_PN^By zNn9Pe?6)0zcEz`wF*$YSO9NLwbvZA)_vX%X=iBSdf8*G__WHwZ@*7NkFuC$)t^sGG zuFqW1{^FsOQ$P4^+f@7U&OiO|$FjKZ=fAhZ*tYN6JyQ%*x9nSZ;>OxP9yt`5-0ag2 z8s2I4Mw6MZeKz#N!GF})bY-N}=F2u~zZGs*oL%L>rjVIwUt|k45-#uUxN_!=GhYog z?>aYk^V|t-M;__Bzo6=qcZ^pejvtvcY!WO|fY1F3+iUe#Yku4ZJGIrx&x)oYRdO_M zMz7D#`(o6A#E==crtO~k<-`HU4n)<@Z@zkdO7m3{*@gH?IkC}aqOYIn_i0{*MbU{3t}e^j6@3?^BG2b1vj}-aF};L(|?^Q{OObY~J)$Po3GCwyXb_ zt2%wwB6@X?ZHbGkgg$q=->!l0BxinkDC}6zZf9Dj$4y$ZV07B4I?GnpIN!GS@jHK?>cw}Y2{gXB}{h^z`wcQK7O_$PNTig8NpxyJ=N^hNrIl6WGA74E{ zSBiEtcifW5sp#k|6lA0fyF!c9-0QUu<}mJ!k%xpF=~Ll=5SDad;%j5(pKh12Grn8; z=ELvo{3lCUQM1d(uO55l%&8wPPHp%3cU4a=?^S7N(-lFLW=Wqld+z<8Cp29Xz4n_P zwf@o6eBtA2m#>bEI`rP0i0@KAaSWJP@8tYx8@8SkzS`R4WZhd$&yD;bZdB*zyFYg2 z_}xa|ce~!CK?Qw#-^#D=;D4b5X5M{)(GL_9RlWtOePd`ZTXegyJ=L#Fdi=)jcjL~C zk6Pe&c;Uskr}qyWc&SI~3rix$d>}MBv!mLfbxZXD$6jBm-+iZl)k;TMrSVtiwV3~E zpGjS3TpHD_=ion+CcioD=JQMLW&J)nt9`4Nc0YBi)0_JnU4CZM8!?f$s(#2CcK)j2 zp-nLl|8!%*kV<}a2OR7ELjCPAeK#3yS)RUkXvBMU>(#o*E=9aM<(e2L?Ra-{?D$Qy z57u7tz5kx*#F%=)^CoOR_T!b1-#&7#9vuI|W9eNNCidtbGAcC4@7RGZ-PeV*Tl49# zsxc9bP9)E}y=~x}+QD;f&YM-CZiDpYx6fDoa=hXGZ>NU_y>dA5)gC>5e?2Dhx3uk> z$BhZFWF`-8wqWa}{NK_VEDipxd;Q%F>*W91r{aczt_{nspJI)xkKXXsy)W*V*tI+7 z-^De+;|#SoQYRbANcm^x2miyF60xjegIjLAh;C z)!r3Y7iMm?|Vb!qeC&wm+wu_NoBG%GGu|4`~L?2a(&{eg$N9*v7#ol_;S zQO{+Qe@I^U__IfcHF@FoB+KacrYxwxVXQ9V-A!-&?*ID7sg18+NI6>biTUj|rloay z%Js{Q_n-gqi{>jIRJpN0jGNQAyR~}#lwm)eo0nGb;6e5MX?y?r`KN!hdwSQVUu={9 zx_$H3q+R_w58wJ?qi-kNzkPH4Qrn*U*S>gVI>kEg+LGC|&hPghQ0JW~BO)HYFkhOm@BYPz8Mz(5&q(dm(KstT zX!{pYmc*ah?5nqRsdVA<_BHOc`!OSW%5?x2e)|pd(*2Kmg)Y_(tfSFV054zH)zP{LpJZHT3WJ)1FS@ou>O|4|*x!xqDehI`7#v@5P9{ zH-l>nHx9QP)+vAU^~i?bUdfp~qi@bFvG!!(kKS4Fq|UPNT5jZ^OEKYnKiT%n{Dcczj4$@;6!F5r=b9g%z(&4r`SzN9`|Ows zGu~^rc}kG~H^%3xZyZoL;L4_Fo?7?SD#Jrtdv&fjX;e)9JC(Zb*gRct}j>0(jD&-_w}!jImxC8)Tpj=Cte1DWK6^TQ=*ZJAU$-y0@YmGceIn*8su%J@W{c71 zwzYkKL!aOG+AK@X{cvV_*3dJf&m4XBXwKQTtxu2r;Xv!wTVevgiEfjgxGJXe?=zQv zJ~8mwW7}5r-_`K9E8X{f@zP(Fn>K!^^REa0sFgV9{Hn%|O;e^u+uxA%pI`d1>mxS} zs}t)qp5F6N|ID{$#P)b`^1BO0{`1<9u^r~#9s1quj&~-kd$RHRB>T3JkI&e@Xy}Xq zi(6l@*B>_c&)<4i`+d~5l+L4GuF`+=sk)-&^1{dO%wOBPdh@!kHOQ_rz1wF8UVrOE zzY$xXtnliRrvjcH6ZCWL?wEHrHcC!xSiSR=FYkZa@1v80ZjH)*x<|j}t=^2#B|g!* z;gtOoe!BY7_d9+Yd(GM4#5?CrGoH<#72IU$v)g7{f9~qPclwqqgV#Uy+UOB!r?Q&4 zt~45S<$Nx!s0-(z^|xp9<=B@!G>v?uz3YEdR%M!=+C*?|qQm^W*tLySJXxf5^ZaX6yMK zuU>NgHpuFCy-~+jQ72la4hi0w@~CK8)!~QM8%In(aBTBaAI#spVsV@7ZpTxbyk)+3 zeA$)*?^Ql>`gYc%-=?=|(;}|T&V$R(c7DZ?dpxt!!_`NNUzCX5i=-A+`>jwunxw&-Bs2^`EsUCbQf794i$3pGD4yf2`swrb#!iKaJ zXKrm9de?tp_lR%KwrFG9Y0~#=+_>BLgIjGo-!>k4c%WEi&MzN~>RD}JgOA6C&Hrm$ z=ca#j=>F?RTbH@~YHm0<_?J%ucAs0>WZ8wqYd_fZ!KUD!JFPvk+BwY;yt~zJ-+r(u zCgEPr;a?j`C)fLpT;6}#psA)-z4ou^*5t!wE9zaboY}GEuw&!4g3Cx;eWVJNzMTKc zHe88DBGFK@+RFJ6PaC`v26w*Hr^1JcRiC~4%ou~sc6>+Jf(GZFJG$Y7-?Nw6RBCIC z8*t-hrFWVdn#~aRylC3F^yNbl87;qUk@HqfLx-!2N58b+vi-)~q=AurXP)kux#`Jg z=Gxlbtd_l?SA3raaRcL$sbI^4_BCf_H?I>p;;#W+9H*xR#J~R0k@NMIzt!9S(_uSy z9Q;o0x=x>fC-{p?pi#~1@R3gU?^PH;n^AgNC&Hdy`K7j@Hbe6?tbx?kD^ruRHZSvQ zk+kWO2k9$cNIZGcVrZSfgVB|?T3*>>2`C)UZ_N2k`0F#AGnwz7WYGF}l!39@x+%D_AA2i2tAsL@*M642HbCtx zeq6?sPvS#rPVYL?uKWbkZ?AD1m)jD}Ed|D(BF>EAZ&V3Z)V1YmZLY z&&tQ6(89nb^4%?C=VC(PzKqj^&#HT9J!*EvXK2cGKRg4oGu%V_Lz~#j9-2m~YZDJ0 zNG%(9=pcILrlp5AK##7`9y*wwh>Gyg6)=ijLp^jwd;q-D;Gsj%huB&)TC)C?FpB5u zd+5q|kYQ(S4;_k;-3fV0{V;k8!K-~Zej+orj^}y=?Sf$sZ0oV9CvU-{X#ADN)SyRe z998MdH#qj`k~xn&(!=YFevJ$OjQ61^-!iNf}+03R0t^Ql}uFv zMg5Vf%AjbxWhxXDZnU_mFi9=(~s98ifZ}sTJ+8z@4EB)WYZ-6 zb2!wR9w$qp-#K(&qw%S!QvN_DeP<0 zj-FghMo}n|+(4xi$)s@*dYsJj7}6t1)q}psn2cw{6$FypNTo<}V>d-UnT+2LlWWpX z_9o-$CWRu&2`c3+*`P`$Jt$H>0{@ZiVNmrja6Ou<2&6}%N|7Ed+!W0Qj|GCc9xc^t zqz5e!Br6zxBHLc3ye&WxTK2eLF1fYZh9u*bs2hPKw*^I3BSg6k&AKE!6eriJ2py8} zC)cXTYf=4*@b)C$G6X!?UujNyw6Daq@8ZUxl{*=KGHNANd%~)u%BHm;88c6*Mf!GC zDblwas8jI36PO(Sx+q;s_(TI}pU=kQ?>UqTuq~b$)K_79$f3CIbSBx)BL{h&23tLn z5rZh|@KqH$)<*Q8dCFPxnOJ)HEqNmy*@o&U@_Ty4jHfS<_(4|!`@58eCggj=7;BdO zpOn&2CzVu2Ij10<`PWh!?-YfMA6wUxGEhoGG+CWeAWCUo^hyyZrO84{q+F+zCJQN$ zLQ^n0SJ6Fc?v#LRPESU9Qi33)Yn-VIRZ{{jj}Wyyat|$!7DFwM!nc-3!Bxv6owPji zEiI3NgO*3$rsdHD*79ia)beP$YI(GfYI(GrYI(G%YI(G@YI(H4YI*dbg_cLlpq59= znU+V3jh2Uxk&5u5eDG-L)V8Gs)SE}al#U(LHb0QT#&#PSXW4-X(x(elw zYim@Bz5=io6a`oOHa;lQmi*R(PU%M~Tjy@$$I;(XDMDYbQiT4tN)bBMBy>NHPJN;o z;HytG3sThtf|8h2JkTxcjjyJI>aJ2GwTDWP)KrxssXalF)Bv?lG@m@^fgHV;yAAa{ z6*|eXNY`Ghk4h1GUzH;CexL}Q{$z{M%=DmBLXyhx$so685J&H?QiMK0r3f8+R(DN8 z9|VffgH&{y;~sQMI#ThZzud;a(Fdy(p+Blpgg!*22>mfoglr;JV!%!5uTNGiSxBI8x$=ufJYAG|_TDMC+IDMHTxMd%e(bc%%@^bn5T z!QF;#Eu`|VOwo*?m8U2FW`ax+dX`#~(6im>Au2jW0}nbSL8*9JSk|4Apj14^uTW$e zlS&c#D3v1gTu`KYB^90Gvj@F0M>o6M(EkaMitiA}=#{y@TUCnCZ7N0Rd7ucrGDoL5 zOtDLz!^*21mnhn&veE9=VO*+RrAVqnrO0AVl_IGwl_IJ6ph#+%+9!&U9`taIKE~aK zZttYxyLED(!g-&@sT84)S1Ce&3KXG-tLU@>dC;qH^a<`Z^uKVVBEyi;t8nzERf^Cj zsT84421V#qRCHR)Jm?V|eTusc{qG*B>=~7!(VnVOg#N5b5&ASxgdU-y)2iq}r*$Kh zO?S7UUx!L%GgOMupHnG9pQ%!WJ_{6~(|u5RmeKm^L9fQqpLe&Z#?fc16rs;iDMFvC zQiMJa6ropB(P^djpht4_`R+E69DRXG5&A-vBJ@QnMd&YpBJ@ZVoz{F0dUcMz*xjZ& zM_-~+oHP^AD7^%mmjf6m=uUt1}BBmH09 zN`-m0KD3oO7hHHNmE}eAyTkJeZ;i-?*iEA-cT4?!Y>m8ma`KDE!Pp~cB~v<38&paU z>K&Ex1GUjjktc<+tty58#s^bRMxp;IDU@weDL+u}gF1!8h9+%Qq%ev*(j7_9QPdsv zrFKV3jJba^Kfix-XHTY_i)DKO7Uln~?iky+usbrZojUDevb?Tycf^Me+y(WN-O$Yx zI{p=R9Kha1OT`@ru+1u^M{d4FrTjp>=cZ`j`|;bVfw=iY(`O(%x$WT237sw{=~$Rk z{1gAV3@UZ$$$`m3`>S_hbx0Wo@huv8=z2hTdni*qbOLq_MLl$Ur~ig~Ptf6i!SPoC z-D#6O#k;#Sn&+pza{G^dIbrJ;7+8~rTTUl}=Z_1OaHi{dDAba&N}BqVg^{;Wc0#*V zTFq%+xfX?XfaEC#lzk|)t2%;0S>@L#v=6$3LfAi}P(Ju43gKS@XbjGTO~-%5d;Dj1 zDh~C_8#9T7xQ`?{SF;9HDfmW5eJnr9El_TOatoAOpxgrG7AUtsxdqBCP;P;83zS=+ z+yeiJ7AR@|uRr&8g#4>t{MLl~=f3#u3I63=e1)GA$`5?85Huv^=!OAx>M@%=SN{4kw}Enx0$0k9 zatoAOpxgrG7AUtsxdqBCP;P;83zS=++ydnmD7V1>7z@xop0=~JZ>GH~eQr;m+0(w* zfI^?s(`WOv)up{T?bB(GPy2h?%hNNb^cgr+t4E3O%DoPtrxB)IzC^ zLR;rLC<01dlvtE{C~+wDQ5v8$M2SafgwhzL2})Cx1e9hd%~29jTA;K-a~G6kloXV%DBVyVL80ppQ0V;s^Dz+5GSiQ~ z3+OrhCwTP#aFpeUWC8peTVx~hBLP2WO~*d|%1tT1^LizlD&%AQx1e+JtU2kCtFTLb z#*@dYeA1z`4QpEDngMw1h<-1g{-YJ@JN=grSzIULc>ZUa;&9_3Ux$k{e@ZLA9f8s0 f!GW)kLmK^0I2Jq~Pa{w^ecJyE{Wp?exBUMD3*$lY literal 0 HcmV?d00001