From 35c25d2b152c3290edf2bddd17dfec64313e8c19 Mon Sep 17 00:00:00 2001 From: William Palin Date: Tue, 28 May 2024 17:37:29 -0400 Subject: [PATCH 01/20] feat(text_extraction): Add text extraction api Add new endpoint for recap documents add new file text extraction --- doctor/forms.py | 1 + doctor/lib/text_extraction.py | 326 ++++++++++++++++++++++++++++++++++ doctor/tasks.py | 32 ++++ doctor/urls.py | 5 + doctor/views.py | 30 ++++ requirements.txt | 1 + 6 files changed, 395 insertions(+) create mode 100644 doctor/lib/text_extraction.py diff --git a/doctor/forms.py b/doctor/forms.py index a3d14e5..04c229e 100644 --- a/doctor/forms.py +++ b/doctor/forms.py @@ -95,6 +95,7 @@ def clean(self): class DocumentForm(BaseFileForm): ocr_available = forms.BooleanField(label="ocr-available", required=False) mime = forms.BooleanField(label="mime", required=False) + strip_margin = forms.BooleanField(label="strip-margin", required=False) def clean(self): self.clean_file() diff --git a/doctor/lib/text_extraction.py b/doctor/lib/text_extraction.py new file mode 100644 index 0000000..d00a3f1 --- /dev/null +++ b/doctor/lib/text_extraction.py @@ -0,0 +1,326 @@ +import re + +import pdfplumber +from pdfplumber.ctm import CTM +import pytesseract +from pytesseract import Output +import pandas as pd +from PIL import Image + + +def deskew(obj: dict) -> bool: + """Remove skewed text from a page + + CTM stands for current transformation matrix. + Pdf plumber has a method to calculate the angle of text which we use here + + Traditionally this is only seen in circular stamps which confuses the + content, or in perpendicular text of the ninth circuit courts which also + confuses the text. + + :param obj: dictionary from pdfplumber for each word + :return: if the text should be returned + """ + if (matrix := obj.get("matrix")) is None: + return True + + # Remove Skew + my_char_ctm = CTM(*matrix) + if my_char_ctm.skew_x != 0: + return False + return True + + +def get_page_text(page: pdfplumber.PDF.pages, strip_margin: bool) -> str: + """Extract page text + + Using pdf plumber extract out the text of the document that is not + skewed (ie a stamp of approval) and extract out text removing blue text + + :param page: PdfPlumber page + :param strip_margin: a flag to crop out the margin of a document and skewed content + :return: Text from the pdf plumber page + """ + if strip_margin: + # Crop margins and remove skewed text + _, _, width, height = page.bbox + bbox = ( + (1 / 8.5 * width), + (1 / 11 * height), + (7.5 / 8.5 * width), + (10 / 11 * height), + ) + doc_text = ( + page.crop(bbox) + .filter(deskew) + .extract_text( + layout=True, keep_blank_chars=True, y_tolerance=5, y_density=25 + ) + ) + else: + doc_text = page.extract_text( + layout=True, keep_blank_chars=True, y_tolerance=5, y_density=25 + ) + return doc_text + + +def page_images(page: pdfplumber.pdf.Page) -> bool: + """Does the page have images of a certain size + + :param page: pdf plumber + :return: True if page contains images of a certain size + """ + for img in page.images: + if ( + img.get("width") / page.width * img.get("height") / page.height + > 0.1 + ) or img.get("width") * img.get("width") > 10: + return True + return False + + +def page_annotations(page: pdfplumber.pdf.Page) -> bool: + """Does the page have annotations which could contain text + + :param page: pdf plumber + :return: if page has annotations + """ + if page.annots: + anno_types = [ + str(annot.get("data").get("Subtype")) for annot in page.annots + ] + if "/'FreeText'" in anno_types or "/'Widget'" in anno_types: + return True + return False + + +def adjust_caption_lines(page_text: str) -> str: + """Adjust the alignment of ) or : or § used to align content + + § is used in texas courts + : is used in NY courts + ) is used in many courts + + :param page_text: The text of the first page + :return: The page text + """ + for separator in [r"\)", "§", ":"]: + matches = list(re.finditer(rf"(.* +{separator} .*\n)", page_text)) + central_matches = [ + match + for match in matches + if 30 <= match.group().rindex(separator[-1]) <= 70 + ] + if len(central_matches) < 3: + continue # Skip this separator if less than 3 matches found + # Determine the longest position of the separator + longest = max( + match.group().rindex(separator[-1]) for match in central_matches + ) + adjust = 0 + for match in central_matches: + match_text = match.group() + index = match_text.rindex(separator[-1]) + location = match.start() + adjust + index + # Adjust the page text by adding spaces to align the separators + page_text = ( + page_text[:location] + + " " * (longest - index) + + page_text[location:] + ) + adjust += longest - index + return page_text + return page_text + + +def page_needs_ocr(page: pdfplumber.pdf.Page, page_text: str) -> bool: + """Does the page need OCR + + :param page:Pdf Plumber Page + :param page_text: context extracted from page + :return: does page need OCR + """ + if ( + page_text.strip() == "" + or "(cid:" in page_text + or page_annotations(page) + or page_images(page) + or len(page.curves) > 10 + ): + return True + return False + + +def convert_pdf_page_to_image( + page: pdfplumber.pdf.Page, strip_margin: bool +) -> Image: + """Conver page to image and crop margin if applicable + + :param page:Pdf Plumber + :param strip_margin: bool + :return: The formatted image + """ + img = page.to_image(resolution=300) + _, _, w, h = page.bbox + width = w * img.scale + height = h * img.scale + + if strip_margin == True: + # Because this is OCR - I think its reasonable to crop half the standard + # 1 inch margin - this leads to much better results and helps reduce + bbox = ( + (1 / (8.5 * 2) * width), + (1 / (11 * 2) * height), + (16 / (8.5 * 2) * width), + (21 / (11 * 2) * height), + ) + image = img.original.crop(bbox) + else: + image = img.original + return image + + +def ocr_image_to_data(image: Image) -> list[pd.DataFrame]: + """Perform OCR on an image to extract data + + Convert the image of the pdf page to OCR data + :param image: Pil Image + :return: A list of DataFrames, each containing OCR data for a block of text + """ + data_dict = pytesseract.image_to_data( + image, + config="-c preserve_interword_spaces=1x1 -c tessedit_do_invert=0 --psm 6 -l eng", + output_type=Output.DICT, + ) + df = pd.DataFrame(data_dict) + filtered_data = df[(df.conf != -1)] + block_ids = ( + filtered_data.groupby("block_num") + .first() + .sort_values("top") + .index.tolist() + ) + blocks = [ + filtered_data[filtered_data["block_num"] == block] + for block in block_ids + ] + return blocks + + +def extract_with_ocr(page: pdfplumber.pdf.Page, strip_margin: bool) -> str: + """Extract the page using OCR + + :param page:Pdf Plumber Page + :param strip_margin: If we should trim the margins + :return: The extracted content for the page + """ + + image = convert_pdf_page_to_image(page, strip_margin) + data = ocr_image_to_data(image) + content = "" + prev = {} + for words in data: + for index, word in words.iterrows(): + content = insert_whitespace(content, word, prev) + content += get_word(word, image.size[0], strip_margin) + prev = word + content = cleanup_content(content, page.page_number) + return content + + +def insert_whitespace(content: str, word: dict, prev: dict) -> str: + """Insert whitespace after or before word + + :param content: The text extracted so far + :param word: The OCR extraction object + :param prev: The previous word object extracted + :return: The content with the whitespace appended + """ + is_new_line = prev.get("line_num", 0) != word["line_num"] + is_new_par = prev.get("par_num", 0) != word["par_num"] + prev_end = prev.get("left", 1) + prev.get("width", 1) + + # Add vertical whitespace + if is_new_line or is_new_par: + vertical_gap = word["top"] - ( + prev.get("top", 0) + prev.get("height", 0) + ) + content += "\n\n" if vertical_gap > 100 else "\n" + prev_end = 0 + + # add horizontal whitespace + content += " " * int(((word["left"] - prev_end) / 25)) + return content + + +def get_word(word_dict: dict, width: float, strip_margin: bool) -> str: + """Append word to content + + :param word_dict: the word object from tesseract + :param width: The width of the document + :param strip_margin: should we strip the margin + :return: The text with space + """ + if strip_margin: + left_margin = (1 / 8.5) * width + right_margin = (7.5 / 8.5) * width + else: + left_margin = (0.5 / 8.5) * width + right_margin = (8.0 / 8.5) * width + + word = word_dict["text"] + conf = word_dict["conf"] + if word_dict["left"] + word_dict["width"] < left_margin and conf < 40: + word = " " * len(word) + elif (conf == 0 and len(word) < 4) or word_dict["left"] == 0: + word = " " * len(word) + elif conf < 5 and (len(word) < 4 or len(word) > 20): + word = "□" * len(word) + elif conf < 40 and word_dict["left"] > right_margin: + word = "□" * len(word) + + return word + " " + + +def cleanup_content(content: str, page_number: int) -> str: + """Reduce legal document line clutter + + Scans containing line numbers or bad scans have pipe issues this simply + tries to reduce the noise and artifacts and align caption lines + if easy + + :param content: the page content extracted + :param page_number: the page number + :return: the cleaned up text + """ + if page_number == 1: + content = adjust_caption_lines(content) + + # remove floating pipes + pattern = r"\s{4,}\| $" + # Substitute the matched pipe with an empty string + content = re.sub(pattern, "", content, flags=re.MULTILINE) + + # remove floating artifacts from the right side + pattern = r"\s{10,}[a-zA-Z0-9|] $" + content = re.sub(pattern, "", content, flags=re.MULTILINE) + + content = remove_excess_whitespace(content) + return content + "\n" + + +def remove_excess_whitespace(document: str) -> str: + """Remove excess whitespace from OCR + + This function removes empty lines of text at the start and end of a document + + :param document: text of the document + :return: Document with excess whitespace removed + """ + m = re.findall(r"(^ +)", document, re.MULTILINE) + if m: + shift_left = len(min(m)) + pattern = f"(^ {{{shift_left}}})" + document = re.sub(pattern, "", document, flags=re.MULTILINE) + document = re.sub(r"^ +$", "", document, flags=re.MULTILINE) + return document.strip("\n") diff --git a/doctor/tasks.py b/doctor/tasks.py index 6c51d38..f37dab7 100644 --- a/doctor/tasks.py +++ b/doctor/tasks.py @@ -22,6 +22,12 @@ from seal_rookery.search import seal, ImageSizes from doctor.lib.mojibake import fix_mojibake +from doctor.lib.text_extraction import ( + get_page_text, + page_needs_ocr, + extract_with_ocr, + remove_excess_whitespace, +) from doctor.lib.utils import ( DoctorUnicodeDecodeError, force_bytes, @@ -621,3 +627,29 @@ def get_document_number_from_pdf(path: str) -> str: return "" document_number = [dn for dn in document_number_matches[0] if dn] return clean_document_number(document_number[0]) + + +def extract_recap_pdf( + filepath: str, + strip_margin: bool = False, +) -> tuple[str, bool]: + """Extract from RECAP PDF + + :param filepath: The path to the PDF + :param strip_margin: Whether to remove 1 inch margin from text extraction + :return: A tuple containing the text and a boolean indicating ocr usage + """ + content = "" + extracted_by_ocr = False + with pdfplumber.open(filepath) as pdf: + for page in pdf.pages: + page_text = get_page_text(page, strip_margin=strip_margin) + if page_needs_ocr(page, page_text): + extracted_by_ocr = True + page_text = extract_with_ocr(page, strip_margin=strip_margin) + if "e" not in page_text: + # It's a corrupt PDF from ca9. Fix it. + page_text = fix_mojibake(page_text) + content += f"\n{page_text}" + content = remove_excess_whitespace(content) + return content, extracted_by_ocr diff --git a/doctor/urls.py b/doctor/urls.py index 54e0788..e151bc6 100644 --- a/doctor/urls.py +++ b/doctor/urls.py @@ -10,6 +10,11 @@ views.extract_doc_content, name="convert-doc-to-text", ), + path( + "extract/recap/text/", + views.extract_recap_document, + name="extract-recap-document", + ), path("convert/image/pdf/", views.image_to_pdf, name="image-to-pdf"), path("convert/images/pdf/", views.images_to_pdf, name="images-to-pdf"), path("convert/pdf/thumbnail/", views.make_png_thumbnail, name="thumbnail"), diff --git a/doctor/views.py b/doctor/views.py index cc2cbfa..16b1de6 100644 --- a/doctor/views.py +++ b/doctor/views.py @@ -48,6 +48,7 @@ rasterize_pdf, set_mp3_meta_data, strip_metadata_from_bytes, + extract_recap_pdf, ) @@ -76,6 +77,35 @@ def image_to_pdf(request) -> HttpResponse: return HttpResponse(cleaned_pdf_bytes) +def extract_recap_document(request) -> JsonResponse: + """Extract Recap Documents + + :param request: The request object + :return: JsonResponse + """ + form = DocumentForm(request.GET, request.FILES) + if not form.is_valid(): + return JsonResponse( + { + "err": "Failed validation", + }, + status=BAD_REQUEST, + ) + filepath = form.cleaned_data["fp"] + strip_margin = form.cleaned_data["strip_margin"] + content, extracted_by_ocr = extract_recap_pdf( + filepath=filepath, + strip_margin=strip_margin, + ) + cleanup_form(form) + return JsonResponse( + { + "content": content, + "extracted_by_ocr": extracted_by_ocr, + } + ) + + def extract_doc_content(request) -> Union[JsonResponse, HttpResponse]: """Extract txt from different document types. diff --git a/requirements.txt b/requirements.txt index 953bd68..ca94094 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,6 +8,7 @@ python-magic idna==2.10 img2pdf lxml>=4.5.2 +lxml_html_clean numpy>=1.19.1 opencv-python>=4.2.0.32 pandas>=1.1.1 From bd2c7cd07b5e104baf420163ca41dd009da6cd4c Mon Sep 17 00:00:00 2001 From: William Palin Date: Tue, 28 May 2024 17:37:47 -0400 Subject: [PATCH 02/20] tests(recap) Add recap tests for new endpoint --- .../gov.uscourts.cacd.652774.40.0.pdf | Bin 0 -> 45085 bytes .../gov.uscourts.cand.203070.27.0.pdf | Bin 0 -> 94496 bytes doctor/tests.py | 58 ++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 doctor/test_assets/recap_extract/gov.uscourts.cacd.652774.40.0.pdf create mode 100644 doctor/test_assets/recap_extract/gov.uscourts.cand.203070.27.0.pdf diff --git a/doctor/test_assets/recap_extract/gov.uscourts.cacd.652774.40.0.pdf b/doctor/test_assets/recap_extract/gov.uscourts.cacd.652774.40.0.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0741378e03a442da5291b2e3535d4d5811314274 GIT binary patch literal 45085 zcmeFZby%Fq_AZ(PcR~m*jXO=_PH=aEJ2dVzZh_#z-GaLWx1hn@CAdrQ;1b}#%$_|n zd!M`abI*Ow{p;7z{Z)On>aDfjT3>Zl!72&`5itf3BO4;c`o`!aA~S#qU~6cB$jb|q z0o#~D%s>DT=hN#SIRJ>6m5B=|W^M%mI{?M33?N_;u#v4Xn4jMf;s7?VMs!U(YP^4N5k^sZ)f-ReT8t8(@Hmt)PhYS_Sg(eDt_{MZl|vYplC};&S<1NT)Ou-*P<)dccQn7)44-Jmiw+QDC)I3dF2^a9lh*O z;)MYh7L~R37?bJDbb@UwCAldNiBM06hBSU2popT&@#R7)KK3kY-M!&9ntE%*nVtv{ zcBY_zzpOtIy|4OqfLBs$AYF76eHF(18p&?K@tDgG+s1fps`_M)(7PzKb*i5%*HYeE z=kvR5$tc@qj$vFQX@<@zEJHa%8r#~AO>P-CZf6Fc^v5-X7(fY}(pBL6t=EGOICx|s zirr>L$e?IYeo_~XM;M2Rs!Vvi=Ctak@b85Teff1itk>!U>(m$Y7nl~P7hY)vS%+JH zw5~ohSWvF(tTU=pvnroou4=Kp>$_|`yt2<(U$oEJC|=+08V*nO`K*g=Gxp$J=Uj!o z^%&h6e(Do=S}u4~?=X7O9&{r5OQx0QE7>hi^$39p`=`@_lu6sc$07MmU_E3dLGRsd>@$KDR8)>fItWQW( zE4q-)QFl$kp{kyto{*lW-eMVXYs$~2eGyOh*>ju6s!|uHV}VxBRu{=*giXjru{+1* zm+Pt(lP)(%JYiAYNNiNM0PUs!ig)!=3Bc;b?1U zkPKL$BiC}!kY+dMz;#-6#M}tEn8;wfUz?asY&C9Sy#F;}nK+``!Nu6(WWJJz4cyWl zXxw}%F>W+&HCD-({w2ssm;K}YObR2ym{cyxxv0aauurCd1GB@5ur~5s7WAUewtp-zopihhOPK z6xe-1n`Ec2iYV0j*-sH}C~lI5$R33sMA&28mBhDW1B_p4h+Ia&PKe<38&1e*N+M|p z5dnMv(vtWZVhOQu{fG{J2NZ|K6q<*$r{bp!TriRCs4p_xU&?!vbF3=5B0G0%Y*IGD zypnh)b*qnk5J;^xLsjJJ`f>SAm|2EpWvl^ zByuGbA_;4jhl z?iT!#uFDUF-#>Eo)h`VGK>0rN;E%2nA4E>y-r(_5VE1EhvYc|=pxiLrylq5QTLapm zFn)8ort^gJ2|8YbyVkpgBmX9_Cf@Lp;~Q#yCYl#v);pRlYIzviEG62H-&Ew@sz`n` zV?xQIEzZX)4j@qxzlcIcwaCn34GWxv$CJ$21z6;c*Tkk2;wtG=*S@0-&r-#cwq}j! znS@S}@Z6+cdLieK)-1F9p}Ze-is2UfE9^Y#V)OXKqbl|nE~qw=7g{41X>km3sRD&> z4#NQ>;ms?Ib(h8K7hwHXv=;ULpMD~=v2<~Q-$-a{#Y!geg*rRPNONFub7W1V!`No9 zurs2PjEQ;4=c1Wer@82@uY;q1;3ns2Ys?*`jT44GMgiva!@ zX*bU5mmPwmGZIiel2>n=k6i3W-$iGU&Rd^_FGPIfSRw;In_S=b>4*_^Cd)_fyha8E z*KmxdUS~+}etOt~((7p2BssS~`*}z1eJrHUP_Pmmv};@y{E(s*0KXJ$xd`Qyi?pB? z?WG`RLOT06BtkrEx03mJ_dZ=ze%d~W;^~_NAEEVzSE}`O@0@S?mmgnnbGr!Dl+xA%qGtT`;YIG@wcMmP zFM@I$7w0s-C?@0nAQMNH$4^<8AY$eu;UB@W46jV;xWKEWC08$s8qCG;-Jy>9=B6qi zKZmWhwXspEdyKAHHzL$i+Jy6-pQVcTs_tiUNtemCht}81t;IXdulEc~^;&-OyrE%u z%-_>Y+3rSmG=~c^OADdTv>eLvOjh251O$i9>`?wQ&j1*mqk`@4HsX&#fsnD z64Rj16NZhv2vB$Irezi*n4rSlhz%7^*-zRvj=kAkO&=L9m@;;b=PR7o3gVvCkT6PY2gZR@@ngKKBLC>N zQpQ&cB4cQ*{bcRc$+z)|*M-AI=^RL0*T4k}TwL&Y9BK{CFPCZPx4wJtK5Nojt)~5cPJ$F1n>^y*x>V~+Nft!bhnLlDXGL%f zpE?bR@lIElRTO)X2#9Eue%1`rl^`%Y)^xZ8@s}1ekN}Pe4fo(|{$5LKk_sppR=O3ly))u ztG4}}C#q$Rye*-Zhd{Ero0GCs7o)EY|2+Dh$&Q)q znp^RJBysIgP~nP6IcjW-fr3jKnnz;x8u^vqtFUR#YdcEDb?-2CqcGMcOvN#0W(8t+ z*mHm4%!!Oh)>LBZ)>KeYWo8BhxA~#;E}S0W_h@2l5yO(~#LgLSW8ihi8w#^A4-pNi zi$`|YW=v5EE9G>EGJf3KRouo1CWR_fMApmZDyQTai-YMwJQUGnOe@_N5&OOn>2q8T491CUFhU!K3L{8d_`kkatmp6@H={86LGuUd_*o|T?WyDjDJ2k&Ydl}#9uCi-FPVPVOs zZ`6qm(48ZvL_%gp59aog1H{6x80H;!6zfyxPI*o0KF?H6f1aVC$myEd6(kC?Fmg1P ze2FPT$Y;#NT|F*dR*|(^h|exVL&sItL$?}OMA6HXi?7V~_1uhpCO(b*%{o?NoIP&r z+o95Sv6L{F8{{@G$D#IWCI=%*ss_Nf&lqvQ?Ba1WI=#aX=BH%#wtFnSV6 znVAxZm>bHJKbzk3d&2XO(=0OwM}>l3i|3Lr6N-h1Fo2{vL*8++nQn8+t-6*D@gH-d zMTDMR+nR-rWLNI8Vhy{sZuflox#(sv9eF4;AI|g;X(hrXrsCAWj3FwssdnT9eyw2g zVG+G=`kNi$rkJqy`H5KyKCHb#XD4+5Y_ffnAaHg+o`kkcj${_5$PEUKoKzbgEpnaH zyoQEV27^+H~Pr3zM%_f zc32++s`qd-CetLaKF1nuinNOMI>|t{9;e2LPTmqFe>K}{(vxdOn4b`(U}`f~?5C<< z3{Vh=wmjU|9OFPEGOBrzf_3fab%u5BB>3i49s%Q+WXZZ~A6;C88$R)Fp9!&*(qaPY`t`_@^%({*B(k-m0% zuCSMRn0dBC_EQSJsC4IE2X%P>MT!&NS9(_?ruVSEO0a{u_<0b7`iP~d6THU0rLvWh zg4?c$UC}v21rgSg+!+%RKV!Y&9w!y;a235T!Oh&PV3TegwA~^R!|;$#Ip&=;ok2Xx z!osx^2K`fbZ-h{8&Gux5vzwhd<~JNIBg+`6)g7B#w|7&1QoW&Mck8W}k&;NOakY9_ zmvp|pz4KZj!s9ps;P5xV8;pkIo@uWT1CQFOoV)sJ)zW=#KV2jz@3+0PJ`g)E9wWju z&R?)faOo@3X4DdCa$6-F3z#)tr65oyUA}^z%H&ZZ+#7zIk2w7*NHGgfnwKiNFEhY@ zqeH3svs_cBh5=mfP$*MDPKRPvYsx^~P_oH5yg7S8kKuQeS})sn{~i5XIqxYoxVFaE zt#2rbL?!(c_7OH|uKZPrG|6VgCfJ<{Qf9vEr=VbrKhA12aMK}I3HiU&%$X5Wl*H`9 z$8H24HISEU!RjzaQ8<}l|Il2Y=~C25OG!dlxF)Kn;U1ATw%4j<5^j3eBs54<6RlZ{ zVuP9}l%{uieo!K}_`;f-^Wd$VX@KxzCZ)&bvM@`YK}0gc7)b%tv-cJ6sC7kSons#Zzt z#k_-RmE6E#;${} z;R8mR&2|;K@+Ei14#(}6xW^i~<34?%`CtHX6_Ga1b(ba>3f4leCyh|<673o1v^>)< z`sx;skx#utof@B}i{OV5hddx-^i~ayb*CY8K$!0B+aPyG?dfYBbV{|^Jw-075>wRLrea8ZL`{h6^%nzm z+-e8Y98Gz!<4wQl+_!fM0_l(v1vI{HuD&u2t2Z$GInWe!;*%n8LS~F zhOk19gaVT%@(RA*3NnJaGp%AmE&J(nl60Bf_s?%-ku9?=SXIL*P}1-UUJ7y2kRi=N zPG)$&ULGuXEvb}o^xYD@g}Apsw|+cmoh9*LaarHKE?b211I=JT_D8Gw3MFXP&6wBw zf-P}nbe+*suy{FKb(qv-EU6hb_P8{y$}1<=b5qFiT#6rAT+D-eKD~&c29P?N(l6oM zxzTSqFaRo3Dtn5J$3P!CD|+8Gq3BB-1+&dzX$+ZcWg~gRi?UOZ7aD2NV>mfhJJiO^ z(2|@pRsd9S_{a;=0Tatj6p>rAQ(YZ^eP$> z*O6^8G9|S*csY2Qnp{}Rvm?QZ65G=q(i_}%9ji=1T79G6d8%yvr8(oX#=4FM59r_| zb4zq1L5`65T-|Z{2zIt#-L}Ql%qf~BE7KbySH^)lGD~bdn&F12zf!`qTU)#f`h+OE zC7LcvY|B_aWZ~6ne-J|>9L9CALG`741V?GHr&;s!?v7eCddxo2ME-%w1UH206FG(w z4)h+t5gkQIwaRf`W-&Jug6XC^|+rXD0Z@j8JOiCD#_ zlOqioUyo;{mX|g=Uz${PvYU_Dc3jpuQNidxZY@;FOCpm`yej!6rLo?!ZrO>F%}NFzqDOFWAa}ZOLi(%_fRlhmIGBQvp92l0$MsNDypPP$-G`>9okWf9vHT36S zBpj4<0qB2q+uKIE(S6{KylLUxTKZ-I1RiYn+bComC5czEh!3Dz>ZDAzlYDkN8|G-d zA@+itMMv@riDa=M4ce`2^dlWf4hpdcUXPA!)ycAJ62s9Ma`aBzsuvPNcPmkE0G_-n zcfSKbQ_7D_*dQndW09#s4Gb#{%@rpd6;*O1FC-;l78^$9ki35a8t{bj5RMv%Zde@ZDhi+JyrWT&SFe!#B@-@_hULGYBO*8Zmz_iV% zubny(YEUPDc8Dkew~jYVATyA|FgzHr1u0ds%yD?>kSwzff2%O^$mC%{IE0HS{hWv$YaOp-zjiG){j z5P3m*@YeH{ICSkQ7Gk$hq@7Mwa)6BtXEVZiGwa0G+es1{L-$uG7@YavtST0g8B~L_ zhKCU25@<$?xI7|sKHqC%RCN=&FY0)}uOfVqo7-TXM~LhcT-{buXYf*&D#<&6cJm#( zG3J^RX;6AKiCH22vJ&xyXv={(ZamG`Eswd+0o2pbImqCOI0vx5+L=vy?5PrrLVDtw zkZasv2uMx+Yw$Of{MOLu5s0|x*J{ZPOyS9wpO6T$u%fb+KI1tHY*MXo`|K@p-Tq3f zzf}HZ)p}7|v8RgVwJ~#)s#hstfOVUo2X_>Pw74-~jcyLrh(f8={sBru-vSdSJChfg zv_t<3>^96=_-xq(lrGwE2w@28*I&WwX?`hhGnJBsS6W+ZD{kj> z7I#=KYqpoal9xKL@q#Ru^0hMf{c%d$saJ^`jOI37jzoE?031l^gZ@sP2Ez)jtS?d3 z-r0OO5)8Gp0X7Nl>`*rpcs z&{G{3R3vNjhKlXS)K`ULr6t%UBW^}zxK4HL-FGukoik`25S&C1GNcn)94w3xM=2!hAc*#c#}#}aBb4K>@m-ZVe4Sk zfPyEW-73^bL=dNlBA8yo;=(GXGR$wtC2)jU5zn#3;B(~*XV~h?soLUfvf)&n$r9Mn z7`gY1wHWCmmoSNIwIpQwkDZe?@=jvI;fD`?9Ei{H`&21se@SR`Z4;K)iGfl+EjPJ|Oq!#W11A+|d)Ta2PV0Tz`Pn#H zT;BUVwBw{Uds1CT=H8*9V5ROzdyB<0s`*iZLup3(^+vH|dJB>969Z+I;r(jU`rP=_ zOi2cOEv4=e@+rD2qCGaEvRbobyo7*n1o%U1?FXP_U_TyV$g`x&5REyPIavV*!$PVHNfVG@U**C#q{%h{M<~12hulDm zzBFd%vr7tF{A+3U^_XbmKBY>T(&wni;wAo)dv#$8D>=!-^{~^j+N0G;l27}TQ(tq; zWV(;?OWlzCdPq_O!Q^($HEoo-_mqpI9Z4{f#s3f82`5s1;>*vD)g{pbd< zfokY$`Q!6D)iXQa62Ziuz5d1QO*Sf>n>9f(;iROyV^0;$c*w>uo$r)%CW{fpn(tJg zsEl`BASkbCix)ZMq{)B^!+HCJ2JuP=JWP;8Coor6k;$*15hO zn778&5jGh5lMA}}^o31B&6MfFNE@nF;<0qzi(X$PP8qI<<=f%R(&FY{0Y)3^J;PUF zUmQ|()6`(y;R`wkP3R6H$hmkOg|Uwb!HINMH0IG`-y7=LDH<;u^M*Z47Gih!-&7RY zE#3)siETH<4whc1YGUaS%YJIaix}t`*iyW)iGBSwTtDo%f&`H@Q!?Z@qz!$vo27a@ zYi?CHRwz}L2|KWO?#oJRiP;39zA0YA6{XbCf@3jmLoCkvy$2&qi_^h+#|*=3c?)ev z7sdu}qhEM>7lE-T5o#(+`$0p=Dc?FDv0SF}N6%4lmH1~~j-%gvr?O<0cJ^AtT6Wt- z*l4(%3$`M&xuss?!w7f~>ZgGq78r*4q4l_y&*}h?PQ{9+(6b{HK8gb{Yo?4LI8?ZF z;fFnp8$>xO;Gv#_*Be|LZ#UR-SgSD{r}TPpmnMr_#9V&qm(L{`mNGktcZsDfz|#^0 z>>+}J*AdCcX_+eOxsWl2cG%|*>9@^=+Jch_GJQ(OVhe06~Fxi8!;kZjGHA za^aE)zL!ySB&_6Z!s`aF)0(KQqSVmEwl?C$UYn1&>`X?U`fjG4HJy3gc&^2J?)C>s z-i$@Jaby&q65gB(Jvb#mX=Kxyh-68Y4bZUq4MZ*YEV`iq4; z!L%tBhr1>5mx=|`LklzhsIb89N#UWMFUUli>O8!*auNNT>7RL;ogFMz&KrKs<&YwU z8X_jhd4MVbohh?!-uI)7R;dacbflIduc+!H@$h}lcJ#bDTb9nJ7USaP3-GkAhUBEa zc*nS9gwq#e`2>;LHYP`(OnREShZU4>l`XsW& zvnRZM4q+@rPb1qH<;WndAgCSYGEh`jsn4lnPyz^haUS}DexSeu+6|B+h6x(>I>8^`gXL3m;GI10_c}6MA-b-_BgRdP$U?1?m05IJ?1e} zD|az6KiF7|4tr%}DEH_%=gt~8GEm(+UWP;{^@_n!*|$4Jyou1`@;+YW;MNa;k|G4y z`*ZW6%IyWipEeUB$E=R6u6=7mdmvGdf?2Wq*7Rjm#|L6>s$DS&ld7$-qq&{E#fY>2 zs)=q=^znzEtKx|E*WK5%T-e>W&a-^eQrJ&B)q(a`oo}&MnZ&;{ zHEGv;MqpVHrD_CB!c-b6ryV-y=vb99VwX7!`XW`$Rb)COYfr71HCo2*N9~7wvPHkU zD<~G&Fzm2fCjgAR;N)lAg58INmu+}a(y27nRZ}o4a%p$0Xaos=k!D2Y8Fu-`R2e$} z^TRaCt+V^kNf2p&T@QaJBVstf=}z6KNB3ymJ`;&C^Zgf_SzWcrPrY->+N*Xi?f10- zpCsvI6vQRQB6n3H^aG2hrmWh|UbNX38WWMfsC;QVzUhPYD1D^EcBQ7atn4)!X;z7)OBAODy7oV%r<_ z)fP22f0cfMhubWG(No2s*5edv!zdD^CL1VMJQ{+h^hM|(bTG>b?csnyCXE&8?-%r z_tlBcz_+GNmc5h&ZPnL(rTrJ_RT;A3kMhzNKxXu%pJLh?@F64&M?>K4aFcmvvthu1 zcSzP?4Sp>|e9TcW4s8NXF^^YDE?y|^UH4r|+-6hL`^?ZoiI4#GpV=RLhvU_Q`#AdF zSxqF$QTM12GTG&)>otQ-ihz()!exX zg-YzS=5QYIq?zpM`sJ;75+@S~2Qzb3{oF1?vqiUtk7$>43Aj-6E8f7onE%JTt6pk<3{8omEx83Mr-0+1K zgw4$q?5GPa`@lK}wMm*xNH)HSh=gmIF_^HGdd-`(Ixo0)<^<_mGb|mr%L79MJgbST zPV$#k#>tlvC)Ck7J3b7*uIq? zN(k|pXvV7i$&lfz+A{RH{^Lgp=@^R64pD#CMO1KNOuDjAqC;erUO&wSPrD<9qNoW!euCM$2qBA6D%*hxo z3%A&w_O=0WPi0UA|GhR|V(+;4Nxt47Uwhe31G-a1&tUZ|okr3(S1Gyo7PUGp+Olr7 z%a8FT>BYJ^%U`^u?~62@B~e@kgyQgA+4`mkz{2Nr=3IG_Dn;QFp?Wa$4u_P7jE8sg z(wZ7=Sj!XM#d#jJ6=F>~(j_%fC7+A)Oc+iyTM}9)JqlhLRY=V!Fh?20$55*xB&sWa z?-uiOU`M^aiF`0t_31EZy4%^mFXDxoJgs#>YS-+4SPJuQ_0hZ{cxd@k!80Ni*s<&hHzJ%U%SrE8Z35d1j z^1uQul&j(OrXNQ`UhnI_lnG>M3xd6E}aaSuDbm8 z_{UsAnqU?TB%dS|qXlJk#@=(}{ZEHT(avPkq_QFo09mn=AeA7MP?fi4K8U@A1{=ZV zEXlMi(FJylMCNTLsL4S!8Cy5yecqDXMPTrOO9E9F{b_2nkAl_Uo+&6j>Gtluew*=- zK!{r-1S#4mC5#pNhKqAV*!QBiaW=%y_UI8~Rw>e`sHyL)~J2X0@hz6xw)v!J0W~Zuu3d^@}bv1 z8w&KI%Q`r^y5OU)XuphpV)ZYlQlxWq0(UBC9;I??*jl zAe?_BzxNfH5QwD?38#N&72Z<`M^@JJv-M4-f@~V63tB$ejV*lS4NaIav=AJm>)h{b zq=OH2VY(YBZfR}pK`7Y6tCrLXHj zu2kTLg;4H$9A%oAw0@>{q&=_voorV*spTJuK~9FZS~4zoXPYl`6>^1UV0UIVnk`j15+M#KT$Ufnu*_V-h1(irZwu#m%hz9{8g`wTonap#3|t8Zr>7 zDA@PrezxLqv4`NQNj>F2~rRS63?&c4!^^N->8kaFg zKQ9a*beq+T6}@YZBMW8_7@0-Qh5Fj?dE{*2qcOYr)>ZZagE3xxxa;+P5+z1Xlu)QW zpPu2uvjiU7Wm@?TfHEi9ZPkZ@8on)U@pBj>0%*REns_3@wD{zFlNxJ0S zN>KedJi(~FF=Kks0bxu&$dlVmb`Z4fquz;k+#hD|CSN4f!CLv=)F^wC3VIt}QqON9 zcjbnBM%qnv3Ejx{!Rn8kjj#WC!{~Nt-4#u<3jXZ~m(0Xa|v1QZs(Iu_! z(TBX~-jqBenjmB>@}YFaWx*#NU2TY9i`@9`#+b_eY~I?{0A!$Sx#wZ*kIn!)A=`mmdTiP!02!A0EH0VI1G4Jz{4F zL<{(0vA4T%hfg|Md*VEPeHWm&UU2*nxk=LRGJ$EHdhMosn{Q>edRC*2EW3^DalF^HY!iDwOQ}=RJmYlO$0m3)JUgCW?!5yl@`gKFaTAi&yL6W!zR>;A zGBeod@wt<)CEae)R!1$g&Cb4C?E_uw&_${Wwk&qh^_Dk~ci?Os->%Ly?#D$3=VVDa zMbfRj@LExiGGPJd<$C#J9Q(8pce0nmM1NrHA=OnHuY=OOtJN`R1tjN${8bNjWiZnn z*SI*bO7H6>#_ZburD8^TugkYyt_Wk|EDybtmUkYy4JWUh2uAp2t_b|nKVqX!NWy(Z zRp|8%gxWzpCth_q4rP0LGH}(J9?~GQGCK+D?_kVg@V)Do<7|4Mk)Ls_Skb6yu^(KSRLw- zbDQ0uv*-xd)zF=kAZJ$q>$F1Y%lDPs@88S#VnV%)m5eVdR;evc@|UQ_+(BMScl=H($H?U^L|wS>KfTfgFm zvOLRrE0UaWnARy8idI@9bKi127Mp}0?P2q-tZ`wC*5)?mwbgLHa3>7wIXJ2b?(n4z zuVzEIDmaYT*ez|$dxWIv%I>-3@m@fGKksQK!k*BU9}jPnOFb} zEKeUGCN?Gj7l=s*C~ROS0X8=^g86@RWUuc>ps5 zp5r5wfXWcCwJLy<3HU4nwt)Z`m_ba>;Si>d02b!o#N`aE!NB*b%3_j=bTa0KUH(PN0y1 zBluaD{|DfIsty#jc?!xfw=o5(J<(|6X#UTp=PxW=4 zB3vB)!8;4{pZ&u61n`gOnBT~g1w#ys4Il=@qwiLh)*KC4#pWoIV*1)HN zCqb5f3O>>GPt?B&x*FI$2{QdvP*(Ooi&|U%gO%U8<9)*B7JiCxdKwT^Y;CRh6_kG) z9@rR-t*ij5UE_zw(r2BxQaY$_mDZYECdr=I@{#$P1=f?;gLZDQ+S zZ2;jnu(Nv_gnk>Jo(bgz{#o>Qd5Ag03jCX+{9(=S9wTT4`TO0c;@@1!%KX`rxUCFq zO!-J%8H~Xu22NHGQhr%;BL`bYTN4OC&DOyfzyJWTGk}=cL3+ZrHjYl#U6Wiww z))SMI6O;kSI~ao<0OAe?Hjt-54WQrvwlcQ{NZMF9*%&A+V)(YbOpPK)B?cbXJ_ojHCxaU@I zur+ov0z2>vJ~3oy00D@YJ3`E@te(sVJ^3$y`e{Hnwsmo&;Q?4bJCQlq7~tgiOp3V* z*cAd`W&|;E01Vv#AQcvM72fCm{1fvpz4_#zva;MFwnk5E+dw2m_??{0ji20)jf>fU z*@%J3$QZ=H%4q^(Fyvw~U@$N+G2wXn!sKEC8~)~(f3N#*xRN%G5Ca<{@E^ELY|Jbm zBV+bw58z~AHR57r;46$D zQ-U~1K{yqx@X0PU_tmS)69xqDlIBg!5Xuv%;j=y5D3k2`2OO*t!$lH~yLIUH@Cy(4 zdThh=n#1y}mj$oO$;N3S-ec>7>VhBVxrVCZ_d4_nPgEwbU3p11{@sk{mHWS#@qbJS z=f7jIu>NOC82VZeJD4y7*Y35u;TXBQ(k5qEAvHw+RL!APO$$xhnf2of{IRWo9Z^{q zO%FpR=*aYQa|sdzPjSB$wr1l`i<>88!-Lzn`bePSd+LO)V23-U!(y@*9JR-wMcqD5 z3l{B8Tr0Nnnj}tCS>h;zJ;R52?xE1B?*VNJTSfUmw@{KF|4s_mzZ>#@Ov-P&75~EU ze`AF$tOeDN2~+Iq4pVPETllaAKF=V|(2yYR`?q*~5}fGkyI<@eo1L_^%zU0QJ`j$d zxcn`vh}0?%#;@Wv3aw4bAYyY}_R$ww!HS3CmE>Y^3yBtLgfAP4ydu{wg$BmiJK55{ zsXFF&ciEZUq6aAlo!e>!X;d=LJ-N!M$|SZ+Jjv?6vjY0-cGGW%e*AxUd_ezpg2>bJ z!}6bKC}> zb<5ZnHU(oEeL5&F>!p_u*YQV+_ocmk<+?$#{l8)5FWZO04z_mByNA!4MeI)&a&R&0 z02K@zp11x$&znL@zi%5V7?^^APit7n^A3jA^Qfc*0R4V>9#)iefJ$ITTPFu2u;bGK zE26Ftab?KUCcsl#T>0ssmEUCe`GHT1KqKX+y&^5()8Q-t;BN~%prrK^xDep?tMEUr zl21ETPt836sHkuPK+g~TlPW6APlvYrmQ*)?f_+Z$KfQpmU}JNGf3ri$_F0F&Z9o3| zc*@Mg^dFxTvt@tv1&0Mr46j+W)#&*cCTQ2uR4P?#<|d6MD_L1tuDf^AQC-Ng#jZcM zI83%bUa`LL!(f@B-D{gM#Mx;I6_|9@48XkIwkQQkm1%00lU8ELioC;(z5_s{3 z5LdjYx?BlbLdHMi+=q;3;qZly=izvT4iRqc%0?`2{{18OXPxF~6?$WTQcxJx2To*- z9FryuEIWbLlRJ1(38kxmW4H|$>IHTBwIEmMTB#zHbZ08hqXoEg$?HODq?}l)#e2Ys z8&>tZ)3GZUzHeai!ue$-Mxe$gzqla5gv!1hL9-+J#^bxJRwqZ7mai<+GU!~*j4;>+ z2?`oN8UdL*yUxi6FFQ`7?@91@<#@E8_Tq(oq9BtNN-teKf|4c6@lt_dmr7n1(` z0J#^e)S@qLR8Ui)ip8;QX)mSqTGx8~B=x$GW(YCww6A1)L+cKwXOaTL;iIlM6K$yQ zs?*A*Co64Ex5Jl;>MT#QX^Z)q%(8ckAb>BGRdxF_F@mR~V_Z(#5h zQ9E${P-SsPHSJmE%$AYE(2k4`eDRi1cYTVhX^)DR$PLN3Va@6;sd{=}kxf(=#5|K! ze)i>q0QQ$UH=-{^@pWl?DJ!#J`TBW*B9V{dZ5m4zZQ85CbAXznxAVa{o>Z?b2?&sv z_u`kfWeW}%=tf^gzM|=^%4JL%V!GOMrT-Kz38ewD+dG2w)p;DZha6pTxtvEcUD!KN zhL*^&sAJm~4*C(QEPqHs5~Jt24Bv)yiKgTm@lRIOdGX7)Cs@cyt(vFQ=-3}fM@eXI z60h`BMg5HCwC4<;-m>95)_MB>kUF>N%J&OJ;_BD+ev+8odx@apWnsPx@6m%qa5sibxERvY?@Wrnlh5X|!xt-yf z%DWgug|jz5mJ3LJ$={M}+FyjHRzX07gw14j^wXuvn=c_9s%QCN4f54qoSUJ>mXBPONS zpcs$KyI~Hxl;QAr%%?GsRUVL8*BgkE-bNLnE!zfhK(9*SM&^n5lFHA%Y1OX-)*lEs zahzv@JZU6YSlcE%H{Qg@@^+vab!c!0Dk;u2R%E3KvVRVya!Q_I$#Q>i7s9UH;Xu5=1tA}Q@IowTG~e;; zo3c*0&I=Zu)EpDH9M`e2cnht~ykRysuFSGBnf8dZRgK2JRK7riJmrNcujyh8i)hyZ zOE`t^byj+_sxn!5q$nHG&9xe~tjT7fY|=Q3uZ zrzlu>L+5OjR;~%Hn2flWSxj7u>NKm~wlOwSN4XY3R~;>xdZX|~pi;=M9{+=q?c0F+ zq(rycaWr$^PSu3&pD=k*CJ|)G)*jRmWg1dE+%J1{9*}?V{j9O$9lOlmXjg@|E*d8A zI5CA1HbbcBPs*vIsG9%GfBx}gf}S0HUa}~lIiD+&9UQ(%Rnhu!e7>cI+jUe_N9Zck z5#U--6MBFdV$eVEOVo!yQz2C|2q&X{glAiY2cD)bp_!grCd4ZTvtN2}4v!qd3@AnB zEFvwT`pM_IgK}``n$7&<^*4n>r}~3;ZtM_gyZ~%C3#Qh|Og47#%0#Q|tn~e>n4Fhy z(0xwan(I2d!1xSR|Q zoK{gxhs2<3Wt8j%R|Fd`67`OMCRCZ|9nU3BFYWEDBzq_8>QrAOmRuC9`Me!zIM(ud zi*6jYM}9tHUOUFxccn56^AwZghCbPaRs|vid07u!z%(bMB<{xOe%a^9)6{$zK8COS zVncf|!zh<{87Cd~@TqxtFeVF0t9X4d%Y@6B{G7UfrFw!*m9+xjd5FQDMIcnbyWZ@p zp)$cRY-Zx-N5X~qQ4m7e}Q^*kYY zI!W&N@_%(k^p|PSQ}X}yH0U=)|7C{H!Nm5T=CWqXVQPa83+$Ln`*ao1JQzYRJnKr> zFCn){ly5Bak(!V~{j4Zs3fDR#PH~quT|5}ugUCNg_8KAN2H$b+EIWSVXj_)NR3G)$ z7+I!I43(@~9LhE1e>iztKpLV>PnLzLb!5Wt(e=n&5SfUZIHcv>Iq`+SO@Lr*^XSq!{)9+1ku*6QUpJkn|^v%Hhg*N z?;mkz&P{1~FCCPl;gf=2+M`zt46#?MAPIbR5P(LoXa2Q%=l%<&Cfrz3pq*^>e{uFs zL864gmTud&ZQHhO+qP}nwrzLswr$(yZp}XD&dfa#Gcj@JzSTp;A5l?Jl`FqonMp-h z)!|C+d*BYgp87mU0X>vV9`>#ENfeu*Ms)8hDGz}vWt2_-e3;d$Ku$DoIVq%nK5(N6 zvG)eteYF#wy#*gPgOT{>N(c(GgmFP?&Qf-60qRy!;f?13Eph%!+@4Tr{=Ykw`{o*zJTc_AVlcC@{{7XzR+qpXRlKb_Uun%V5?y^iL&igMyN zI~i3Q-Bk%?&5t68k_^s)AJ9B1WNovuNT+7EesdOF8D;ZpKjSx-*WBGh1qVAd#fqa5 z;jJw}zM}Mob~I>YM4Pu>In_2PYkqXh=VKQ=3W^aq4!@ELUbs7-yDG9DJSFrnP3W z2F#AbE=SNDpgC(wv&fKU%oR1gI27m{X4RitBqf4E@`wdPSM1CZX_77tzK24d0F^y$ zeb23PRKEK3=Ce)M{6qtDPED@8u=9FB~htzzirbsSFh zL!~AP4D?c}yx9$}OeWl}<1D*s+p|%@LN?I_w?qUZJY8lY&}Qd_v zwIobTJ0(*V)&qC43(!3aJ#Ws|5r-R0XDIUi&wYt9-Bw-k2UT#u%ECdkL~)87(W$v? z00&v+`Q~7Jl1B^?PSJUW38|#qo!kPe|yUWJNmnH+HN&=;FF9T8}*%&(P{ofqj{l!+x)p$Bi zGtzL`N!erKEd(BqpLsQeT0T@PZKkOHSe_`mc4k#Q6K$Z4v>j8*NdFi+iK$_L!<~5Fe@4d_V?S5Sz;F2wFAsG77cJT|6No4dGK7h5h97j zsmcQdJgMAYTeWLABlY6|?x_dOX8F^IR#X*ESEcie`l~}ndv6fhray{RMe7yXa+?O> zb%yk!Ps3>$_8Yr}7eUuJGL%vHT>P1?#~`USgZlZc2FgfYbEyR9e=v@pu$|dla%Xuy=E&wwtU_3Mp`#aM^<;<&KrCzu$5n!*&!E`Grb9ox8>?PMZ1|iHEXZrgy&M- z0k&Fk<;<4(W*!XsHkoDpRfIl4(jlMe!3c0%d#2)SOuaN{q+wTvu*UfGh@H^e(ITau zBct4rmmpLeB!R+e&O74hjVwVLHp0eU^*?ETcet9)XTt(Of&EjOi97LUQPx6UA6sv?ezC(I4cJmBvhi=m~3?o6Vz=@b_|P~K%xz? zwaE6cc`R6YJJ`PUA!X&YZ1-6ln0#rN%4rI~;w;zv!!2sBbcs2d6@tx_vP@w;R@%=yP!#{(~e}?z}Nos4 zi>s2CX?U_qG+T@&hJ-_^zvS}KF3bloj(JTWX}ITmWR z@>DS`5T-mHA=IF-EHb!G6^~leg1Qr+HY^c&MVKU#@2-*kM$1~MW!Us?P_jTawjwNL zA-sI3?DmgZvY~J`s#Pp_fQ?W6ZZYF;i^v0cao=qSooGZeciS zf5F|TI2r&Bi>^}!BD*Gq> zMo7bWI0{xltH6$heZYFznvD$=CF!H@8&GBGiUax7(SMgVrs>{`e-?%wKuAk!Jq+Xt zIY)9tH)#pTf~RePCG*EMpnJ(vt3q<@8wPr2J+;0?K6{JwSW?S*R=>4c60*%vWenM; zY&k$FE3E#^5$l!c(k`}llCq>ocwZPE9($cfNa4~K-FTOd*i{s)G7b0biFZ3sfA$IJ z6_>)Z)6A*o)YI)*NFQ!dR7*X7Dz|_Z-#!W%)__`&AKnLQGig$p1e;4Eo+!hmI^Dfpo)=%qt_9|7>G5XX)Dm368}{SO(S)`Z zAv;uyvD}n>c8VoQY84%S_A{NZwhrdBWV0Vl;!PZx9&IMQ*e%ZMz|ft-4i64ur}Dk{ zT|WR2fQr+l zQRxE!7}p;@wUOhJ9{wPbn?xyzx?v_N8zqUt6pPHHmr@vZGK%{L8S;J6HWa6?P4Kjb z4|9|^CTtkrB0Rjq5{Qk4#fL#Lb>zw-?4vc9B{QZ`AG96+O$N?{1BfDNgXXC5K+KNF z7>0*)L40rma46}Z=QxE%b7%rN6z(i3F?;HCd;sdAla9BuvYjdLc4A8A017PRPfi^_ zZoZ(SoT!x1V*`jb|DnNjw7n=I($3P-*22od%=A;N`0aXUC%wHP>VJM<+50>Vh6g>&Mla)PR=HvowVJ~II80enILF(hOX2|OlLm4Idnm?i)-f$tRLQy@Tr6BTwu zfJYMQoJXsGpbDib)T%)Ii^c`28&D?%JkM)^k`?3^y88!0CaAK3sRkDN56n8`Ygq6B zs{>9B*xA6xy<7)SU2y#1%{}Nlmk&5zVE&(G2!RL)SVdtNM6ko4cS1x7njvvEf=~%g zrSKL4T?u+8XiUMfM0X09sGy=^7{xXUc@>DLP$^+s0n}nDMRCQO3cO|7WeO{>7f4w# z>O$CgHVgV^Di<6sWZeKdarT0(`Sf}B`J;1o44AO6g+UEN9>#+VkZCR%##4YYRA)Tq z0L(wrMvWStHGr#dSK+2cpzA=_e%FlGoYw?yIGA2!~Re0cky{ek)8^2sHTT_D^-41|CTnG1vFg*rq$Bs@e(kX9mB zhXIJvJ0dj%dE|P8a7g=zCla0|=}IJ$5?Yd7LR|7(;-8~r$gGobClE~lJ;^&0eG6+TpC@HpH(j;F>7MlVzObh$@EVfrbROup@bF+IutZgXj8l3qLo6JqbEg)pGPerARQs?F7!z}L7Dd-)whBTXu zC8v@GNu8adoZ_5tI)ysbI=P+hPA(qp9wQ&SPq>fqDGN}ZQGrmHP~oU_lrq#xs5YsZ zP@qxeDR$L^QlC?SQdcQ))h?B@RMiw;735TR>wOeGwL;4dE0PM7%AC|prBaKm>L*oc zm3hnm#?VQ-7m+VepYuLrvXZjOvleRAYV~jSbj5i^c;$Ij|0RYE0uv@yE0!tNHWpJ> zT~hxyb5!%G4^1z+5VgKlzFOT{PFtK?#yi_B{Iw)5CoWwsPOf=YShuMz*e=U1_tus- z22Yq?@h)Ij)>mUsh+nT?>NgC~#=vrbmBWCc0i}1@i_+e5XVFkNsW90v%&_^O0&!-1 zjAE|h&v|HLnPbR<-I3mrJQ*69B-slYyo{-gdd6v{Tjq~dnf)kJHB+~(9Gg4)p2e=^ zk5lF#(`-}l)UB2RjSp>`ri->uOH0$ScAJKrrlppswyHKPa|MjQ7~@eC>*nT$SMiJG zl{;G+8&EbfTmL%NCfO$2h8*3R=B%b(zt6PXPMoE>HM@~~dwd(e3IAci>3~axv&Uh@ z!MK}^Lyp6uvy=nZ>GROWaOU0iDbJbFQPb{85B1^Yf!6uv9oZ4uq1wgky6z6|Z10Be z=$|3u+%Zr2mh$#9yE#L8Q~EUZ;w94w84l2)hV| z5^fbH7N!bh|15a&PK#0`jrh_Hyw)jMi;y1aOnh?)qTEn?=f zt6A07sH%qjIAgBR7%RQSK4+@%g7+4%D6W$UMkaNT*2ONbw|eB%!3OWJgKG$?^{-9+5qH zD5)tmDS;}%%R$SDEZHr+mdrl(e!^TSePq4L0;u0IFOaUG+M&gmub8Ts_RPY}@@A6e z4^4lYUYgxaUKy*sW})_c;0{jF%Q>LS`bf z{l}RnsAs%;No}On`<#Btz8Y)sw6mc}px#0MY}vH0*ofPn+1>3K_8I@i$%kGKS&Nd1 zo`~W{X^yP*F@0AZR)^*`a(_zGNWe1?}={3hU$amP643!r-_n-dge)6k~s_#}h)mhc5RqZPBx(E0g+!q`TreU3A6=l7J zcZA=rdM&rDS+1qxkK)X7e6{ek^u1Y+uEoMa!HUA-$KS`r;K1^1E?KOsua_*VEW)ru zXP3u`;&p$-Ua{xWhS9dxwyYK%?RVV2H`^EY<8mGN7JZT&nM}EB?WwjaZbEGpzFxm( z#=XZS&fd=kDpSk3x^KAs8-M!zow#IGUOhXWN69J8k?rqxpflUK@l<(MPCu-RaTRyz z=is<9vc(I?`<>oHuiJU;_hD48eAh|srY@)7+Ua$Pb)+@sI(2p9i{@*~ukkg%YQM4P z_vcdVO!g{U7kCPM7LE%>uj9n)>e2S!n9{qN9%cpKh6luz;wSN`cx&GkZ^l;rtS<#v49-!@;KmroxTLHVWrb$*4Phu!)({ukMrtjs@2zfK2hhw6{@aXoskUEZty zuMgSB>`%_2_9uIIzGEJ1pM2Nf!#=0r*Wpp|UijU7p8j4P2|W$>*#N)*Zy`^g{~HDR zUuypU+2HZtGt+-H{r{0&{`b7{e|CKQXIY+J$kN4G!PH6E-qyk1?mt`s9RE)b4FU7N zvibk8Br!8GFw+0`P9s*1|8wGa?G4VO`uqFaSyEbrK*=ncl4;VeP-vmpLIO*w87nU> z9WCXZ-a@QYiBicjKQEv}=zW6q)^*e~_q**q%KL`&c(L^M^zq$`f0E~Y%X#<2SN~?s zqYo|ka{&kqXD}d&5Mc1@>HlDi5zr5`uZ6 zFbh$4jq&f8{YTM8WgkGnhvSAz5w9p92MD-u5EMX^7{fpEdl7V|KpKj$bd(2J0pnA zN2x5$OZyQt1OyV7(?l`D3*KG!pr=MNV?zlnen`kerUr*tbV~j}xW&W~Qu#p`j_me& zSW^{ec^pwusxurMwTjwRFy;)=i!O<6Pzxl8)$dBiBYQ9pmedr5Z^L!D$NcVrSv;ze zoNp-Ta|_$+c+9V=odFg#4<76HafU`iL6gC-rv?`gCbYzdqsMFr%s-FDEe!2njjrkh z_{S*jlj$2W$%Y1(#epo{p-KnTJiWNGHyEz2w99En(I`Gpq4`nLRy(n^VsDq4-zTvm zv(n=4_5>$H!h-~Im)xtH+@I+I*C*z!m4Vc0c$QiS+-4l~CSWL-5dxCKcY`6PODQLEWGculMim%;u zVQ!%NPKi@g#_~@{|F(xdPVaR?zE;hyO zSoYH(nOcUk*a8~FM0i8=e-0@w}0C?SxBH`w8*pv>WI)~`wOU4F5q7|!c%H#=Qr z-i%c=v8`tkn|Kzyy|0JFa6gnXx znZt#-+bq&2sFl1Y-$9m@_T*GlCH`w|jeDX5Wwu=>%Xr?H!;NQ1SMK#Y2Lf6@U#?$b zMvKqYQ&a%TO74R*v?-?9w`)&6Mk#$=rXIB9e4OmUADpf?I_(ZRoIT9A77gllV4!*cj81l zb%ZUigVQ`d_B8yo3(2V|}v1t%kV@fZTzQ)z0QG?E2VBrU?KtmA38{^AmbeY})j|>Th z)aUc@J@|LVbl9(_sn!)}U5V1)k5Gm=0*43Tyu(0$dJdFh?LdG)9S&FDgsRg#T5b^R zK>Cc&&pc>lQn~r33IBuS?l`!_oBr*MN~T}vKDHo{2gV2AuIHBKwwhYnUtp{t=@YS} z;sAw%2Y<0aV5Z2iqtal1Q14Bd`pVMwfyNo~2*d59B7di5eobn4&h|Hu4`Wr$4<_w) z_ltVKe4l-P@?iccyJ#>=&xH7`O)@8hjH!{-IerCOaFBbvft>MqVW?a#;e_=b&0CBS zz*49~cD`g6QVQN8hT^n7!?toe{*&l(A`TilqLkPm>&a^KjQC6GU?t_HUzDrlyEy5+ z>f_@LIOQI5&jE%n{OESz5SPDpIo!O~>*t3>QE3e1ZR`@tc%$73RMb}6v}0hi+JiPG z$t_&yNPd(wNs9%~_LcKx5XA%A10HSFCpyfe+Ol}T{oOE1q6WxDn|U**c+gwLpsu*f z-E&NHsT&)f9w|v0uXi=~z_RfNJv}_^-HNlsHcd=@_p0#e0EIp7;_6Nh1|1|K*o^B1 zaeDCvoOS#J!61+v5Eb>6SoPKcR27VW#0rjsezoo348i%+Q`WKLJn~bb@Mg4G=A)LLXOh9{gA+ zUY$@_lOX}#;~|K3gw3a2^O7Ann{IfvL6!$sT60d8)ao$!19gSTGfS$P{AQj}<&EtQ zwZVR|M;aO$Jiam{(ZbA-$z`y%yX`CPn8130s9kImbq^-3+N!I|`vxPf;qepuaW_%B za{V=wgxp;nZlDCAbFZPBm>FB|>B=p}`j9#EpBS2c&6I{pbkAC~^dmbi7<}GCc?p+Q z6CIsG(hI_UdD32j3No>XADQ?FARf&H-~v-T=c0I#OLukkkb>IYJ^u(a%>F_VoftyG zHCcN)ykGV^xWERt9TSLnfPo%#1HW}($JWx)0|FsA8pVm>Lu`**6d;>?;EPXZp(aN} zNT7@s{DQsSpdvd$oH7A!U%ozAw9c@1V8b$DvNY6G?B8*8&eT;AaQoNfWlEt(RuqGC zxUvEq7=AV_UMBvbA;faw;=zG0`ZnXHpkU+fJZXp=-5=Ig?+j8OjfIBnZ{9n@7^kR| zoOi3;7>5r3;cNzW{-B=l_&Zr4|GUe=h|L>(xv1166wMO!8+p0Hjb8WBO=H5|1Tcd9 z!I}z^ur)R(tKR05c%LFdNkR1SOl92JyEV3kFRJmTe+ZxC@wrq!S12Bz-|YqI>H{Gf zWyiSPl%MKAX%-QZ5~h(qTvG0leY`i%Fk}RA*5k|TlmKUywb$eMN6#?d<59W53O*>4dg4)T>J4Fir?pLh5a^ekee;asAaz~sb(gA z4Y(yo434^rhFB&x9~x2-*{W&Ls)cXoV0)b?v}u^%o&g)ntzPS9(OtoHj7^~f;{+kY zMkk0_d~Mqilt+w0*qSg$e`J0k~+`Q0RLf)&y6^|$@D&Wy@cQ_)0N*U;dFB{z`-9`4VYj& z2?A|M@FxKe*&&?)BLI|l>K&B_>sGTB*j3SY?>u|4b7V1UWB z7MJnCa%Z|*IKtOIMM`_>({imqCl*;mBG{)TQ;$N_3l zWD@XqvfuWLWj#9KF}@#I5E(9z*-*)xWY=%CTbZ8vCeSqW<4e24R`Xci>WRW6Jh3F) z@-I~Ins*1G4%#cU*o}MTM^#djviLc()MFl5`Q;Slna}ilwi$SIcTyiNmsEfHRwn0k z3&upvFQJ6n?-%1*z5X2$m?kVc)g1l%=K|rQBl?`UysKuzL49rcYhEvIy3f<-(N+50 zPOSg?z29Rm_(ZzgnBKNG>8r^QPWeZau9p@JjuEedeej)E{zji(a}OJ><{k6K$l8qa zU0B0?!F+CB;FfRNqIFfaQl3&Nr37mfOT({8?v0PK6)rSa#&a0$?p7TxrxYP>40?8} znhRjEGvMvRjCeUbBlX;8*dFM;zFYnF3jvo_$eRI1865-x1OgGzM-W5wgxM-v6h)lB z7XlR;ngeb@mZT2QRTXv(I40Hed8*SdoFSp%z4RnLOEY6dL-{c2MpcF_JVZdJ&7c%O zQuc%8F#v6Qqw!RflOh%VcAI%pCTI8*3dOM-Vnp=Y&_G7Ey1ruPxYw!=_*vE@lL*3V zc%={(6BHCw9tmk$dg}e5SBRNic__iTp0Z|XWrf&L_&Ap!i=;#kxvUOWPzu3Bppg^s z2f)BA4w^_r^a9(FbL zMB3@?Xn&to)9*c5mA)b2?y9}5A9>b}MZVnIo{wjwY{=EB_dS$$b$ z_Fha(aTkn^UZK|4si@$2UrUM!%Aqyfi_GmOd@)QI{e#Z7K)vYC^8g0qDKuzIZMd|r zBb|@QPTDR@W5Y~#Cqreo2%O&t0`i^{lTtVp%yv5&N|+;)QU5&k6i$px*rf%UAN@({ z(ejFY#+|>@FC(A|8p`z7W_D7mEJeIpDmpDLyXRHZ3~UUR9!Ic}@OByxr6u3y4eS0U z0GJHf)AU1gANBWl8u+zdyXgqiZ)u+277+W*9)_32Q{nj0nf=HvKeC_G5J53ySMg2j zOnf-*x1PqNMFsG(5jjpP6cwf)Se0R61oAc&Ve_K$olewo(-x{v@I!fVw)ct4FjBbZ z^Wu#G)avoG5_5a6?%QoTPMb{SLB^A|QVV-&)NOtaPNFfF8y_L_GNAH`~OM_wJY zO)6_NQ~%;7ecEK?CY$f?X7vX4EhLx%5x(D%EfsceD@Zhv;-oOS{ zkmcn55^TyLAoj+75oS2~j@^2Ix?1Yxq3E1@d zW+1x}Qol*z39J0G_qZ{3(K`&k_7NG+=-SUn5lN18)5cOZ@bk!hKead zb7I6|(VNY^s1e)*{`V?2Tb^mx?<>~{EFpiy@&n%^jgykn)^mOo8Jt)WIF5*=U$ok_ z;C9Z)xZ$N4P^J$eFsQ?p5n=iLpm;bvEGla(SdBP<^bl9S8)r?v<|_7&x1=+s`^y23 zwYJ#}ya3~%k2Gw1G!oB#@2GWd>Q}&Zh9fte}-$-%C(DJCq6 z@68_0;wJP!WIJ9=iu&I5*&ZCJzIgqM``d)aYXwpLvfRkD+LS}o&pD+O89e@ zu2lev4;@Cijg##jV@*!v*U8_52w6R9tV{p<0RVvzUb1{Xh7 zSH`vvMDV${RK+|#&&xX&SDLm67$pWsI~RT)-{SHDx!~a#aLb2gxt?~3Na?iXbFQUX zxPxNl0AnyZp^3^C0_cKHO-Tw~k>R?C_zTRV7#h{Cw{E|etc29UZO!MO>^7NSJ%r_8Fi;x3X+bTa zOp109Tu%GK0z}8ZD$lTS8cmN9{h=P;_=jv{io%;hm6>WiUNV7%n+_2 z&P08tn&lLO-(MmoH|&S47F)3{<8RFl=lJ<=te zM(VL}n=GNdNvg|?MirRzEvGPHZH9zNyZ`~bt4d#h&OU;81rvg++v%Mij#*Dz)((U~ zQq6d(wKNmXIELRP-W5x9n_xgf(HkNt61i$OvM8i}%5CR{b%0ZRbdHC^W)6+!VZ7PV zqE~ou0}5hGx!B#~F3xX_64H7mn^RPzhJ_m##4Hz>sv%cL|8@RPdJ^R*z|oee+VT_V49zvL~*US0rJhuA$;fF*5D zY@IcYi|iR~4@z2JLflcnbji?E7jMfv@-+-Nmlyo)@&8#YX}9u`;n|jI$&kGzW7|3s zuW$39@%*IP8uJ{C9GIb~F6Qr%@@E&4vQ0gb*|xP+YN3Bb-Kn%P^PLYWs9o~GqQZb6 zL<}u`HmGN%FTMp7>4?^xhXPMl6;8PX+0CR6U8zehcM*@xt;fd%6&1gpdB-z4R2Iux zOG$wayzW|qv zIj>H0xuRcF5Bk~TM$8OG7bs`gf!HC_tjHeBNfOrppj6hAz?7p}> zAt>lUc2$mYWbde9!7)iSIHl!0{JtcT(@U^dd1b(832tl+mMtoPOJ~{Jsnak>J)qKc z_b0>SdAjo(oI5(QUatj7VSxivJ>-F6waZjc`MH*3dX&wY8n0D3&ksVklaiR!ICAQ- zB9~i|*5yDa#*qDE-B;XW8=|6B!vrU4S%o8cOs9*xX{_LreAYQKxz%O#FKBk2h@SX( z7qpH$;9%bqJt_VmDW3D4Th|K#^`G0M^7eXBtSgB%Ztijo>xxLXyF7ip{t_Vd4E#Tp zRTX;sJtAO1F(qE*!{W(-E@&`pH9NA!3u<1pM@Hu}03*PWCk9CYmKAeoCL(fl05!SVn^b6)d+D+UINamb z2??=}m7T3~_2pvCZjK6O5Zh;6xl~_*YlA*%@A{qAyI^efaTwiblR-n1+3=ndyC2B( zx*B(VXHuVd0&w_*g3!P+-c)^ZvZH59qF@!fBS9vx9+OKWYSG%m`p%5l6NYtepLX%< zP0)^vmoo)c+FSPs4cH$_y5fiHI%Z;T3o6Nov0Q$74JIIFt955wbN3=aM8i)6t5gDf z2_LDs96LVYa%Fx}#tC2TRpp>H2T{)%5@~Enh^!iWUz+2XsbS747ED~wkybuFIIrST z!c8iDdI0t$PHiGcxO8;1t;|g+!TCH{zgF0j<@w26XU5fU*=0gY@SVgxXXb1b_U|ZM zlJQR_!W9{*v)L17B1dDUIz0D}uGT8G*YNl+TeJLKzx6G*#rR1iMCC_n2n_}Bh}pgS zV!Nb=_x+LGA+QEsNpmDRvYn24Lh3zKq-@@$%DOaljI^)4+~%xwkr zJuOp8nPY5EQnZ7c6f(f)&Gs)aK0@g+JIs?AON*fT}j42fT^Qq_S3uKWnkgy)Rr77mFxxcCf%A<&b1% z;NR`Vk4#$L9tY_}A__oq07Vk*6U9|2__Y0kEy5=s|^0Vb*2<1dsY@h-1_&|g!x zO|*@A=1S=kqw~0WD5AC-tX1ichaHm)tQ0%RogtZwBVPA^bm#>9ONj28ORyJ`x2mQ_ z$K>kJ%0OFBE6{kvtSum>`d;JhD^OW&aWfNBb6q8z?N-z5Xvkz48UUCSi!y15EV*~$ zEg3x~*QAm~MOlb$+rC_2^1VIeZoP6xQ%zin@YDwdQ*UJTteyI zZ@ev+fLFK1yv-8Quc6X6ntb++xj2_SRT@{8VDE*SXL4%$Ttu zh~10TVRIp+Jbv6_mh;_{PYGTr6SjW*8qS?h7K z-PwGg+&$>nwmaHq`&IMzFWxrbF#Jef6{v@Q45I7tK_X+Z%^q*00TEV(=<`daS=t>j z*|>f-Z3QU9IZ%2eb$jNB$l=kVgG&J_2z_06BIOm3?ylJ^x%5iGw1UCE-gq018fFR( z0^_3Z@OlHxAtUCY{`NOiOe?ylym6p+BuZcUTX`ZC*x^HEuS*1+L1~lrM)erEgy~`r z`A(Cooum>Jap*S)1So7VcBHDda;w`y=bW>RIku_I0gA7Iurq0pY!!+llGAHfUs$+Y z_AakR&djAJF8d|s@ye}T3m6b^txQkUO(yZ`lky!90htrBktvo(>$tpI(j^BgMW*}i z?|EO2hw|lef66)ra+b_R_n&Un*x$O6~Esi~=|s&3sZT(!Vs<$hl4oC=%SN}SLn842_A`_g6BSmRxF#rII}59ixr}SbY^L&qN*E`OGjVjT;o_I ztUIM=;Xl0(SOXBQZL+Wb+I@| z*tbU9E7R7~y=gbjFgUwv#b=k(DS6NKrKkL!G)u~hk(xBZ_f{oYjrX0R!z-%Yk*~5o z?jtgV$?qhNL#xLgFQ3M?)z%k6AAkmo`2ym34JFCz$Q&o%mdq?RyDzs$MMe!N#tcY2 z*vUxynsW{i*jOTP7CSHj6WTJ0^>l5HZnV|C3Wpc(+iLIg`HQbb)o;uUnF*vC{X{oy zY=<+-``)DE-NQ;m#I-N7?j7=?8?q&Q#rWy)xOfI-g?2_YmKIr^PMJi_hScjzHQ|G9bZ%cj2-Ne73+{bDOIiB0mcExIP3KR@$F@GXDM2-HCwO(0tD8W(r6QZ>(oMFV<@c2lx4Wz{k#}ZP z6)UKvYjP*5X8^UW0Y>a7t`!_?ic*)~55xNk)h-VKmJ16{uFc*+y@})6H(MUVMIG`% zZ}N^PaL$gK0$lQ1vt1dZFj3G0@0VZN$Fh`JD|U5C#|t4M(L#ahz+!u~glQPd=wz-6^{RkYNGKmwR;wI_&#sN)AoF{5+M^_Bm!BBn44ttjOgu*#>j zj_Uh`cEME>V^o+J@3PL=dP*w#epFXnpXq~s8rbNhQj>7X@@|hOu?D|DRexGneD*2GwVQKvn5G5Avb^QxPYQs?KdW5tuAtbi(6}~Df z5aTgELnbUmHm*j$axj^FL5(4+gme^G>{9b)C!x*DS8B1U%(E9YXvfU&BPDWu&_Fec z!{-Ydscd<6QD>T+pd)1Ff|<%nkF;dIAsgU}Rk$?e1^O6&Hu%MW4lTg}eOrk0w(!L~JKcO0|CbbS%Q9tR(rn(oe<1zqwSu^3!V zfowhXXxW#4c=t|aO>uD({*H$vxW(Fxb|EbxzSARE=XK7h{(2zoHQxJ=GrquhHt~RA-)WSGDzXT!j(%E5l=5rlscijQ5N0 zG0CKqlr(*Q>;nsv)|EGUjD`wSHCp45t@66esq-9oez=I7dW8bK>UvY=+3OAS#pd5Q z)xobgo{;gd{rY>7kB#ZbWN}!0$CqnPx&TqDA8oPt^BetL)9lx!`wX7kKZj8SsszW} z14XW~BI`K1OSR+Dw`xbav}G7?OHC_mGZQ~Sj2OLTUX4%Fp2^#Ly?&)D+Ipf|rzg>C zUm0Kq^O6&;uJfhRNcgw1zCak9~y|m)L`Tl%kuhUsdyQn9w zwBTKy-}QR-x>JRej1Rq{GPH{HuzECRl~Ae=zpN?+bX2d`<@Nr1f7|;s#_<+T0```$ z)z6(W2=B#`p8{^OjxdU1ZMp(a-<>(C(EsA>Gl51ffVP`p0VPJ4!$ShdnX z_hc?!F*x~)Wk$qTV*2BX{53Br)PiSu%-)>a`7-MO099PKxF@Hc>XNiO(9{+W7?V_%w(Dmp%kF9)P<-lmRB|ekUgWk4}#G+zQrPRkd}+x#3gr z68R^tqQA`@REN$-iP(#p?5nrR^4*IYNsAGZ#D6qL)1VL z?)P(<5NrdVt|z(FhI)rl^P)cm6O7CwBZSFAq2NBaI9^>!B=JR6E2t-_s1j1*N`m~% zHJ9wZbzH=8A=a~Ac!Fc_(tTo$6x&I5_RB00`)^|^fER(hor(sy;e-9if#v8vQx!xo??MRJ((XvRh;7r9=7 z2skU2evS8}3W_)u?+cLN4HSW$Am}Ee#z_G=#Q+5XNx_5w7!emJpf)1FM}b9&`x-QR zi1?17iV#LB0uB*VU$h=kKnM$ph{7YBreV$o9A;$H?S+?iRGER1*yM#vc7wr}{w)N3 z!GFQuV^`MuVCFrF7#L6@8orF>o!4^S^FS7gn?moBPr^niyM`NpxZCSBFRJJqT+*jNc}4X% za&VC{#k9@!P&($MCmyTUK|9^+J3DQYkv3F0J$c4k8n)Y;ZOyj4`O{WKNqHeD!d2{k z!)#Gtlk!WiD4StNJajNyRX(WTsX@V zQ|$eqEjZh1t)7fT+-~>H`Dig(+5Dky4<#WVeZ(N5*@aDXVl_-OS)-?_mJ`Q=f!X4C zcbUo`>YJbKRr=Smlf_M|%TZu9SXp4Z!k_%IX|&F8i+xQcIx$!&L`&_>JRXmSO?ege z;Q_qq5$LZXE^ThOn;1>I%Xt5Xw5#UHUwNNc4Jx+F=3u@Zlvdg=4GS5U^+sXsSN|j2 z4zIvH9^9pUc^_oAYr4rELNwO}dQZX=e&w-B61?>}4kDaxm&0_;Dy~m9a3DkQ`ntiv zp{Vg&a#;m+-0B9mNav4coU+aNE!01HDXLi)SQ*wbQ@zRvZ{P8oQdW6xHh#XawcjSu zh{%BI(V$0~PSLeDYF!?4tXZwIpUvc)oGwM1o71p+ZKi8U0WY_DmgU8stSc!+MjSvD z0}(MaXQMAqj*acJIW*oWO9Pc;(IhfEkO6$i)Gi{|u-Ic*6M26Xovt?ydk)b4i(&Yli)>#-QCn95lGlayjJ znKPbW_ZE-6`QRs+WtU@oEzMJ3KX9;dpeZ+7VDsjX+GX1p^zAkg$~xh;*>cftdz$l7 zEy2$%-nmY+(Mp%Lfw5C3H5Q+|`m`b-dYtrSa9e=*?r>_L!GoMG*TO3Qur90m#TUr* z)Gk9aGxd{?B93Yvk{mg*Y8Ng|u({^-+oI--+Mywt?Kd=&jTe{dTFBo^lhX`aD0tz! z3lwcHC_U`$^Hx=7HqZI#Mg z=F9SKh*+|?AlG(dd`H6`4gFx$hoh4H*;kLzd7m4pIxhW@eL2<^^XJE*9h6NAu3S#( z`H^?@b7{xbzKi@_7NxnA1ihFK1?jbyyQry#*t#c4nP;Ws)7MDPIo@-)$}sJ8+ROHe z1%Uw_MG>+gmLZGgD!O}J%*pAOCtx#FdD0V5!(`j9*suHLw8CN$HZq&NQsQUP)rMn^m z3Ih+Gd3!p;;k})=>4S^UYPLsy+h6vTcf`E)#gdzGsbfQV1$aIckGh_B_BB^7buM{q zaQ>i4>mKznvgoaJrH?54dp@G8A5@Pz54X+j`Ms?}A^Gr9K+iPHamVPk5 zDbJQlMpINA^jD(7XU^)&y>4pUyuN9buflkISAAKUJx>%Q@?QEwG5M`I*8ZX^szK}` zxv*5``gns&wezx)YAu{HO7LUIDd~KVlt|f?tGD`%OB2auOX%KP9{VPHdY^?{ zdtTiAw&{88VZ%qKHaZyI$*b^6dR`=~X?!VHG5c-^>FyXNR2G7u=4u>X`a&>n$?|UM zsMvx9`|J317C)M8GVpa!K2w*ry>C(f$bLQaINu-Jw)M2o6<)Q73$IsC9;t&GBPiP| z)aQDVR z+y2RHtFlq2@N?^r61Rdi?K}#~HV(=0HjU2}l!^PQ9!RZSEJ-<$pW3RrK5h34DXABc zQiqdQ8hho+9+GS%2qiByNpUhTsCrr_PS|9a&@EADn<4u-J6lfc@v)Y9*+$asdz8F+ z55AM@RS$b3;pSQyNtby$AlX5^R@3IubFus7Wd|Ag{C=91vD?Fu7xgsRa|H?SN@Uy} zUM8lU82j4p5bAE!5xbBYnG*Kb*5d1R+KS575|aDqDv4r=ciZX5u6EZS3eqMu-7i*b zS3FT-6Lu=3+jC`Za+d9|?!wZ+y9TAayURM|HARS(YgTRTEsL(&8M;MM%l7fJbiIVA z)*Z7x_4+pz89h;cHROASXP$%aYC-+0Qk!nOeC^;3N_3*$sodYpL-%XJ2|G&dSm&;f z5jXncQb^v6J{x)ZxT9mGSNC6W-{++AA73J-ZaS-c?pc?E$%i5eQ=8-l)CzhJjgJ=! zhxLb~7_C_uaW#RuS)omBO_j~EKN?bJ1PIsP3Qn)i-6fCNd%CUqS$S1^-qEJn)Ms9! z!%-68|3dqX7D$E9j&r`+SZb9ctx+FB4I89U&fnT9D40&4civz|o3KK=NVn+C9wn5J zmu^);{>N?SW-06`mDETW0>|C)|HDkY;kjtVG>95h0d!_uMr=PXWIFPZ1-|5IxdeUy`w0RGD_BSXO89=g? zH)qMuEG$7lPib>Xc-^|Gtfo`*AN752632& zun4{;fbwLp6hRa+%u+;xu~T8HA{?Hfouxm`)!)S(Z3;7YcrqD>C}gxP^I8$Rm_MAn zJUn+RTX}f7`k_o+ccCnNyqvsMSlmNo3Kqe|Kv;^9L?8{4WP_y|gOtd`Y63fv8WynG zup5925%?c9Fbj%fLaTBCj7?kUuc1OXoymkr1>{cbn_GX23&O1o0;S5r{$f)w;V>Ku zrfFM^Z4vA{Vr;S{HVxBcS|%3Z5}>5|w?0G!Zf$C5EICY*H2sGY3)Yuu)8WZ*pW#Tb zIlv!~mSLwXvJM{_hy@WA;I`Y(2$c|!7Py)1&<1PQ!t_>D6b=E*bzs>V9xj;K6Q%)P zegK3QkASy0aO@EgFwbR~6!jQklPR_2LfcXp7l!*kq7O+Bj`fLM`y9|aX6ays~PVL8p z4CZKw)XLQIpF!_16vZQzfawC(<2SK){u$OVYy6^ZJunO?9e_GaMB$OH13?IdXM!33 z7qG*K`pjlv-I>G?{swRFk_~_zCW?ghZ0rzyo5(9g66;OSty`Rh>$UJlCw$V$TV9!F zl~i%GVerj@T{AZDsI3|(X!!8Jo?jsKR_e7U(bouZDJ5^8CEk+O(+Q6$5uDxmH7d3~ z|6!b%p!mL+JFcm%9oufw#&1(4^tHwg2kwo26vIERK~FGWs3xfanej z$|z$27l$f=3d+VSwFUAgszo#`mKK*?;hE+7Xn*>#n%Yg$GvmAFU;bEzF>ri6=bG*4 zdz)7W+#Ab%t&tGf#KzT-u!0A_NKh$p$`?dG|r=`_v*$DbS{g>j3 ztZW|6vECW#ya7*-6qA*Fkhjq7`LeLmA=T@BFJ(|kmuJTOrJHo5qf-A;{gQ{{GsVQs zWpmCS?0hzUobRxsNtd?adR|{@T`GRyPQM+2bxu@g6(6flT}+jlM6oU z_l?n{l?XC9=LX|NPic5xi%AP!+n*&9b^oDP;EyYB5(Vb^ySJsB4cffNu_J8F)h*VO_Nqd)#~WjXPLU5rHKmlO^=jcP zZq2r|*OWjBZrxXy5=tKOePQzOXs4WT(YDINYs2{r_w5qO`0i=z@6wW1E$348Auxu< zJ7@T;ui_J-<>vJbbj8E{yHXw`o?lsMv})U?xcB!8^;G@he0dghiS~>sL`O$k+o3D2 z5Ar@drTQAH?eyvXlS?m#Zf*$DD|q+rjZ}HH}gh)|>4P2-p~EJ1fnz53oLPc-5WURgcYrzCY@#((LqBIOD64^!{6)!Hy5tpV?=& z*Q{IS*3ce8@1}JQm42&zCw(QUtnl%6>LuZze8N1%%))!eLKm$gtCqKp8UfcZ1i#|i zRM!yC<+@GlWH9GMjyJ*O8nS1;Y3DoE!iB)OGp94N4JIfo+Q%2==H%%I*cV|6Mt1dR zOC6@%Yy&f3X@bJ2W4M?H@mwAk+ri+hvOjY<$-nPz5{OK96NY&Q>j#GP3wINc9Q>Q^ z<|IFpn+22WojEj^1njgv7$}O}Hvfk61^eFc7hX?sz%_%z@DuP$!W@&o@r7L@j(Y^> zWUyVrjFu!u7`SN!gkKYmL23j}6_N_XkeOllHzO6C4-Ua@94v*u6yTz-V zR(b4Z`rnQW&bVOoIBYQt8Dso#+W~Avj1d8cV9Q3V8rT^~3oIYb3tJ={!?tnwH?p-s zY!Ds^%#k#)H12wsI)SvvIAA^}rr>A^hZq|hmfnnan413A5@6+1jT&*(r`ZfaaCywG zW%t(4jT+0MAO z05*bdD25F1x>CRr3jd+JnKBTDX>lgVuwZ2c&e=p644E@oMkJ7@%7}z1d5L5&&?l7# zQ~^`Y#5zdejBSbxhXEsXQaT8pb|%ZnV6vJdBf_U56J!v0-Kps)uwhP2hb61Bqg0q8(G6I=6xjb-YNu1n%AS-Ed zIy?nf*`)ID6j1XN83a>|PpB79Axx#TAnF^SC zA>h*E+=v7!#m(87ipM*V381-1S`KIfZ#N$lGV1{zdyimOFnGau27J9Ve`GX65QYNr MFJHdi><|9`16lj1ZvX%Q literal 0 HcmV?d00001 diff --git a/doctor/test_assets/recap_extract/gov.uscourts.cand.203070.27.0.pdf b/doctor/test_assets/recap_extract/gov.uscourts.cand.203070.27.0.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2b0184a23665ac491ac43857f362c2f2af6f8fad GIT binary patch literal 94496 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 XWGv-G><^0uE5;KfH8t%#>?QvnSO1$^ literal 0 HcmV?d00001 diff --git a/doctor/tests.py b/doctor/tests.py index 2ad282c..e295fe7 100644 --- a/doctor/tests.py +++ b/doctor/tests.py @@ -24,6 +24,64 @@ def test_heartbeat(self): ) +class RECAPExtractionTests(unittest.TestCase): + def test_recap_extraction(self): + """Can we extract from the new recap text endpoint""" + files = make_file( + filename="recap_extract/gov.uscourts.cand.203070.27.0.pdf" + ) + params = {"strip_margin": False} + response = requests.post( + "http://doctor:5050/extract/recap/text/", + files=files, + params=params, + ) + first_line = response.json()["content"].splitlines()[0].strip() + self.assertEqual(200, response.status_code, msg="Wrong status code") + self.assertTrue( + response.json()["extracted_by_ocr"], msg="Not extracted correctly" + ) + self.assertEqual( + "aséakOS- 08-0220 A25BA BAD GDoonene 2627 Filed OL/2B/DE0IP adgeahefi2of 2", + first_line, + msg="Wrong Text", + ) + + def test_recap_extraction_with_strip_margin(self): + """Can we extract from the new recap text endpoint with strip margin?""" + files = make_file( + filename="recap_extract/gov.uscourts.cand.203070.27.0.pdf" + ) + params = {"strip_margin": True} + response = requests.post( + "http://doctor:5050/extract/recap/text/", + files=files, + params=params, + ) + first_line = response.json()["content"].splitlines()[0].strip() + self.assertEqual(200, response.status_code, msg="Wrong status code") + self.assertEqual( + "1 || DONALD W. CARLSON [Bar No. 79258]", + first_line, + msg="Wrong Text", + ) + + def test_strip_margin_without_ocr(self): + """Can we extract from the new recap text endpoint with strip margin?""" + files = make_file( + filename="recap_extract/gov.uscourts.cacd.652774.40.0.pdf" + ) + params = {"strip_margin": True} + response = requests.post( + "http://doctor:5050/extract/recap/text/", + files=files, + params=params, + ) + first_line = response.json()["content"].splitlines()[0].strip() + self.assertEqual(200, response.status_code, msg="Wrong status code") + self.assertEqual("1", first_line, msg="Wrong Text") + + class ExtractionTests(unittest.TestCase): def test_pdf_to_text(self): """""" From c4514ebbd840d2b9da06604e5100e28a004c1863 Mon Sep 17 00:00:00 2001 From: William Palin Date: Tue, 28 May 2024 17:38:14 -0400 Subject: [PATCH 03/20] docs(DEVELOPMENT) Fix doc docker call --- DEVELOPING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEVELOPING.md b/DEVELOPING.md index 2eebdd9..b81ee32 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -19,7 +19,7 @@ If you want to see debug logs, set `DEBUG` to `True` in `settings.py`. Once the above compose file is running, you can use the `mock_web_app` container to run the tests against the `doctor` container: - docker exec -it mock_web_app_doctor python3 -m unittest doctor.tests + docker exec -it mock_web_app python3 -m unittest doctor.tests ## Building Images From 5cf0869bef327d5128ba03171f663ae87ce53b56 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 28 May 2024 21:42:16 +0000 Subject: [PATCH 04/20] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- doctor/lib/text_extraction.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doctor/lib/text_extraction.py b/doctor/lib/text_extraction.py index d00a3f1..c63f7c5 100644 --- a/doctor/lib/text_extraction.py +++ b/doctor/lib/text_extraction.py @@ -279,7 +279,7 @@ def get_word(word_dict: dict, width: float, strip_margin: bool) -> str: elif conf < 40 and word_dict["left"] > right_margin: word = "□" * len(word) - return word + " " + return f"{word} " def cleanup_content(content: str, page_number: int) -> str: @@ -306,7 +306,7 @@ def cleanup_content(content: str, page_number: int) -> str: content = re.sub(pattern, "", content, flags=re.MULTILINE) content = remove_excess_whitespace(content) - return content + "\n" + return f"{content}\n" def remove_excess_whitespace(document: str) -> str: From b02b7aad8293f10f07daead3c827d45ca273416a Mon Sep 17 00:00:00 2001 From: William Palin Date: Wed, 29 May 2024 09:53:30 -0400 Subject: [PATCH 05/20] fix(text): rename deskew to is_skewed And update its doc strings --- doctor/lib/text_extraction.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doctor/lib/text_extraction.py b/doctor/lib/text_extraction.py index d00a3f1..da355a1 100644 --- a/doctor/lib/text_extraction.py +++ b/doctor/lib/text_extraction.py @@ -8,8 +8,8 @@ from PIL import Image -def deskew(obj: dict) -> bool: - """Remove skewed text from a page +def is_skewed(obj: dict) -> bool: + """Check if a PDF plumber dict is skewed CTM stands for current transformation matrix. Pdf plumber has a method to calculate the angle of text which we use here From bd3aaced6ca4e858629f2cc91cac3a00a18640b1 Mon Sep 17 00:00:00 2001 From: William Palin Date: Wed, 29 May 2024 10:00:51 -0400 Subject: [PATCH 06/20] fix(text): Update docstrings ocr image to data Add detailed information on config str used in OCRing the documents --- doctor/lib/text_extraction.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doctor/lib/text_extraction.py b/doctor/lib/text_extraction.py index 293d6e9..702ba91 100644 --- a/doctor/lib/text_extraction.py +++ b/doctor/lib/text_extraction.py @@ -183,6 +183,20 @@ def convert_pdf_page_to_image( def ocr_image_to_data(image: Image) -> list[pd.DataFrame]: """Perform OCR on an image to extract data + Detailed Parameters for `pytesseract.image_to_data`: + - config: str + Additional Tesseract configuration options. + - `-c preserve_interword_spaces=1`: Preserve spaces between words as they appear in the image. + - `-c tessedit_do_invert=0`: Do not invert the image colors. + - `--psm 6`: Page segmentation mode 6, which assumes a single uniform block of text. + - `-l eng`: Use the English language for OCR. + - output_type: pytesseract.Output.DICT + Specifies that the output should be a dictionary of OCR data. + + Reference: + Tesseract OCR documentation: https://github.com/tesseract-ocr/tesseract/blob/master/doc/tesseract.1.asc + + Convert the image of the pdf page to OCR data :param image: Pil Image :return: A list of DataFrames, each containing OCR data for a block of text From c246bef473e37f7ff3b6458860411f64cb2b0ffd Mon Sep 17 00:00:00 2001 From: William Palin Date: Wed, 29 May 2024 10:02:19 -0400 Subject: [PATCH 07/20] fix(text_extraction): Explain get_word Add explination for get word func and why we chose mysterious parameters --- doctor/lib/text_extraction.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/doctor/lib/text_extraction.py b/doctor/lib/text_extraction.py index 702ba91..911be6f 100644 --- a/doctor/lib/text_extraction.py +++ b/doctor/lib/text_extraction.py @@ -270,6 +270,28 @@ def insert_whitespace(content: str, word: dict, prev: dict) -> str: def get_word(word_dict: dict, width: float, strip_margin: bool) -> str: """Append word to content + This function determines if a word should be added to the page content + and adds the word. + + tesseract provides confidence values for its OCR outputs. We use those + confidence values to determine if something is a good OCR output, a + likely artifact and should be excluded or is bad ocr but not an artifact. + + If a word has a zero confidence or starts on the left most edge of the paper + we return it as an empty string. It is likely an artifact. + + If a word has confidence below 40, a number that usually equates to 3 to 5 + standard deviations from confidences found in other words is entirely in the + margin of the page - its likely an artifact as well. + + If a confidence is below 5 - for a very short word - or for a very long word + its likely part of the document but we have no idea so we return a square + box to indicate that. This is often caused by stamps or lines in case captions + + Finally if a low confidence word starts in the right margin - its likely a + bad OCR that is multiple standard deviations away so we return the word as + empty squares. + :param word_dict: the word object from tesseract :param width: The width of the document :param strip_margin: should we strip the margin From f9c0b3de4df428c5e9c59fd034d7da8ef499261a Mon Sep 17 00:00:00 2001 From: William Palin Date: Wed, 29 May 2024 12:27:48 -0400 Subject: [PATCH 08/20] fix(text_extraction): Update formatting and docstrings --- doctor/lib/text_extraction.py | 72 +++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/doctor/lib/text_extraction.py b/doctor/lib/text_extraction.py index 911be6f..e1f131c 100644 --- a/doctor/lib/text_extraction.py +++ b/doctor/lib/text_extraction.py @@ -44,15 +44,17 @@ def get_page_text(page: pdfplumber.PDF.pages, strip_margin: bool) -> str: if strip_margin: # Crop margins and remove skewed text _, _, width, height = page.bbox + pixels_per_inch = width / 8.5 bbox = ( - (1 / 8.5 * width), - (1 / 11 * height), - (7.5 / 8.5 * width), - (10 / 11 * height), + pixels_per_inch * 1, # 1 inch from left edge + pixels_per_inch * 1, # 1 inch down from top + pixels_per_inch + * 7.5, # 7.5 inches from left edge (1 inch from right) + pixels_per_inch * 10, # 10 inches from top (1 inch from bottom) ) doc_text = ( page.crop(bbox) - .filter(deskew) + .filter(is_skewed) .extract_text( layout=True, keep_blank_chars=True, y_tolerance=5, y_density=25 ) @@ -65,18 +67,18 @@ def get_page_text(page: pdfplumber.PDF.pages, strip_margin: bool) -> str: def page_images(page: pdfplumber.pdf.Page) -> bool: - """Does the page have images of a certain size + """Does the page have images that are large enough to contain text - :param page: pdf plumber + :param page: pdf plumber page :return: True if page contains images of a certain size """ - for img in page.images: - if ( - img.get("width") / page.width * img.get("height") / page.height - > 0.1 - ) or img.get("width") * img.get("width") > 10: - return True - return False + return any( + [ + image + for image in page.images + if image["width"] > 10 and image["height"] > 10 + ] + ) def page_annotations(page: pdfplumber.pdf.Page) -> bool: @@ -154,25 +156,23 @@ def page_needs_ocr(page: pdfplumber.pdf.Page, page_text: str) -> bool: def convert_pdf_page_to_image( page: pdfplumber.pdf.Page, strip_margin: bool ) -> Image: - """Conver page to image and crop margin if applicable + """Convert page to image and crop margin if applicable - :param page:Pdf Plumber - :param strip_margin: bool - :return: The formatted image + :param page: the pdf page + :param strip_margin: whether to crop the margin + :return: The cropped page image """ img = page.to_image(resolution=300) _, _, w, h = page.bbox width = w * img.scale - height = h * img.scale if strip_margin == True: - # Because this is OCR - I think its reasonable to crop half the standard - # 1 inch margin - this leads to much better results and helps reduce + pixels_per_inch = width / 8.5 bbox = ( - (1 / (8.5 * 2) * width), - (1 / (11 * 2) * height), - (16 / (8.5 * 2) * width), - (21 / (11 * 2) * height), + pixels_per_inch * 0.5, # .5" from left edge + pixels_per_inch * 0.5, # .5" down from top + pixels_per_inch * 8, # 8" from left edge (.5" from right) + pixels_per_inch * 10.5, # 10.5" from top (.5" from bottom) ) image = img.original.crop(bbox) else: @@ -321,9 +321,23 @@ def get_word(word_dict: dict, width: float, strip_margin: bool) -> str: def cleanup_content(content: str, page_number: int) -> str: """Reduce legal document line clutter - Scans containing line numbers or bad scans have pipe issues this simply - tries to reduce the noise and artifacts and align caption lines - if easy + This function performs several operations to clean up the text extracted from legal documents: + + 1. On the first page, it smooths out vertical lines if they are detected. + 2. It removes pipes ('|') that might start a line repeatedly. + 3. It removes artifacts that appear at the end of a line of text, specifically single characters + following at least 10 whitespace characters, reducing right margin edge artifacts. + 4. It removes excess left margin whitespace to improve readability and formatting. + + Example: + If the pipes below represent the page edge (not characters): + | we can remove the + | the left whitespace + | and shift this entire + | page over four characters + | which keeps formatting and + | makes the text easier to + | read and process with the API. :param content: the page content extracted :param page_number: the page number @@ -341,6 +355,7 @@ def cleanup_content(content: str, page_number: int) -> str: pattern = r"\s{10,}[a-zA-Z0-9|] $" content = re.sub(pattern, "", content, flags=re.MULTILINE) + # shift text left if possible and remove excess start and end whitespace content = remove_excess_whitespace(content) return f"{content}\n" @@ -349,6 +364,7 @@ def remove_excess_whitespace(document: str) -> str: """Remove excess whitespace from OCR This function removes empty lines of text at the start and end of a document + and shifts the page left if possible :param document: text of the document :return: Document with excess whitespace removed From 8d2dcbff93c07be5a2a0c36bd57382b9427d0f7f Mon Sep 17 00:00:00 2001 From: William Palin Date: Wed, 29 May 2024 12:44:07 -0400 Subject: [PATCH 09/20] feat(tasks): Drop mojibake fix as unlikely to be needed --- doctor/tasks.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/doctor/tasks.py b/doctor/tasks.py index f37dab7..1077925 100644 --- a/doctor/tasks.py +++ b/doctor/tasks.py @@ -647,9 +647,6 @@ def extract_recap_pdf( if page_needs_ocr(page, page_text): extracted_by_ocr = True page_text = extract_with_ocr(page, strip_margin=strip_margin) - if "e" not in page_text: - # It's a corrupt PDF from ca9. Fix it. - page_text = fix_mojibake(page_text) content += f"\n{page_text}" content = remove_excess_whitespace(content) return content, extracted_by_ocr From 6d7fe01bbba43fa76c186053fd606a73838391ab Mon Sep 17 00:00:00 2001 From: William Palin Date: Wed, 29 May 2024 15:21:18 -0400 Subject: [PATCH 10/20] fix(adjust_caption): Update adjust caption Simplify the adjust caption and add tests for it Also move it to the end of the function to avoid any whitespace fixes that might affect it --- doctor/lib/text_extraction.py | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/doctor/lib/text_extraction.py b/doctor/lib/text_extraction.py index e1f131c..0ffb7b8 100644 --- a/doctor/lib/text_extraction.py +++ b/doctor/lib/text_extraction.py @@ -1,4 +1,5 @@ import re +from statistics import mean import pdfplumber from pdfplumber.ctm import CTM @@ -119,20 +120,13 @@ def adjust_caption_lines(page_text: str) -> str: longest = max( match.group().rindex(separator[-1]) for match in central_matches ) - adjust = 0 - for match in central_matches: - match_text = match.group() - index = match_text.rindex(separator[-1]) - location = match.start() + adjust + index - # Adjust the page text by adding spaces to align the separators - page_text = ( - page_text[:location] - + " " * (longest - index) - + page_text[location:] - ) - adjust += longest - index - return page_text - return page_text + page = [] + for row in page_text.splitlines(): + index = row.find(f" {separator[-1]} ") + addition = (longest - index) * " " + row = row.replace(f" {separator[-1]} ", f"{addition}{separator[-1]} ") + page.append(row) + return "\n".join(page) def page_needs_ocr(page: pdfplumber.pdf.Page, page_text: str) -> bool: @@ -343,9 +337,6 @@ def cleanup_content(content: str, page_number: int) -> str: :param page_number: the page number :return: the cleaned up text """ - if page_number == 1: - content = adjust_caption_lines(content) - # remove floating pipes pattern = r"\s{4,}\| $" # Substitute the matched pipe with an empty string @@ -357,6 +348,9 @@ def cleanup_content(content: str, page_number: int) -> str: # shift text left if possible and remove excess start and end whitespace content = remove_excess_whitespace(content) + if page_number == 1: + content = adjust_caption_lines(content) + return f"{content}\n" From 0b30bb96fd7009b9bda6d8fb5357ed30e3e11993 Mon Sep 17 00:00:00 2001 From: William Palin Date: Wed, 29 May 2024 15:23:34 -0400 Subject: [PATCH 11/20] tests(text_extraction): Add unit tests for new methods --- doctor/lib/text_extraction.py | 4 +- doctor/tests.py | 270 ++++++++++++++++++++++++++++++++++ 2 files changed, 273 insertions(+), 1 deletion(-) diff --git a/doctor/lib/text_extraction.py b/doctor/lib/text_extraction.py index 0ffb7b8..9fa9d96 100644 --- a/doctor/lib/text_extraction.py +++ b/doctor/lib/text_extraction.py @@ -124,7 +124,9 @@ def adjust_caption_lines(page_text: str) -> str: for row in page_text.splitlines(): index = row.find(f" {separator[-1]} ") addition = (longest - index) * " " - row = row.replace(f" {separator[-1]} ", f"{addition}{separator[-1]} ") + row = row.replace( + f" {separator[-1]} ", f"{addition}{separator[-1]} " + ) page.append(row) return "\n".join(page) diff --git a/doctor/tests.py b/doctor/tests.py index e295fe7..0893004 100644 --- a/doctor/tests.py +++ b/doctor/tests.py @@ -3,6 +3,7 @@ import re import glob import unittest +from unittest.mock import patch from pathlib import Path from tempfile import NamedTemporaryFile from zipfile import ZipFile @@ -10,6 +11,13 @@ import eyed3 import requests +from doctor.lib.text_extraction import ( + insert_whitespace, + get_word, + remove_excess_whitespace, + cleanup_content, + adjust_caption_lines, +) from doctor.lib.utils import make_file, make_buffer asset_path = f"{Path.cwd()}/doctor/test_assets" @@ -547,5 +555,267 @@ def test_pdf_400_mime(self): self.assertEqual(response.status_code, 400, msg="Wrong validation") +class TestRecapWhitespaceInsertions(unittest.TestCase): + """Test our whitespace insertion code""" + + def test_insert_whitespace_new_line(self): + content = "foo" + word = { + "line_num": 2, + "par_num": 1, + "left": 50, + "top": 200, + "width": 10, + "height": 20, + } + prev = { + "line_num": 1, + "par_num": 1, + "left": 10, + "top": 100, + "width": 30, + "height": 20, + } + result = insert_whitespace(content, word, prev) + self.assertEqual(result, "foo\n ") + + def test_insert_whitespace_new_paragraph(self): + content = "foo" + word = { + "line_num": 1, + "par_num": 2, + "left": 50, + "top": 200, + "width": 10, + "height": 20, + } + prev = { + "line_num": 2, + "par_num": 1, + "left": 10, + "top": 100, + "width": 30, + "height": 20, + } + result = insert_whitespace(content, word, prev) + self.assertEqual(result, "foo\n ") + + def test_insert_whitespace_vertical_gap(self): + content = "foo" + word = { + "line_num": 2, + "par_num": 1, + "left": 50, + "top": 300, + "width": 10, + "height": 20, + } + prev = { + "line_num": 1, + "par_num": 1, + "left": 10, + "top": 100, + "width": 30, + "height": 20, + } + result = insert_whitespace(content, word, prev) + self.assertEqual(result, "foo\n\n ") + + def test_insert_whitespace_horizontal_gap(self): + content = "foo" + word = { + "line_num": 1, + "par_num": 1, + "left": 200, + "top": 100, + "width": 10, + "height": 20, + } + prev = { + "line_num": 1, + "par_num": 1, + "left": 10, + "top": 100, + "width": 30, + "height": 20, + } + result = insert_whitespace(content, word, prev) + self.assertEqual(result, "foo ") + + def test_insert_whitespace_no_gap(self): + content = "foo" + word = { + "line_num": 1, + "par_num": 1, + "left": 50, + "top": 100, + "width": 10, + "height": 20, + } + prev = { + "line_num": 1, + "par_num": 1, + "left": 40, + "top": 100, + "width": 10, + "height": 20, + } + result = insert_whitespace(content, word, prev) + self.assertEqual(result, "foo") + + +class TestOCRConfidenceTests(unittest.TestCase): + """Test our OCR confidence checking functions.""" + + def test_confidence_zero(self): + word_dict = {"text": "foo", "conf": 0, "left": 10, "width": 30} + result = get_word(word_dict, 612, True) + self.assertEqual(result, " ") + + def test_confidence_low_and_in_margin(self): + word_dict = {"text": "foo", "conf": 30, "left": 5, "width": 20} + result = get_word(word_dict, 612, True) + self.assertEqual(result, " ") + + def test_confidence_below_threshold_short_word(self): + word_dict = {"text": "foo", "conf": 3, "left": 200, "width": 20} + result = get_word(word_dict, 612, True) + self.assertEqual(result, "□□□ ") + + def test_confidence_below_threshold_long_word(self): + word_dict = { + "text": "foobarbazfoobarbazfoobar", + "conf": 3, + "left": 200, + "width": 200, + } + result = get_word(word_dict, 612, True) + self.assertEqual(result, "□□□□□□□□□□□□□□□□□□□□□□□□ ") + + def test_confidence_below_threshold_in_right_margin(self): + word_dict = {"text": "foo", "conf": 30, "left": 580, "width": 10} + result = get_word(word_dict, 612, True) + self.assertEqual(result, "□□□ ") + + def test_valid_word_high_confidence(self): + word_dict = {"text": "foo", "conf": 90, "left": 50, "width": 20} + result = get_word(word_dict, 612, True) + self.assertEqual(result, "foo ") + + def test_word_on_left_edge(self): + word_dict = {"text": "foo", "conf": 50, "left": 0, "width": 20} + result = get_word(word_dict, 612, True) + self.assertEqual(result, " ") + + +class TestWhiteSpaceRemoval(unittest.TestCase): + + def test_left_shift(self): + """Can we properly shift our text left?""" + document = """ + foo + bar + foo + bar""" + expected_result = """ foo +bar +foo +bar""" + result = remove_excess_whitespace(document) + self.assertEqual(result, expected_result) + + def test_left_shift_when_artifact_exists(self): + """Shift left once""" + document = """ + foo + bar + | foo + bar""" + expected_result = """ foo + bar +| foo + bar""" + result = remove_excess_whitespace(document) + self.assertEqual(result, expected_result) + + +class TestCleanupContent(unittest.TestCase): + + def setUp(self): + # Patch the functions before each test method + patcher1 = patch( + "doctor.lib.text_extraction.adjust_caption_lines", + side_effect=lambda x: x, + ) + patcher2 = patch( + "doctor.lib.text_extraction.remove_excess_whitespace", + side_effect=lambda x: x, + ) + self.mock_adjust = patcher1.start() + self.mock_remove_whitespace = patcher2.start() + self.addCleanup(patcher1.stop) + self.addCleanup(patcher2.stop) + + def test_remove_floating_pipes(self): + """Can we remove a pipe""" + content = "This is a test line | \nAnother line" + expected_result = "This is a test line\nAnother line\n" + result = cleanup_content(content, 2) + self.assertEqual(result, expected_result) + + def test_remove_floating_artifacts_right_side(self): + """Can we remove an artifact on the far right""" + content = "This is a test line e \nAnother line" + expected_result = "This is a test line\nAnother line\n" + result = cleanup_content(content, 2) + self.assertEqual(result, expected_result) + + def test_remove_floating_pipes_and_artifacts(self): + """Test to remove just the period""" + content = "This is a test line | and the content continues\nThis is another test line e \nFinal line" + expected_result = "This is a test line | and the content continues\nThis is another test line\nFinal line\n" + result = cleanup_content(content, 2) + self.assertEqual(result, expected_result) + + def test_no_floating_pipes_or_artifacts(self): + """Test that no floating pipes are an issue""" + content = ( + "This is a test line JW-6\nAnother line\n" + ) + expected_result = ( + "This is a test line JW-6\nAnother line\n\n" + ) + result = cleanup_content(content, 2) + self.assertEqual(result, expected_result) + + def test_adjust_caption(self): + """Test if we can align the caption correctly""" + content = """ 10 + LESLIE MASSEY, ) Case No.: 2:16-cv-05001 GJS + ) + oe ) PROPOSED} ORDER AWARDING + 12 Plaintiff, ) EQUAL ACCESS TO JUSTICE ACT + ) ATTORNEY FEES AND EXPENSES + 13 VS. ) PURSUANT TO 28 U.S.C. § 2412(d) + NANCY A. BERRYHILL, Acting ) AND COSTS PURSUANT TO 28 + 14 || Commissioner of Social Security, ) U.S.C. § 1920 + 15 Defendant ) + 16 ) """ + + expected_result = """ 10 + LESLIE MASSEY, ) Case No.: 2:16-cv-05001 GJS + ) + oe ) PROPOSED} ORDER AWARDING + 12 Plaintiff, ) EQUAL ACCESS TO JUSTICE ACT + ) ATTORNEY FEES AND EXPENSES + 13 VS. ) PURSUANT TO 28 U.S.C. § 2412(d) + NANCY A. BERRYHILL, Acting ) AND COSTS PURSUANT TO 28 + 14 || Commissioner of Social Security, ) U.S.C. § 1920 + 15 Defendant ) + 16 ) """ + content = adjust_caption_lines(content) + self.assertEqual(expected_result, content) + + if __name__ == "__main__": unittest.main() From 1078bb9b803c663f951198cc5c291a316f2bc183 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 19:23:47 +0000 Subject: [PATCH 12/20] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- doctor/tests.py | 56 ++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/doctor/tests.py b/doctor/tests.py index 0893004..0b605f8 100644 --- a/doctor/tests.py +++ b/doctor/tests.py @@ -713,12 +713,12 @@ class TestWhiteSpaceRemoval(unittest.TestCase): def test_left_shift(self): """Can we properly shift our text left?""" document = """ - foo - bar + foo + bar foo bar""" - expected_result = """ foo -bar + expected_result = """ foo +bar foo bar""" result = remove_excess_whitespace(document) @@ -727,12 +727,12 @@ def test_left_shift(self): def test_left_shift_when_artifact_exists(self): """Shift left once""" document = """ - foo - bar + foo + bar | foo bar""" - expected_result = """ foo - bar + expected_result = """ foo + bar | foo bar""" result = remove_excess_whitespace(document) @@ -790,28 +790,28 @@ def test_no_floating_pipes_or_artifacts(self): def test_adjust_caption(self): """Test if we can align the caption correctly""" - content = """ 10 - LESLIE MASSEY, ) Case No.: 2:16-cv-05001 GJS - ) - oe ) PROPOSED} ORDER AWARDING - 12 Plaintiff, ) EQUAL ACCESS TO JUSTICE ACT - ) ATTORNEY FEES AND EXPENSES - 13 VS. ) PURSUANT TO 28 U.S.C. § 2412(d) - NANCY A. BERRYHILL, Acting ) AND COSTS PURSUANT TO 28 - 14 || Commissioner of Social Security, ) U.S.C. § 1920 - 15 Defendant ) + content = """ 10 + LESLIE MASSEY, ) Case No.: 2:16-cv-05001 GJS + ) + oe ) PROPOSED} ORDER AWARDING + 12 Plaintiff, ) EQUAL ACCESS TO JUSTICE ACT + ) ATTORNEY FEES AND EXPENSES + 13 VS. ) PURSUANT TO 28 U.S.C. § 2412(d) + NANCY A. BERRYHILL, Acting ) AND COSTS PURSUANT TO 28 + 14 || Commissioner of Social Security, ) U.S.C. § 1920 + 15 Defendant ) 16 ) """ - expected_result = """ 10 - LESLIE MASSEY, ) Case No.: 2:16-cv-05001 GJS - ) - oe ) PROPOSED} ORDER AWARDING - 12 Plaintiff, ) EQUAL ACCESS TO JUSTICE ACT - ) ATTORNEY FEES AND EXPENSES - 13 VS. ) PURSUANT TO 28 U.S.C. § 2412(d) - NANCY A. BERRYHILL, Acting ) AND COSTS PURSUANT TO 28 - 14 || Commissioner of Social Security, ) U.S.C. § 1920 - 15 Defendant ) + expected_result = """ 10 + LESLIE MASSEY, ) Case No.: 2:16-cv-05001 GJS + ) + oe ) PROPOSED} ORDER AWARDING + 12 Plaintiff, ) EQUAL ACCESS TO JUSTICE ACT + ) ATTORNEY FEES AND EXPENSES + 13 VS. ) PURSUANT TO 28 U.S.C. § 2412(d) + NANCY A. BERRYHILL, Acting ) AND COSTS PURSUANT TO 28 + 14 || Commissioner of Social Security, ) U.S.C. § 1920 + 15 Defendant ) 16 ) """ content = adjust_caption_lines(content) self.assertEqual(expected_result, content) From 0a2cd5e91d5d0a5abce4101b175ca0405c9f0607 Mon Sep 17 00:00:00 2001 From: William Palin Date: Wed, 29 May 2024 15:32:06 -0400 Subject: [PATCH 13/20] test(caption Adjustment): Add new test class --- doctor/tests.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doctor/tests.py b/doctor/tests.py index 0893004..2a38c9b 100644 --- a/doctor/tests.py +++ b/doctor/tests.py @@ -788,6 +788,8 @@ def test_no_floating_pipes_or_artifacts(self): result = cleanup_content(content, 2) self.assertEqual(result, expected_result) + +class TestRECAPCaptionAdjustments(unittest.TestCase): def test_adjust_caption(self): """Test if we can align the caption correctly""" content = """ 10 From 9c1c44c8fae7496042d6da2ff351528e15f03e3e Mon Sep 17 00:00:00 2001 From: William Palin Date: Wed, 29 May 2024 15:34:26 -0400 Subject: [PATCH 14/20] test(workflows) Add v3.11 and v3.12 to tests --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e60ac21..647cabe 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.10"] + python-version: ["3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From 7a29189044ef008a473ee42b93bce22276bc6b78 Mon Sep 17 00:00:00 2001 From: William Palin Date: Wed, 29 May 2024 15:50:22 -0400 Subject: [PATCH 15/20] test(adjustment) Add fix for test --- doctor/lib/text_extraction.py | 4 ++-- doctor/tests.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doctor/lib/text_extraction.py b/doctor/lib/text_extraction.py index 9fa9d96..fd3be5b 100644 --- a/doctor/lib/text_extraction.py +++ b/doctor/lib/text_extraction.py @@ -122,10 +122,10 @@ def adjust_caption_lines(page_text: str) -> str: ) page = [] for row in page_text.splitlines(): - index = row.find(f" {separator[-1]} ") + index = row.find(f" {separator[-1]}") addition = (longest - index) * " " row = row.replace( - f" {separator[-1]} ", f"{addition}{separator[-1]} " + f" {separator[-1]}", f"{addition}{separator[-1]}" ) page.append(row) return "\n".join(page) diff --git a/doctor/tests.py b/doctor/tests.py index 35a6718..5d8c935 100644 --- a/doctor/tests.py +++ b/doctor/tests.py @@ -788,8 +788,6 @@ def test_no_floating_pipes_or_artifacts(self): result = cleanup_content(content, 2) self.assertEqual(result, expected_result) - -class TestRECAPCaptionAdjustments(unittest.TestCase): def test_adjust_caption(self): """Test if we can align the caption correctly""" content = """ 10 @@ -816,6 +814,8 @@ def test_adjust_caption(self): 15 Defendant ) 16 ) """ content = adjust_caption_lines(content) + print(content) + print(expected_result) self.assertEqual(expected_result, content) From 0d12f95e25238fac76b20c853a0fe5782c3b9e3a Mon Sep 17 00:00:00 2001 From: William Palin Date: Thu, 30 May 2024 11:03:08 -0400 Subject: [PATCH 16/20] docs(readme) Add endpoint updates --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 7b8538e..c5da289 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,25 @@ Valid requests will receive a JSON response with the following keys: - `extracted_by_ocr`: Whether OCR was needed and used during processing. - `page_count`: The number of pages, if it applies. +### Endpoint: /extract/recap/text/ + +Given a RECAP pdf, extract out the text using PDF Plumber, OCR or a combination of the two + +Parameters: + + - `strip_margin`: Whether doctor should crop the edges of the recap document during processing. With PDF plumber it will ignore traditional 1 inch margin. With an OCR it lowers the threshold for hiding OCR gibberish. To enable it, set strip_margin to `True`: + +```bash +curl 'http://localhost:5050/extract/recap/text/?strip_margin=True' \ + -X 'POST' \ + -F "file=@doctor/recap_extract/gov.uscourts.cacd.652774.40.0.pdf" +``` + +Valid requests will receive a JSON response with the following keys: + + - `content`: The utf-8 encoded text of the file + - `extracted_by_ocr`: Whether OCR was needed and used during processing. + ## Utilities From 5d19f5781fe9fd5c5166109513581fa397f4ade0 Mon Sep 17 00:00:00 2001 From: William Palin Date: Thu, 30 May 2024 11:50:54 -0400 Subject: [PATCH 17/20] fix(text_extract) Updates from PR Small tweaks to doc strings Update func names slight refactor of adjust caption lines --- doctor/lib/text_extraction.py | 110 +++++++++++++++++----------------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/doctor/lib/text_extraction.py b/doctor/lib/text_extraction.py index fd3be5b..b472814 100644 --- a/doctor/lib/text_extraction.py +++ b/doctor/lib/text_extraction.py @@ -67,7 +67,7 @@ def get_page_text(page: pdfplumber.PDF.pages, strip_margin: bool) -> str: return doc_text -def page_images(page: pdfplumber.pdf.Page) -> bool: +def has_images(page: pdfplumber.pdf.Page) -> bool: """Does the page have images that are large enough to contain text :param page: pdf plumber page @@ -82,7 +82,7 @@ def page_images(page: pdfplumber.pdf.Page) -> bool: ) -def page_annotations(page: pdfplumber.pdf.Page) -> bool: +def has_text_annotations(page: pdfplumber.pdf.Page) -> bool: """Does the page have annotations which could contain text :param page: pdf plumber @@ -107,25 +107,24 @@ def adjust_caption_lines(page_text: str) -> str: :param page_text: The text of the first page :return: The page text """ - for separator in [r"\)", "§", ":"]: - matches = list(re.finditer(rf"(.* +{separator} .*\n)", page_text)) + for separator in [r")", "§", ":"]: + pattern = rf"(.* +{re.escape(separator)} .*\n)" + matches = list(re.finditer(pattern, page_text)) central_matches = [ - match + match.group().rindex(separator) for match in matches - if 30 <= match.group().rindex(separator[-1]) <= 70 + if 30 <= match.group().rindex(separator) <= 70 ] if len(central_matches) < 3: continue # Skip this separator if less than 3 matches found # Determine the longest position of the separator - longest = max( - match.group().rindex(separator[-1]) for match in central_matches - ) + longest = max(central_matches) page = [] for row in page_text.splitlines(): - index = row.find(f" {separator[-1]}") + index = row.find(f" {separator}") addition = (longest - index) * " " row = row.replace( - f" {separator[-1]}", f"{addition}{separator[-1]}" + f" {separator}", f"{addition}{separator}" ) page.append(row) return "\n".join(page) @@ -141,8 +140,8 @@ def page_needs_ocr(page: pdfplumber.pdf.Page, page_text: str) -> bool: if ( page_text.strip() == "" or "(cid:" in page_text - or page_annotations(page) - or page_images(page) + or has_text_annotations(page) + or has_images(page) or len(page.curves) > 10 ): return True @@ -179,24 +178,24 @@ def convert_pdf_page_to_image( def ocr_image_to_data(image: Image) -> list[pd.DataFrame]: """Perform OCR on an image to extract data - Detailed Parameters for `pytesseract.image_to_data`: - - config: str - Additional Tesseract configuration options. - - `-c preserve_interword_spaces=1`: Preserve spaces between words as they appear in the image. - - `-c tessedit_do_invert=0`: Do not invert the image colors. - - `--psm 6`: Page segmentation mode 6, which assumes a single uniform block of text. - - `-l eng`: Use the English language for OCR. - - output_type: pytesseract.Output.DICT - Specifies that the output should be a dictionary of OCR data. - - Reference: - Tesseract OCR documentation: https://github.com/tesseract-ocr/tesseract/blob/master/doc/tesseract.1.asc - - Convert the image of the pdf page to OCR data :param image: Pil Image :return: A list of DataFrames, each containing OCR data for a block of text """ + + # Detailed Parameters for `pytesseract.image_to_data`: + # - config: str + # Additional Tesseract configuration options. + # - `-c preserve_interword_spaces=1`: Preserve spaces between words as they appear in the image. + # - `-c tessedit_do_invert=0`: Do not invert the image colors. + # - `--psm 6`: Page segmentation mode 6, which assumes a single uniform block of text. + # - `-l eng`: Use the English language for OCR. + # - output_type: pytesseract.Output.DICT + # Specifies that the output should be a dictionary of OCR data. + # + # Reference: + # Tesseract OCR documentation: https://github.com/tesseract-ocr/tesseract/blob/master/doc/tesseract.1.asc + data_dict = pytesseract.image_to_data( image, config="-c preserve_interword_spaces=1x1 -c tessedit_do_invert=0 --psm 6 -l eng", @@ -269,46 +268,49 @@ def get_word(word_dict: dict, width: float, strip_margin: bool) -> str: This function determines if a word should be added to the page content and adds the word. - tesseract provides confidence values for its OCR outputs. We use those - confidence values to determine if something is a good OCR output, a - likely artifact and should be excluded or is bad ocr but not an artifact. - - If a word has a zero confidence or starts on the left most edge of the paper - we return it as an empty string. It is likely an artifact. - - If a word has confidence below 40, a number that usually equates to 3 to 5 - standard deviations from confidences found in other words is entirely in the - margin of the page - its likely an artifact as well. - - If a confidence is below 5 - for a very short word - or for a very long word - its likely part of the document but we have no idea so we return a square - box to indicate that. This is often caused by stamps or lines in case captions - - Finally if a low confidence word starts in the right margin - its likely a - bad OCR that is multiple standard deviations away so we return the word as - empty squares. - :param word_dict: the word object from tesseract :param width: The width of the document :param strip_margin: should we strip the margin :return: The text with space """ + pixels_per_inch = width / 8.5 if strip_margin: - left_margin = (1 / 8.5) * width - right_margin = (7.5 / 8.5) * width + left_margin = 1 * pixels_per_inch # + right_margin = 7.5 * pixels_per_inch else: - left_margin = (0.5 / 8.5) * width - right_margin = (8.0 / 8.5) * width + left_margin = 0.5 * pixels_per_inch + right_margin = 8.0 * pixels_per_inch + + # tesseract provides confidence values for its OCR outputs. We use those + # confidence values to determine if something is a good OCR output, a + # likely artifact and should be excluded or is bad ocr but not an artifact. word = word_dict["text"] conf = word_dict["conf"] - if word_dict["left"] + word_dict["width"] < left_margin and conf < 40: + + no_confidence = 0 + very_low_confidence = 5 + low_confidence = 40 + short_word_len = 3 + long_word_len = 20 + if word_dict["left"] + word_dict["width"] < left_margin and conf < low_confidence: + # If a word has confidence below 40, a number that usually equates to 3 to 5 + # standard deviations from confidences found in other words is entirely in the + # margin of the page - its likely an artifact as well. word = " " * len(word) - elif (conf == 0 and len(word) < 4) or word_dict["left"] == 0: + elif (conf == no_confidence and len(word) < short_word_len) or word_dict["left"] == 0: + # If a word has a zero confidence or starts on the left most edge of the paper + # we return it as an empty string. It is likely an artifact. word = " " * len(word) - elif conf < 5 and (len(word) < 4 or len(word) > 20): + elif conf < very_low_confidence and (len(word) < short_word_len or len(word) > long_word_len): + # If a confidence is below 5 - for a very short word - or for a very long word + # its likely part of the document but we have no idea so we return a square + # box to indicate that. This is often caused by stamps or lines in case captions word = "□" * len(word) - elif conf < 40 and word_dict["left"] > right_margin: + elif conf < low_confidence and word_dict["left"] > right_margin: + # Finally if a low confidence word starts in the right margin - its likely a + # bad OCR that is multiple standard deviations away so we return the word as + # empty squares. word = "□" * len(word) return f"{word} " From 5801d2d5d0197ca408e295504ed37c4e4a99ba92 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 15:51:13 +0000 Subject: [PATCH 18/20] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- doctor/lib/text_extraction.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/doctor/lib/text_extraction.py b/doctor/lib/text_extraction.py index b472814..5bcf985 100644 --- a/doctor/lib/text_extraction.py +++ b/doctor/lib/text_extraction.py @@ -123,9 +123,7 @@ def adjust_caption_lines(page_text: str) -> str: for row in page_text.splitlines(): index = row.find(f" {separator}") addition = (longest - index) * " " - row = row.replace( - f" {separator}", f"{addition}{separator}" - ) + row = row.replace(f" {separator}", f"{addition}{separator}") page.append(row) return "\n".join(page) @@ -195,7 +193,7 @@ def ocr_image_to_data(image: Image) -> list[pd.DataFrame]: # # Reference: # Tesseract OCR documentation: https://github.com/tesseract-ocr/tesseract/blob/master/doc/tesseract.1.asc - + data_dict = pytesseract.image_to_data( image, config="-c preserve_interword_spaces=1x1 -c tessedit_do_invert=0 --psm 6 -l eng", @@ -275,7 +273,7 @@ def get_word(word_dict: dict, width: float, strip_margin: bool) -> str: """ pixels_per_inch = width / 8.5 if strip_margin: - left_margin = 1 * pixels_per_inch # + left_margin = 1 * pixels_per_inch # right_margin = 7.5 * pixels_per_inch else: left_margin = 0.5 * pixels_per_inch @@ -293,16 +291,23 @@ def get_word(word_dict: dict, width: float, strip_margin: bool) -> str: low_confidence = 40 short_word_len = 3 long_word_len = 20 - if word_dict["left"] + word_dict["width"] < left_margin and conf < low_confidence: + if ( + word_dict["left"] + word_dict["width"] < left_margin + and conf < low_confidence + ): # If a word has confidence below 40, a number that usually equates to 3 to 5 # standard deviations from confidences found in other words is entirely in the # margin of the page - its likely an artifact as well. word = " " * len(word) - elif (conf == no_confidence and len(word) < short_word_len) or word_dict["left"] == 0: + elif (conf == no_confidence and len(word) < short_word_len) or word_dict[ + "left" + ] == 0: # If a word has a zero confidence or starts on the left most edge of the paper # we return it as an empty string. It is likely an artifact. word = " " * len(word) - elif conf < very_low_confidence and (len(word) < short_word_len or len(word) > long_word_len): + elif conf < very_low_confidence and ( + len(word) < short_word_len or len(word) > long_word_len + ): # If a confidence is below 5 - for a very short word - or for a very long word # its likely part of the document but we have no idea so we return a square # box to indicate that. This is often caused by stamps or lines in case captions From 979adf3cd6254c2c447a60fa6e1848c67969d4ce Mon Sep 17 00:00:00 2001 From: William Palin Date: Thu, 30 May 2024 11:57:57 -0400 Subject: [PATCH 19/20] fix(text): Fix variable value --- doctor/lib/text_extraction.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doctor/lib/text_extraction.py b/doctor/lib/text_extraction.py index 5bcf985..6b9f5f0 100644 --- a/doctor/lib/text_extraction.py +++ b/doctor/lib/text_extraction.py @@ -299,14 +299,14 @@ def get_word(word_dict: dict, width: float, strip_margin: bool) -> str: # standard deviations from confidences found in other words is entirely in the # margin of the page - its likely an artifact as well. word = " " * len(word) - elif (conf == no_confidence and len(word) < short_word_len) or word_dict[ + elif (conf == no_confidence and len(word) <= short_word_len) or word_dict[ "left" ] == 0: # If a word has a zero confidence or starts on the left most edge of the paper # we return it as an empty string. It is likely an artifact. word = " " * len(word) elif conf < very_low_confidence and ( - len(word) < short_word_len or len(word) > long_word_len + len(word) <= short_word_len or len(word) > long_word_len ): # If a confidence is below 5 - for a very short word - or for a very long word # its likely part of the document but we have no idea so we return a square From 47d4a046ccb8eaa54dc0f90bb097a4ada653f9f6 Mon Sep 17 00:00:00 2001 From: William Palin Date: Thu, 30 May 2024 11:58:36 -0400 Subject: [PATCH 20/20] fix(tests): Remove print in tests --- doctor/tests.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/doctor/tests.py b/doctor/tests.py index 5d8c935..f285ec0 100644 --- a/doctor/tests.py +++ b/doctor/tests.py @@ -298,7 +298,6 @@ def test_mime_type(self): files=files, params=params, ).json() - print(response) self.assertEqual( response["mimetype"], "application/pdf", @@ -814,8 +813,6 @@ def test_adjust_caption(self): 15 Defendant ) 16 ) """ content = adjust_caption_lines(content) - print(content) - print(expected_result) self.assertEqual(expected_result, content)