Re: [GSoC] Questions about project Text-Extraction Libraries

Bruno Baruffaldi <[email protected]> Sat, 23 Mar 2019 15:42:36 -0300
Newsgroups gmane.comp.search.xapian.devel
Message-ID <CAND-c9OXOFKdJfAbuAvkiKpS33BF02HGiza14uuxG=WJkKOX2w@mail.gmail.com>
--0000000000008c5b1b0584c756c5
Content-Type: multipart/alternative; boundary="0000000000008c5b120584c756c3"

--0000000000008c5b120584c756c3
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Thanks!
That was really useful!

I wanted to share my approach to this project with the hope that you can
give me some feedback.

I am think that applying a design that foresees the incorporation of new
file formats is the most suitable way to solve the problem.

In the attached sketch we can see:
* Bug_Box: It is responsible for encapsulating and handling errors.
* File_extrator: It presents an interface for the different formats.
* File_X: Encapsulates a particular library for the X file format.
* File_Hadle: It is responsible for directing the extraction. More
specifically, it determines the file format and which extractor to use.
* Ominex: It represents the rest of the project.

The idea of organizing the code in this way focuses on two fundamental
items:
* The possibility of changing a particular library for another that
fulfills the same purpose without affecting the project.
* The possibility of extending Xapian's support in terms of file format.

One of the major advantages is that if a particular programmer wishes to
add support for a new file format or improve an existing one, they should
only modify the objects that are in red. In this way, with a proper
documentation this kind of tasks should not be a complex task.

I know it is an ambitious approach, but I think that with a good
documentation it would give the project great flexibility and the
programmers would have the option of adapting Xapian to their needs.

**The image only presents a simple scheme to explain the idea, I do not
consider it as a design for the project. I believe that we should discuss
about different design patterns to choose the most suitable one.

Cheers,
   Bruno Baruffaldi


El s=C3=A1b., 23 de mar. de 2019 a la(s) 12:10, Olly Betts ([email protected]=
)
escribi=C3=B3:

> On Thu, Mar 21, 2019 at 09:31:26AM -0300, Bruno Baruffaldi wrote:
> > Firstly, I think that trying to isolate library bugs in subprocesses
> could
> > get to work, but I am not sure about how to handle deadlocks or infinit=
e
> > loops. I feel that using a timer is the only way to deal with it but I
> > would like to know what you think about it.
>
> There's already code to set a CPU time limit for filter subprocesses
> (using setrlimit()) and to implement an inactivity timeout (by using
> select() to wait for the connection file descriptor to become readable
> or a timeout to be reached) - see runfilter.cc.  I think both mechanisms
> should be usable for this project (the CPU time limit would need to
> allow for CPU time used by the child process processing previous
> files).
>
> > Secondly, I have been reading the source code of ominex, but I cannot
> > figure out if it is possible to group all file formats under the same
> > interface. When indexing files, are all file formats treated in a simil=
ar
> > way, or are there special formats that require a different work (beyond
> the
> > use of external filters)?
>
> A few do - e.g. for PDF files we currently need to run pdfinfo and
> pdftotext on the file, PostScript files are first converted to a
> temporary PDF (because there doesn't seem to be a Unicode-aware
> filter which converts PostScript to text), etc.
>
> It may be possible to come up with a common interface still though.
>
> > To sum up, I want to know if ominex use multithreading for indexing fil=
es
> > or if you consider that it could be implemented to speed it up.
>
> Currently there isn't really any parallelism in omindex.  It would help
> when indexing formats which are CPU intensive to extract text from
> (an extreme case is if you're running OCR to index image files).
>
> When dealing with external filters, the extra isolation that
> subprocesses gives us makes that a better approach than launching
> threads - if a library used by a thread crashes the process then the
> indexer dies, while if that happens in a subprocess the parent indexer
> process can recover easily.
>
> Potentially we could have concurrent child processes working on
> different documents.  I'd suggest that it's better to focus on getting
> the subprocesses to work individually first before trying to get them to
> run in parallel, but to keep in mind that we're likely to want to
> instantiate multiple concurrent instances while implementing them.
>
>

--=20
Atte. Bruno Baruffaldi

--0000000000008c5b120584c756c3
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div dir=3D"ltr"><div class=3D"gmail_default" style=3D"fon=
t-family:tahoma,sans-serif">Thanks!<br>That was really useful!<br><br>I wan=
ted to share my approach to this project with the hope that you can give me=
 some feedback.<br><br>I am think that applying a design that foresees the =
incorporation of new file formats is the most suitable way to solve the pro=
blem.<br><br>In the attached sketch we can see:<br>* Bug_Box: It is respons=
ible for encapsulating and handling errors.<br>* File_extrator: It presents=
 an interface for the different formats.<br>* File_X: Encapsulates a partic=
ular library for the X file format.<br>* File_Hadle: It is responsible for =
directing the extraction. More specifically, it determines the file format =
and which extractor to use.<br>* Ominex: It represents the rest of the proj=
ect.<br><br>The idea of organizing the code in this way focuses on two fund=
amental items:<br>* The possibility of changing a particular library for an=
other that fulfills the same purpose without affecting the project.<br>* Th=
e possibility of extending Xapian&#39;s support in terms of file format.<br=
><br>One of the major advantages is that if a particular programmer wishes =
to add support for a new file format or improve an existing one, they shoul=
d only modify the objects that are in red. In this way, with a proper docum=
entation this kind of tasks should not be a complex task.<br><br>I know it =
is an ambitious approach, but I think that with a good documentation it wou=
ld give the project great flexibility and the programmers would have the op=
tion of adapting Xapian to their needs.<br><br>**The image only presents a =
simple scheme to explain the idea, I do not consider it as a design for the=
 project. I believe that we should discuss about different design patterns =
to choose the most suitable one.<br><br>Cheers,<br>=C2=A0=C2=A0 Bruno Baruf=
faldi<br><br></div></div></div><br><div class=3D"gmail_quote"><div dir=3D"l=
tr" class=3D"gmail_attr">El s=C3=A1b., 23 de mar. de 2019 a la(s) 12:10, Ol=
ly Betts (<a href=3D"mailto:[email protected]">[email protected]</a>) escribi=
=C3=B3:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px =
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Thu, =
Mar 21, 2019 at 09:31:26AM -0300, Bruno Baruffaldi wrote:<br>
&gt; Firstly, I think that trying to isolate library bugs in subprocesses c=
ould<br>
&gt; get to work, but I am not sure about how to handle deadlocks or infini=
te<br>
&gt; loops. I feel that using a timer is the only way to deal with it but I=
<br>
&gt; would like to know what you think about it.<br>
<br>
There&#39;s already code to set a CPU time limit for filter subprocesses<br=
>
(using setrlimit()) and to implement an inactivity timeout (by using<br>
select() to wait for the connection file descriptor to become readable<br>
or a timeout to be reached) - see runfilter.cc.=C2=A0 I think both mechanis=
ms<br>
should be usable for this project (the CPU time limit would need to<br>
allow for CPU time used by the child process processing previous<br>
files).<br>
<br>
&gt; Secondly, I have been reading the source code of ominex, but I cannot<=
br>
&gt; figure out if it is possible to group all file formats under the same<=
br>
&gt; interface. When indexing files, are all file formats treated in a simi=
lar<br>
&gt; way, or are there special formats that require a different work (beyon=
d the<br>
&gt; use of external filters)?<br>
<br>
A few do - e.g. for PDF files we currently need to run pdfinfo and<br>
pdftotext on the file, PostScript files are first converted to a<br>
temporary PDF (because there doesn&#39;t seem to be a Unicode-aware<br>
filter which converts PostScript to text), etc.<br>
<br>
It may be possible to come up with a common interface still though.<br>
<br>
&gt; To sum up, I want to know if ominex use multithreading for indexing fi=
les<br>
&gt; or if you consider that it could be implemented to speed it up.<br>
<br>
Currently there isn&#39;t really any parallelism in omindex.=C2=A0 It would=
 help<br>
when indexing formats which are CPU intensive to extract text from<br>
(an extreme case is if you&#39;re running OCR to index image files).<br>
<br>
When dealing with external filters, the extra isolation that<br>
subprocesses gives us makes that a better approach than launching<br>
threads - if a library used by a thread crashes the process then the<br>
indexer dies, while if that happens in a subprocess the parent indexer<br>
process can recover easily.<br>
<br>
Potentially we could have concurrent child processes working on<br>
different documents.=C2=A0 I&#39;d suggest that it&#39;s better to focus on=
 getting<br>
the subprocesses to work individually first before trying to get them to<br=
>
run in parallel, but to keep in mind that we&#39;re likely to want to<br>
instantiate multiple concurrent instances while implementing them.<br>
<br>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr" class=3D"g=
mail_signature"><div dir=3D"ltr">Atte. Bruno Baruffaldi<br></div></div>

--0000000000008c5b120584c756c3--

--0000000000008c5b1b0584c756c5
Content-Type: image/png; name="sketch.png"
Content-Disposition: attachment; filename="sketch.png"
Content-Transfer-Encoding: base64
Content-ID: <f_jtlu97ds0>
X-Attachment-Id: f_jtlu97ds0

iVBORw0KGgoAAAANSUhEUgAAAr0AAAEnCAYAAACkMftgAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI
WXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4wMXEgoi5kcICgAAIABJREFUeNrt3X90k/X99/FX7jP3
bboVSpMJs4ItXzVBdECtCgbPPZmuiKL3QIFS4nECI9pO5FedMCAQYQpIh4DSDTZvSuXHpPd3whQm
4nZsGP6glk1so35tR+0U1pRQZtPv4Y/cf9Rca/ozhSJNeD7OyTltcuX6XPnkavvqO5/r8zGFQqGQ
AAAAgDj2v+gCAAAAEHoBAAAAQi8AAABA6AUAAAAIvQAAAAChFwAAACD0AgAAAIReAAAAEHoBAAAA
Qi8AAABA6AUAAAAIvQAAAAChFwAAACD0AgAAAIReAAAAgNALAAAAQi8AAABA6AUAAAAIvQAAAACh
FwAAACD0AgAAAIReAAAAoJu+QRcAAIDe4vjbS/VlfSUdgah8K8WuQbcsI/QCAIDY8mV9pYaMzqcj
EJWK0lVRb8vwBgAAAMQ9Qi8AAAAIvQAAAAChFwAAACD0AgAAAIReAAAAgNALAAAAEHoBAAB6iL8+
oLETfipTn8yIm+vxlaqvPy3X4yvlPVwu38fVyn54ofz1gR5tZ7hjqnwfV3f6vOyHF3a6TXePoyf3
11uxOAUAAEA7Sv+4WY6Rw9vcv+mXCyWpx0JiR+2gZ1HpBQAAiFIw2GRUelvzHi6PqAoHg03n1Zbn
mc0q3vlaRLsH//yOFi1/Xjte/qMmP7RQR//mk+vxlZry44Uy9cmU93B5mwqy55nNxj5bPjZ2wk/1
2T9OROzP93G10Vb4+eHX6vu4Wlk/ylPWj/I0dsJPz7nCfbFQ6QW+8n8Prdbx+k/oCKAXGdjvaj3k
WEBHoNfzfVyt5c9sVuWRlzXoygGa8+RarXlumxY/MeOc9zn/sWlauvJXyswYojp/QLeNGqEx//tm
DbvhWp1u+JfcT/5Eg64cIEkaah+sUMN7CgabNOfJtXJOHqd9Jevl+7haj+Wvke/jag26coAWLX9e
i/Ona1/JehXvfE2/LdqjFUseNfZnuybNCMmNJ0pVdrRSufNWaeeLKyVJJ07Wa+Oz+TFZmSb0Al85
Xv+JJt70GB0B9CK7332OTsBFM/qH/w6sWXeMUvFmjxLNCe1u+15ZhdKvukKDrhwgszlBzinjVLTj
VQWDTTJ38Jz22pGkWQ9PUMEv5spsTtD0B+/V0pW/kskkbViT3+E+BqelSpLM5gRj+IUkWS3JSunX
p/nv3Gdf6HTDv2S/Nk2SlDP5LkmKqNgGg02q/fyknFPGyWxOUMYwu0bedL3eK6tQZsYQ9b88RVZL
cky+n4ReAACAdrQ31razIQuFvylR4W9KIoJyYxSht7MxvbZr0jTUPliD01JlSek4bKZd9V3ja+/h
8oggPeyGayVJdf6ATgXOdHosjcEmVR//3PjebE5Q6ncvN75P6dcnZkMvY3oBAAB6wPJFLoUa3jNu
+0rWdxpUo+E9XK4z/2rU0Q8+jurCOX99QJ5VW1T6x80KNbynuuoDGmJLk9Rc9e2XnNTp8xPNCUob
9N2IkF/7+cm4eH8IvQAAAOcpM2OISr+axkxqvgjtfC9m89cHVLTjVT0x50FNf/Bebdn6Srf3t+/1
v6jCV22E3lOBM6r8qPn74p2vfXWM/2NsH67shodmlB2t1OF3P1BmxhBCLwAAwKXOdk2aljwxQ/Yb
72+e8eDto1qx5NEuhzZIzWN6W8/VG56lwTllnCwpybJdk6Zh11+jNc9tU6I5QX37fFuTH1qojz75
e8S+LCnJck4eZ+zzy8agRt50ver8AVlSkrXumXnKnbdKpj6ZKtr5qlYseVSWlL7G/nwfV2v+Y9Mk
SYn9R2v0D2do47P5sl2TFvPvkSkUCoU4VQHJs3cWF7IBvczud5/T4nsK6YhLSMVrkzVkdD4dgejO
l9JVGnLXzqi2pdILAIg7Bw4coBNw0bWe77Y7q66h5xF6AQBxo6CgQH379lV9fT2dgYsuPH1Yy4vb
wrdy70txMWSA0AsAnaj6pEoTfjBRQwdcb9x+kj1LgQu0us/X3R4uXtitqalRTU2NJk2aRKcAIPQC
uPis37Fob+keHfviAx374gONuGmEtr+4I27aw8UJu2vXrlWfPn3oGACEXgC90y2jb9HJL06qKdik
snfe17L85Wr6amqevbv36oW1myRJgfqAfpI9S0MHXK9l+cu1wLVAVZ9UnVd7klT2zvtGFTjcdmfH
AcIuAEIvAHTb26Vv68ZbMpTQxfQ+21/coRE3jdCxLz7Qjbdk6L8//vS826v6pEpPPfmUil4p0pGq
9yRJv33hRWXcPEI33pKhA68eUKA+oJq/f6YfP/IQbxZhFwChFwCiU/dPv+4ZPd6orp784qTuGHdH
p88J1Af06Uf/rbH3ZkmSRt8+Wv95zeDzbu9UfUDDbhym624YogRzgsbfP17vv/u+AvUB3THuDvmO
+ZT/aL5uGX1Ll6EcPe/s2bOEXQDn7Rt0AYCLwfodi54t3aP0q9MlNQ8veOzh2Vq18ZkOn3Oq/pRO
B073eHv/qKmN2LZfSrL69m0OVAnmBN0+doz+9a8vdd0NQ3jjLoLc3Fz96U9/UkNDgxF+ly5dKkla
tmyZ3G63JMntdnN/HNz/2EM3yaVVnPiIyjcTrVFvy+IUwFdYnOLrU/VJlX7x81/oyaeeNEJooD6g
FQtX6NH5j+pUfUB7Xt6jJ5blK8GcYIyjzX5oirFN+tXpEc8J76cn2it7531tKthkBPB1Tz+ntP9M
k8Waonsm3sMb+DXa/e5z+lnWBq1fv15ut1szZ86U2+1WUlISnROnKl6bHPViA0B3zheGNwDoFT79
pEqnTzeoX0o/SdLRI0f1ee3nCtQH9P6770uSklOSNfja/9S+V/ZLkkrfLD3nMb0t2+uXkqyjR47q
w79VqCnYpD0v79GIm0YoOSVZ21/cofH3j9fkByfJd8x3ThfN4fxcdtllmjt3rhoaGpSamqrU1FTN
mzdPZ86coXMARI3QC+CiaD3G9qknn9KTnp8pOSVZGTeP0J1336l7Ro9Xfu4TcnzfYTwv+6Epev/d
5pkW/HX15zymt2V76Ven6+e/+Lmc9zp1Y3qmJOnHjzykvbv3SpIybh6hBHOCJkydoOfXPM/8vhcR
4RfAuWJ4A/AVhjfEnpbDEJJTkumQOLT73ee0+J7CDh9fu3Ytwx7iDMMbcKHOFyq9AGJGU7BJy/KX
t6nWnqo/1WbFtdZz7iI+UfkFEC1mbwAQMxLMCVq6aomWrlrS5rGSN3bTQZd4+J07d67Wrl2r1NRU
bdmyRQ888AAdA8BApRcAEFfht6GhQcnJDHcBQOgFAMS5O++8k04AQOgFAADxz+fzKTs7W36//4Lt
r7i4WMXFxZIkj8cjk8mkGTNmaMaMGfJ6vT1+DD0pGAwqPz9fPp/vvPovGAzK5XLJZDLJ4/H02vOB
Mb0AAADnGIKPHj2qZcuWKRgM6syZM6qsrJTNZovYprcym82aPn26tmzZomXLlslsNp/TfhobGyVJ
dXV1slgsvfb1UukFAAAxEzKHDx8uk8mksWPHyu/3G1VGr9crSfL7/crOztbhw4c1e/Zs7dixQzk5
OXr77beVlZWlrKws47ler1cmk8m4hffRui2Xy6XPPvssYn9+v1+7du3SfffdJ0maM2eOVq9eLbvd
roMHD0YcU0st23S5XAoGg8ZrCFeKW1dMOzpOr9crl8ul/Px8o0+8Xq9x3OEKdEftSpLNZlNSUpLK
ysokNVerWz6vZX9kZ2cbFd3wcfj9fuXk5KiwsFA/+MEP5PP52n2fegMqvcBX+pot2v3uc3QE0Mt+
LoFwmJ09e7Y2btwoh8Mhj8ejRYsWqaCgQCtWrNCiRYtkt9u1b98+5eXlaeTIkVq3bp3cbrc2bNig
uro6nThxwni+z+fT8uXLjcpscXGxioqKlJGRocbGRrndbu3cuVM2m00ej0d//vOfI/YnSbW1tbLb
7TKbzSooKJAkOZ1OZWRkaNeuXe0Gx3CbgwYN0pw5c7RmzRrNnz/f2F9jY6PKysqUm5urSZMmSVKH
xylJhYWFKi0t1bJlyzRnzhx5PB698cYbqqyslMfj0dixY1VXV9duu4sXL5YkjRkzRgcPHpTD4TDu
a09FRYUWLFigTZs2yePxqKioSAUFBSouLlZeXp7cbresVqtycnK0YMEC5eTkRLxP51pJJvQCPex0
0N/pJPgAvn6evbPoBEiSKisrJUl2u12SNGnSJLndbjU2NspiscjpdGrq1KkaNmyYJkyY0O4++vfv
L6vVKqm5wrl//37jsbS0NL311ltGW3379tWgQYMkyQiCLYcq1NXVqU+fPkpMTIz6Nbz33ntKT0/X
oEGDZDab5XQ6VVRUZFRdb7vtNpnNZtntdg0ZMqTL45SkrKwsI3inpqbqtttuk8VikdVqVb9+/bps
12w2y2q16syZM8b3Henfv78yMzONoFxUVNRmm7q6OvXr109jx4413qfHHntMx48fjxj2cTEwvAEA
AMSE/fv3y2q1ymQyyW63q6KiQnV1dZKkjIwMpaen67777uswuKWkpBihV1LEcILRo0cb91dXV3d5
LHV1dWpoaOj2aygsLFRiYqLRZnV1tTEmNi0trf1//jo4zvBzognenbUbrdb911G/nDp1yvjearUq
JSWlV5w/hF4AABATZs2apcbGRoVCIYVCIZWXlxvVw5KSEtlsNhUVFUU1htTr9crr9aqurk6hUEil
paURQbIrVqtVffr06fZrWL58uXH8oVBI+/bt6/Tir86O80K2e65aVpjDIbi+vp7QCwAAEA273a7q
6mrjgqvi4mLjIqnwLAoul0tOp1PPP/98t/YdDAYjPqq3Wq2qqqrS8ePHJTVXWltPxWW1WtXQ0NCt
amlmZqZKS0uNYRIejyfiorLuHmdPtVtXV6ekpKQeGXNrtVp16tQp7du3T5K0a9cuY2gFoRcAAKAL
FotF69atU25urkwmk1avXq1169ZJktxut6ZPny6z2SyHw2GE4nAAy8nJUSAQiNhfRkaG0tLSZLVa
NWrUKN111106ffq0GhsbZbPZtGTJEtntdplMJtXW1mr+/PkR+5Ok1NRUY6xxNFrv1+v1asWKFZ2G
zc6Os6faPXjwoMaMGWME4vZmb+ju+7R69eqoX+PXxRQKhUL8KAHNF8xwIRvAzyUurorXJmvIXTtj
4lh9Pt95z3HLa/j6zhcqvQAAAOfAZrNp2LBhKikpicnjDwaD2rJli1Elj3dMWQYAAHCOwkMdYpHZ
bNaqVasumfeKSi9wgf57/rrXIY/l9d9ba7maT8ubx+OJeB3h1YiivQgk2na6WkGop/vyXPfn9Xo7
PL/Cq1JFswRq+Hw5n74EgN6OSi9wAXzd65DH+vrv7enfv3+b1xC2ffv2r6Wd3s7hcOjgwYPyer3G
xTvn8g9ae+cLAMQbKr1AFLqzHnp31iH3er3KysrS8OHD5XK5jPXaw9W24uJieTyeLtdlj4f137sT
8DuqirY87vO5+jgcBlv2XbhyevjwYc2ePVs7duxQTk6O3n77bWVlZSkrK8t4bzvqp/Dxh/vF5XLp
s88+i9hfePqlaM6XYDCoSZMm6fe//72CwWCXfZOfnx/Rdn19fcT5Ej7OnuxHACD0AjHC6/Ua66E3
NjbqzJkzRpANr2UeCoW0bds2FRUVKTExUcXFxZoyZYp27twpq9VqrBcfCoXkcDi0aNEiI+ydOHFC
O3fu1KZNm/Qf//EfnR5L+DhKS0u1e/du+Xw++f3+Nuu/z5o1S6WlpRo1alSHwTF87OGq9Jo1azpt
p6PXG34dhYWFuu+++9TY2Ki0tDRj/ffS0lJjsviu2j0fxcXFxnFXVlZq9erV7Yb9aJnNZq1YscI4
9n379ikvL08jR47UunXrNGXKFBUXFys5OVknTpzQkiVLtG/fvog17lv3k9/vl9vt1s6dOxUKhZSa
mqo///nPEfuTpNmzZ2vBggVdni9ms9mY+zK8xOf27ds7/HThr3/9q9544w1VVlbq8OHDqqioiDhf
HA6HiouLjYnwe6IfAYDQC8Sg8KB/m81mrIce/ki4oxV82lsvvuUciwMGDOhyWcew9tZl76n132tr
a6Na/72j19t6/Xen0xnV+u8t223pxIkTxpySXVWFg8Gg3nrrLeO4bTabJk6cGNVSoq3baVndtlgs
cjqdmjp1qo4ePaqMjIx299G/f3/jPeysnyorK9W3b18jqC5evLjNRTDtrVvfcpL81ueL2WxWUlKS
sRRrZxwOhywWiwYNGqSRI0e2u82nn35qvHfhfjx48CA//ABiHmN6gSiCQnV1tREqt23bZgQVj8ej
JUuWGNvOmjWr3X2E14sPGzZsmBFSol03vaNgfT7rvxcWFkaE1mjWf+/o9XZn/ff22m09Xc65jLWd
Nm2apk2bZny/fPnyLp/TVTsZGRlKT0/Xfffd1+GUPq3Xo++on6IJ4V2tW9+d86W1wYMHd/p4MBhU
bW1txHaDBw/Wp59+yi8CfG2+ZRmqitcm0xGI+nwh9AI9KCcnRzk5OQoGg5ozZ44RCsMfA1ssFnm9
3g6Xh5w1a5YKCgrahKauqnPRhI3zWf998eLFbUJPR1qu/97V6+1uuz0l/BF9TyopKZHNZlNRUZHs
dnuXFyZ21k9paWl66623unw/L9a69eEqfXfPQaAnDbp5CZ3QytmzZ5Wbm6uNGzfqsssuo0POEcMb
gC6ELyYL69OnT5vhCJ2th97ZevHtOXz4sI4fP25cEBVN6I2X9d/PJ6zddtttEWNnx44de94XYYVn
xXC5XHI6nXr++ee79fzW/WS1WiOGKng8njZTjnV33frw7AvRDpHpyuDBgyPGYO/evdtYnhTAxbFh
wwYdOXJE69evpzMIvcCFM2HCBNXW1spkMikxMVHDhg2TzWaLej30jtaLb69i6HA4NHHiRNntduXk
5CgrK6vL47NYLHGx/nvrfy66KycnR6mpqUpMTJTVapXD4Yhq0vj2xvQOHz5chw8fltvtNlYqCleQ
i4uLjWCak5OjQCAQdT+1fv21tbWaP39+xP4kdWvd+nCAHjRoUI/MH5yTkyOHwyGr1Sq73a4FCxb0
ePUcQPe43W698sorcrvddMZ5MIVCoRDdAEievbO0+J7CmDz2eFj/3e/3q6SkRDNnzuRk7M556/Fo
zJgxcRtMY/nnEugJBQUFqqmp0dq1azVv3jylpqZq7ty5dMw5oNILxIFYX/9dap7Z4Lrrruvxfwba
W3EtXlYfCw9/oRILxC+3221UeFt+je6j0gt8hYoSwM8l0Ju0rPKGUe09d8zeAAAA0Au53W7V1NS0
uY/Qe24Y3gAAANDLFBQUaPr06W2mpExKStLMmTMjqr+IDpVeAACAXqa9Km/Lx6j2dh+VXgAAgF6k
oypvGNXec0OlFwAAoBfprMrbchuqvd1DpRcAAKCX6KrKG0a1t/uYsgz4StFf1qra76MjgF4kzWKT
cxSVLFw6+vbtq5qami5DrySdOXNGqampamhooOMIvQAuNWfPnlVubq42btyoyy67jA4BEDPam5e3
K8zbS+gFcAn/0XjhhRfkcrn4IwAgpnSnyhtGtZfQC+AS/qPR0NCgpKQk/ggAiKl/2Ltb5Q2j2kvo
BXCJ/tEoKCjQ3Llz+SMAIKb+Ye9ulTeMai+hF8Al+kcjXO3ljwCAWHDgwAFNnjxZiYmJHW7z5Zdf
6lvf+laHjweDQW3fvl133nknHUroBRDPWn40aDKZFAqF+MgPQMz47LPPOn184MCBXc7de+WVV9KR
hF4A8a7lR4Ph0MtHfgDiJrB99XsN547FKQDEvI4mc2fydgCA8Y8DlV4Asa71BSAtKyJUewHERWCj
0nveqPQCiGldLdlJtRcAIFHpBRDj2pvmp3VFhGovgJgPbFR6zxuVXgAxq6sqbxjVXgAAlV4AMauj
ydzbq4hQ7QUQ04GNSi+hF8Cl6cCBA6qvr9ekSZOi/uPwu9/9TsnJyUzeDoDQS+gFAP44AAC/1+IP
Y3oBAABA6AUAAAAIvQAAAAChFwAAACD0AgAAAIReAAAAgNALAAAAEHoBAABA6AUAAAAIvQAAAACh
FwAAACD0AgAAAIReAAAAgNALAAAAEHoBAAAAQi8AAAAIvQAAAAChFwAAACD0AgAAAIReAAAAgNAL
AAAAEHoBAAAAQi8AAABA6AUAAAChFwAAACD0AgAAAIReAAAAgNALAAAAEHoBAAAAQi8AAABA6AUA
AAAIvQAAACD0AgAAAIReAAAAgNALAAAAEHoBAAAAQi8AAABA6AUAAACi8Y1oN/TsnUVv4YJYfE8h
nQAAAHpH6JWkiTc9Ro+hR+1+9zk6AQAAXHAMbwAAAAChFwAAACD0AgAAAIReAAAAgNALAAAAEHoB
AAAAQi8AAABA6AUAAAChFwAAACD0AgAAAIReAAAAgNALAAAAEHoBAAAAQi8AAABA6AUAAAAIvQAA
ACD0AgAAAIReAAAAgNALAAAAEHoBAAAAQi8AAABA6AUAAAAIvQAAAAChFwAAAIReAAAAgNALAAAA
EHoBAAAAQi8AAABA6AUAAAAIvQCAeOL3++VyubRmzRoFg0E6BECP+wZdAAC42CwWizZt2kRHALhg
qPQCAACA0AsAAAAQegEAAABCLwAAAEDoBQAAAAi9AAAAAKEXAAAAIPQCAACA0AsAAAAQegEAAIDY
xTLEQAx7d8lC1VdU0BGtTLvOrv0P/IiOaCXFPkQ3eVbSEQAIvQBiS31Fhb6/8Od0RCvfpwva9aeV
T9EJAC5ZDG8AAAAAoRcAAAAg9AIAAACEXgAAAIDQCwAAABB6AQAAAEIvAAAAQOgF8HXyBwIan/tT
JWRkRtzyVqxU/enTyluxUofKy/VRdbUefHKh/IHAebVzqLw84v7tr76mlb/e3GOv51B5ucbn/lT+
QECHysuVt2Klgk1NvNEAEENYnALABXPwN5t16/Dhbe7fsGihJOmj6mo6CQBA6AUQf4JNTVrw7FpN
vXucrMnJEY8dKi/XmIdnSJJmTJyg1fPmypyQcN5tbn/1Nf3454slSd+79lpte3qlBg4YoAXPrtUV
l1+u5S9skiQtecSlhTNnGIF82s8W6q8ffaQlj7g6fS2bd5d0GvIBRI/l1dvH8urt687y6oReAL3C
R9XVWvnrzfpryctGIC0o2maE0HN1qLxcL/3hVdUePCBLcrJW/nqzXn79gOY4p0mS/nHypE4dKtX7
lZV6/OlVuv/OO2RJTta81c9qzoNOZY+7q8OhEgVF23TF5Zerqew9HSov1+NPr9K2p1fq2rQ03lDg
HLG8evu+Txe0qzvLqzOmF8AFM+bhGcZ43vCY2I4c+bBCaVdcoYEDBsickKCpd4/TP06ejGrsbMt2
EjIyjaquJN06fLj2bFwvy1dV5fTU1IjnOkaMkDkhQba0NNnTm8OqPxBQvz5J+uGtoyRJ9995h/r1
SYr8w3z6tP5SflTfvylTkjTCbtfNN1yvunMcnwwAuLCo9AK4YNr7uL+zELt5d4kxVECS7hw1So1N
TV0OcWjdzvZXX1NVba3RXsshCJIihitcdcV32+yvLhDQqYYzUQf71iGaIQ4AQOgFgA61HFPbU/7r
4JuSpFOHSmVOSIgIxB2xJie3qey2p1+fJP215GWGMwBADGB4A4Be4cbrhhjTmEnSyl9v7vGpwfyB
gF76w6tdbjdwwAD1+fa39cdDf5Ekvfz6gTaV35S+fWUfPFgvv35AUvOY5JunTG0zfRoAgNALAIZr
09K0cOYMfW/C/UrIyNRfyo9qWe6j5z17ww9vHaW//+Nz9bt1tB5atFg/eeD+5rHC//M/HT7HnJCg
x3KmqmBrkRIyMvXtRHO7wyDmOKfpHydPKiEjU9+bcL/mPOhkaAMA9FKmUCgUimZDz95ZmnjTY/QY
etTud5/T4nsK6YhztP+BH3GVM6L2p5VPKet3/4+OAL/XcEn+XovLSm/VJ1Wa8IOJGjrg+ojbC2s3
fW3tXui2EF9ef/11OqEdwaYm5a1Y2WZlt4SMTN08ZSqLW3xNDhw4QCcAiHlxFXqbgk1alr9c94we
L98xX5vHN6zaoKEDrlfZO+/zzqNX+ec//6l+/fpp3bp1dEYL5oQEbVi0UE1l77W5vbPjJS4gu8AK
CgrUt29f1dfX0xkACL29yW9feFG7tu7qcrunnnxKVZ9U9Xj76Venq+SN3Tr2xQd6ZK6LswtRmzp1
qqqqqlRVVUX4Ra8JuzU1NaqpqdGkSZPoFOA8+AMBjc/9aZtPrPJWrFT96dPKW7HSuJD3wScXdjqn
eWcOlZe3+RSMi2zjMPSWvfO+NqzaYHyfl5+nY198YNy8H5bKcbtDkuQ75tPWXxWpKdjETyJ6jeTk
ZP3yl78k/KLXhN21a9eqT58+dAzQQw7+ZnPEJ1YbFi1USt++2rBoYY9cBHvr8OGa86BTzxW/pGBT
k4JNTXqu+CUuso230Pt26dvG189sfLpNpTU5JVnP/WadJj3YXLHYtXWXPvxbhRGYhw64XhN+MFFV
n1TphbWbIsYCh4dDhLcL3/bu3hvRRkdjevfu3huxr5bft7cf6d9DNTobk9x6m5b7adlGe/sH4Rcg
7AIXX/jahfYqsYfKyyOqwtFM4fh/xtwuqXmO8vA85eH7CL1xIFAf0PvvNgdTx+0Ojb59dLvbJZgT
NP7+8cb3/6iJnKDed8yne0aPj6gYS5LzXqfmz5ov573OiPufyP1ZtwOl816nnsj9WZv9tBxnHKgP
6LGHZ7cZqrFh1QYty19uVKgTzAl68CdO2YbaJEmvvLxHgfqAqj6p0m+e/60kadKDk3THuDs40wm/
AGEXiCEfVVdr5a83668lL+vUodLmn9mibV0+r+WUiwVbi/RYztTznvqR0NtLjbhphJJTkjt8vF9K
shESa/7+WZvHbUNt2lu6R8e++EDPbHzauP+13+/TMxuf1rEvPtDe0j3GPo68XdatYRId7b9lpXr7
izvkfdMrx+0OeT8s1bEvPlDRK0WSmivUB17IPpYpAAALMElEQVT995XU6Ven6+FHfyxJ8r7p1et/
eF1bf1Uk3zGfbENtevAnTiWYOdnjMfyePXuWzkG3nT17lrALXCRjHp5hVG7H5/6007G7Rz6sUNoV
V2jggAEyJyRo6t3jmucYj6LaO3DAAN18w/W6+YbrNXDAADr+K3GxDPGp+lOqO1nXI/u68+47lX51
uiRp6LChsg21yXfMF1Ex7ZfST9bLrfId86m2plZNwaaog+XDj/7Y2P/o20c3B9s3vTr5xUk1BZv0
ee3nev0PzdNX3Xv/eCPAZ9w8Qnn5edqwaoOOvF2mO8bdYbR5x7g7NOnBSdq1dZfcC5a121Zv9eb2
I1oy3sRPYjdt2LBBH3/8sSZbv6M/rXyKDkFUEq3fUW5uro4cOaIPP/xQqampWrZsmdxutyTJ7XZr
6dKlksT93H/R7p92nV3fj9OfwYO/2dxmbG1nIXbz7hJt3l3y74wyapQam5q6rNz+18E31fCvfxlf
Z4+7i1+AipPFKao+qdK8WfONcPrEsvwOQ2jLbfPy8/TIXJfK3nnfGLrwzMandc/EezrcVmoeS/vM
0lXatXWXHLc7tGrjM0pOSe5w+7279xpDGopeKVLGzSMkNQ9jyM99Qt43vcZxf/i3ijbDKFpr2WZY
y9cgqct+6C1YnCJ6p0+fltvt1m9/+1u53W49+uijejNnMosNIGr7H/iRxry0S+vXr5fb7dbMmTPl
druVlJRE56BXnafxtjiFPxDQQ4sW68mZ09sNvQueXaupd4+TNTlZTxX+SgVP5OuPh/6iqtpaLZw5
o1ttfVRdrbmr12jtgvmSZHwdr1M8XnKLU4Qrr5KMymtHjh09ZszhO/CqK2Py9dadrNOp+lMR9113
wxDjIj1JunzA5QxriKOwO2fOHF111VW66qqrFAgE9Pjjj+ub3/wmnYNuu+yyyzR37lw1NDQoNTVV
qampmjdvns6cOUPnAL3IjdcNMaYxk6SVv97c5cVs/kBA81Y/q5y779a1aWm6Ni1NOXffbczmcKmL
i9CbnJKsETc1V0+9b3pV+mZpu9sF6gN65eU9xvdXDEzt1a8rPIa49a3kjd1thi0cePVAxIVvG1Zt
YBGOOA27QE8h/AK917VpaVo4c4a+N+F+JWRk6i/lR7Us99EOhzYEm5q0dOPzuuqK70bM1hD+OpqL
4Ai9MeKW0bcYXz+R+7M203tVfVKlhx+YLu+bXknNH/9fd8OQXvc6urrQrj0tZ2toaVPBJgXqA/zm
IOwChF/gIrIkJ2vPxvXtzpUbXnny1uHDdW1amrb+YqUsyc3DF28dPtyY03fPxvXG/e0J72fDooUR
wTh8f3eHSRB6e7HwhV5h4SWHw7eWSxP35lkNvpv6XQ27cZjxGsLV2o7mAG4KNhmzNUjNY4bD/eB9
06vtL+7gtw1hFyD8AnEgPKdv65XdEjIy26zEhjgOvZL0yFxXRPDtyM9/8fNeO6tB67l3nfc6I0K7
bahNY+/NMrZvOawhLz9PGTePUPZDU4zV5xjmEBu2b99O2EWvDb+/+93v6BSgFwhXbVuu6ha+vbPj
pbi9WI3Q20nwbbnkcEvhpYnDsyf0VulXp+ulvcURF6ZJzUMyXtpbbAT2lsMaHLc7lP3QFEnNY5xd
c/69It2el/ew5HIvZ7FYCLvoteE3uZOPVAEgVsTFlGWIXUxZdn72P/AjpiwD5wvi7jyNtynLcOFc
clOWAYjk8/mUnZ0tv99/zvvw+/0aO3asvF5vt/bn8/mUn5+vYDAor9crk8mk4cOHa/v27XK5XKqv
r5fL5ZLX6+2Vfef1euXxeDiJACDOEHoB9JhgMKgtW7Zo+vTpMpvNqq6u1rZt21ReXq7s7Gxt2rRJ
ZrO5V78Gh8NhhF8AAKEXQAzYunWrUWn1+XzG/cXFxTKZTG0eCwaDcrlcMplMWrRoUYf7DVdwTSaT
XC6XgsGgJKmsrExJSUmy2WwqLi7WtGnTNG3aNHk8Hnm93ohtw3w+n4YPHy6TyaSxY8ca1WSv16vs
7GxlZ2e3Oc5wFTp8DOHKbLgiXVBQYDzH6/Ua27as4HbUriRNmjRJv//979scKwCA0Augl6moqNDl
l1+uUCikiRMnqqCgwBhyUFRUpLq6OuOxXbuaZwBZs2aNJKmxsVFOp1P79+9vs1+fz6fly5ersrJS
jY2NEc87ePCgxowZI0nKycnRtm3btHz5ci1evLjdY/T7/Zo9e7Y2btyoUCgkh8OhRYsWGWFzx44d
ysvLU2Njo0aOHKldu3YpGAxq0aJFcjqdCoVCqqysVGlpqRGIW7/u3NxcrVu3LmK7rtodNGiQJOn4
8eOcSABA6AXQm/Xv31+ZmZmSZARRqfnj+3379slisUiSBg8eLKm5yltbWyun0ymz2ayMjAzNmjWr
zX7fe+89paena9CgQTKbzXI6naqtrVV9fb3OnDkjq9Ua9TFWVlZKkux2u6TmCuvp06eNMJ2VlSW7
3S6z2azbbrtNkmQ2m7Vp0ybl5ORIkqxWq1JSUtp93YMHD9bEiRNls9kituuqXbPZrKSkJNXV1XEi
AQChF0BvlpKS0m4AbTmEwWQyadq0aZKaq7vVUU5sXlhYqMTERJlMJo0ePVrV1dXy+/2qqanp9nHu
379fVqtVJpNJdrtdFRUVRthMS0tTYmJim+e0HF5htVpVUVHR5evuTrsAgPjzDboAuLSUlJQYIdds
Nqu4uFiffvqpEhMTlRblxObtDVkIBoMaOHBgt49n1qxZKigoaHOBW0cB1O/3y+PxqLS0VA6HQ36/
X3l5eT3WLoCL/A/7kCH608qn6AhEfb4QegF0ye/3q6ioSA6HwxhCUFRUpIyMDJWVlamwsFBOpzPi
OZmZmdq6dat8Pp9sNps8Ho9qa2tVUFBgDAmw2WxRtW+321VdXa2ysjI5HA4VFxerqKhIxcXFUb+G
ffv2RVR6z7ddi8WiYDDY7aEaAHrGTctX0gm4IBjeAFxixo4dq+rqaiUmJionJ0ePPPKIamtrFQwG
NWHCBElSYmKiioqKtGDBgjbPt9lsWrJkiex2u0wmk7xer1asWCGz2awxY8bo4MGDUR+LxWLRunXr
lJubK5PJpNWrV2vdunXGeOOOnuN0OjV69GiZTCZ9+eWXGjlyZLeGJnTVbvgCtvAFbQCA2MeKbLio
WJHt/PS2FbaCwaCWLl2q6dOnR13t7Y08Ho/GjBljzNnL+QIAsY9KL4AeYzabNX36dG3ZsiVm57gN
L0oRb4EXAC51jOkF0KNsNptWrVoVs8fvcDgIvAAQh6j0AgAAgNALAAAAEHoBAAAAQi8AAABA6AUA
AAAuKGZvAGKY5fobtP+BH9ERiErK0OvpBACEXgCxJ3PpcjoBAIAoMLwBAAAAhF4AAACA0AsAAAAQ
egEAAABCLwAAAEDoBQAAAAi9AAAAAKEXAAAAhF4AAACA0AsAAAAQegEAAABCLwAAAEDoBQAAAAi9
AAAAAKEXAAAAIPQCAACA0AsAAAAQegEAAABCLwAAAEDoBQAAAAi9AAAAAKEXAAAAIPQCAAAAhF4A
AAAQegEAAABCLwAAAEDoBQAAAAi9AAAAAKEXAAAAIPQCAAAAhF4AAACA0AsAAABCLwAAAEDoBQAA
AAi9AAAAAKEXAAAAIPQCAAAAhF4AAACA0AsAAAAQegEAAEDoBQAAAOLAN7qz8e53n6PHAAAAEHNM
oVAoRDcAAAAgnjG8AQAAAIReAAAAXHx+v18ul0tr1qxRMBikQ7qJ4Q0AAACIe1R6AQAAQOgFAAAA
CL0AAAAAoRcAAAAg9AIAAACEXgAAAIDQCwAAABB6AQAAQOgFAAAACL0AAABA7Pr/EAG2SjJ8NpcA
AAAASUVORK5CYII=
--0000000000008c5b1b0584c756c5--