From 9941ce06e97701502060e94c230d089ae86e5e32 Mon Sep 17 00:00:00 2001 From: Gus Class Date: Mon, 20 Mar 2017 17:25:40 -0700 Subject: [PATCH 1/3] Adds document text detection tutorial. --- vision/cloud-client/document_text/README.rst | 110 ++++++++++++++ .../cloud-client/document_text/README.rst.in | 22 +++ vision/cloud-client/document_text/doctext.py | 134 ++++++++++++++++++ .../document_text/doctext_test.py | 24 ++++ .../document_text/requirements.txt | 2 + .../document_text/resources/text_menu.jpg | Bin 0 -> 53217 bytes 6 files changed, 292 insertions(+) create mode 100644 vision/cloud-client/document_text/README.rst create mode 100644 vision/cloud-client/document_text/README.rst.in create mode 100644 vision/cloud-client/document_text/doctext.py create mode 100644 vision/cloud-client/document_text/doctext_test.py create mode 100644 vision/cloud-client/document_text/requirements.txt create mode 100644 vision/cloud-client/document_text/resources/text_menu.jpg diff --git a/vision/cloud-client/document_text/README.rst b/vision/cloud-client/document_text/README.rst new file mode 100644 index 000000000000..659e4111f393 --- /dev/null +++ b/vision/cloud-client/document_text/README.rst @@ -0,0 +1,110 @@ +.. This file is automatically generated. Do not edit this file directly. + +Google Cloud Vision API Python Samples +=============================================================================== + +This directory contains samples for Google Cloud Vision API. `Google Cloud Vision API`_ allows developers to easily integrate vision detection features within applications, including image labeling, face and landmark detection, optical character recognition (OCR), and tagging of explicit content + + + + +.. _Google Cloud Vision API: https://cloud.google.com/vision/docs + +Setup +------------------------------------------------------------------------------- + + +Authentication +++++++++++++++ + +Authentication is typically done through `Application Default Credentials`_, +which means you do not have to change the code to authenticate as long as +your environment has credentials. You have a few options for setting up +authentication: + +#. When running locally, use the `Google Cloud SDK`_ + + .. code-block:: bash + + gcloud beta auth application-default login + + +#. When running on App Engine or Compute Engine, credentials are already + set-up. However, you may need to configure your Compute Engine instance + with `additional scopes`_. + +#. You can create a `Service Account key file`_. This file can be used to + authenticate to Google Cloud Platform services from any environment. To use + the file, set the ``GOOGLE_APPLICATION_CREDENTIALS`` environment variable to + the path to the key file, for example: + + .. code-block:: bash + + export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service_account.json + +.. _Application Default Credentials: https://cloud.google.com/docs/authentication#getting_credentials_for_server-centric_flow +.. _additional scopes: https://cloud.google.com/compute/docs/authentication#using +.. _Service Account key file: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount + +Install Dependencies +++++++++++++++++++++ + +#. Install `pip`_ and `virtualenv`_ if you do not already have them. + +#. Create a virtualenv. Samples are compatible with Python 2.7 and 3.4+. + + .. code-block:: bash + + $ virtualenv env + $ source env/bin/activate + +#. Install the dependencies needed to run the samples. + + .. code-block:: bash + + $ pip install -r requirements.txt + +.. _pip: https://pip.pypa.io/ +.. _virtualenv: https://virtualenv.pypa.io/ + +Samples +------------------------------------------------------------------------------- + +Document Text tutorial ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + + +To run this sample: + +.. code-block:: bash + + $ python doctext.py + + usage: doctext.py [-h] image_file + + positional arguments: + image_file The image for text detection. + + optional arguments: + -h, --help show this help message and exit + + + + +The client library +------------------------------------------------------------------------------- + +This sample uses the `Google Cloud Client Library for Python`_. +You can read the documentation for more details on API usage and use GitHub +to `browse the source`_ and `report issues`_. + +.. Google Cloud Client Library for Python: + https://googlecloudplatform.github.io/google-cloud-python/ +.. browse the source: + https://github.com/GoogleCloudPlatform/google-cloud-python +.. report issues: + https://github.com/GoogleCloudPlatform/google-cloud-python/issues + + +.. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file diff --git a/vision/cloud-client/document_text/README.rst.in b/vision/cloud-client/document_text/README.rst.in new file mode 100644 index 000000000000..72117cdc7aef --- /dev/null +++ b/vision/cloud-client/document_text/README.rst.in @@ -0,0 +1,22 @@ +# This file is used to generate README.rst + +product: + name: Google Cloud Vision API + short_name: Cloud Vision API + url: https://cloud.google.com/vision/docs + description: > + `Google Cloud Vision API`_ allows developers to easily integrate vision + detection features within applications, including image labeling, face and + landmark detection, optical character recognition (OCR), and tagging of + explicit content. + +setup: +- auth +- install_deps + +samples: +- name: Document Text tutorial + file: doctext.py + show_help: True + +cloud_client_library: true diff --git a/vision/cloud-client/document_text/doctext.py b/vision/cloud-client/document_text/doctext.py new file mode 100644 index 000000000000..c0f1e10a78a9 --- /dev/null +++ b/vision/cloud-client/document_text/doctext.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python + +# Copyright 2017 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Outlines document text given an image. + +Example: + python doctext.py resources/cropme.jpg +""" +# [START full_tutorial] +# [START imports] +import argparse +from enum import Enum +import io + +from google.cloud import vision +from PIL import Image, ImageDraw +# [END imports] + + +class FeatureType(Enum): + PAGE = 1 + BLOCK = 2 + PARA = 3 + WORD = 4 + SYMBOL = 5 + + +def draw_boxes(im, blocks, color, width): + """Draw a border around the image using the hints in the vector list.""" + # [START draw_blocks] + draw = ImageDraw.Draw(im) + + for block in blocks: + draw.line([block.vertices[0].x, block.vertices[0].y, + block.vertices[1].x, block.vertices[1].y], + fill=color, width=width) + draw.line([block.vertices[1].x, block.vertices[1].y, + block.vertices[2].x, block.vertices[2].y], + fill=color, width=width) + draw.line([block.vertices[2].x, block.vertices[2].y, + block.vertices[3].x, block.vertices[3].y], + fill=color, width=width) + draw.line([block.vertices[3].x, block.vertices[3].y, + block.vertices[0].x, block.vertices[0].y], + fill=color, width=width) + + return im + # [END draw_blocks] + + +def get_document_bounds(image_file, feature): + # [START detect_bounds] + """Returns document bounds given an image.""" + vision_client = vision.Client() + + bounds = [] + + with io.open(image_file, 'rb') as image_file: + content = image_file.read() + + image = vision_client.image(content=content) + document = image.detect_full_text() + + for b, page in enumerate(document.pages): + + for bb, block in enumerate(page.blocks): + + for p, paragraph in enumerate(block.paragraphs): + + for w, word in enumerate(paragraph.words): + + for s, symbol in enumerate(word.symbols): + + if (feature == FeatureType.SYMBOL): + bounds.append(symbol.bounding_box) + + if (feature == FeatureType.WORD): + bounds.append(word.bounding_box) + + if (feature == FeatureType.PARA): + bounds.append(paragraph.bounding_box) + + if (feature == FeatureType.BLOCK): + bounds.append(block.bounding_box) + + if (feature == FeatureType.PAGE): + bounds.append(block.bounding_box) + + return bounds + # [END detect_bounds] + + +def render_doc_text(filein, fileout): + # [START render_doc_text] + im = Image.open(filein) + bounds = get_document_bounds(filein, FeatureType.PAGE) + draw_boxes(im, bounds, 'blue', 3) + bounds = get_document_bounds(filein, FeatureType.PARA) + draw_boxes(im, bounds, 'green', 2) + bounds = get_document_bounds(filein, FeatureType.WORD) + draw_boxes(im, bounds, 'yellow', 1) + + if fileout is not 0: + im.save(fileout) + else: + im.show() + # [END render_doc_text] + + +if __name__ == '__main__': + # [START run_crop] + parser = argparse.ArgumentParser() + parser.add_argument('detect_file', help='The image for text detection.') + parser.add_argument('-out_file', help='Optional output file', default=0) + args = parser.parse_args() + + parser = argparse.ArgumentParser() + render_doc_text(args.detect_file, args.out_file) + + # [END run_crop] +# [END full_tutorial] diff --git a/vision/cloud-client/document_text/doctext_test.py b/vision/cloud-client/document_text/doctext_test.py new file mode 100644 index 000000000000..4ee892a832f0 --- /dev/null +++ b/vision/cloud-client/document_text/doctext_test.py @@ -0,0 +1,24 @@ +# Copyright 2017 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import doctext + + +def test_text(cloud_config, capsys): + """Checks the output image for drawing the crop hint is created.""" + doctext.render_doc_text('resources/text_menu.jpg', 'output-text.jpg') + out, _ = capsys.readouterr() + assert os.path.isfile('output-text.jpg') diff --git a/vision/cloud-client/document_text/requirements.txt b/vision/cloud-client/document_text/requirements.txt new file mode 100644 index 000000000000..540c2fa7db4d --- /dev/null +++ b/vision/cloud-client/document_text/requirements.txt @@ -0,0 +1,2 @@ +google-cloud-vision==0.23.2 +pillow==4.0.0 diff --git a/vision/cloud-client/document_text/resources/text_menu.jpg b/vision/cloud-client/document_text/resources/text_menu.jpg new file mode 100644 index 0000000000000000000000000000000000000000..caa678b3e7ca1854e42c2459c255057567ed2c3c GIT binary patch literal 53217 zcmbTd1yoyI*De|eRj%3gc#XYZLQ&z$Sw*TXX4v6`}~G5`w;0Dxj%fQJ=8 znvy@v5dhHC1n>X=00ICm76kx^>0x1B04zEH?tl6KfEpJ4|Lp5w2?4M%6Na#3w z_;`3bdw8;l2nYfs6je2G{yht({io0IpYG!+#`xb!fI6J*@JE?{FBL-{IsxPaSl!qr zK&+<#Y;r6hIo3ljfEjZ&xLE&b|Cxr_U||DsaPja79uX2@c4&MIz{Uasv2lR7xc{C8 zD+Kd90EZlxf>lTXk5bnL|0$eGI3gvFfK9Qs3#2!G$Sz{*75Rve`Uwp!9S0{DH<(9M z?3uWPq}1~lO3ErwRW*GBLnC7oQ!_hz2S+Don2Wd1YhOSAfWWBenAkUO-yu@pr=@3n z$oz=RFDNW3E-5W5ud8op{L<9i(%RkA+t)uZIP`sDa%y^J_Sf&ZmDRQNjZO5{_Ri7q z$?4ho#pTuYzql~>^S@wWw*Q6ff5SzN!G(>31H{4q7Z(<`-@m}gad26M@F)~?@onIg zPlY20s1#H3YP%k>iRc}IY`w+_so6zWIF9~>_8(;b-+)E_|3daZf&DLB^ML07AT~DP z|Em%Fr%&*IXoUZc6B0fmARr+jBp|^&RDuW0L9l>0IC!{t1bBD^1o-&)|A)!{m*Iy+ zj979$%mIjjSQudfk^|%br)6#*7>l1vHK_toTO{&6&+sK5 z0CIOO3&U)5RquE|OAP3n>;lm#3pYo*=J!@|=(94p>jyy06UGsLX+WqMO0x-vLIG6Q z__T(KD$&VrxU0`fyfZ2E0r2K>=EH9lnJ|=DWC(}m(`ucRfztB*g2`LVZ0Bc@(v-TY zxj8>!3n}ja^WnI3Zp&H&x96g$--*(b-+F&Dqf4p?jK%Dx(z0`S*8PZn%^3e4rHX*= zX(ou2L`)@;UEVpr-!%dIC`(ik1*Oa+|Mnh!n!HF?10H5mInYpCbm2-d;@glh{O5Df z^j6g{HKmlgbPn&c6P;ay8S%6GbgIv&lY6S(clJ{frFbRC`0j-xT_XK$rSFe-(vr&c z&E^x86c|kR)H+QNw_#GqM+%i65E*l}V4;QIM(2grB=)1_$*`*ONxWgMXgwT|8i~4$ z{=PtGelKMfd8?_m>-Q9iw>?*IY`$w`v?f}?UEV@mo>yjLH_Ch$SZB4AOsC-W zxmj|x@QHGc%0#+ROzu>iVsN})<$8n57hIl`Ju`25Z}NeX+Re)9Oqb!tUzUxIM4f@g z1{~gB2!&Oo1MKd@is;-+$2UTc88-ZBM)e>B)se2AuACv#_>h2V#A^pNHJ$N%kT@+D zqnM2LT6N}2(kZS7K-J{!c@5Hfijg_KfV5*}JKlIppkt*WMJOJPvdsUcdf9l`SwPVO zpzxHktJ$6e`NtdV%EAs@iI`*Dg3K4+`%|ty`^($J7D+~X?Nk-$Rwrj=F*!4Wo z`#NzMaq0oQmFH3X>dSD!6m@i3lhwbHy*5mSBqnum)i2xnxL5ab4N<^dc>^(l;*n~f zTpOYjzX?>pe(xt0$G@K@NI6pd#~pmNttCV`Wh~;@#H|IvePPeySou?$&g}`1Hvs>v z$}ovdj5&Qr=pJOdDD>xg!hI{&Z~->1jz9+KsW9FcQVxKOJv>`NpWP;ic0=$lr~M00 z%Q)YkRL)uDrKR`N;9s2;2iVQu-h*KHC01zl4Q7vt=)amt4`YAdyiJae>eF^D=k=+E z?b|rW*wxZ(pOx`9a?cjnjTw_9XyqZ1sfc0mu35mbEBkLK+0wniUwi|Oiw6K_xGVBm zUCf|$&>f_V&%=S)-}?@7w=F7Cj$Mckim)kd8DuMYJ}W!5IcvgTcT@x~@NXw}r5>;% z>D(bDak;v6O#Z>+OlF$0%M&IOcD9#lC%g6f8i8E8Gta{)BDDxaIy-^mh3aXa;twucjh1TVO|u^KuN@~@aCvr zU~4~;tWK_nwTzx*$Z5QAY|6*SA)h_mvyuwdx^#*(#h1Bfy8<4lLa(l;3>wX|lcI0E zHAn^cBywCQ*uH`f7 ze+-RfK!uHG(t-ierQg)De4IM?nk(R=IjFn9?!)uXby$P!WS9%ysp@%RcDb$4_q!M= z+y6;P6d9DPi6yt9f%x?R$eHH-fk?Lqk?YUP%Fj;rV}y-sVurJ)tFmt<9o`zfdbDPV ztKZg8s0z(<7Vp12v4$}m31;cuhN#3wqZVqq%CMeWaB#gQ*|zGYn7VokwcNw_ zWR&5%qy;ueD@Kt*Toz_N=a|@)Xn}p2?cmLv(oRkIMZ&i#pDIJ6uI^t}q;BSl8nTPJ zb?)xVjk;(mcV#BR69bQ377q00RYKR6 z;;^!8ih1qt!_3U*0qsZTx@K4t6@Ru@FpueMJK~K80lswoUQT)_6i)$vcL}*f&(wk5 z)ssy?tzz!h_4JGPFQM=*&`Z;=%!hfWl-aRmD`Q!y=37#CVNw~u=;2={+KJm&`TYE` z0SA|B7_2Ux>9rRD_XfmS&~NT%U)(Dw)kfj>L7SD@*++`DVtK7%`Smx(lEi!2b|+O5 z0_GE?B#)*ZD*%y$9~9KaTe8;>KeBWsw)MTfU&zwqr_7}^q$HF)0H%%fPS+&LKf6dL z%8fX;4>=ID@nH?g7zN)`U&RqypJUKmR97GqVmR5}w;opi^%Z@-GV?sy`#wajyERq~ zp_cM%<24!CAo_rOL|N{`L~iT&#(V=aM$Trd8>*CD!dG+0Hu~j04l7Z|aJ#F@ecT?K z^|VYzVlh;m6&89zZ+S>))M`$!6%KwGTPq22@FM_!K5@>O(U!fnxi^@+4;!tLK*B_; zh3I0bW&(BY8^WoPO8nw59bh=%L*BS+^F-Z4x?kAJqG)DG>_DGYN4-`aLYhY$U-Z_*D5*LyN-?~q-Ga|DCiqYHa*$5$_J@svF5GJh zD$$VZEcYI1DxT%;=LE=_ipfJ{yc&SFum%Wkg#XDz%I3A!Lov z#{Nr>{y3gBnbXk@jS%mbhV}3RD{`~6vY|3wW^d&Nmp(Ott>8)WJ|TCA7A%!=wDise zH?*h2Lv6!xmh0r?^xmMZZ^1xXXz<$L>j=*zM{WM{gtR-;8BqsFw}+Unh}EK=>T*{v zr0G{^W1OFCfSB=~99mSA?O|fO`nA99Rp=I5E(6)IOG8F&eT6%hOuQYVglr?p10b1n zhSo0UYFEef*FcM}99sYqkm_OJZ_BkK@m8{)p zw=`Y#Vhj=CP+M!d+5>>vldP%A+27~8a9#W%0o(q?;AYWOjas(bNJy(L zJU+_Mx`nNzaWD@UD-3XDpglm%^;G7 zL`{c*RSO^eBn!CwELC>8B<%x$t%_Z@p89jiuA&Pf=mCHV>`&5*&$eD43(h4N#ksx* z8B>ZcPZ>mdckUWh?f3Xp+fv2bV*_MM-umfF6eA1mrVdkj8Gr%yw~61Wh5YRv_$J536v(0MXFhF%kZl4z%s7Z|V|GP$;8|;CUfBsagiWI0oo; zHXWg~ys}YE7eGSUjgIsxH!f!dwutlt~(>ev_a_q!MIYmS~(wyW#% z&Rda#<0{f?{>oyT`$mte2BdA!qC4UlGHk`2ndGyK+P-r+OE`jPAKzB+d-T}h z--_sn@{xK!Pl!#dDXrYoRyWqG6c+lklpuRZZXD%U=j=3s0(}FW`7mI#G74=;!vDVi zm$eEz>GHMl(p*j^gLORO>H)Ai+imT&C6uTlLskWQWYXOT5(_O!fJyyO_L8!v5V?&B z;)-f>ug23}8N3f^-|gP7LO$a$#tBR;mmycV5-xt^8C z-j*$!nasG~F$;xX@zAho77fOql$qw9Ki;$8G8~M5@%jw&{aQZ~V?ipE(#S`PbnW8x zpMRbtfT&zye%jR!?d@16tV_sA+v`9h@=y610L%^(?Lm;HO#E*7+Y5L(gGQHHb(||0Q4iT&BA;_72~i*lPEbS)3>CsCJ)P= z&gwJNFxSj9a*VA>em~olAEPYd#fozf4gQRekL++yX_9WG?8kSh_gESsUr43A<$r5y5w`yuD(f5R zYvN>ZT^l+#=+S(JxZKX!u#o(^cl^|&`=fw*>lcIH{p(N&=#usp*7`yTPbzV`5qDZt zHBL5Ttpsg${W^t)OUxatu*36LpRgF0`*f3w4dJ!rao(H)zuV6>SZ~^TLvn*_nt8X2YbLp40LkGp+CkzXfKAB-j4XET zbl_44$T>4cZd6q>-AZoAet67m)p=3aIA$ojuQGL(->vj@H#hG6S><4`A?=o{;*B<` z;G*=+jDaO#eBipzDR#IhrLnfz^9lhtvU2Ik^WCe7nm3Oh2MiVpZ?s?9%40~2y8ilC z4WBB_TTb_O&#H)ZJ?UVud00y^Gp)|~lt+iVR->AYD!!4IpVf@-5jo9H!%V;q?n_?Px-#O<)=2`4*}T1;{7U?7DrO z*$=@rN(8-UPeh?XAI{%S9p%W4ie=HxmWU}{Xb}qroS&8cZ7hPwG2b^jTZBm|e~=Bk ztUAmT6o@KeIZ2mWIjcblyqbG9_j|2F;(GPl{A|^e@(a|5z43A_nOZ=$s|gRJj_mXw-%b1v^CcLU~aQi z=%lK<{{uimjNkBG%fr+`t?IX|^JIy^+ilg0YWBp8Sd12}V$)&JlQyWs1&Y!soRw@A zVg*iTt`4CQm2^cg*xOpqTu)LL++zG;2zA8UGCjA#->R(xPb+{==YC#P`L9UyncmQrZhWBni!WDg&eS-(K)5Y7yy%)N zmEqmB7Ns{vc(>Eor+%KRAXgID{Q!u5%dpHOOa|hxXjKwI7QE5HaV#SVm09z|DA(78 zs;|ombve2tQstR-4e*+1Wu#Dfo8^7%R>vpzfqJj{>@EDiNc@3W(?oPh?COPeYtxg` z=-PZJ%ddB9drt53dN;A)sDi(gdq-tcPKxj8e9?>0M*W*Wxr3yiVL2{S-oU})ehxXR z;>;gvtF|Ixs3H!DDcj^~Fo>oMmo_&qdV;zrKTzSic z_;g`m@W!i0=UYMO!|H>sZ^GQZOy5 z&lE}&jbE)&12S8h3-&ViCCkM>-ZQ<(;cYe68~^*Z?u@=!#vAdz?;hfuv_Bat>7m3_ za?2ZuHW{WBcz>`S%bu#GcG9`l=(2TvTlq6aSV6*OtZYAIVAs^h>aky&3nllB*CK#_ zT&1kK+tf%fko#f{b>C6-lyK?kSD*NFT8S;`5NYJ5PX~o&GO6l5ty+8#<)4XGq8dtE zTAQwZDF*b|YtbJbR22-uYr9eX;4RHTxfNcZbi~S+Q!dm=pGnJ6B+FG7a5g8Ty?kP+ zdw~&^D0PD}Gp>(_ouE3IoXCtBZ=CuN^B2AJk0Ne#!8`evlF{7@Aq2ofL z0`QbQ5H_E2{eIiqL&O`zyD{QTQjD;`uxBk-q+6b?t zaILh=+4-1O^pW_!gzf@q`pEFg2W9t1IOj5v3oDpByz@qEh**|_Vk9I+^<>jiIHOqldtaS@ zKRV-z4;9;~8_*Rjf#>M2$`NXQ14Gw|1%bYDortfvu?K0f>*NKH9T||ZVtlVEGNC{MB$-P`^H&@n6Mn1pXF)Uif$}A`X=BuM4bTPzcw_sQy%LNT zwwn4W#wH7f9frDZgqo$4nfS6{hyfk{65Edm1)HDF^P0KStPy5LRNpnG>P#Ah_2KHR z;mxs9u6mSenpki!;Uwm79?$$e+zzflbq%8;un~=(>?U;O2h!Iiq*cSPas>pdj2+61 z;FF@&-Qhf~hUQs1A@?0MD`t2K8Y!@)-unJfj$mF@gLKOPxujQtWF=z9`z?9x^~v9% zGJbceThkY3!__Kc8z{-OB&d!Whcm^+(I*K6pd$Pc|wv`bQ= zAwu~s>O2n6JDxwkJ4Qh(mY^ddMHM;l-n?u92t#3YV-&yZsn`jquH_^MIgodjCgLn1 z5W+F_FmqrJIHP5{UCnh9le{uc83m%M)ERLrMx_Pxq=@|iEC7ahPb`K=NLPu=obX_g z_VZar3@u>>0|RyJe<#6Ls5~QvY%^I~nWTc?x?GWLLtO0FIZKUW^+%dig#BV2(RPNs z@n|lt8re6uu20F{gj3#hdwGv|LGZlizCL#5`d7{R5i!_Zf-WdGQ^^!E03nk1ui?S$ z>+3C@dH|fn5Y5+w(>z1{&U7LTad^<~TK4#poZo9G8`DQC+u~pM-J?8YoVI@%>m==I z+d%8%>g!tZ`37nf;%%$$@>f)s(QFLxFRic5(&=X+EM6C#@5{cKY`UD59?J4(h&f}x zI9L;jLdGn`u}&P5xww9h12gsx5Yx3&3-NoSY{fy-b$7gK-G|&a9a<8j?b69VzW8w% zdy{Ek4OJ~NEf3`gLRv#Z8$a1_OLCz$UMeRrsW61`P3N1sFEMuXy-$p6)g)c1lPora zwfW%8?0>YoAK~?RF107r#TZa|@L2Xw7DU=8Aw3CXY*x^Nw++nybwI@`90OdH4-+uRMs4D4K=aF^DotLs4Xo0^ zl1Jc57{D=2OkDKu7&f^E+n?Jz@VcJxggr6dC!_!yPSRdKu?F@_O-wz|DBun+YK-*_cT%jVIZ zl6|(lH)>TSP~^&~jwh!uLgo(PE%~HHDz&@@5wUn(_=Mn(tO@01Qq9UFV|gl2YK|zS zB};~34gUc!#al7HPgA-$dwX$kR#|0hDo)Js&)U^vUg|%V&3vj>X_NyH{F2#kFd@bj zml~PSX?>-sABmaUv$v;JoMtIGhDY=(sSCW;!3#MHH^$#(xeqJmRU=8qJjvj@@3*Z& zEX-#=-6~(Yzt3C7yA=$%Z`Ab_{=^{~oZ?nS`T!{L@RYKx3i%x7KPh9iJj8FYp*0dl zd~q>QqK1}Tz=VyMq?`|z_h9;yCw33B2Y$=8NKL_s6w81yQ9^HifbK9(ZP|TTcbcju zCMuX9hvxm>)xwJ{d{G1!`dvb)%uRG@nD-Q_B6=dGg7gJbX;KoVB?nC_@;DpM6&mw* zVpSXx77@!JmR`yL2(D3O+lsWHy3IznmCCI##PsLnb;nYTxe1@ub#BlW9TUP}MLFb# z>_{wO#lgre+ZCE^OtfWZnj4zc~Oo@~xHxYG#(T6mu?feWfCV7Hz^zY5evp}=d zGV-dZOuwAv(@9w*T~=v#JO!#b<0@?EFRE5Eo%F8{jw{fs>8uR08fq7>dcqY{>^*rn z(e3cSq{N)ZbpDK#EKhKxs@KBJ86x)aL0Of-TD(%vsrWh1hzo^F+2+}uW+Bd?(HHoQ z;vsPAFpBp-$u$y)niffAjbsr$kwI%><_4FUdftFY6&7ql>vg+QoX9ZZNk!=|fi$yV zha*C2R+tnR8!@R&opIeFGWgI%YK?{nI@ffGvn-m)}Dr{cKj^rWZ|8qn+O zGW5}bDdnwY+)w8MRSq9%b7va;1^bi{u!*1a=LLP58OxYeAwe!XPN~@bFs;U7O+i8; zJvxnv$CH}MWh9C}^n^@dYI+_e;NoB8DOzm*>TKUI)YUDx1HHWswRMbAC^9ULhzDzm zabqK?OO0r#)A$8onw-+aed1J`E-(-q9atS>afh{5?Yt4TpNm8zg`g?JP`XGkRxVI9 zHd#06WT|}l#Sh&$-EF9m2|YLlw1l+EG|BJ zx!af=GD5b**tK_H!KF}8u-mQki}=}>2`xcwOM=sjQoAFKpgEb_LE)t+2wsRQ(?GXZ zUyEHf!S6UXpM~$LXkvopv#t@IDs)eFfm=#jKTG{%>~C_>5#zGi6F|!_`WKQ{zlhiK zMM`fCd`rT*;g2L4^i$kO)-Q2hcsjheml9GkiwmU(?CYQp7smA{CSy?>e zKkcMd#j}sa^Lx5IWIDrbQTx3o#&J5TymFWN z(dkymbP_>6^PaDBsiF|rj0k`f7O_o2!MA=GG##zwQtYzegw*h52KQL|R=G;oCw8pd zE7`vjF*DlJ6J8LHwrlqZv=1RwfqX@5764^tW+byLfY!cx#`2*Etz)f5zs$6ie^2?YpCUxQR&NG4)}6|JN7f zs@d78SisNQdd^67Zpn8~@lnZ1E{1t=NJlky4 z4&IFsTr$kFob8IvaMVP-Qxs%JIUp%6Sn{<`jy{hPElcgTKEn8;*HB$Tvjk~ShgYFX_42f05Nnon8NU*Z2 zJ*adIcaoRgCY-O(R|c3AI=%GW#S_J~W(dzwU;8AmbIkU*@p!2JH)C4n=tWu?S7Q6O z#!st%VuV}Gh3~Ic08kj!7w2WtOORS z=*j0})xbUuyfmb>5HcAx@j>*b!DlMuyPU$}&xM>qni5Ezj{8=X+>~cyN;J9R7;ZNF zF~U{9NuLC0gR~AzcM*@qq-WE5#aaf|G)S~QBxw*MH+(vn*f7;xYg2Y5VMRbGKhgAr zRWb^KaA|dH3EmM*i3*10i{6mcja0Wg&SPbiXWaI_ha2#T8Nv@R@pZ+5t~Dk#yOMX* zBE2}b&p+})Bcd%CpO#NSD{OvX`{kU~2!E71=PcG+`(LV7D}0g`DO04f>Eqhi5%udt zi=+!7&vO36I9Xm=PKOhx>@ni)RU}!{5F2BS*=$Mm{vgN+IBw>GC8+$kl}Yqcmh!8j zcT?VcO~y2+8>=%&^fl>aZaDtby)pF=9M; zmK#6U;!rj%94*F7r_Jz=NHi#M^>4~oo|?mKY%T3}pB$!XdoS;&!ifb#shro514#RO z0xOZ>L{nR@Jgx2`wZ!m>Smw8VZm{#}HqivGuekWfI=I-ij*>hI9Lh?P&g}2~2QZQB z)0{#B`mef3Ko&E4qS&k&y#0@8CN*#h5rlZhRHTXrBmU~1jhF~0y>p3aS*L69>5(z0 z`)e8$d~zQ~_|?N%S=#CPbvd<@j8UnEUCjxt7*s`brShLJkCFDE&eo-|Co;_Iy!{PB zv6ASL?U$R0%b=~?qn-#IWhJQ=6!D*RT#{^Gv5DBK@%PjS?qaBsWrrkD z#MJcHil6X5493i*m*EuinYbD!yNS&MWy^Z68WP#8(!bgI1A*JA@Jr+m|IrUQUlXa$ zhgj@(XR7@RdUK=kX{6_w(9uKZ467BF1-+#eI6`aD#JxTXfuU?TGn^kJtSA?4jV$gK z{;^!EvZ23y{77PO^z(t4EZ5|hm17#{Pk%{kg{wNLh*8=~RRV!tV(x)in%zreETU!B zpO|2U&W!SI1h$_9FHU&>=9WLV%Pr1Ua8zS>_b zJ!qxWJT(g9g^!+`X&I$AtCG8FL4Uc0@h6ehK0vQADUpJk{++RKbzQqLW ze_gq1Ykymns)ChBHg(2S+@gJ{;QjzWqwZy41P>FVlY6f$+_*1@dpWwB<5~Nr{0O3s7}MUf34`^7ypWALweVE z!#wUX=W&X{W=RZ>8RKSV>7d=Dy=!q1I5Fu6IGHOG63LxBNK{cf5FLgiNU?ZStoC#A z+cqgA27pgn-+o$~>(iPUAv^pc6_1YEn*~*x@}2Gx^$};O_bWCn!UrXG2>vPs;-M-l zFhtVsz2T~q(^~}`FO>_C(WyYYD`WjUOE1FPmcJ&pO&Wa#)4gjm<%>I50X+L<6FG}rHScV^-7`^k4~w0GV{n(-l4FJEN`w~Shr992`kZ0EydAG9v_%v(>t*~~M+ zPuDT>|(>W#=LVT#(_GpWzp{d0w7j$Ay* zz%Cz z?<+>#$yX7z>tnKh#r9Vc12 zFHOz)VfOaM5H0{wnXKY%5+i~@zT>Y^)puwYDesL=#EP1v2x%N|_apZ-@a%4H#zf@!@TT!xVMDBo7D{$CLn-3}Z!$ zSgFppHK{5&v7BwxRa=vBSrXGu)L?nU$J;g9X71p(iVfZ1)vUVA%!R2q4c_|@ux0W9 z`8E_&?jt@ii4_mV|Cd~x`iR+_;^pGlEoGWvlAh>mz0$%?9ZmW&SaEXyUJ+G8mP@#s zy+1+~q|Ryxpisp@l{C7NL&wpP!Vof+q(El@uY2kv)pRfA$!zb$kjpJHm&KFOCbZ#f z4>>S7+;17Rq4xl=SGoH$HP##UF!}eFo@4&|+iUoNDpkvt!u4b5DZB4*09wID9wR*l zUgB4$rCoAsT2>RO*0SmArBgZ>p5kelAO~Jy@@e^Iw)a*TkANy$6V>Q5WZ3o9MbUqf ztj}u&c3j#8>E1iFvr@_n`&S5&qr$W`3`JL~N=N0;b8#e;Yp9uGH3x`U90Uvz zkdEV66di^N`S;&@h^z)7k-IeT0_w|G7xY;q`+9SPl@`SN$4nHHNZ zN#p(PE|F!xTecX>!WfIFGcFcG3nP*Dy$SK|zfS>z*JL}c;<`u6R%s+Zu@>1*B2`%B z4-QP46p}(EM>}R}J&Y5fy8~snJPffZctxS~TsUD?VO0(mFEO+wU8xHKp-90rzZCLIboyQnnugllSGq>h9(%CiJ#!p0OK8<)3 zAukHyX#~i<7Eb+y#N%KQJu|bxvHA-*E0%WPC4W*V@6HWJC)xdS zcOE6oPkLN5RsR{4D15@FXDB+e#)SxUcJMUC%sNqt3HmIRhv%43$PxZI5>H(Dq7)EEvKJ#CQ)nB6Ymq(m%TG!NR>=$OSrRrqd0U*sd@>_K z!!|D#<#*&ICz+Q>TWl}k6@gv$0EnnVZ-FBg#LYa*TiwpjNE)icVrrY2pGUgv^0Ov4 z7nguKVPSOEK_9;Gd^db+EC(Ol0kt}PTWT0(4A%DNfTn_2V>Rl&s!+@QW;JKmC*SIv zWEUI0)b4kcI$@{3snl+BI=wgibR@0w6(Pj&m8U$VL+C0-;hxW)0zbF-nQvEF<@AOn z?q#aI1T4Pf3yXh0eDtS3dRKodhr7Kw!_YXEL%Gu^;p1E8C6+_&u?d_&yD%wF(56{O zFE}rm{cRf=ik1tuwYvieLhN`nUI;z1>4}K^u@LVa@5cz&AdQ|t&!1K%@b>cZ1KiC_imchr&7I-lxHH`0>x`1YsI$&>wWQugt)L3Z}F<@v-s z;kiMiX+oe|{YnCxR7H5BdZ_&D4=Lt2Hh-k+yG9#nYUiKWdwE!iDm=x1HkN~L0leEN zhRYW(=i8WEU$En<=NdWSk3CZk&7FNx9Q>p?QHbokYBsHao`T+BL2k~D@|m_40n^mj z&m{cIIe3Yt%t=5NFu)^S1R(WD5U`jN#eiH3CSQeGa)^tYwPa?6Lx z$Qy7uV^mqT;G9u+W_OOOlT7dM|GCu_d(=4xT^EqbNka-mR4P``Ey6Y)<66x9tfUG| zfyYW5L<~PuS9yNeKlMtWeo3t)p~*$}1H(G+Q*qhi*4-a{N_<+_k*bhzTCU?#(G(V? z6H_`ZKbjuC&|kzRcV4i$oQ%{0<+WJ7lC2(mRDbfmr<7H^z=1lwwg3TD3i^AoiuZl5 zb?HE;wjx-@xYFu3%g1Wg=6Dck0$JJs9JuaaH^?Q?wVFTPh9Blk?At_r{5;iAz%FDv zr=u+)Tqdl3w8pG0ltEj%;?GDb&od(eQ2rZ8T!y35ZJ+29@NO6dS3p&M#00Y}#Vtz0%|;H(oHZ`*FoEf z;|Y*pYaVEqgI=m|R7UKvE4Eyvt_1hYCe+>Se+0@PXsTWPv-)NgxB2&OYd(sH9;q&F zNl5BOY+;gmrX{3`;`-*S0KbVDK)&&Oj>AgK78CDlvtxgWFI{DkN>=)*mS zXYSxtPq%OU*-gt}#aI?HZVh}ter|v4$Aial5#Af0O+FR~MDF-#(_^v3u3$rd&FRJs za6zy-S?*ku+YSNE&3+#?6m!`Tdko>>_#A+ZeBqD$>)8vyG8|Z|_`zJ+jn-WmnH5e~-=;FttanzeXeaTQ5V|TPY=D zAyFGdo+l#N%x#MQR0}C}{%-w-bNDkPe2wXBWXCMO)X}@qfWkBp0Bjld9kvH~)<4CT zWQEGbHL)Fn*25mlFrI(JabpVrW^gY+6;9dsC*zNn>YHhhPx?&IsP6>dX(;JyJ3lab z;bul^4PU8ZaE8MN{lb__Cu4iJz{3wrJfD1C57>2U?dKooUUc&-oa9H(i>U4 z)EV=ibu^Ay!|xQ_de}A>bFjD|+|49W1MW?$69x&Os_5@sL$cNqK0g3ODm0Lg7=Ut}-Y@TWjz7u(gK*Clr?bq`zMA+IZWQC2nAB4MD)?>j<9rZmZzTrssQ=uF&>u`m_GAWzOJyTB zWkI)C)KBzA&tpGo*wT=92`f;q&YLOQS}}0<%NjCjsmgn{&L%o0>9&3OI#rYZ;&`J; z-I*;t2duCXX|B#HRQDOjjwOD5=JuN)>aVevnZ=(UqO6YkL9p}S0Vbjzda*WHYtIrc z;vPTUKHnv=ON)s`l^{3xxq0)Nf0L-KKZi0)1Yb}}9GDqwY+-*kY%+c;R_gRbd~BGU zxQ5OwK)MHvPdW)TIGIK5Dh-L>GOyaVHbt(;{v9t!x}=B6ei0guTNjCwq7iZX1C zT~wz^l&JE{ujTqdF+{mxEWzLuF;w&7@I2M#ogK{K(+9~6+hXIP`=^MCfmhtQ1wUl` zR;52Sn)pn8seQx(%3>; zDtL_fqd15(v4=&_7K>%?mF?G#C;r$=f4Or6e@166s<4(UjT8r z$|8@THh(ARl)1-E%4B>7N=K@oGpp(Ml`UK3_B(!w+Sk>8-uPbNEq+pKtc--x3G3t$ z8hbF%d`~6JP8tA>^K$~<$~H?#Ks-ajNE=T!P?7s|s-}gJckxLlSyy`+cJSU%1Dg~z zQZlU|!fPVXk6jcoU$NKmyyD280K`hx-CpzP8dPO8j8ev!q3Frq9ruQb)V5HkxfSHE z4HH@@dkp#j&>8L-bb%rZWm1*N--Pbv*JrTCK^IF9Mz(|+3WhJN#mSNx=Ue2sYxKr~ z$y@=vByGC9o?YYy&jR;5uj=<*Eqk<~Q%`yFxx355LGoKvq)~IFP9sg%zNq4z@Va>d zF2I?_?}ZXAsr+wVWOip&|Ilg@&qY7cOYydTYiKGLMl24zEK6GVE9)ydirUfLvTde}41?RijVORo3<{9DE)>o-9 zzsS~5@^B07$Y48H2XF6J&)dJ&%eZGusy4yz)&=y~7S`<(CHAada5P(nljQIhnnizMG@Xv$Hn*mO(oV|f+)=b2y+L|7^ChC`^JoObOS$b9~r|~hg0SWuSLDIX#AF) zuTFG!tPVjBnU&dg#|lBqqt6z3hBvX$o>Xak{N^(~k(U^5k-No6rub$>bE=N*2OOL4 z75yC@C1vv{&rj24NWUDpW%g$WUsNV}l8%ZZi3uFqooTWuBfb2G73I3gDQPlz^Km^q z1i}+y-2I5n!^pXC;7@$GR)_-5Gsvz#otY8)$<{r{(IE%6ky*<6+|3ZM#^w@E#`NvX z(dvy>5k^!L|Jj1dF@~wV3{xlee3XiCl`m}O zlLFN;46t4yggz-1(aXyv>I$?*PucCK+;;6Dbae)p1Cxe_MR_ySmE{u#A0|sqQ_pZj=zfzGzZ7J;T4Fg*s zQ|t_aT@1^fvTdF!?MfT^mak7=L-3D?L*GzcT3jd1MC7}I<+n&fns0ZyU0)Dme^-DE zoHB&IHi6IL&wjpt4O}?62&0S-(t9PK{+csj$fJyFC*Y!d+dJytHP31YH~Ab94Sq#y z^BX7TBoFPHcAXq$$sq~Z+fajnw8`&>k8Iv&bMKx(IzF-RN|u^T)o^+IcmUMw>OchP zPPYg~wAH|v63}1oMnmrx!MT%J2wcI>A4|kosN$t2f7uFA0o7H%VosFQ&Po8Aax1NN zGSK_kWvIZ{8%{-9_8%J&XF_?;3?SzPJ!2x;K)UgqMo*s=Wpfj zdeZ~`HLDw+3M0Ymtb;f)%E`)P&slYRof$d%%-cAv02^PV})%j7(xNuKcs8BOSdE;BY+?59S{)$JKAa z0%P`=Ggfv9J}G4v_?xm1x2(#&{IcX9J+78OOFOdsHRL%SOT|BmWGoZ4smQQ| zw!QYRn7lRmxOlJJ*X*YjoT0X5pM3i5#qw!IG}1^^YxTV*Rnh+d$3Qs0sRbg3DWx?V z8hDbL0L3txU9>9F0l1)waWvWq0@Q?2ibs?1!0YYb^ri(n{Y4{E@-ReRtj7vJ&!tt; zJVO-gx+xMx{_+sOeqAfZJ}7){x0NNfjwzg;kMbgh835sqaDJJ^c;AJ!d9Bz<3z*z} z;g6B9dOD69{PRh(d^Q@kCQVU;mnyq^CvJ)DbM4I44S!uoBWYwLDvoj2o`8Fr`D0S} z{{X1ue)Sh87)XadT#`@F8q(IjK3zOsMAqmTl!j*vyM{jcso-PNCmysM)%~Rz`zgXv zsM2XWb=zmu_m2qtPPMzphEJGvNBJCoz)#*D<2BW)A9G&~>G=dYzSjpT$Z+a@qw*u6 z9dlN7uN&Ty3A&%thAWTz=K!CmrE}J)mSSN`+PGdkyw1&Cd0YICusmPl5p5I7RJPv3 zuRZ>PxnBf)Yqz>P0WnF($tD4A*-{P&`W`#ihw2_a)fNDf9nmu2$`j4rr~A?=BR;1C z@U9BdMQ%f6f=)rf1e4H?N2eI3UjG0)A9KCpj;y1nR$jlK zHO>4(@mt$MWsW~IgUHSR9nT(>@#dh%?{0IB<(QFik`*a5mlot>_ig5O zz|kY0^JYik>0z%_)Fmb z0G`o*-(&o1;>C-dq!33{ZPb=wJp81C!5t4z{;0F3+B3Pv@Xg=s=El7uAU z`K;cWH=rQrVn+8|rNB9h)&N^q>KiZ=Qk><(1=1I2Zo7X6{c#K{ub%a}>&T{vdK(SmNTNS9sE7ThQTk@QtHxgt-f4;?ghaRtv9Y|4OA;{H zCxPu;Cb!{aK@Na_Q zx!oJgR&WCY7!C+ihe8Mgc1X)}#VG1!m|-3fu30&$Ue4NjUi!1w?tUR!C?&2V9B#pH zn*?M6J0DPM#c#ElXLgiG;Fcyf`NHk=3qYbFc!NKWkSmPZrF-lb50 zs&oFy$Gv1;>m>c==hLvyBy9r&*QGb1)s|r?;#-wUkx`EE)jPeldVR;DXkQ$WB2~Ca z9#zODAP8VO7AFd?+tBr^-XHkW9P*?~1j<~MR?0s-oU*CNQI1$}JL0^Gcnc}Rg#(gv zfN}gd9Fl!2(|!W^201pyR$$n6JhLJDyK;C;^#cPu^HjAk%rI{WQV~*fjFW0sR(?y( zbv;xJ(N1Ql%_Ep=H4G@l8>uEHEg%%#)a=s{9?C*#%qa<`21km#VGX2yZ0)sr35-a6aTgnB%D>i5&X@&2aV; zNh@uNCzXPhWkoE(M^+$k2h@Ujz-(1XW2~m4^Q%Ogkl}nX%(#}@w^?RPPpnlVL2#k}&vr428f8*Z>Ms~`$ExWiOMpTOP z-xKSvb#W!bqNka+C<%34suTqz0(cqd4r|r^7sG3+!eYFPHPk=@D*ozeAUq@QjDkv$ zvHiwy0TtqU^djEkc-J^dULY9cj4<1~JnkTjaq|K?=C+rS^7&0nJZn>UzGjr2o!2Z{ zPvec7daG#lH#83xU0N%xwCx%(+*1L-ILRs;5UhKU22VIACa2K;DC%L1%W-isL{+2& zBgPb-k_Akvz6i(!uU;`wKY}lkAv4=bB5a-51(ACfj1wY*)E%Vbs9MeNr;UxY$uu7@ zQ?^+1#Hvruj5z?~C3j;CJ7ne+?s|E=FjZ-LTm-pXWZdH1;_coMlS!oaNq$E`;{O1R z7dP>kWDq1pm9UE2vaOJ!Ld10(;Xyvt$_s1(&&;QWUJ8(M2t7d^k6QMBjXoE(mc=iv zU{KD{J3L51F*w6Cp*TBE0XulcP5>sntHB-vyS;2c07V#ST#*v-z|J!AAMUR~$s>SU zPoQNu%ncaSjwY0)DMBf`xvA^YHe9yfe?vQ5@dd+Ub;RwS?KFxxAb$%0Jn?m{ zs#r#_$t;ma!z`Ob>O)|G9m57voZ}1u9Q#&Bio5}LYmspS6#oF8v5z)9dV-^J@z-*I zGI=%Vf3ru#AkFp%B19_h2S*5~N0|`^KOhVWb{Q+c0-C>5&dj5Rb>mYC*RqmJ+56Fy zTInTzW}ovXMQAxYvVi54&T|zk{fxFL||4()uuv!-iS6)x)mT~9>*2+zlAk+nh2zHF|(qxBLWH% zIT$>TUU{uq^Bk~+Nk*Kx<9o(d!Bm|SO$X&yh9gnMS?TqtZbJlhDhhdSGvLhQAS^Vl8h`XN8J{c~mpR$AwuB z-p63akb3p6tK(lzJ*yW}@D-$t9!qFl#xUg+w+ADiW6cQ*6N;^gOWL^3aoTP+mAgA= z*Q(I@o8rI2r?s4$c$>+S1w63MIr;(t_BicUY`z2EG(th;?jRp2iCF;jEz0DMqZ}UQ zzNth2UpQ-qGD_(^T%fkCJ>H;%mJ&ZIZz+lIIT-BQgR` zH^jg)2JS-e!>~E7tKyHsiDqTFvx{=dqk1S*a8DrPfrDQ~NOSHzz(3Eu3m>QH{sOAV z{r2_sQKtER!jm#ll3Ge@$w{U6BmdX(pM+lp?xMI^t`tV7+rIL% z$k@OiF9AnVdi1XE;_t&5??gf=qm5%OS!51DCjnRmBbDTHp1#%SIM(t@7}KjsTP?}no@I|oaEA1mafZTyQ%wyG}4sdDvZhlD46lc}XB#-uRKDFuP zYSbp1Ba_YR=6LR}@OF4k`)BhP`-clEk4&5_gZ}wHTC3nM4qPqLv5H8*Z=Iio+k?1( zcqH@~&3l*QRo~qI0EJ4>xpPV?4o{Ukq}}ZNud&5^NAN@3lrgso7!=*Kj=Wc~ZRV84Ma^1mB;?v!q}|fLZo^mn{VAiZD+*?R3QVnqD@`p% z`cf$giHc|xpi^i8NuU~0K&nLnTEX#uf}p&NM{yW+R@}HOj*Wr~E2#{mgM)*}BzLXD zO?qTBo{wW6!rl*p)jYd+#A+JM#aWZgBOp7dA~B4e%s}AQuDPwp1X52cZHgpm9lGHZWRM43jAI>h zL7%gYtz~1B@HfHRYbhF7jHQ`&e)0E(LUKZk4oT`xPXf9*{2gx6iP{L7VbW5HWaFpJ zjFazPdEyV+M&3Isd-S)tnj4uKCBmdkj5h`IJk|peGVMkO3`q4ElHcO(`N0|;;Zx3h z`!Lu%kCe;(YQ(9{{RbYt`6y~qGspj17n}7Aq4woxjzx#dgrZ9kpa*EJpc+nAO|() z-Uj&B9mLORJWpkOnLlQjgXSkVlHOs3nGO$39uESWVey2?tI4IT0IX1XuW{xb%Krc_ z$Ya}#eB2$`>&FzwWO^Av`TjW`hdh3DUfV~BSh~j=xfm{}s>B{}NFDtu;Wg&ESHziy ztv;P_s1c!Ci#Zia7mOXUMs$muXStn5+|8uG)CGqxKJ|a%GT@z zh&wM_6UR#WC&SuXLlVZ*OK?4uf<95~` zZnc_=3wg^dOeKv}64{OR6(h01=K}{h8a@i~tTB~>*GRm! zMkMF#@xuzX4jKM@@oReYT+b!H4w}JWsmI9p<&l*zF2MprdJh{;GHVw_T8KNR^^!PRz{BACx&I} ztYVE=VY}qyW7jp>cvc-oDFjnAS8!nMx&HuDa=81VXhQjN5<19*IsX8bW34#+JTcx2 zs3h`)gKf+^NlD22vMxU4gP}bb9&>?-y@4J_r1+ujgRI)5w%1UStqswRcqPY1McR@w zzZlsd#(Gz;d@T5aZ(#EZZ6L5D1LeNl{PB~{*6K4&@#n&ruB3)zut^!@ykbO>KjMwo zj(@t{LG`NX@M;)}wWPCIkieCJvjl(~m1}uJ#-aHIkShRqAoEQ!&mK>XQd?eJGft93 zB*R*gT5Xvhy?}qS$SL339Q5Dt*OtHY!sGt^wR%5<{uae;Eb^%?XMN;4p$gal>^pOY z#z;Bm(z@TVFZUDv`Css)?lb?;^S=lDewl7XmZ@$n=WU@SjOG~$IL{-6Eyh7OBm<0$ z>-=U7kR2)MSFJvw6%a{7#M?hD(((L z1tckUL?N6=bwo8I?FJ3OryEasbD_d{*9<@k;9BS^FYLh6qz^!^;_w(E~{#Z2Y{k zC{Q@(IqiGk$BU#f!De*(+i?_N8Rl4)Ez8uMvKGsn;|hNY^4%WhZ6j2O#!z6gx$a1mLF^Z*l@@~?m&5$^AW%+r+eM3{ss zY{C*sf^tdy-okT_n4Sf5o-Ogk-ma$7#?s;lWcg>ixkk595$chvVb1P_lxG|Q3COka zD&6$0F)b|8StOafqa<;=$Qi*iPC_eSl>|lz+78}>IGX{^>;C|>jLoSC;E@*AIZ`G~ zs>XKS5=Sy;fTZnEqk^rHbAi@=(H|We%gTb;&|JuOvA}Z_9XAC$Z;`%4-Pk*P+X$~F z@%O-~EcE+1B92C#WDRg5R+dFs5QG>|%tTMHa1U~On(2Ha@KSlK?(c5{wcPN(lCCi% zU?vhmr|vlb1djt^=Z(zy279N%KNLxIWdzbNX&G2M02DJL70w3$p7^fFe=6~x*;7?! zuw-O(@}?jMjpN9W2Ow`%Cu=p{e7z9n>1C54AWj^!%tov3JXjx)6uxaDQ51j~(;*;-d<_tUWRT z=B+%Nhcb>kFd%+_&@;=vGI-K!cd-!4WAkn{zBb|1V~5SXQ@zc>Ye=GF60Xw;jdp(VNEtlt%NFGE+m+IMO{i*;xwf0^Hc__U zG$P4!F(Wuq*-&wYBWVf<1e3Te4+?xXk#!A44YR{(EK)|2C{YntSn=gyiO41RDme#^ zK`!uZmZhaDK(=3Qw=7v6-dN+9XBo;$R07>fmN+@V!N9u=)bW;we`5@nQEGEcA_~nF z%y1NCBm;vSXnXzK^UpP*7LjqOLj~Mgh1HOfB@GM$282429hAuvIV^bPir@?Ya!)y}7+CRD(Z~ z1YizAc~M4r@0#Kw_<3-;*}fY-%Ib>#J^22WVrkWX)#o@noSt7JkgNO(I(H_J ztWX2jr5kB6#V+6T)~GB5Q$fW!={D0CnWZU61r1OwgrFrZXbn_}IlqX01BUwATUo|Z zL4eo=qL6*bQy}4yuzAQm#e9$B&xvdM#U;!FM}d{2ZO(*kVBs909%NgUSjPEMK;o$|JoDl|!wmRz*`gMB zZ6T3VXC_zxlz;{@ScAoKe+sOwudJcDeR^n>*B(kOq8PRvo>_NY#Hb&5@_N_PEPv1W z?T*#wx8DFXsT{lM_T`wCVh}FoW0J%!2Pc!qH1110m-dIWHrDnUmA$~YpG}*}dx;q( zW{%-X2AyHrq=^awqi$539G-c98fiMc#Fn=joK10K3rBFLOIVzY6?9^*eDDbBW69f) zFmO-QItRnMJ7jp^wt^_+$C!y4?2v(gTpk+(rfZ;#05C8B000000l)wbFb8Tb2bb$Q zcAc$R`Qe`})AlpbHvU-d+^@ zRqHD{M0ZCTCgPyB2InP?a5xwlILY=l6wTEGN1l9O_*`$27m7gz-L$DSyv0i@l|M2t zQmj$eAdL6uYrM5a+Be{~2JN{DTO5&|a8DwpVN6p%G3qHP)z3xacum{c63cLrEWuew zSz=>?(KqqzI1DJEw1|4wGw~bZJQ{o-Xt>|AdZrKtbGY(C_Xsk_9N=-2 zO%CTytwm%(;>a2Wxmi%#vMY&80UpN22`7c?gPw-7wGWB5F@`c;TPDnJ%*mDA_jAvF z)m9zOoDcK-siamc{x!A`eWcG9+3*|A3?4G4p$xgtuwopDhwx{_*STLY ztZuE)#$-p6$dM&bGlek7?5sy;RqOS~9cBAKPGc8MU_QiU@|t9ye9;2_U!5!-SYIhy z@8UvK0&#$FSVyyhd8p@+0!cjp?oZOZKIh{eqHkW(D|<#M8JSt0RTnW53JCCo zBQVIwE&&{lYt?)c<4Erz5}+!1St4w2hDAGMia-e&R>&k04{Y_Suow^V*G$gQc@q$D zLI;;=&OT!rw%@76cJ_CxB8Nr{gaQ~Gf;$j>E5kfl1=gK(7SXMtw!M&H?qV`U1;HQ~ z@~oH>AGx`J-+(^w71>3n-57|t)L}_M-y7MYMS!CvB!XEd6Dh$TF4Kd?2;D|$bKs`or(<3B(Gnzit^!)4Qp8$9v zB$g>=j_C!;td{c!om$pa<)C0m^40mDPv&bk!`>x|<|Up6-xK7kV6N}LfN}58_N(m2ujWa>9{D_13pQhzf1YUzSD)&C zAGEmLk*}gGrw_Aqs)QU6?trS`@4dpY!QlCx<>cX}1!HA-svCZ@8qC^A9Hx?gM{AjCHHNH2AY)WWjE(V~N;gCod@; zzFGp?eaNNmC*HWEW8hpkmRIMp+&<+zGzj)~ zPeW0(XVBLL;0v4h#Oa~hF@wb_U{89WnRe`u{Yc0SVEa#zjr zX8SQbj4b zDu$Kuiqh&Erhv|kZxgd`hDaGcLREs!gPe?vidGXl=;dDE{{Ww@N@XAZynjmh{{Z2? z?G0v@u&u?-)YIXbMr(JO(HP}C_kjdRG0>c34`W{0rRr%cX*5nAITc+TWCm8~aCsj? zK+Em=dV17bs4vAMwt9Qx+m645A(AYesWIR6uO0YF<4M-y^1}93l2~1(jo)w00r`jp zRen@b3gmIf$=jN%@Sj+o{{H6qrIcDlx*KSBkqn(O?1SZVv~S#Ua_Tt26+*f0Dlyyi z{$Jxy+g>~1kBRUtt^MOQ+s6#@2T56HWHIr!0D}mJxMTA7#tlv3Z;lgOv?e_^W`b8$ z^OEA$PbpaA%#txK@Tv|^%6JF90g$=tZ4cA)rmGM0-n`FN_`uC`C8dqAyqXdF_cAON z@HYe_$U!CWN8MKEj>fb;6Z}$LK_+h{p=){C-a)-&Q!1z}v4=QPaCZQ54-^!4rRdE! zeHg0-Mhytc(BEw;W``1`3z zCa)}z26odepqSvC!?m7C3T*`C{zY|OS#mk(aDFTJzFkW0OS?eDH0wKSfq=@wMU|zL z402DHiZ+4DhW_;yCg<9Pe>!TK@oyb`ePLx|J&=v1)MQ9wd3l1`Qm4)HK*n7d6$z2f zeJU$|6zVp5osFg4)ORr6B&4yoST@TT&zBP`oCA@o0|R-zS8nuB zazVivsefpn4I7;}>Tq96aFIuEGDn!jqZo(}aT?tUQ8||w|TB4WR`1dX(JoNEF%IXECOySc9tZO)M0!v)fx+k zE~eF@x3hdGwUbbNPHWBMYVY1yKyp=xhj0gsmPT>7=*K8NzCz^|749q{AOL*7F|VXFJ0G)KMv~5C@*)c*#H1;8jd_+r zP6q>)CaS|Vw((wb@u%Xu>9O0$mfvX;POvcZJgtS)nDBO$CENrB%BU^L72oOFf=Y=b zZn8%rhDi{IM@Aenu*hIXabAD>LHIGQ^vk%TR(V1RVF{4tXc$O=G0yHgb?Hd~Qpfgy zw-PK@uw3b~ISQuj2icv9lZCs8yaPBm-s(@MBRx*1;>M2d+6>x=?h-<~=P7q1pxyqB z4#JZl7$k=T1DK5zJHtY)gaBPJtwV?<4s2 zXl!mThncq5B71gG72Hzi9#h2RZE{Zp@O^79#NV`ZF+4HH1hUCBvfZ#}hTSdg-|n>1 z%F4Tm2jyIz52&hN8~*@jA$^%`<`%aSD#vh0W{UCQ$tNeOo}i6Ch`+Ps z7i|Q{%N51EamJ3(EyNPX82J`>7_RV*mO`wIq@H;oy$7j6*Y=r-^!arNttVuHRgP3F zgD6N1G%~4ZrA6GMH^ufFDiF8Bm;tR zQ|P}7uG`E@%jKTk;dp+@1*~?~_;nz=D>SZH1I8Uk9V?~yY2c=@w2IWs(}+VVNXiks zt;EM0D)4-z!fx-3@k3}5I#xcs{{Z#9DOEasMRMLNvb}4IBW)yUY?3*=4UaNN_Arf5 z6l{RR6Sa_n2P9-yPR;&(Ych`mv+?e&d2y*Nw6@mYVU?0QSs?SJxWevMmCUh~Nk`pa zxXJH~oGRtii5#=5*@!qLyw|aS*rnwO%#f{KN(tDe1{{W;!p-@EE5nzSbgzYJia!KNK z?-SbFeUDRzR(q?68CGjsiDEY`6x>`WjG|2&q4|t$^5!rCiu%^?!jL(Io+M_sIf0mE z;W*lSwmgil9eJgn!glQbV?hf)KRZPkbL-CB(Q#OpMb#2`(pcCuaw57qkX6-yAc8va zULX5L=+`$FdTqQaLNiGxn9)4e=^_LEye<@}Ooc~f$vhH3uY0$EC<>q`1AqWf2Vel; z55k^7^*_?34WBybe-1Bn;?cUT{-1VSTtNhWTiHn|!I}tOM$NlqnIl$a2j&2s+2u6v z+3BK=Wsb~!rpDv#7IQMAN2uGjSX(*I3>28K{{VG@zs-^>>qj47^Y8CWc)ERmFQs2G zC(idD3}%!Sf(aq9)KE3ez7-|YFLAhBByM*3ZbsP=H+=g@2QExr82Ce}S-$w~tnRKc zv|n6Z&RcE(IJRhC$r#|IQe)n}kO}$FR*RKm%zPQ};%i%(&+b~*>uk>!4q>|hEQTdz zA)%8Sxge`#^Sg^aCiqIS-7U&GplF&4xLI=@-Ma&{9i(lRHa{aB!v%&uY>z@Bmj<)A z&nSoC1=MP=!K&QFY@}_B#{`qcgQQX1G7`uK1I<|*9a*YvU*JScWb$rqtrlWT@j%g- zCuaN3VwyP?Cw@z`K3?WxPEH8)`a-ns7ChrZ_!(^vkX7y(t(ce{>}}D3%Cg3xl#ZKEPIN<0{HWLV6x+rZm9c=lu7kNXV3c27i}t z)9|S?_57*JOZm`Q|I+Hv*W@yB#8*P!T z_YW~wk)ArJAd!$d*QvE3@19Ir*d9 zGIRC2@e9KD8+5j7JBjr8B8{fBj4zqz05WBWvX;jMN6pT120;e-u*nt|SDjxQ+&@7*e7@(_O)J$v!!E3O%#ut$x2L-35#>pFCT z7B=w5E6FC+@`Q!dfakjma4<>FwR=*YoB@uV2VZWKv9I)}1^Rk>)L3T`@r%L|-dN3V z3k7!ofKCj-z*{qRAW&IGH4t-WDP^iF!sJKm?K@!*jJs9lF;e@eVuN%X@gB z(k`G|XO2b=)~XxJUA|mOvmEZp$!u|7OBDYAKGdYsxQ`I{v!%%_kiYg-)TJR$F6P$e zC~hHkA3QFmNd8nHV+`s}PZ;KJ1?ZZiS>7eepPn~cSmt<*-sTLuXO=zph67G<~9wVKsT~&z)O9otg$i!!* zdSAou2Bnp(Hp$3|0A~LHo{~2*J~7?1f!JcVnm_?0fB+ zPP~Q{yk&Xexq+uul|UQfWR@Z`jN!L(PhtgWd?ENhE}t#Sz1q&VL`dkc`AjZJCFKpg zt_tA-?alzp9&6IrRZUM+jubLWB1ani=aGUc{Ym3K+?r!BJOQm<%5EO&2<_wZO4`N4 z&LK~i%$h}ZL*^fuLV!R%)z&K-<9s#ocTc*P$+x?Ld3Lkyjkgl2Kw=L}uHnaA8terF zxyAT*;Y=`HUtNcJ9{XUCBnjols0b>UQ0yB#?f;5Z(V_4K+Cex9OdgijU--nh_IhH$1WRUZ{VU1rtxeJ{8 z^{orv6I-Emd7(y)RpeKZ6{AM`tl*GT92^sj;=KFgcg0C9bn|^=(9E&T2J$gFG%X-W z0u^8thC#{uqqlkmbJC;JBM#C8K_dlLaH<`ZbF?#KaSM}xPZ_FyDe%m9P)lz(W{PAe z>Ip_FeI0op;Z-a=eQNTg3p`(Fk|dd6+&t40uHecK-tWNYignkI?Na7DHkk#~sAP^F zcd`xK@GvvAhzA6PY<<&%P&71sA~<4>7?dP&B1amIiikF-{J%3+@%a9K&YzFgyf?re zA-TQQFXU<6EcE6U@moeh$25+=ym`R{xdavmKivZxTY6f9J-uK2_x$K%{(Jubjd`bw zK0HAM!Ly1Bo7f_p(UHfw6m#IfL@u8ar|nmN$pBA=yBHs93Ml2$Ky}g?O!l{%Qv7vWwz7iX(ff0TlsEt zZ*x2h#ZaqBB(bANSwne6lpbl?N5tJ~EmB)qE#hXnK|B`IT%WVstYd7SX1Q1kFmd;y zDmIakoSc>@`g96TmEgY={{U#`wYz&n7Lj>S$0YMzyoF0hrIs6L;sK>@JwYJn9Acc` z9Pismmrxc<46sQa<&;cexU~$vbkVD#MFAW4yx%ExowGnz*H0Out10CUf< z9Ok@V;m?b;x!Tg^XzeAjyAIBfe6ra@%329bj{g9@+%Om_=O?B!UduhOWh#0yvY+=@ zVEqjZ4D%NKrgXi`1;Z6a*wZW*4{EGCHOP#_2f1ulq}bmqh_4$fqo`zbA(7Pb3X#DC zbDHp-2f{j@m2V}i5LsT?DV3v=X-%`m9EF&r!nATMzF0qaFx)!|%>9w=&BcZFyrcab z-Aft>*`q{Rky>=Nkv6i#va^(BAdgUK*hu<3A+IU$=j{<|ai~6?is6*Vklt43OAND3dn=5W1bIj$QV9k;jldDcati}JZ^U1;T+v+ITCI#>?aJ`w(qCc_$DFR*d)JBG z=ysP-*y}o#yWTsf5`Bs(9@s_mm}I%LW_b^lxsklR{{S;`Hi5Ffnc|CiwRoc^Hj zN8&g?TJS%IU$f=Cz4h3d#yKMM7UIg~g1Av3+}7;81$ZRMLR9>PdHHD~g!tj{&g)IS zv}G$LjL`0qGM_mC)JY=94&fprtE_k+g>lt^7(O=rp(V7{5>%AjX|vlyGav!gB5bSN zL$!A)hYHN4h+xbx2wmQZ@w?&F*D~qT!5T$F6iRZf12EhdE3lK-AT1_@&ZESh9k`4e{U&CYe%YSN zNes4k(J%%4hH}Q%cV1A&e6s%ld3h{5PXPGpE9-Q)hjOcAG;TJ_42X8g42#+0U{w0! zjMp*n+u_~DpER*YB1xvUWQHa!_M1sb1i=^}td{Nb5tdTC02?_R*X;dkAiCA05lIcS z*FoV~V`z&>uq@7~;4uV&^J53GJknr~ZC z|I_UiXy5Bd8kE-o&>*D6Dhfl2KrI_6Bi@Bt0BKr7Po~gKg;Cy~%R(A<+N%M~d`a;E zx3apKPS%bISx<1mPSQJPIL2!a_J6&aO*Yy||O9(l)2lI0_Ovv#b^G~nsm}> zvd08(BfCVTAS}T=z+Lu^SST4FWS>gsJS*{9<|}w$x6$vU@}o$DN#wyB6&Nj-kUle> zswvnRg}1m8H%X{a8$MdVVu|T{I~bl z7Bi-obrg1!D{ObSFDB<){HrP2h@hP3ImZ;x9XH26j+5G~kwFB}NFF6yxnT`x!H8$s z^Mc22RBqdr^{%hO9~q;2c_+Ardr0Al9!aN+M-+sNF@$8fB#ebB3CP7{e$svsxVyE6 zC?Ybkxrv=YQLzR{W4VCZjf|0#+yjhNzm7i)roFLPA!QOq(8v*q5y;Tv_iV%N@-iC- z1OtQ6uraTHYI|tZJeHTK1AW=vIMG~oWr)e=;EsUCGut^C_B}H6NQok3qpG^_RFz-| z%AP^>Q_{X=@aMz(xOQViS*`{@(r>SP_*9SLjT_A$kGTDkx~FNi)Zw|o6A*~Q6gjLj3naV5M!C=Q}% z(bUWi233O$5;2A~rLO#PA8C6#OIh#djAm~n#~cuHIC-UXQvChZB=C5wy+h#?@?Gf{ zM`-&LJ0=277543IgJxt0w<}!Lr-g3x>zmmuZnWo$=0=uJwa8LSX*nf`LVVqXoF-$) zz$6^8Nn8ybd*agHT59%ZRV>r$npi&(o#v7NM1mjfhqH; z3A-ww4DnvS;opNBG=ru|C?%kpBO)mXttliF3`rplIV6*cECyf19~0l)*d@h^z>rU9 z@=xZ;BHct8LBs|yS1P-?EDmvw^_%-K>sRwy+q=9CViHwC-fQ1GBW+U5TWA5dXFG`) zDZWr~DT9aN2E*R*xu|qcX9PP{yas zkhoBUu^0yg=abJJDO^W#2XEKYHS>m_qz!Xbx)&g|j+o*&t&jS-rpZ>8ME)U=a?PFs zsMFSjHC&lHmbbvzki4Zxg3 zZynM?`*v+fynqQIV+3{>$y|)rjd)kYdZw#ybAKJ_vxYM;wzYyd*_+7(gL3ktlehu* zcJ<>U2E9kXzXGi+b=Gw2)5}Ow%t3B-2fD@dLr~jLhCyBaE&n zx)Jlw!HA@#* z_ZG8DZz*C~z(zh;a>Tn3zbR+S5)Mf<>3TPWt>AfNh8W|LcMmh5!%E{gXFbkIJa;7b zr)d5bf)|!ZVU8!AgUrY_nOt$X&vVb`pIU9)48Mx2a%^tJrhe1*d3>F?55I5lXN~yI z-kjIRS956zq@=LQW7d;nWm;eD54Udt<0^h~nabg_$6T8Gv{eW2^dHTuJa5~QQ+W0O@YtY+}R>25i2BW8(;%yJGQO|_eZF&tE7Y+5&@S; z$yt8kl};vT{ZJyN*5fSl9jmyC`gZm$%F0Orm5`8rU>Fr79@qzudgT5S{4R$~wOd$O z+-iDQw!MQ;NQ|*O z<}I>D07)(8M3GuH87!n{CmHAj{{R6#9_ltz-J6K5qqVz{?tG}Gd0yIgI5CaUsC1D@ z$OHw)0OyZj(R2u)jber*hBe)`IFLq)S&KOcpa5BkV}Z#e^H&93#be2S1b7nW#q|g! zK(@_z^Vz=iVA0Lyyw~zrWK&vj+ zBOnuyGI%xUU{jdVxa@ha#7}|{-OiVB%O$1UV_=#kj!oz@wPlKAc-wAH*8^|_jN+s4 z{{X?+1H6}djot3}WPrrtC~dsCK-|U{kyOZ_VM*ze>t2|&l2W*iTj8&P7Q)smM3zaC zE#V$rzF<~j%7HjraD(qie~BuH7`&(KZsuoZLiifxe_wQSnNrqi6jk-tf?CX zkZ>`)5;+4Kj(7AQ55;d9!whK@NHC~?Dya4Y*Qq^8tLu~gf6p`#>-qYAJ+Vz(2JQU^ z{{XA&KwMWTrTkR2lID9sCduu>7ZPnmkt7)sLm@k4PvJNuhT!72wVx2f0NpgPLZ_oh z>WX;J1fF>G%`&c8SitFl^Z)_hpuqhpa0dVnzyY7gRZC5BCr>dXjpM;4MRjP@0g_7s zKmc>e72qEh{{U%-B9_uiE9j+I=i7M#;nrJb7F;+2Gb78aG0{QZB% zqe+1Ql;v0g52#_dAIQ^z_ocAJ+d&keXvHgz!$G7YH6U6{Qx$|-T1PbHT0d87zMUi9S@)~9W!U}S8b^n_IAKmNT$Dn((fNxGyb zKmM=jQQ-dokxVRq|J3Z3o=qlcYtK4R+);{CO(KA3Bs8cgpk|#xAZb--Wu%P#DWM_a zoLk@4noUSoJt~2bgZ_W|^&o$L{X4`qE;RkEi+eriaY{3m@tH zsX~5V=bBK|hLDDnng>d7ub4hB{9eDb))^pYmKd$zl-ht99y8{73ED$@KNE4^sFArOPWzC55{?GdrSF*sT!&(=dJ+me>%7urC@mL#Y<^xadgOBK@-YRNDRRS zag)IM*N<3!)#ajThL?8n#4|LA(3n%yqqC`S2Pc7!_~#2&Bj^&;fY+CJxAuj$h6`z7 zR=Se(X4V8Ml1YqiGBc2|EM$dZ$M0Zwu4}@7w6v05#ba?~sVt-n+guB?4ng^+P>Hoc z7-BL3Bc5qlf$qYj#dt2G`#{~j_0@%@oU_dYg%!-jA_%D)G_(A_AUk0 z03R>cPrJF7Pd{k2xkyA{P9kJ&f#<=C%xK|az_eam8{(nhb>V>&C~^gBtq+MIHOKtX#v6(R;KWB0g_cVik;L+eaa##Wh;;Ah_`ftNO5UlQ**4pX|hKyy_ zDHcajoMfmu#z7esi{gKdx^1kc39gV#yu4_yDTrVk%jJd<;1EvYFbL04UO(|q!?Ec) zhLL@13d3qMX>;W+0P{kK*}{%@XK`lg$_H^?dwbxy?Jns$j2Rihw+Z^BsTEqS3=?;5)mPWD_E3a9g=*p;c{>nKD}ye ziaCFRe;bm+PrQ!)R(G(xp58FbUgqEuOlZ5#NZv>c$7-iJ3OM(#hW;&*^42SfZQj+T z1-zFzV7d7ioB}tl7zO~0@&`)rJ$v?N`&PAf_YgnWZXsz_Xx&%Ix@3tNI3d{O8L&Y{ z$j)VFAzZBp6fwYy}ww2e1f-WCgRS0F4CMUS18bMxnbqwj7zQ?MQ9iF`*Lv=dy+ zNQwyFM<8VFL6QI+N$e}YFTZKK^t2k2>5;CU&Z?x`x7wOFeW@L%`{Sdt|%Fa5$#q8?4W=f z<-r_v8${3@FU3!b_c7eq*y+g&TwbA+NjPVQ7(mG$Yp34a z-ot8TwvC=6Z1NaxFsB94*K{~+Wp_UW@^O>N>Hh$;bj<~_&3sn!#hGmHEzqNjQU)Qo zj#DDa6z2!1PzFw1zeC|KgV$n5lTp;3`5HHi?7}3swvssj4d+HT2Rsv=2+90jgqdFl zZuP5(t#2l~wUP^fvc0=olxU!kWEiJM``}~ca6sru>t12;2jYIAE~k5G9M`DO6-!H7 z6@^P5Enm*Ll4T$v-U%eG;nSh7O_%mrj46g4M^S>%us>xw;fCt< zFDz0>qnt@)aNAiVg}z}4K*XOTh5h1;_Q(RMG&>x(#y^8veV_Jq^mh5MX`@TXUER@R zxl!dynHZSFS;i26c=Y2(_L=aEv0T|*!wOAj4Zo0~p?kq>jFwc;_87`V5 zxUsjop7P^UMviGM?b$6Ynbo$riBv}#1~_Irn;6N!7`GdnZ8h}0Lr1uhM2+J~ZD1EM zT((b_I!_oc9GS!A!Z$v1SFf5RH@f!REW42Y8^|MdmfU_Q!K6is4md1x_~&j_OeMV8*%~w8lT5 zN|si@2l@4-6oBzdnvl4;{{TMK8K;_PYN3d)OS|xPZ9w$^pl?%-EZrmhDC;TJukeKNlL#dpl@h7Zcq{_ZiG#Aq)e_ zxGQoqoE|U_J*k1|W}3@NJ$-*4!y|)BNJB9|ALshlo$H^pHk$nX{!!L@^->kbMmKkAvlUvRL%@YxnBmzN4Uzu1E2>fY2E_lY`&e+`B!jp)b zGseZ0{?CF7#6UkXHVFiBp!DLEfb3Y(8u@z9m6?2yv6COXrVtAfVY0Myn$r8q4CXt2{71w4HyM5hBtVp4RaBmV%c zN*Da~{AduMP@dGF(}Mp1pXpU`G1P^rbNsz2szPcy|+Fa?BmWg8&jNmL`K!3~lFcOZ}9IQlab#eioaMo$EQ0}wgJ z>}25fCV`#}<9~zK7IU_tq!N-68hbE6j^RNiglc|J%t<9O2IG)avu^V*26!s+_8oba zCyGn2D1?z7Ao2!gk_9pD0oyVSXa7}#|@SDP~X=80|Aq??G1Ch$_Vp)Qoq$xW=?~3Yzf1Z@^ zwAj(k{71D7Wp<>vw`nZ;vH@ z>B|h)*c!Efk~fXM?1;#5)GLCdgV=z0u5aOg!)UbYRJ4WUbVBXALJPAd1DvU@yTINP)gfe#-%itX z*te;gMP|5_&|`2_2^lQFV=Vriaf5;>ZHv^IHTgrdW`Rz&#NFP1h zd;q_=y0^H!xwMb$&aS4)28MYGuwWWZ*b3xre5uMa4l|Ltulxd?Zf3dDZ{ESK4sIjz z)_9%ISr9e~F+BCaY@Bj)?BLVZN_@bNKhkT3{5de@^CqDcS*k^loFk^sl4 zCxJ@rEO|z)`!`w2mcg3gX0?SNOSql${&zd;I@+?r6BN9m8bySWCH5RMm>u9c^ zvyxD^7YgkP5ZG{^dkz6WeH5IK4muoF-GnEF`~huf)4jYxHo26|HVY8)o~#s{CVG&d z43c`2TkPHc0M9hLYmo7G#ON(Z9ELw6y{` zP&Why2Lyrv861uX?0Oo0Xj z8Hz-Z4yHF(0Qw!I;+5DIIj7>h+v0D<>o_Bx54S-L-<2SZe8lr(l&RUl+!eQU$m`m& ze`oKD27Mte?`8qu^OELQAY;jL1IR!Fb1n}ZXyto~=dUpQs108t{C)kTZ6}V_OBK+5=?@vjqymlJa3GR%6P~m5rQ*D!$(cJlDN-}9yEI$KI-Z<4n^ z=e0Dh2h_NvGXQW%2N}jdJAH6Yaqo;&c9+WPu7nhIS5i7MxC9V?8u_R8!|*5#ZK&>* z5eiz}`Ep2(w$ezXNSg@zr*LH;hRDy{TuN6N^un+sAmn<22>b}htb5NH+N7Ra+`y6^ z1Z^rS{R)%8_BHd4sU&(m<&W4dne8v}Z!Npb_d6tUh%RH?%+WEC)EphS;~fa&d>i3S zFk0$1nyWli@mEeZYxYiJQ+UGr+JCCeg@}^Y*sIim*)qJ=j?wBcrwu)uWh14d#K{x>5#HU zqcLSOvvA#l;X@DrC*>4b3imv};r{^bN-iP!tZyE8<0fHm5NHgFGRl%O0F2*wB!n>O zit8Q8(ea^JNV!nmV?eNF<lI8X$8`uj81{}5*ucFZUAl^aBvPg3g$m(4~VmA_I`8tJTZyb;bYy}^<1&F8 z0;A^Cmfu1$>f33zI*+tz8y4;YkUOF9l0@GEE|ODYa^>Pu@w398z|ft_zPFiP$9s{ z$-v3!k^srax#u4BF+6`i@bt&EXL}6!A71fIrkpKqw5>_zStg1(Y^1nrwYY`YE0vAe zrHW+TpOAyN07G;?SHUJgI3qY<4^R&{KI6S%#qie1OXsbnu$b~?SYugp$0dNyc&?Xc zYInIw9tEg)UTre&?%^#O{>JwYDnt?PZKcK>c}_>01NHe1;7Q=-xDN+>DZ06|xM-k~ z*{yE=)1^mn3Nm92CB6yBhC{dj*Z{W!1AXYGj!oH9 zfZUQ*vxDpDZk$prUo$4hk!pXk_MYTp?GeNudA5pq64Q1`J7CV(!6cFp0m-HR0ES%B z{{ZKVpZEG-@vm7vzO;FV&{O6S|JLa>O<^KNl2=qk87$-~fIZD~z8LtuV|6E$1#l?>_&G+^a|@%ORNoNgS-R!)LP@Y^oXU~UPa=+j!kD} z1h;SnyqpDFRbltZ{x&=!uNgV(z|R@;J!|%q)FE^mEhcvv7SVaK%mz7DWCX7yF73D( zs<1QakL6Nt72$sw{yN;*Er5dE4EI1g!zN2F3Jgj|@fjIYcVa=o=CQRuhp;K?i9hAHuqlYr%dId~1K~iM1QujLR&5 zd2xu$jlf92$;mEuf=+6lgLC2==*8qy+uEc2(Azvkw@3Ue@3~Jtqzw8B3qFXTt$0Vp z{{W3QRxnz^ObdNF=1D$d1PG;8Nl{JD?TjQ7S5pXk0Y)+L<D3@#o^BX_kWFBS{&iNcOp905BwwR1>=c0As1IIq+|RwJlB&eKw^% zv&)u(ICl9l$H-m4uPOO9I+2_Pe$>`7MWkA##NTL=Iim9>*bvOhj7x-4K+m8iuERc! zv!8OSblj@g&m(XL9QDR(&d>4muZ;dE{5iO?)8W37_U22scmdlptT2Wf)gwhJr)U5c zU~|s|99M7gqsJ56OQvb-J6p$l9CA-G9gg6DHiyXCx#aC5E>IJKK>+$b3&bRV%3HV$ zr2atWpt#jzQbCe6DmOBhP|CmFU`{~yuamwi{6DwTZ*;M4T^31|ZX{`>X;>_YwVC&p zQ0L`5?I7bE)cW_s=x@ABa|HX0W+a)FSg)KCH476kJjQdDPKS?ElEb<67LVdsCM+SA zDT-h>mg@US>AMGv)?TskHpUhSHRZH!NC94C4Y-^EjPb^-X*Qab=AQB+O&mxf zKmyx9ANQs*i@4x3Hsg|`HO!^fi*KUtj9W{2aSq+bY?m!|`7OBez#|fKoB>6IeM#aU z7~9*!_KByCI0g@xSQKpV0+GWOCxAK4alRk@qjb6CSeD?UJ1WQK#Vji;F~Wp-5mmR7 zg~2&IcdwQ_NpCpP^ofG*v{Q2J`?B#vGe`_iENTf@!g+(T@~W(_^9gzF&}Q+X=L0a)7v z?vo@PqaVTv#!o;^c5uzPLtu>H;EWNtX9RkT^Y30;`%8EU?{w)FCEYX(mk@w5?9m*$ zCprgA^AIi$F@SmF6~*d59O1pw z^>;RANNj|Wv~M5@bQd|vOtfHa+<4A0UK?xh(*8>~)zxP=X>=J-qb%)ik$DX&!oV{) z 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 literal 0 HcmV?d00001 From 4093e85ba9f6ba414e5dbe21c35d6d496df8f38d Mon Sep 17 00:00:00 2001 From: Gus Class Date: Tue, 21 Mar 2017 16:27:36 -0700 Subject: [PATCH 2/3] Feedback from review --- vision/cloud-client/document_text/.gitignore | 1 + vision/cloud-client/document_text/doctext.py | 49 ++++++++------------ 2 files changed, 21 insertions(+), 29 deletions(-) create mode 100644 vision/cloud-client/document_text/.gitignore diff --git a/vision/cloud-client/document_text/.gitignore b/vision/cloud-client/document_text/.gitignore new file mode 100644 index 000000000000..a4c44706caf8 --- /dev/null +++ b/vision/cloud-client/document_text/.gitignore @@ -0,0 +1 @@ +output-text.jpg diff --git a/vision/cloud-client/document_text/doctext.py b/vision/cloud-client/document_text/doctext.py index c0f1e10a78a9..0109e9499d1d 100644 --- a/vision/cloud-client/document_text/doctext.py +++ b/vision/cloud-client/document_text/doctext.py @@ -17,7 +17,7 @@ """Outlines document text given an image. Example: - python doctext.py resources/cropme.jpg + python doctext.py resources/text_menu.jpg """ # [START full_tutorial] # [START imports] @@ -38,26 +38,17 @@ class FeatureType(Enum): SYMBOL = 5 -def draw_boxes(im, blocks, color, width): +def draw_boxes(image, blocks, color): """Draw a border around the image using the hints in the vector list.""" # [START draw_blocks] - draw = ImageDraw.Draw(im) + draw = ImageDraw.Draw(image) for block in blocks: - draw.line([block.vertices[0].x, block.vertices[0].y, - block.vertices[1].x, block.vertices[1].y], - fill=color, width=width) - draw.line([block.vertices[1].x, block.vertices[1].y, - block.vertices[2].x, block.vertices[2].y], - fill=color, width=width) - draw.line([block.vertices[2].x, block.vertices[2].y, - block.vertices[3].x, block.vertices[3].y], - fill=color, width=width) - draw.line([block.vertices[3].x, block.vertices[3].y, - block.vertices[0].x, block.vertices[0].y], - fill=color, width=width) - - return im + draw.polygon([block.vertices[0].x, block.vertices[0].y, + block.vertices[1].x, block.vertices[1].y, + block.vertices[2].x, block.vertices[2].y, + block.vertices[3].x, block.vertices[3].y], None, color) + return image # [END draw_blocks] @@ -74,15 +65,16 @@ def get_document_bounds(image_file, feature): image = vision_client.image(content=content) document = image.detect_full_text() - for b, page in enumerate(document.pages): + # Append specified feature bounds by enumerating all document features + for page in document.pages: - for bb, block in enumerate(page.blocks): + for block in page.blocks: - for p, paragraph in enumerate(block.paragraphs): + for paragraph in block.paragraphs: - for w, word in enumerate(paragraph.words): + for word in paragraph.words: - for s, symbol in enumerate(word.symbols): + for symbol in word.symbols: if (feature == FeatureType.SYMBOL): bounds.append(symbol.bounding_box) @@ -105,18 +97,18 @@ def get_document_bounds(image_file, feature): def render_doc_text(filein, fileout): # [START render_doc_text] - im = Image.open(filein) + image = Image.open(filein) bounds = get_document_bounds(filein, FeatureType.PAGE) - draw_boxes(im, bounds, 'blue', 3) + draw_boxes(image, bounds, 'blue') bounds = get_document_bounds(filein, FeatureType.PARA) - draw_boxes(im, bounds, 'green', 2) + draw_boxes(image, bounds, 'red') bounds = get_document_bounds(filein, FeatureType.WORD) - draw_boxes(im, bounds, 'yellow', 1) + draw_boxes(image, bounds, 'yellow') if fileout is not 0: - im.save(fileout) + image.save(fileout) else: - im.show() + image.show() # [END render_doc_text] @@ -129,6 +121,5 @@ def render_doc_text(filein, fileout): parser = argparse.ArgumentParser() render_doc_text(args.detect_file, args.out_file) - # [END run_crop] # [END full_tutorial] From d3694a02af63e37289153d379ddbc1c8269f160a Mon Sep 17 00:00:00 2001 From: Gus Class Date: Wed, 22 Mar 2017 10:13:34 -0700 Subject: [PATCH 3/3] Less whitespace and fewer hanging indents --- vision/cloud-client/document_text/doctext.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/vision/cloud-client/document_text/doctext.py b/vision/cloud-client/document_text/doctext.py index 0109e9499d1d..9fb535ff65f7 100644 --- a/vision/cloud-client/document_text/doctext.py +++ b/vision/cloud-client/document_text/doctext.py @@ -44,10 +44,11 @@ def draw_boxes(image, blocks, color): draw = ImageDraw.Draw(image) for block in blocks: - draw.polygon([block.vertices[0].x, block.vertices[0].y, - block.vertices[1].x, block.vertices[1].y, - block.vertices[2].x, block.vertices[2].y, - block.vertices[3].x, block.vertices[3].y], None, color) + draw.polygon([ + block.vertices[0].x, block.vertices[0].y, + block.vertices[1].x, block.vertices[1].y, + block.vertices[2].x, block.vertices[2].y, + block.vertices[3].x, block.vertices[3].y], None, color) return image # [END draw_blocks] @@ -65,17 +66,12 @@ def get_document_bounds(image_file, feature): image = vision_client.image(content=content) document = image.detect_full_text() - # Append specified feature bounds by enumerating all document features + # Collect specified feature bounds by enumerating all document features for page in document.pages: - for block in page.blocks: - for paragraph in block.paragraphs: - for word in paragraph.words: - for symbol in word.symbols: - if (feature == FeatureType.SYMBOL): bounds.append(symbol.bounding_box)