!Y%~~7#7i2m9S)UD%QC^*Mj&7mim*UQ zbf)sru+xRXP{4AGf}PW|rH*1oPbU+s8saffj}DK35fkABJl--On<{{*#5fN&U*zDa z2LP!ntaO0rft=3;QX`cVE8V8qDSlc%TNe*Dj@Hk<$foCncu*Rl+Sg}hE^MuT>P%fE zDsK^q`kBcq8^5WanV30KZ~SHe@SdS8EaJx{ytmYfkh&oQhA_lB%wT{=n-YmOx@j|m z6?>y|(hO~OMOnWvecPG=1%1R1&rblK)&q6Ao(I3;xFg4BbhB3r3f3-e*x#|C`GW>q^Eo?>mivI7Pcv}HRy z6%1K1LNl6l s$s@$@LSacp-tbb<(82+Na(Ik-&>P|6I-)r~))VbS!y{}T zp5)8k3X{x86FUorcekXIIivep8|u8#8NeT;tw$$u(9BJ>b(v@~kqVgsL!-D6N~fG` z!ia=f)5W5Y3LqgtLYuNcKi-_px0B~s$U{v#h Q_D9b!p=-@!6QI_gK% qHt(0o52#=V_#9$gw%%y+@CC!=|q^{;c&5>X*z?<}h!LZV?ZJ(K$ zfj{bh!o-5k-wq2=)f=R(wQdvs_J9K`*AW4Wt7adRrU~7I#n_bGbNK^JFgVamh$S_e zkiLrTGnguIGZ%g$ZAkdL=%hHH?UeRKt%i9rEI_udpvtX4z|ur8fYvNCEeAn7E0(66 zKlQ;;IYp#x7r-PZg_(~n4m|XcAMe`r 0qc#8t5-Vl;PMd%9{kv@AOCpQ$Hc$;$gY2V>9Pmdve+{F zb}83PcxTwJRit;;Mv4VHpS41PR5Gom%JE1jin0Q58Oo%cT+&EHpov4!!+0@7#X>=Z z7AP nga%Tfn*Qy;B?n_YP(D~t)x zx5O<=m!mEHl*-* Tw6|3zXR`Iiw}GrX-6vf4iQ_YqmBy%agZ mJ 7kWnzD20<&klz;<4{ zjAAX5mR{BSYumdLa2%!MNvIr{3{2wLoD@!WEG>0UXNOZN7}-opPnPmIOroV4DoK?D zWn{(f5SBl)Y%yD#D-i^%*kiuc2Yj`ePL8E)jLahQgf{bUU;8|vC6XFfe2TH;&lRNq zTFw=E)c9Lkjb~^roc&2{f4tM_iiD$?RI-?}^En%23BP>_fr(@a!dYnf&`P7n>DQco z=syQe_e9u$*_iBIQPAyDU%5li$w>z|2;l2>D4U$;>X9O@HH-2I7qe{z8BDP;mEsAN zC#*ftD2kSPyq`TmP0;iy0%o^&%fsq9TR*KJ)GsOdU>$xl=~3I^Vyd E^Xte$AY zZn1zdzczNIjD7={h3qcRL8|^5=*+w>9vk;Bio!+bu 0;`x@F}6R$^R4F$ z9j* +%xAW_ zG|K+iJar+CcwcSnic)7G2#1p}Ll(^E9_mg+V$n#fqiFZ!qS3U|3q}iv47R7r-6hJW zl6s_+&A?hj1hvbKiC8<+DY?_`U>Ij*IoE;jDNN _ySAbpw>K=35 z>n8_ZVSJ0HWk6Y4hTaU*m(U&bJGHTVCLe)lRw(btl?t|90OE^ H$%Pa{@QDQ;MiL<(F6Gvf?1(c>Ij@t3! i9=$=URtGMz4A|H0$Zm4NYA>?ka1{}tJFPCE1 SYBv<9W|EZrD$tiiwMIExawOBjP6bKU<| ztuCa%3>E0!+Jv2oDC&d#m(S($`CKWB(?T{|P$CGP!#5*;m=N2BJji6o %H*sz`JZIK~n #7M+ha-^b=9FZ{fIx&%5s9|_ErlzK_dzxal#b^?(Ejw>z zwtY&*arxFHsTJq6Ay?GoOh$#Ji1~ce{DXL5HRI3HnwbF~Znp*-FEdNd$2ZSKJK*KM zIG!)sFkiFDw3>}Fu8YM&Due)uQ&fh&%$sNvIgmngbWPiohoRt^_AOtGCvH56gM(z< zxdKO-4@$UlszlEm6JA{IK>_A_Q|fR?L@JzsKTU1-+_mF-6+K?Nx{oow5Z{&l(yEm! zS0ytd+UKl}Ijf7#Y9IS6O5LG03K*z>22gL9Rt@y(ZDe4}geIkJ0RhA_nxw$tL_}2Q zN!~eRp@;$^c=a2ki4mj?<$7O-GL9g_V)xy<1QGz=?YcYR`)D|>d+|i&!%Z{fKR{vq zB~!=g-KQb1Tk~VzThWQMxlhzC&l+9bC6Gr)o}CoPwvc`aGNFo`?rvz 2 zw|D #J1H6X@@0~rb#hSSW2WzXMnAc0& z$_RvG@tBj0A}g5l?}%e9x|T{3TXxMrdrLNOdcg)y_xZjmMkhv+MhIQ?UZoO@C@ {B5COT(wjFQKkTQ!tG2llF1DoIG6VxbD;%^sGO!1` zlsyP!$i#qBo|6QS6tSd1=*#uRgu1k#IY$D6=$dC7a-NFkn&@Fq*Fp;sK8bo`TOH{u zzMTkbQORo->W|LAY8jAL?(7BWMf5!oZ?9EBaazg@Ab|xTuxKO_&4w)zMdC_4X6BM1 z-9$hL@jP%Ua(pm4;3S}kZhj<>nNP~7ruVi@Uh}~60Z&z#0Zda(q^ndt#{`R@I+GQ| za^OGh`s&}v+@#M`CO B6OyjNJ+V!o*udCJbm3I5fw|NW5YJ9YIRVE0Mg4v6~ zbQDW@8y=`aDU57COLWDOcGz*Ci*mUHa!ZDiwKnfzA$$52iB0L5XYv6Cw;VpNsj! z^sL9%Fu^V)JtJ&U*OM~A{Gr2pnzCiGOG5559L;ApY8wdl0+XNP^o|F-VE%-{B70{< z@63hg5WKG(cirz+tBrTnvmDo-SU88V=|pW)HW6g6G%_|!j-IDdNyIzZ>7L62ujvft z!+O}x!{aZRj$~#Jf(cMWoNsE6okOy#FFlt!O1%U87I=`=5jOMLmtE3e?t^r5xDsp6 zj6L`VAG`QNXD<2JA3QjAM!fyRi${L`^CK^wsGNA=$j^RupI z6zj=ESljcPN=n@Zay{s}aBxc>;4vu!JtQH~>QN+Iu-sGZ2u!iv)S6=&@Zodb*rD3m zR1CQcy2xaaPgsg45^+pwf}s$i(jpekLi}^?SPJ7xr&Nf?w+E!_VLn1yN=*_SCyB9K z@5zDIMuv5uV_ald&O?MWeo`0r?42^+w(H5Oue@ROXN~tmFlIPa?7OGKBOh;k<6S%N zGaHz4a?kxdJwI3G)|zY3qW-QlPjWa} 5 ^Z1!_l+SVaagk2w+5n04S5dFvkOha-i$2oxY z3rAUez}LdjGVulRmtO2;dktd33(1i{iWVS;$ecz~GXFWpLP2s9dp71%p6X1PnWs{< zb3N6OTtK}4&Tlks{PR1-7w&xU8@qOW ~p0GRjHV#u`Qc$ <|F^rqcw!$#F| z^kzAFvmCvFCu=!+vmCuyj@~RsZ}@9!Kc8+ndh>6M-k35v@rd;DtNhqby0dnXji9`U zB%;L*BqJh*hLB)debkJE0~?XGB);S<#q%jFSb(Hhgh-JTTR>9moRkAEDb{xrdBGen z?&}#g%~(#C%rj_aqpP)MRK8LMrNiQpnIR;baG?Goceq*|M&xXw^2ZNjJsFk!s@5?0 zDMA5_|1Bfk9OFj%Bi%K-jedd=>eO9}$nVRMho$4A?$+uMFs%49b2~Mhy6cv&>F+%M z`-nks+-5Fh?yF4#D1b<@qhzNGsZ^o0oP!4-9RMmQ0L4oY37V1w69PHK!eVipA*>0& z@ni2_MZ1<--GQNo&UVS*g}=gsw WM54l)S~?0?WgWu^I`NK(F-0AI5M}(r_yvS?WE9bsA9r0MhBw;z z;f APB@LT8{f2i=L)|FXu<(W6R-ppn02$rc)|IKA;-t;OoS0a;g!9q0( z7j5gPfEzV|91EROSL6P&8m;7m<~l08at1F9^bmidaQ;3p0AsbSCgeb j{WiYyD( zra~3?I7N0Wgj5M+Y|)fuB3&TfOs?gq;20LhQu%6QvY(2C!<^gCUFAFgTlC=rlMnfw zzK=UDBar{^*23b|DDD&A*VbbttbEO~NDqdxG(Ju$dKqOxcQ*}h%;&P8@&2K^ui1as z-Pc}wm$?4gyYJeMjl^t2Y}V4^y()f*4;cY!$He*(%-_l{4&Jp43|xLeD1O=B-x%%h z7w_%E&qAbE{%*#;efv9*!#;px63Nc@BH+FU$q;{p4QpmvI0lXp1^44)xt-YXIbi7f zSft6qc9bZBwKO9?B8oms6#E324eus4VFftUmBe%SG7ul9V0#<3b3|E`XP>}Qksa7x zA<92aWMeC!j^YDE9iJxZd=I{VKpiDK>)>7IE~0Lrs|;o? H(rPmk?Gn#D==pJxnxs6}GPs4PpJvp`Q}1UxDoi(FSZA zQQt7`yLh*X_p0dI2;Lp}E27a+Z2wHO8U5daXD>QQG +Q^D7 zB2%^#U#FA^pQ9invIpO(^wLUv?bwes$_B71+iHCGxE4!E4uVqG;|s`*Sc1^SN^P3} zicze+wFPUojnTz)35`ypWCsH+fKR+OBe2@%jpVy1^*Vh3Nm#M7MR>e zS7VvOYiU2$*}M*Gg}#-h=z6+=Zp1Q&&(oLb&*+PE4?RUsV?-W(ij^1}|GH3uGhCCf zc);oh{%78u`@>D$Fs(o^6pln=@kBC}&SZ0WyHM=t>_Sdwxo1W1%D(=}z^c`2)~*{I zTEAiAuv^_UGP-%oMPnCVGG3dQymaff?K^f}wrlt0S6um)tA1 P)cwp=Wi$}7t2XJ=7f zE@yDv)x2(151CGXLH`wh-^Cw8`u}ITxdkiw9D)SnWl(PdeUsMDYd3;IAZ_Hfg=Qep zhO|d$3*_w O$P&&$*M=V;w&kMZIM{HMmM_Et%HN675$0qJo z@5>{<^EuV#y!ZU~<*}{)Ips^d(<{r1UcLU2`-!n=U4(DZu{ChcToT4n^?k{@|F5 @Imo~*&FGZ*%SDd-Vm$BW;|b~N9a-d96bj~^&Dhb9a85h$fo-tBS`$C z% 9S`;5~B(;V7LCb=!s z3 6YwI!bc{RHtjr)330l*xp7Tv)n6wH4Cw7dFG*4>%14!cqUSS zgp{>$^)YL@%=@nm~j3-1Hl!7OuEC``FrM79-+ zBqE^8aM-|K#EN)7&=1x}iTRh!axMttFM`_;b4%X`t%h>kRya)gylg9gwxVb&!fior z`7Z;fpwPH~*(~=9A_26vL|gKiP#_e_Gk1j}WZRgrfmY)9l!V)g82F0@qTUZ}MS{_| zf7vYOf(ZViXbW9i`aaqU+uT+pLWM$ + +目前光功率计缺少将数据直接输出的功能,需要人工读数。这一项工作单调重复,如果可以使用机器替代人工,将节约大量成本。针对上述问题,希望通过摄像头拍照->智能读数的方式高效地完成此任务。 + +为实现智能读数,通常会采取文本检测+文本识别的方案: + +第一步,使用文本检测模型定位出光功率计中的数字部分; + +第二步,使用文本识别模型获得准确的数字和单位信息。 + +本项目主要介绍如何完成第二步文本识别部分。 + +## 2. PaddleOCR 快速使用 + +PaddleOCR 旨在打造一套丰富、领先、且实用的OCR工具库,助力开发者训练出更好的模型,并应用落地。 + + + + +官方提供了适用于通用场景的高精轻量模型,首先使用官方提供的 PP-OCRv3 模型预测图片,验证下当前模型在光功率计场景上的效果。 + +- 准备环境 + +``` +python3 -m pip install -U pip +python3 -m pip install paddleocr +``` + + +- 测试效果 + +测试图: + + + + +``` +paddleocr --lang=ch --det=Fase --image_dir=data +``` + +得到如下测试结果: + +``` +('.7000', 0.6885431408882141) +``` + +发现数字识别较准,然而对负号和小数点识别不准确。 由于PP-OCRv3的训练数据大多为通用场景数据,在特定的场景上效果可能不够好。因此需要基于场景数据进行微调。 + +下面就主要介绍如何在光功率计(数码管)场景上微调训练。 + + +## 3. 开始训练 + +### 3.1 数据准备 + +特定的工业场景往往很难获取开源的真实数据集,光功率计也是如此。在实际工业场景中,可以通过摄像头采集的方法收集大量真实数据,本例中重点介绍数据合成方法和真实数据挖掘方法,如何利用有限的数据优化模型精度。 + +数据集分为两个部分:合成数据,真实数据, 其中合成数据由 text_renderer 工具批量生成得到, 真实数据通过爬虫等方式在百度图片中搜索并使用 PPOCRLabel 标注得到。 + + +- 合成数据 + +本例中数据合成工具使用的是 [text_renderer](https://github.com/Sanster/text_renderer), 该工具可以合成用于文本识别训练的文本行数据: + + + + + + +``` +export https_proxy=http://172.19.57.45:3128 +git clone https://github.com/oh-my-ocr/text_renderer +``` + +``` +import os +python3 setup.py develop +python3 -m pip install -r docker/requirements.txt +python3 main.py \ + --config example_data/example.py \ + --dataset img \ + --num_processes 2 \ + --log_period 10 +``` + +给定字体和语料,就可以合成较为丰富样式的文本行数据。 光功率计识别场景,目标是正确识别数码管文本,因此需要收集部分数码管字体,训练语料,用于合成文本识别数据。 + +将收集好的语料存放在 example_data 路径下: + +``` +ln -s ./fonts/DS* text_renderer/example_data/font/ +ln -s ./corpus/digital.txt text_renderer/example_data/text/ +``` + +修改 text_renderer/example_data/font_list/font_list.txt ,选择需要的字体开始合成: + +``` +python3 main.py \ + --config example_data/digital_example.py \ + --dataset img \ + --num_processes 2 \ + --log_period 10 +``` + +合成图片会被存在目录 text_renderer/example_data/digital/chn_data 下 + +查看合成的数据样例: + + + + +- 真实数据挖掘 + +模型训练需要使用真实数据作为评价指标,否则很容易过拟合到简单的合成数据中。没有开源数据的情况下,可以利用部分无标注数据+标注工具获得真实数据。 + + +1. 数据搜集 + +使用[爬虫工具](https://github.com/Joeclinton1/google-images-download.git)获得无标注数据 + +2. [PPOCRLabel](https://github.com/PaddlePaddle/PaddleOCR/tree/release/2.5/PPOCRLabel) 完成半自动标注 + +PPOCRLabel是一款适用于OCR领域的半自动化图形标注工具,内置PP-OCR模型对数据自动标注和重新识别。使用Python3和PyQT5编写,支持矩形框标注、表格标注、不规则文本标注、关键信息标注模式,导出格式可直接用于PaddleOCR检测和识别模型的训练。 + + + + +收集完数据后就可以进行分配了,验证集中一般都是真实数据,训练集中包含合成数据+真实数据。本例中标注了155张图片,其中训练集和验证集的数目为100和55。 + + +最终 `data` 文件夹应包含以下几部分: + +``` +|-data + |- synth_train.txt + |- real_train.txt + |- real_eval.txt + |- synthetic_data + |- word_001.png + |- word_002.jpg + |- word_003.jpg + | ... + |- real_data + |- word_001.png + |- word_002.jpg + |- word_003.jpg + | ... + ... +``` + +### 3.2 模型选择 + +本案例提供了2种文本识别模型:PP-OCRv3 识别模型 和 SVTR_Tiny: + +[PP-OCRv3 识别模型](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/PP-OCRv3_introduction.md):PP-OCRv3的识别模块是基于文本识别算法SVTR优化。SVTR不再采用RNN结构,通过引入Transformers结构更加有效地挖掘文本行图像的上下文信息,从而提升文本识别能力。并进行了一系列结构改进加速模型预测。 + +[SVTR_Tiny](https://arxiv.org/abs/2205.00159):SVTR提出了一种用于场景文本识别的单视觉模型,该模型在patch-wise image tokenization框架内,完全摒弃了序列建模,在精度具有竞争力的前提下,模型参数量更少,速度更快。 + +以上两个策略在自建中文数据集上的精度和速度对比如下: + +| ID | 策略 | 模型大小 | 精度 | 预测耗时(CPU + MKLDNN)| +|-----|-----|--------|----| --- | +| 01 | PP-OCRv2 | 8M | 74.8% | 8.54ms | +| 02 | SVTR_Tiny | 21M | 80.1% | 97ms | +| 03 | SVTR_LCNet(h32) | 12M | 71.9% | 6.6ms | +| 04 | SVTR_LCNet(h48) | 12M | 73.98% | 7.6ms | +| 05 | + GTC | 12M | 75.8% | 7.6ms | +| 06 | + TextConAug | 12M | 76.3% | 7.6ms | +| 07 | + TextRotNet | 12M | 76.9% | 7.6ms | +| 08 | + UDML | 12M | 78.4% | 7.6ms | +| 09 | + UIM | 12M | 79.4% | 7.6ms | + + +### 3.3 开始训练 + +首先下载 PaddleOCR 代码库 + +``` +git clone -b release/2.5 https://github.com/PaddlePaddle/PaddleOCR.git +``` + +PaddleOCR提供了训练脚本、评估脚本和预测脚本,本节将以 PP-OCRv3 中文识别模型为例: + +**Step1:下载预训练模型** + +首先下载 pretrain model,您可以下载训练好的模型在自定义数据上进行finetune + +``` +cd PaddleOCR/ +# 下载PP-OCRv3 中文预训练模型 +wget -P ./pretrain_models/ https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_train.tar +# 解压模型参数 +cd pretrain_models +tar -xf ch_PP-OCRv3_rec_train.tar && rm -rf ch_PP-OCRv3_rec_train.tar +``` + +**Step2:自定义字典文件** + +接下来需要提供一个字典({word_dict_name}.txt),使模型在训练时,可以将所有出现的字符映射为字典的索引。 + +因此字典需要包含所有希望被正确识别的字符,{word_dict_name}.txt需要写成如下格式,并以 `utf-8` 编码格式保存: + +``` +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +- +. +``` + +word_dict.txt 每行有一个单字,将字符与数字索引映射在一起,“3.14” 将被映射成 [3, 11, 1, 4] + +* 内置字典 + +PaddleOCR内置了一部分字典,可以按需使用。 + +`ppocr/utils/ppocr_keys_v1.txt` 是一个包含6623个字符的中文字典 + +`ppocr/utils/ic15_dict.txt` 是一个包含36个字符的英文字典 + +* 自定义字典 + +内置字典面向通用场景,具体的工业场景中,可能需要识别特殊字符,或者只需识别某几个字符,此时自定义字典会更提升模型精度。例如在光功率计场景中,需要识别数字和单位。 + +遍历真实数据标签中的字符,制作字典`digital_dict.txt`如下所示: + +``` +- +. +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +B +E +F +H +L +N +T +W +d +k +m +n +o +z +``` + + + + +**Step3:修改配置文件** + +为了更好的使用预训练模型,训练推荐使用[ch_PP-OCRv3_rec_distillation.yml](../../configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml)配置文件,并参考下列说明修改配置文件: + +以 `ch_PP-OCRv3_rec_distillation.yml` 为例: +``` +Global: + ... + # 添加自定义字典,如修改字典请将路径指向新字典 + character_dict_path: ppocr/utils/dict/digital_dict.txt + ... + # 识别空格 + use_space_char: True + + +Optimizer: + ... + # 添加学习率衰减策略 + lr: + name: Cosine + learning_rate: 0.001 + ... + +... + +Train: + dataset: + # 数据集格式,支持LMDBDataSet以及SimpleDataSet + name: SimpleDataSet + # 数据集路径 + data_dir: ./data/ + # 训练集标签文件 + label_file_list: + - ./train_data/digital_img/digital_train.txt #11w + - ./train_data/digital_img/real_train.txt #100 + - ./train_data/digital_img/dbm_img/dbm.txt #3w + ratio_list: + - 0.3 + - 1.0 + - 1.0 + transforms: + ... + - RecResizeImg: + # 修改 image_shape 以适应长文本 + image_shape: [3, 48, 320] + ... + loader: + ... + # 单卡训练的batch_size + batch_size_per_card: 256 + ... + +Eval: + dataset: + # 数据集格式,支持LMDBDataSet以及SimpleDataSet + name: SimpleDataSet + # 数据集路径 + data_dir: ./data + # 验证集标签文件 + label_file_list: + - ./train_data/digital_img/real_val.txt + transforms: + ... + - RecResizeImg: + # 修改 image_shape 以适应长文本 + image_shape: [3, 48, 320] + ... + loader: + # 单卡验证的batch_size + batch_size_per_card: 256 + ... +``` +**注意,训练/预测/评估时的配置文件请务必与训练一致。** + +**Step4:启动训练** + +*如果您安装的是cpu版本,请将配置文件中的 `use_gpu` 字段修改为false* + +``` +# GPU训练 支持单卡,多卡训练 +# 训练数码管数据 训练日志会自动保存为 "{save_model_dir}" 下的train.log + +#单卡训练(训练周期长,不建议) +python3 tools/train.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml -o Global.pretrained_model=./pretrain_models/ch_PP-OCRv3_rec_train/best_accuracy + +#多卡训练,通过--gpus参数指定卡号 +python3 -m paddle.distributed.launch --gpus '0,1,2,3' tools/train.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml -o Global.pretrained_model=./pretrain_models/en_PP-OCRv3_rec_train/best_accuracy +``` + + +PaddleOCR支持训练和评估交替进行, 可以在 `configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml` 中修改 `eval_batch_step` 设置评估频率,默认每500个iter评估一次。评估过程中默认将最佳acc模型,保存为 `output/ch_PP-OCRv3_rec_distill/best_accuracy` 。 + +如果验证集很大,测试将会比较耗时,建议减少评估次数,或训练完再进行评估。 + +### SVTR_Tiny 训练 + +SVTR_Tiny 训练步骤与上面一致,SVTR支持的配置和模型训练权重可以参考[算法介绍文档](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/algorithm_rec_svtr.md) + +**Step1:下载预训练模型** + +``` +# 下载 SVTR_Tiny 中文识别预训练模型和配置文件 +wget https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/rec_svtr_tiny_none_ctc_ch_train.tar +# 解压模型参数 +tar -xf rec_svtr_tiny_none_ctc_ch_train.tar && rm -rf rec_svtr_tiny_none_ctc_ch_train.tar +``` +**Step2:自定义字典文件** + +字典依然使用自定义的 digital_dict.txt + +**Step3:修改配置文件** + +配置文件中对应修改字典路径和数据路径 + +**Step4:启动训练** + +``` +## 单卡训练 +python tools/train.py -c rec_svtr_tiny_none_ctc_ch_train/rec_svtr_tiny_6local_6global_stn_ch.yml \ + -o Global.pretrained_model=./rec_svtr_tiny_none_ctc_ch_train/best_accuracy +``` + +### 3.4 验证效果 + +**本例中的评估集和模型路径,可通过填写[问卷](todo:add link)获得** + +* 指标评估 + +训练中模型参数默认保存在`Global.save_model_dir`目录下。在评估指标时,需要设置`Global.checkpoints`指向保存的参数文件。评估数据集可以通过 `configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml` 修改Eval中的 `label_file_path` 设置。 + +``` +# GPU 评估, Global.checkpoints 为待测权重 +python3 -m paddle.distributed.launch --gpus '0' tools/eval.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml -o Global.checkpoints={path/to/weights}/best_accuracy +``` + +* 测试识别效果 + +使用 PaddleOCR 训练好的模型,可以通过以下脚本进行快速预测。 + +默认预测图片存储在 `infer_img` 里,通过 `-o Global.checkpoints` 加载训练好的参数文件: + +根据配置文件中设置的 `save_model_dir` 和 `save_epoch_step` 字段,会有以下几种参数被保存下来: + +``` +output/rec/ +├── best_accuracy.pdopt +├── best_accuracy.pdparams +├── best_accuracy.states +├── config.yml +├── iter_epoch_3.pdopt +├── iter_epoch_3.pdparams +├── iter_epoch_3.states +├── latest.pdopt +├── latest.pdparams +├── latest.states +└── train.log +``` + +其中 best_accuracy.* 是评估集上的最优模型;iter_epoch_x.* 是以 `save_epoch_step` 为间隔保存下来的模型;latest.* 是最后一个epoch的模型。 + +``` +# 预测英文结果 +python3 tools/infer_rec.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml -o Global.pretrained_model={path/to/weights}/best_accuracy Global.infer_img=test_digital.png +``` + +预测图片: + + + + +得到输入图像的预测结果: + +``` +infer_img: test_digital.png + result: ('-70.00', 0.9998967) +``` From e1f947b961596623b7340700f8881938300833d7 Mon Sep 17 00:00:00 2001 From: andyjpaddle Date: Thu, 16 Jun 2022 09:35:09 +0000 Subject: [PATCH 07/45] add case --- applications/imgs/det.png | Bin 0 -> 66713 bytes applications/imgs/rec.png | Bin 0 -> 13765 bytes applications/imgs/sys_res.png | Bin 0 -> 291470 bytes applications/液晶屏读数识别.md | 577 +++++++++++++++++++++++++++++++++ 4 files changed, 577 insertions(+) create mode 100644 applications/imgs/det.png create mode 100644 applications/imgs/rec.png create mode 100644 applications/imgs/sys_res.png create mode 100644 applications/液晶屏读数识别.md diff --git a/applications/imgs/det.png b/applications/imgs/det.png new file mode 100644 index 0000000000000000000000000000000000000000..6f21ee170ed272e6ae9c3ef475f60855a064cbbc GIT binary patch literal 66713 zcmYhj2Rzk({4aivWABhXLnv8C_Exe&^fj`HlgQp%va%1d9m+^{$lg0Lv-jRBd*Ao@ z{qBAI{~nb(j^lIQpVxSf*Q+oMwHHMAwD=GRgh)y8nI;4RRRn*(#>EDI-WQQv0iQ6P z U* GR}h>d^tp6z*TN{;4e(O#pl&rl?@?C`tHSgI-p=5Mj7IKm$x9-+&5%)tQ? zY{b`ZSFrI&Vf @AY*P65d_qJ*4LL9W>O%@6qf z?~6@at27RXb+ak`Lt3)kSR*qOFI9)<6-SQ8&c?$2?+Z)*+E11B<=!+($#t?y8DqaG z%a%URxH@QTu-l)$`jw}Bo`G^x95%nY3Co@j
10<;Upze9ipt<>gvIa GxWAr1dj(Qztul`tSU3eQ6 zX+NH68hVF*_{39EqHfl<0DPwg=Ud2E@Y#UJ+Q~_)!;GKx0DQ-Zry;V{J*hz9Th_$j zpnDXI@C^Fhy7JBWEZrGG0-PH7QQ$@TNPHZa?W(3t(=NQF`uG)~2a{7%_|`3V*E2Rk zqqbH5JxcidzA}DbJrKEm <(nc^KfN}=m;Z56{IwBsd-@ezSod#R?Ed>h zEnVwL9_tx}(oJ2#Q|p|K(gLbYbdjC<*4?`FxYvz^_m8Hhrwg CW7OAFG#zX5rJ|T#(A53a_HdYWPf@nOdH9p!V^;H zWwX(^*QkVi=izZtG~i}EFDxUK;N0#jeZ6KkKVe21fz^LM1k3W3xR}`A@$p2ch>~oU zZoR^{dzh$wH)rSX-@eI9N=p8C{RsS09(kRh{M^UKCyQj)RUe!+QUIe5uJ@Wsq&Z-{ z>>Ss<#z4FB4N+#W$zcQaAd>CXw;}g!kG{xxj>KM5Sr}wkM_7;;H%F7}7&TDc1Sera zWgjFzu7^S9&s eR}|#}Hh3TU#44J2p19kNyLQw^@1KvGMUXdJ{#%elz69dJ(HEyNH(6 zFhrJ0q3F%$ p!9l2M6@N^39L& zZ4jn3Rh3m$I^f{8wzlvIOAL5$PB}iPb1saIj@~a+Bjnj5tHbIdgBclwXkrL@t520h zfH+K0X6G(07sO0DR1t4ou<4onSi!o{$Bw^dE6!b|%N>k>Va_3NG;kP&iTg9?NlA~B zSR7EZ)KARUJo?+~FI c+b`F`^vwQlQb()9^cfjKUiC KcL_ zf+*%8dg_@E>*D+)E*24nm1bp}O5ipG6m`tIK$epGZ~3vMs*XpJ$!+cn*XVLvu7x#< z##tB?7QvYzVYlbrnSz`}C1E8&<%~E|I4^KK5F*E2G~PB4`e(C2uB_WX_Z(OIx?6BB z4(*ALT3tZxFi@9H=8b6Vr7~aen!~wdsGHcU;U7>!et-Q4i+Q bY z)4nQY5Zb&D(K;C|O~CG89j*a0;-l3O>r^S^)#fao{NO|XZkF@BoS~k2du&WQi5Exr zlE*@pu%lUq&sLbbzm?5`kYp#l@#5Tkd1s;9$6(X2h6WYlWFNPEQY$7d9>{%Z@IVVv zMHiR^<@cKz*Aqo`Z8JopgMA=Fve$br3(_Ps7CRws+GrrP5kg0T_)YwY$8DxbgA-jz zK=lB3-Nb~sFQ?+qM`2;%lckRE2u9K7F2>(R( x8lbR)TAZGqZrW 1x({%icqjpA>QU-gxm$)0vN zb+%H6Nw(n6oH%#LaHhSi{U=7gXa~ZZnzX7`ijq34d~xD_xS>9dNCuXc8&!f-ZEw5# zMI$^?mqrh6EI#IBZT*-$oSldAjHQ_NKr{k6w%q4mHs4003_6sF)}sUgpJVsZURar6 zqR(Y?Rjcj{rwN}=k>T3;jDFqh*vyQ9yEeVLr9oqV<1d4{%F2Yzyb^1|pQXBIoab~A zQkI?l-sZV)K+Bk)FB!>G-);{hH Q5;h2W$%ElZ1B$-RZLYW&K~%@WeDc>xnuPICDP8Ztm>#Rlnk7`@(0bJv_~f zB{H_{vU+r(N*}(>uwsDgR=#yCY+1rtd*&dFWqNxvSC{~I_AAEOxTn1oP^7KGz`(Fr z w=V+cYWSZUT8l&ulm5C!9TD#)dYi3+E+XLptKRWO+_0j#_ z;}#L(E)-rqD#Lhqy|=xQ8E)#L@JHf b>8A!rYY#}G-uO7RjMYYN zNf4b7>TEWN*~yTT!ujIg>cNh7L4s)l|ADW**E*C8`fvV%DF}lZngvJnV?MXff^om% zQ37#6qp&5nW fxp;kT&9d{qLx|4~V|ge~caR)QsZldc?{2a5fd3E% zg>5BGI4q!?X5YN;v*hU- |7>?(nLHcW^{Cn24iM#OR`v3Ep}l;>T;+ipqByGFVP z8C{67*h80f@fp slDRk!N5G-&A6t(srxTZP)Ft zo-1-T(C<773+vqb@%Z!ODvl2tF}gj}tS(WE7&04B>^1yOOit*AR9>02x_3`Yd&1}2 ztkA-^c%sfOenqChuCj~Niny}K1aWL8;V404DmlDHwK;X+8EOH j$bh+MNt_=f|@|iCr3o#e8GMOveMWr@Ec7L+-ZA7tdZ$6Py9el!8Ky z_r!6)JNb$AcXAqzAe%P0&l7(h(~@#hhSSo};LXd^7-pFVFT}kp6mb1;KDq1(pcN-y z_ iqmM#35Nnl(7$`XW1uul@a5>_WHQu`gk5CA-EyFpUBYtR31h-5)L)lf z>46+>KdDa?1EEQ2F?FM@L7Ra`fV<6#!BBm6_x*XOzZAa^2~o2M4a{lXl!Pz={-1A` zj0Z}hto8aSZR7&7u9q6_lvDxx2v=TX@>ur7Q9<05*|ZP1ecSQhJnA F3vk zjg9@9C-J|Mad_B$H}zzDoM3R1L3ndfx(X{!z53!>m!5z2)s9brG8F+Ob|@SudR%G3 zW6z^1g-xNY`F-EHYA#_6nt@ujKDzMEbx)rqW2EX`b)1@+iO(Lyxg^G|`C7|jRaMn1 zhzo7+xG}m4eh}ZgN*L!Lw1V9_tBQlj_(Oj+)0%zlhr_0BD@x6;EyeL=^Yeh(lgo|m z`qY2}_uSr>HtjT20?+0Rq|F#)izT(YFZVj<>Pr~EILZ^4bcIojb+vS#{AqYVB0V&q zYn&!iT_wj!L=#o;XvPACLXm{&6TYTzz5I3B4`b72D0Nyq8BPGmw56q`R6{k512c)@ z*B>;pf?A|9|JE!RZEb+k-Nwcr4x~S=&cRAb`D1C~wRbuCzEU-|`te(O*6i A|jF3;zwD!$F<*2_Xe2X &Lg}HM ~@B2(8B)_^bt_% zXqeX!!oT-gABcM^m|+M&x>p=UU7VfY>i#JAOEkZXhz)OJKD_=G!nkzs6acM%e^Nxm zPx&FAGwd> 6=_|4%zW8P7)bG8vL=P bcwoNau-2H9W ztSOGgzI@+7b-($FEgM&v
ou<^-@@z$FRP)9|tVGhJL=m8bF>R7YNeThS8qkp 9IiB^UH2E z9A4cuFFq`3>St4v*rE5`a$iW7ZV)^6edDmKX4=b3{82HzODIxT2r2AuhSC-vo@WK( zV-L~r=#P7+8+w@f*oK-1uCkC_V)m|-A}840L@kJu?QmH46JgOI8ZmHnv0As)Lv;>J zMp{SVNt&;85BA}A;?{37W?kGYH^R6Y!`04jVw_gGPJ(MpeI@?>(;;St;^ytnk-E+( zKP(=4_s+-X=1F3jS7%s|$ijB>Bd#>pkG(r%)YzRT)x-T6+3A;xRVl~$MkNTfoW+{s z5b`kk2@v+BX>7j3f}@?C3JSP}vajebvE!h9-gZ1J5JXZ$;7&bUGNp^tT&EMYYce)8 zbU0Qka)mJn!8l_~Qh9H>3I8KcbS=-AX83bNS<~_=zg#%waTcsT5c)e5Is-lu96EC( zyW{CJGq6%!qOp?QayPMOCgZwnd~B#OGrBxkqmixGt;ewh>W-ar^k>fM11`k!`}~%| zk3P9li<@ItGr*ScBL!bpR#e3E)6Zkk=P*HJ9?;wJOEyQJ9E3e%2Im@36QVB_AB9TK z(k>W fS DcB4*{a9Hf1U4I4L7y)gK%T>YQtCdsSc^5bmu zOijHR rdhI8v$$Dm7MOX2W3+Io?Pwb_U_7^x)g@QAyS4ktcl5VMC1QOJ1b{Cx2f8_u)% zV(kKpPti@{@5D;ss6Fhu$I<*@B`%pkhZhoX-_Ca3naozQn@jMLYppHgvdxkZ+MCbT zI|ePuFLW%|dgbq_VN$~e)~BkU_0iOqx6HOap>`s1;3Ki+mT+Eq+g{@2HcKS+hn$62 zaU;l!NeW^6w?W;YcOq=$r*A~y;UVu!t&_7egd^!Z7V~@$%&DokW>85F3znH}L$B(Y zYE@&s5^;|u&$|u2zDHL6F5^!E#Y8IrSsEJBv0YeD7K=kkZ1S!;cb;PSM=m9B4(-O& zsfb 4$zNG*H8$#^!>;PWcO#;2A!bH+vM95IZ~F$zwL7L9h->4#JBN8m)2*y9OQ)+H z 4A)k{CwvV`j%fcQ*b~WN{2*)j A@ z(9}J=&Fx}7sJX o(B9V-PVZBW}k^mKVn74CWBlaK)i1ly*`%ih+I{m=Q?q z$CPyKy1qJ3o}PH=5_6!NI#3fB5vaorJ8oMJAQpnWN{c-ab+DxIQepIaHpln7FNAJM zWO2Ev+%;pxS$>@m;LqSdx3I-au@2AOJ%RD_8$ $a#|(ZmI{(HS)};J|lJ?68Gk15WgtJpTP$DZT zEUd3|=Z|snbE`4HyO3`5wX))Z9UGjv;8T|`>r!hF>v-bC%yKsp9NGGr&twD~i%t=- zUGF=P&Q698blFN@NnBowf18QS5jp5UUFjMGFP%72l7~>}UQKkkYDCILQNNMU?xZ>E zMQvK|I8u2%X|JWx*_o~GTI}qRC$LR3^ff3pw`)oME{r2ya=0S($;CUZ*z0(7p9&_r z-d4-uRO1~E8wy9~k@4fPuBLSb&b_8+Duw#gA^SuzR}S--FY$Wg?ou;x_RDm= zwbHD&ljDB^Mpi!~lqSc;MJC!8zs k3DEpY*)i9Z2;N9ZqwWACBDdHaJryLMs z >D?bOw# 9fTCFEc8B zcPRIO&nT3>>k+BkLnPK|ADdh!9QVD>qx(0DOt)D8S^&T+;G)l_)E&`z!^+dO9^Z3* z;dPvTPUIl{JDx2l2&h%2c?5-21OzgG18Y#WO_S8s)*fG;Y(sAS<#ROg{ClrSSJt!F z=H})O>MFj)QzVcNytRco$fToax $ae|Ko}M*&?zG%#m$3LM=+*|!q?=ov;Q$ab XFUtHa$&SS^%hCP zN5+NNpJhJ`coI!rZHquoJxciOdw1q1%}4j?GvQW&P6>v| TwEA%AY+t8c0U%jPDDl4C!oStG&zSU 6^#O#Bq6sDFtr_j?~7N$#kwzt!qR+P!~YH~QX){auFQ`cwWc|MiQqb60<$G*im1 zpV$gQ_E~*42hM#O*|uX+RQ(yk*hgk!LSzC2*LUXTtUHco3^NTN1GY9dd-&+rhRCH$ zUrmT|r}-9^lpucn6Lo5_KENElysTxj_?_pS7v76w-F01?y7PSEwb;4o{r+=_U%%_? z>NfX8#xVqsUrmKsYc?+J3Haq%-lt(XUSzk}c->$$zP0r}h9ODn5}U4z(^DkCUZuuh z3_O-=_cqA`yLLU#66%TQPaER(Jq%ZM?_RDh)8AVOS(`uHhBzn={ZBWp5b>2Y$1pKw zgh5}Mec9w5+K+Us4qD6bwgV?Y9{mqe-Q|{Tqd-IzEW#c!pvPA1Sw7iU-#uI6l#8cW zt-qcbr2?C%MrO75WmP!Uiv5l-;ZH0bm@ou7yey5xZE()%14rTaM%+Zq@U?&dC`eF3 z$ndyh4SiBL)dY;P@%Fe(yI>QfrEI>rhuN&I3Uz#TbG(FvtTf0Vn0#P|2%ndOw89q$ z2q_Oop)m8v>}>j^;ffw2k*agi>z{+3q(}GV
dj2P~Tk@!FM 6SprPfJr}*bkYzDLvg=ZYJycJF=Oa!_3US z;M$Lu-Ze3N-V_Ho8?&>svL+Kakq?|ml#-7i9@t}3vyUlB7M4Yc@geyYUcr;g2#M75 z*vG`J1N(;r2@sQL;m%@SpJ%%FoR>np*PPU(!$eyPC7zX*mEDu+zCT9JZ&lk6GDhPc z9U{6uiUJyJiE$G#4}2kd9m03>FR`hw8=0sKq?NF?^R%IsVoxuxz@hKj1uf>#ikUzb zXxmXJgB{4BY#s0s6Brdm3^Hot%y<86PONK$+`+q3FFk@cu{Y?f?W(1}|F!9gt%-T& znz#e9!-d>j);%x=%KuteD&rVqVu{vdCA 9$lG$kmraVu>=(lc;Mguw2X5;GU*6F*i6|lA$lKcNa-;(LjkFR{HP`C0Xy3%y z#2Nn&!nP&ZM#rCTLYVw>rn0!QnjxD^@Cl|&_D*<^ndyR)lzdD>jlEX{=UnSr2v@rj zE0qX}ZZEJ`MTiz^={tkpRp$+Pse=*mnIOOE^lw*7`O-O84< cyRhau2Uhm?6ksHtd)(aq{_ziSG7G zL!%3xBekzw4@D)$w^ Zk#zFv51=Wq~29Q5s~jeO%6G;-v6J-dpUxoL}2G@1nlZx z+4A!T3DPmgUBG>2n^i}yWMoIP-&|Bl_7;VVcr}NbNKG2xh &af(_-P_ppek~uI-7*e=fNfi@|IHx>8CTi zK4qEQJB2-9JUO1RkqZ59c)DYBxZhRoA)dXx&hVXRrYNgSv!3pfld9Ryn;|A{F_Yxn zd;nMj$;uZPyXR+S{w6%u0TyiD;h_UCkI}7>CH7~YwpacOFt2d96m)rY1-m*-y0;gP z$WlrXq08L28{_U%s(kYw0)ZfPMdX)u01oaj$|uu5OdF|yE32^;kSShjhG~`<(W4 zms{ct(?4w%`Vf*7KbuOTf McmYtqYFqpx^Xr!8rf5kuB{xJ8N9pP?d;WiXq_;y z4lj{jup3tU`iJ~s_XAUkkxCijm=`2PgA!`}^TtiS3~M;QRIig9JR*h$^j;#_; 2A@jetm%LMpaWGfUN=Ri!Q?8Cy>0}kLyyq)k%b}ehk7m zKU5=*?`NKUx>& `3t0H>A+Oas=gq~1$83|IF_Yi5 zL#W#&-t4eiG7 zHS;~Q+XySRcU2CXW-`zULjoyhM&QAk(c{?y(J%S}dJNE6vXhf(e85G^+D`5MDmHE^ zCg)IltJWZk;G5dOW_zZI{kKugRl;bCUwsdU?sVe2mnE_H^${uQxJOoX;(h)uU&{3} z>=-2^MI}+xok~jX-Bl`7vTEQCN9k@o)flBLW@e1``t2$OU;6QEt|MP_Q;vw7hVqFi zdSDZsE)`dFsizIOYovxb**oT9A2}q-OgX$XFxATh!w0;L=W U@ L$8=K9#&qo4xKLb{o525N@SdNwkV&Cx1)mb1vyS!1s= V1sD&8N!(MI`RT4|&Jc8I<= zL+>`eMN19;Nfnl_A P3KG`YLhhX@G#Y-vTZ+R!h>o^g!#>WYtA0_ InGdG--M| za~?#mOqZ~DYi1@5{e!?IH+WxYq5*nyvrLS&f8bs0tLS}?q;6E?;Tl|cr|=FulgFSs zhW`gJhoc!KhrxRXnf(~N)2+cQ`C6Z=UsBfxZ6@@M*Z)))#GDmzNEqWQ7{=VM&&w2E zya4H#vprs74OklZg7@R>Wqu=>KKKbE)4HF!J-_AIrFVa_9b$fFK5WcrswA%C_Kt10 zQ|s=SuJP!M?WSS>JS{@gbC7aOH~+OjMaI6;Z{0`H!aoNy;vFt`BPdk%Z)8j*`&*9C zbhs^q#M<3mq)mfMzSiR?S3yC+d1H_Tlx}p<2fPqX)A!6k$S*B@1((LorR(PZ+pUsM z8}*G%Nlu$-klAB-N7OZ+M*8r9Kg6=5a%5x#RJ@TKl|+G%QcWa`)EiXj%YVJRF56>I zA|oQuN*_ELS0Zx(k3`^x@hC`Cq}+@sn}PkfhBL8uu^FQ{_E(ivabY3mLV$&P+HZNv z{x6EEBJUdA59I* D~n}E2T!}=m>qcf7O)_GHN zqUt3^7=n)xN5ePR#qPt0peKQ)E@MgiBqSu(uCAv=hB}OOwnC|5_6z>R^dh8d7vL75 z>jDt6CnT{wYMj=iq8P+;!IT`}u`ge~+yrTrlAew((io&)0~sGSw}nksY}b~Y*xs@F z5trUNfe=w*Q$O|5zmna_K2%EhS%&BDubZ9dA_8wsU%qlMz&SWXWG3x=ZQgx0Q7=WX zTH||D3y!qS*NCM1TQ!r<@hj39U<3kd48ntZ4aPST*rxSQ_vRW>9b}7*8Xj38=AV8^ zx;3u0XK8!0nTnW8f9fvKzTUi?RGI~IZJ?aQsY?wF z4#sqLbp WD}ZW($VODT;|K zmiV}%mYHiO=hQ~P5#M~pE&|L5 zy|=Vf08?V<;{?F$81yU4iHXgTJeRA}4?r_`Z)PS3E)3K#aG?LGt49k73qJ+uIwvQG zd7bqBuYO8=EOb(+sHmWe95KTbmu{HL17bhsk-eUp!qT `#jOu>^YWhZ^WXb~9D65N zQBy-R5m6^>D{9&U!Iq)bw{9lR)H5*n3&OpXKGrnv4kUb)?d oy_HT+myT;$`RW+qezLpOLa#y49!w2X|z3!vIOm6FPM#jShaU$KRMnVm;DP3`xW zNkx2%=bS7k4@Z*c@-&hc=*GLy0t3OwmDsxpj_=KzH^1ABO{2gp=K26i2VhzI2I;Gv z^5#aq_G?vo{-{b1>71SZhw2YHO_A>_e*k#&Np}xqyvxR5Rw@5i&HQ)o-z&r6@XO;7 zb(hWI9KIKoZ(g45&yV9Ud1nHYvOQL$Ps_wKo(xCG`5DXudio!zC`M6r)x`xH@H1H{ zz6aNR=jo!JVd`n!?e9)cPq!|PV&vzvfD1IdDG;|$*rD<=?fD{)`_2#ztBtZ}on>E< zVDrL_jP3>T&V!d)>5^VTZ*6NB18^vO1}erGYrPtPVn{&6qd3)5>b0o>WY_^$)5UBQ zxO(H;e~Fj7^S8UIr*KNe%a*5oPq5pn-jne Go;>L{sE(DboCL3GF%!^6Wp!S{gf-r3nX_gg{?7orhg3BjetdJ7xd zSPUyFdg61rnJ3$rW(cY8r#BV&1WCFAxG6UF9%#r`Ab?4jr2c~HpZm+s)m2*wxdCnm zO|Tazah1~_Kuf+ZY7Z%?lQy0b6;uD+xRx-VlWwTjJ=510fd(5AA5{{0tXy4%;{U6O z74tqX-J7kWS~Ih;QMI kxXLbL$Z?hu$G1;+%pyv=*e`*JkPvZ$B9qgh3);~cyqzc<%hpVE%NFpUAWvg4m zEtyQb>rAm$o|=`nw?uo7hRBkP6w03)HKd*)Yh!I|t0pfm4<%)k_ALacAD}O3d_Qv| zJVZof zy&r7`k#junNsDx^A##fBWvDZT z(DP4%0o}^V%05#nTaC1u3nxjd7yq__0aNR=t|s#L)4t#B#X2yUYTXabV#d*T>2wkS zhCBX(>fL5ba@pY{THH(iv@gBxn>Ur{19G+N%hTQI#iXb8K+teLKUh5A$=%$vnyq$_ z2hLSAlXQRm*DTHajf rdo+ z&ok*CzbVo_`M26j`l5}<`O8AGMQ4ZJXFf6N;>Wci lug?z$QC??zXuZvpAQka-Q`jLtKc7p|?^c5I;BdLCvbL6X?@v~B z1ROQ6eSL8>H8rLA;zh{i {v4Ff4&F}O5p2gmJs zU=V*3P(Q)_?G8jtf;=fgN9TN_513W0^*s3jg5e &p#E-Tc)OD81U zkBo`}E#N`i%ZH7TvhmrVDq&uHsG0_fD=-LxjT$`fXRNYtXM{^=v8gBPr B|ZfMQ5NWVXp z&{9>xFNWVFxE4NIAgunPoMX?(#@u=S;>C-=uOLE|rnum>4$Hy+F6tjXd? bljX8pJ%cc6PWCTe_V#?_ogyw<@gPy; z9*$XKy_yOL2*{K{R@lu;J>lm5{-y|x^|IKoPZzUr6UpOgf=mr4&dpUD?)a?L#oU9L zSi>dSm0&V^TcZWCjg|-mfb02eO2-%Lr~&|w0lf5h-1|qu^jRAJh0?A+k%e`)WDiiL zb3h 0?@-D!1u(nd(09#uof$k_ksduWY#I8HM^BhO<{!$}ly8N$maAPsg_$7P<# z;PnGZDI9J+Ekg5@To&2RDUpI%VAj)Q$NLmyRcJj?{|SSh>;`4r<4){NKKrXUDfb!@ zv+h1a1_^%Zc@cu@Tyo&W{M{RxoeueBmk&$RXfA2IR0heP#ak`TNxBoV(zmvj3yLtA z+SS_07hR2L<5vQK1PYW?YnXiZN?PBMP9#$FQ%iusFNn-q>7)&I$5#|mj=dRmcY#6> z<1*6Izcw~Tffx9>EhJ^66Vv-)d=J3IjqX@hbO+s=Zz=(!_5RKCVSBbuw?k960{n_O z%=-<>I_p0})iDN-VMqq*Svc4&7zR`u&c6gq5}%V%9hQ3kMMsn7B;{$lxnpH4#7W}^ zijMX5j*gDf)QDEQ8MkpRnP`u*ubv32W1{gHdCqQ3|M=W|bQoSfn`o6Jg7llm+J0hq zHp_527_*M4tM1&Xg!D47dAD%kWwkF6m|dg7wfnc%^rfL tvz$bL7?LC @e?LEWd<8vRe!fAhCGd`7@W^0| zd`$64ZeVuB(Vp$Z*ZuEik$evtwIO-gszUcYVDyj?(DMMUe0$k@?Z~)>207ksnG$n1 zzzZym>m(AvI=5+QZ+;LCP!Dk6@Ekuo0NUWEt1~ut(k(BaA?rHnPzrq;qXfyHwAos0 z3sD}~O|$?VbQ7e~VmsGca`o<$pxuOiG6u-(tScoQ+$~yiSZ8b``ss|yl`JHi1462N zyT?v(_!w&9?_jU{JEMlv!b*Z>{Cy=Ye&wv##j`G~(hA^4fd& z6KZpFQ&p}jD9{1p5di_g8)M_~zkgqA*hgz!7_j*JIwvsEFKFveVSgMNdIg&8(9n>E zzv@GGz=huOTm4x(Rm%eV58w-+BwMV#&=kRs#MlJ_Jea%q6c>4&R1HWPsnB85x4*~p z$#nRiwzpj(`80KzoZ1>DW!ofb4`pZ^*kd{T6{mOv2iB{qb}p`*V$wD9vjO`J9`RUW z5b$keQAiXi>?(rVv_2pf0=x-&z>f(^4Yi{p4AMqTMMZ_yxWdB1NHabM{8k@avfG0$ z{>gN!U)cj>M9lrbgs-1*`gz`x0F!SNxhOTv?Jiw!xI}kc@^B*oZ+^^|6tc;WQ+3XW zI@D!oadewbdd6K*5jT4JM&Q#EU>aaWk(iy76M*#<0e;FkOPwO^r{dzNdL|@9g9xND zXA8(@K&64M#@OllZ>2|7v )F3@L0aP<1x8=|)M zc@Q7FqlKKLMP(k%>0vm;Z&z50_1`w~9~U1D6KBQ#EKDpV4Q?g5b@8$60|s(H&mMX% z7q3(!FvOm@@NGldk0Z%=c1y-adFUBYN4%@6O=e8HfG)Sp6zuf6-v^KmIkG@nIq9+~ z6~UQSbSVOZ`7M Kmztlb|KA+*}M34 z(b%ccOtjRcBG{Rzw}s@ac=; z+;4LILW(Z_U%q_#J3UP&1=H}^f$(m3iOkNvh}Pp+NfC7_flk^F!vg32XFLqgo@)3B zr`#^Tay*^=aT05bc~$#ftN7E9FwgpqS!2vESf_Et!0 8!22CuSH;8G}u&{58}8M2dbnm_mPE3Rmu=JW&|0n~ihd98}PB?I5-ry-!R z!I WEv7Th_*kS@4q?a+7j5Xq%+qS5!(C?p!2O#8 zj2ZKHk zVPN+lh(BwE_!cN-=n)jq;@G(;0++uM6A|U-<-Mq~n;*NruIDkT{|>MvW^hl^?1`BK z?t|6_eaPG_l~o<_$Ur5gAlP667yUzUmaA2v)NZym2XuK$vsScncz%AaZyizDg=H;B zi(V1{JuH{kw~$^L=Jm~QFINel ><7(6dQBv1(K zP(PY^mH0v_IqAEOf((T3O+=e4YZOD**-3RiovBrq{vu6pZ?CDZyDtC |M*{Oq2*?fe#w!9rE1c^hC((ANKVprv6;8E&%_ zGe~;A9`3hVFHDs71Je?mbj%Bt;Zi8bV &fK7x_$zS?Ul=eVIfj6FH%C-A;e61bP|bAapJ E3JOxpakPn@Z^J>2 z_>!2|w%E@Ta`?vMI^h<2didt+HwVQI^GJUVM!KVon+br9C_clXd+#}v$cW( =v<4A~x$UJ% zoiD(Em!tqxr|}>HDgmB5P*hwNngf{6jTF@gqgPZx)d7>7YuvJz?PoPO*87JABE-Ga zNlv$}o5Sp2s;rqbUs;B7!cZ&!b?YLzfjR@1lhe)wKZCfdDnPjd?PJ;L=ap~~U4iL) z;BeY>(^i!xg}p9+{TICsaKnF(?t|ALtOk36n?M`@%n|R*PAFB@$n>_G9vdtzgE4iO z3Q!h*ul@w`9W166@q&x&a2m~=mdHw=o?F;~zHr-!SaJ&I*lh;ZC2x!YcEPobg{n$W z3u<#*g4*7+NRd8zI8i>rW8#fM(kdmVQ>yZP#Efy*9!@6W{+5@=@eNag#57A#af<6h z^KT{b{o|yJjDB3jl-w-bw6d~6uw A(A -W+D3>Xk8eyI`li0XdiC$n@*dXLk zLTV&-eAN0*NJ@b}z3=VN8$`FEeXsNx^xgvm8RUDsq%EH8J3(52T!<{5Km@^}o1TBd z6TkQrMf@wL{rM&)1J%x@d6zR&XJ sJ|KoN`kc?kAe0WEdc*4wD z`pV71u%(Cc2<-qo6%(WF=UI6fQQ8h<((N`9X~Lf|04RabUeH`S@?el~*C1h(7z7h+ z7|isNo`P}72<`})W nJV69E^t;nzn4r(L7g~Z{WzWLvRp!u1m>*a`p^SZ z%s+j7pUR0nzEs5JAGza~HG!%4_ars*&CULRW}}HskUTa$ci4Xzm`3`#pvZ!E*&GFt zprVu+&`T)at{yO07Y_xit1gSJSVhIfXq+I6hXNEo!|QZsvRMYtT% 8j^JRYyOIm{H<;W202Mh{J;!)UEsjSCz~b-(?Nj$V!*C1u(IoOZYLQ zFeVG^2m^$MP#mv9j~UJixF0;V6!*va(szH_& ZB74m zxOBgqB>6Ut+gd8W=exF`8t`8$0RM|G7%iTl4V3}lRkS3m-|nfg4Eoa*q8F@xjvtfA zuO{0>e0rQ-=Y|wum!dD~Y@qqJKXkI|(->8353Chn8;k*`>S1T-R{@3k`-HNf`=6h? z^9=&7KrcYZxAb|$+q?0hl=fxPfF0_Y-__}^hHP`187^2v0*ZJ(z@0(o)&-S@G_6^! z#M#9m)Ff|nCTD#8{wyt-+0Q~PJ2wQBQHC!VDw1HG%bgV8TFxbvg8MsF1zju6A-CwA zEjFUX?5r8wnkISbZCXU_j0-Dvm%~Bb{Zvg9B~HXW!6jP8!QA%Xvx8x`TQ{LKS#Qip zZSbEtjEuzPM}PZ;d?RMXVY_*#iSyzT&!5%cHi`k~5tSe${f*WH$ ivJ8WZ#!E!k~mAdm%Fj#fYec${Iq-8b)JZvlj~4Z D?#M@-%9Np=2eNw;s zuPE1{D(!LHp@8--8p9iZcmUkGA%eTGZE3FwT7o~SGWDu@BPuwmmyPwmut@3+#hZ^) z42+BsYCPf$!Rr+~#|SI(6oeH%2}Vo8zc1Z~ee&PajuV)aJ&hNvyJph7tJl4wS+oD+ zqM5Q~Hl@qY&-Xao--&j^%BVUnS}{u~%b?@VO{rflwOyfPSFOYkhRNKP)u`#^bm;3o zr|OgR&$aoF@0KR}QXF@q>CUO`OPT?14ol{`yDC{XW ~}O0e|Ysxp6J =Qq-26|X|Os(34B=J|?Z!%dBZI~SCb&1+B{p~7HJRbeS z+Cq{~On5m#W%sCyN^Q}O(@oVR86+n2o2{IZ(&vXh$(>Sg>aI9QzAPZ%J}*e5VdfT) zZhdtP881vv%a1!2wPTfzxh3oglz2?h`%62RZ`9;-o4qjg<|1&9kfnnls*V#Di)oMsi%2NthIjQ1)W?@6XIuyU> z%`ynFcHN>X>VP)hZ~lAFQEASRai9O;9PvnO3^`mBFTAK9ZzHVNAL?Ai!#O!@&Dy>@ zX;y&JUdeQqIvP{;^2FQhX*U01WAd8y5xOgA&h^u&JeZLsz>;$8ebqnDL7jM~iMn*9 znZ!XFgROpWK7si$Q?vV5ir_qd3Te^?Ldw@wAxg>NQtH%9)~y1rkXX)AUvt1gKHV=@ zZ)$th%*;lrcbkob9wm7=DEvRynCdbXx{~Z>x=DvDMbp7YPq=TpBW<&bYc-z#O@-Me zLl0!T-$O$NUS3`X_gI7)?`$P2bltrr@@oWKG2jCLHn-bx=-d{F>#3<&E>ZbdDW~PH zvJra4a_^yJ(rssF=VV@5ua(A8Wy@BYL_32U;Xaj(>&prUn~@BK9%frEj6LoyaWMrw z$^d2%-P#UFzYk?8WM6IiLp`ChOYA3G;ZV^$>k;P1Zfpo);{I0akMIBGrR+0fEkD(Q z&nfrf#!i}d)J+G}%a! KhCW2KdJ-tM_yJop3<0Be)O>d4bt5@CfOO0PL(Bq60}Y6 zS{Vksf z_-$Lw*%X*M?J1(8yP#N?lPnwjt3+uTJIXvhI%=4E>l;OBrc;Xpdf5jw&K42UC=}ng z=FsqP0Svv!BnB82Jv-R-$P4>wUbF=0amp&?Mq1DOMLD?y?-Xvwv$kI4N(RrYAAfW= zy)*4TS+$_sKik4nOoapABmBzW+yh&RnR=j6_X}gTuJ6u+ThkhAzr5Z=z 3%D>#RB}8Ri1zEwdF!#_y$V!mId%! zfl(CyZlD2oRBQ3xF*Tl3r}`!*Ew7zK)iimfA5?uH()6O)9h7Ojw^yym&^i!cFZ=Cd zUnBtI5SkBi6AZ5jrfdu&3im(#{YZq;lw5Gi1_{j^^!=YG?pyIkGAjLV?Z3wpWs_mu z8p4p*dxp}4%kEtuv&jIiXNYzJ9~YpVPtnOI+d~eYnXyp}n1PJML$rtSuyi++Y+qmR zo>GNwGWrupmICTZy_3Xe5|4c6lW`Z3*CNeuBsYY@`cyWh-OGt3?-velRD3s%9)O*e zVIMv|gK$|CBYWCm?fb0$S^knD0l$s%?F`kVO?M1{kp 3 zfb`?sYD}pcFWUb6c`v*O-||s;`9yUo5X+$7hXFkRG`dipJ= qZn2^l$E4%DYuJ!?+d2Kkpo)Xoo`PhyY+Ev>QNEm|v@d>7?(pp+^$N^|*FJ8Qu z3)MWCBLQ|YWbzN-UqLU|jz1?Bze!629S5suSVBtz7sFp6@o~{OfBe6$8*1B1o+V~R zDRM=*uRj0l++_3?dR>>a * zC?95kHXfEUIC0WHaeVw;&ja@QRYg|L#VbVM?{*7Ck74RXqqO*iqRWOyz0aghBw+HK zixXmEm@&!$Opb}3vLDmBn%Q@N!~w=Y^v>d%CdG%Sw?#$znZ8?hrP;b&fD)fc&n>Ou zg)@y9y>+I{k6Co-#gP4%dqOj6+LYXJd&H4)eR%wRz!(A+CCqd=SdP*&Gkc=rJmSAv z+@Mi&+rIk7$!^hgHeIjv*vdzRZeclrj3;N^$DEv#M9gZRU9{GP(~`Zjvm XbMS=H@V69+D|0bhq7KY~cve*9t(vXn*>H8tDD>q%Vs#H$*YlJD>y?iiUD zf>q$N2t#p2UDeao4OwjhWD3UF>h^(}wgB^Wb?GiJ_DtG3LR(BJ(C!0w2Tnq;WXZT> zcmRLN-G)Bv{1y7`&KW+j%3pVLf`zk_6jQ1Ox0Ynvsp1b8QzOK+cY&>cXn~3M5n0Rx z*@(hfbmHdVxam>;Z^^aF{J*l9N0w5ouHvVkh|A4aS$U&qgw7=tfK^9erS@<|=)}a` za}?LC*By|Yft8h6&&~xVNmC?ZKAZJ5QRWrPdCIPuCjl?XK(lKD1}w+KvshsWb!E-+ zm6HU5d*cM{JUTE~woT?9MT1-iUr0mR?i-i=!?#*-V1?GS^nm9GdM!Db4!9m+>6Zg2 zi;T77h2`+59y5KL7OFMVxChU+2AgFvwt+n2vJft6G@2g##ck*~{v&($TJ$!sbT?;{ zEZ&2>bzA1z$XJ6(NyL+NWyeM2iO&o8!yguHQctKJgWX1-JhRm?JF}WAYrnrZlA!`9 z3XUnQMk^nHVHz~dIWXpd>yrmFGMMAo+*n!TP>S=w%h=Cc{G~O+LbKwy+$H1rFa4!5 z mjGTKMvwN{2nYcwFIa*t5kg-JI@3ylL4sU<%1A`0m zS&Zs}*K(M)a( nW`iDCFTIvjUD1ffXyC=oSJTD2=F zu28LDmSztbOgTgPKELrMIk~r~NnND>x%8QRGFZ{uYd{eWP^pQa?U}w2soL;w7f&%m zuwA7=8~0WSNg$6JWvL{P%XUsE8YnJ-?3P_wSt(rz#Bc!DFGxy;*^$Qpla0Y-O5B`x zS7r6(3`HJb905iGBf}4X*a4@~$cs46tQD#B_JwC+v-R^r!|vZZ%F5 ))%y9Gr>M4F~}AP$q~p4y&&C+aQYpF$}E*?6qlOCKidw~dXHpqi4~VAz(FlzjNd zEh#AphHe(*$vJrd43=0BHE8&Fy!h(Ya&-8PMf7;LuAZi{q#&)k5?>d&2)^P{w}g@Y zzL5s4ikCjR;RaKzV{%r}_4lh@areP)Pl$2;z#gg#ijc8C(v|r3_UABbZ~7*^EI!w3 z60f-V*62fMUnXR=l$4a!H UdZ{~XgVd*~=QjrKw~MWUbO zeEWt0iOyK1yXa5j%f;-3pue)*E#d@^H7`fpXc3U9;n@Ou_zPIX!LsY!DKM%)`)o^7 zu*+OfDCQegb1fsiN;ij_L8&IK33vhsZMzY^`mx@hDKB+;1PE`mPwW^=oNUJE*9oM0 zPk(8Hl7`H8?(4gy%|=FFiZ!B1*&5+Z2v#`PP^B@musi}r3|6ite@y)Psu9XCaNJU! ze`fo>>DSo{G*|qt&84HOL}$i 1WF?SB*F0zhJKKh?*L{E<6FhUKQI8-i6?*Zc(NLhO&<7fOpzTG ziZ{cS(!G~YzV%3oJ I~axlCM;b0h2uoJBkb(w6S zBug3kxw%Mvxz{O$zg5B1(-e4k@cg=M1TjwDVj+jvuE-u~u6S7-slYZZE$t_idw?rz zoSqvhv4&^&3xW%PT2G+?w=_Vd-ta^Oy8;yuJbGMi?E#ufmUXQ9aEOevPW;o{FjL+~ zkFPK0${`qS>gww);Jwn>qPp-v4kSkj5b}0CjP%6qoi)q7g&_+Dm-PFncdoTz?RMd) zgCiyxAk;m2nO^a%DMs<~%-tt5cr>rVf=@S=?#}W__nb=Fiq!lsWHYe%Kx`UiIsKAa zfhM1LPzUj3e#0$gv5LLp*3&zO@z1zg7+<2VVJ PX=u(*Uq z^MC%ee?jjy`R)P)0PS8m@JB#a5X{@`!^F&txpj@gz`Q}mQ`r}n9Bi33xteSOJaI_F zavq65W2pGK;y34}1UFTcLh$0p8fU)dEtu%W#KqCRb%WyUVyYhbtlwT~Qk+hXFTI+f zmr2QS9#Qf7qUH|Z_GEIp@UZtMhyT;gG+)*kDY-4xa?L1NA+ys|GJmApnRc#ycV=V6 z*$V|R;f1(LGuxTlw>(L-H0kpcu^BejF%i6(D!!LPT&2Yza0o@W_^`0Bz@R+T_$+jE z3qTY4v%JjI<^@!@|8+&WA5105hH{{R&2B(t_JsFI7E!o1cOqV#JzUYMYORVg{TwSz z7>jpB-utiKwAtr>hHHJ+5x_tZFg+!b6rojoAfYJ&kc{$a`|g~abjw1#pp_*>I_(hU z4FsicoVCxbOCk$FE Jqa4w|#EqB12d5IesPA z>6ZJVMN|Q%gtJn}+XO*&DWL~?3BvTR*!gHm>gqD+6=vKjU$9xl g!S7Dwfq7Xc(I%}IMz1WWVrl+yH* z_>AQosg-zKS6WZ6@7zcXt!&E|r}p0Y+A;uEbJHcbbdXee+|fG97(TA%D^yc9jRzDa zhp{KDId%kWH{N^#!N%$}O>RqYPV+C}EF}F_ zjH|2)z^9 %jS)ZM| zyPS!RotF8~y$=J11%`&7jHqB#Z>{jFG x_3`Gl&_uNa8Wff^nT2bNoBB6 z-A$j^Nw++HSHF!V;dI`-)u}^D>5!+-(Z(MJ1l>mkM7np^n7BAS4bQ)7+Ivr_XBV&H z)!ks4F=|GwOA)tyw><|>gSMI%l0Y%cwKG?Aa??<25UUWuC#+pQ6QcVm$62>0ok!#B zP76d+?!?SaWD?xgp8TbyeBtUqcWe@q2$h2ib5zeii7@f N;6p(0*K(-dgnKN*WNdov}ZA`T5F4MlhUzY4La&DGKK6Ot8>*h-w215 zO?a6zc4spL3D1T;igPsaa#IlcZrgpcL*m@8Hm6VfNsoX<+_`IBgkeCUfRLaYlO4y* zCIRkUG|vkjlu; y(_6GtzD3I&OYR zFn3v5lr6HmySt0=HzkkAOB1GCeu?L$h(o)~Lb+N96E`~7h~AdNX3Q($z17ErbXiPF zKKu>zJ)~5p^Di;+SsLr^?j8M36H ;oeWyxFC6i!Lw$TgGW1`&8yr?Ky z97Ic+&s|$76bvy}jx6Rp1IqHHF@UWAMWE F{-I7u^nFw4>v=k;?OepLu@baJv}4zH$= 6K(wxHN9(UPZ6ZcJA0^_W!P^zuTbrepR0R8 $_|p_j^BOrt IK8KTz7@(3 M4)Dy#4}%C98EyPko6-?dXd%rM1LD! 4Fpq{hIwyW5y$ zX>@LP2CZE_Bb{lj@3iK7Z0uBZkV_~H<+sGDV^wu^ES;k{%P(1FRHm(B27NI9W}n2% zA{j{pjB91+#=oiz#kJ#i_?+IlZ2uKX7C*5_5T+$eBa4Qg=H=-l!^XM(Yi+0}gv198 zE=5MTs{4mCI<0GuM!B($ahf9dj5$!m?8@+0y+0kAS&3`yB1XStR2aJvcF)a{Z<^fD zVtT=Qt>{Xq1 s|h3-2KSiAFoyC z+rAGzRQ^fGs0$xbIJZQsR`I4jw|IuJvrrg$Yl?b1=lZ`dJ${p~4DsXJ<7=7)m)O_d z=q1zqSB(!frXZZQ6r&-zp>*BzghL*DCfHC# zy{cI&Ms#5v=oESI(9=1h z_?r-AezwWIn(F`01qdHS%}26axpp^*QO<9d&Du!e>?c$D3O9GDm)>qysib 8UT#dZ{yo2<~=7l*NwKzXEh$Z)Z=};xn_KBSAr`i z@!uq$R!E93Pl~nZXpc>$LdQ&^PHvoRsfm0~qMWPr2fGZjbK^P3`Mb8htr7WTCw;ME zuXJYLc9lB6nYw$=?y}U5Yf)fN4O{Bko(cc_tbaja4WblRhpba~Ch3^E_ztEkGN`%s zOGWb#pHgP?_XIp!@2owK;qh~&YI4p`#l;p@j9O2-MgK(e6l7Fru+3ke6GDUBv-5qO&DFK5CA16^K)-Ij0GAj=ES+b?BZkYOe3=<-Duvdm= z?pP7s**SCiq<-pM;01*&*M!$QNoV<|nY=f0R4gLBs>3C>)fTEfSZL)`(Bz1 jAoU|ySvs9!_z!Fp)4_N ze!9$^XHrQ4l -;8YPhz5&1 yt(hGIR z9?4x|6|#2bCXP4|5#pPXOTTJH&$r=f{1J@mx7${9|LSzlcku9EU5fnfFpo$dWWKCt zpo@6Giu3KZ@0sFr?$I#%opT}n`P%SL$)B1RTrcDqv-ZAjW @O9_r+i7XkWrE#?-Th&ZyI8su6~+ugy?x5OhLap(5+5vfpmBV%Q~`e<3uf z;KymgUXo;uGBuLUp^UIy-eV`e;2MyJF!(+Ap`U+_l(o#)ku_0Bw-}tnNm;aAQ~7q1 z@HBVFcTluQ(29X{9vmVWnVyG+X#;0UxA6X 2a& zsp4wmv(@rStgCg&qG|arL=~R(CfQjNRbsWBaK7sd96=S*x2@?if|9V_-aJj?Kp~Bz z*vov)?;bX@cW`hJ?L`@^c#Y;)(`@S$(n 6mY9MUCRb2>c-9l}9b~u_pADH)p2ro|i`jwz{<^k1Jf!#l)LY&bUqL z;B8snD5A3{i8d1fLz8>k4~T lT2rr}mApNWkD zYB$Tx(;+V&anAF`R4L4ivuh&34~_Wpk9ihjNcgMC;9FnkIzOc|UNG0-dyPAd=cGoy z&rF!iv>b=Uss+4B6)|a+bDEy$PLq^Q*mVY>oYMhpIe)