[weboob] [PATCH 1/1] add library capability and backend and application for archimede software aloes http://www.archimed.fr/aloes/presentation-et-avantages-12.html (second try)

jems jems at ldjm.fr
Tue Mar 13 19:49:55 CET 2012


Signed-off-by: jems <jems at ldjm.fr>
---
 modules/opacwebaloes/__init__.py        |   23 +++++++
 modules/opacwebaloes/backend.py         |   70 ++++++++++++++++++++++
 modules/opacwebaloes/browser.py         |   78 +++++++++++++++++++++++++
 modules/opacwebaloes/favicon.png        |  Bin 0 -> 22966 bytes
 modules/opacwebaloes/pages.py           |   97 +++++++++++++++++++++++++++++++
 modules/opacwebaloes/test.py            |   27 +++++++++
 weboob/applications/library/__init__.py |   23 +++++++
 weboob/applications/library/library.py  |   80 +++++++++++++++++++++++++
 weboob/capabilities/library.py          |   58 ++++++++++++++++++
 9 files changed, 456 insertions(+), 0 deletions(-)
 create mode 100644 modules/opacwebaloes/__init__.py
 create mode 100644 modules/opacwebaloes/backend.py
 create mode 100644 modules/opacwebaloes/browser.py
 create mode 100644 modules/opacwebaloes/favicon.png
 create mode 100644 modules/opacwebaloes/pages.py
 create mode 100644 modules/opacwebaloes/test.py
 create mode 100644 weboob/applications/library/__init__.py
 create mode 100644 weboob/applications/library/library.py
 create mode 100644 weboob/capabilities/library.py

diff --git a/modules/opacwebaloes/__init__.py b/modules/opacwebaloes/__init__.py
new file mode 100644
index 0000000..bb0ece2
--- /dev/null
+++ b/modules/opacwebaloes/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2010-2011 Jeremy Monnet
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+
+from .backend import AloesBackend
+
+__all__ = ['AloesBackend']
diff --git a/modules/opacwebaloes/backend.py b/modules/opacwebaloes/backend.py
new file mode 100644
index 0000000..31305ec
--- /dev/null
+++ b/modules/opacwebaloes/backend.py
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2010-2011  Jeremy Monnet
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+
+from __future__ import with_statement
+
+from weboob.capabilities.library import ICapBook
+from weboob.tools.backend import BaseBackend, BackendConfig
+from weboob.tools.value import ValueBackendPassword, Value
+
+from .browser import AloesBrowser
+
+
+__all__ = ['AloesBackend']
+
+
+class AloesBackend(BaseBackend, ICapBook):
+    NAME = 'opacwebaloes'
+    MAINTAINER = u'Jeremy Monnet'
+    EMAIL = 'jmonnet at gmail.com'
+    VERSION = '0.a'
+    DESCRIPTION = 'Aloes Library software'
+    LICENSE = 'AGPLv3+'
+    CONFIG = BackendConfig(Value('login',    label='Account ID', regexp='^\d{1,6}\w$'),
+                           ValueBackendPassword('password', label='Password of account'),
+                           Value('baseurl',    label='Base URL')
+                           )
+    BROWSER = AloesBrowser
+
+    def create_default_browser(self):
+        return self.create_browser(self.config['baseurl'].get(),
+                                   self.config['login'].get(),
+                                   self.config['password'].get())
+
+    def get_rented(self):
+        for book in self.browser.get_rented_books_list():
+            yield book 
+
+    def get_booked(self):
+        for book in self.browser.get_booked_books_list():
+            yield book
+
+    def iter_books(self):
+        for book in self.get_booked():
+            yield book
+        for book in self.get_rented():
+            yield book
+
+    def get_book(self, _id):
+        raise NotImplementedError()
+
+    def search_books(self, _string):
+        raise NotImplementedError()
+
diff --git a/modules/opacwebaloes/browser.py b/modules/opacwebaloes/browser.py
new file mode 100644
index 0000000..9c9ff19
--- /dev/null
+++ b/modules/opacwebaloes/browser.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2010-2012  Jeremy Monnet
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+
+from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword
+
+from .pages import LoginPage, HomePage, RentedPage, HistoryPage, BookedPage
+
+
+__all__ = ['AloesBrowser']
+
+
+# Browser
+class AloesBrowser(BaseBrowser):
+    PROTOCOL = 'http'
+    ENCODING = 'utf-8'
+    USER_AGENT = BaseBrowser.USER_AGENTS['desktop_firefox']
+    #DEBUG_HTTP = True
+    DEBUG_HTTP = False
+    PAGES = {
+        'http://.*/index.aspx': LoginPage,
+        'http://.*/index.aspx\?IdPage=1': HomePage,
+        'http://.*/index.aspx\?IdPage=45': RentedPage,
+        'http://.*/index.aspx\?IdPage=429': HistoryPage,
+        'http://.*/index.aspx\?IdPage=44': BookedPage
+        }
+
+    def __init__(self, baseurl, *args, **kwargs):
+        self.BASEURL=baseurl
+        BaseBrowser.__init__(self, *args, **kwargs)
+
+    def is_logged(self):
+        
+        return self.page \
+                 and not self.page.document.getroot().xpath('//input[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl08_ctl00_TextSaisie")]')
+        #return True
+
+    def login(self):
+        assert isinstance(self.username, basestring)
+        assert isinstance(self.password, basestring)
+        if not self.is_on_page(HomePage):
+            self.location('%s://%s/index.aspx' \
+                          % (self.PROTOCOL, self.BASEURL),
+                          no_login=True)
+        if  not self.page.login(self.username, self.password) or \
+            not self.is_logged() or \
+            (self.is_on_page(LoginPage) and self.page.is_error()) :
+                raise BrowserIncorrectPassword()
+
+  
+    def get_rented_books_list(self):
+        if not self.is_on_page(RentedPage):
+            self.location('%s://%s/index.aspx?IdPage=45' \
+                      % (self.PROTOCOL, self.BASEURL)
+                      )
+        return self.page.get_list()
+
+    def get_booked_books_list(self):
+        if not self.is_on_page(BookedPage):
+           self.location('%s://%s/index.aspx?IdPage=44' \
+                          % (self.PROTOCOL, self.BASEURL))
+        return self.page.get_list()
diff --git a/modules/opacwebaloes/favicon.png b/modules/opacwebaloes/favicon.png
new file mode 100644
index 0000000000000000000000000000000000000000..dd2b0ff7aedc474f412ba18e90de3496c340d11a
GIT binary patch
literal 22966
zcmV*qKt;caP)<h;3K|Lk000e1NJLTq00Arj0099A1^@s6!cUl;00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyY<
z3N{Rp-;8kp002aEMObu0Z*6U5Zgc=cQbj>jPf|J{XJjpEaAjv8b}=q6ASiWnX>MmA
zNlHf`N>D{dAa*z~DJ&plWoBV at Y;+)Tbzy92ba at I1M|Erf03ZNKL_t(|+U>o0)FnrC
zC-}RO@!q#om1>cYgoNY*gancRvj_>b4YC9R1A`fsZjXCxPWQ1rmf5VfIi6!|4?bhY
zr^lz;Yum##J*SVC_88mkrk7#2d)U>;9>7LuLHmX_N?X<UeeY$)oj-Dm%$JcF5gGa3
z`@Zi5r%=_)%vf*SxcA1rze~)_$O<!qh>HK3iuTDMMQ^*_R@*au3^u=ajkDffh&ibD
z-=+_)eQtiALBxi42+RZ`_xhXK3OTQ~>(<t`&9l%YueXU_ZJxRI(RH5YHFr(#w5`4V
zzTR%}Oew{-%wQ1=tKMGQv-CO8)IHO at whhH*F+z;Zb-%bYTdiA}-U72I-VMc!{pOV`
z<Fj2i{XO4jVHuWboNRc;z58hU-Mr_nx}H=ppgK+H46BKLhzOJ<3F{RVq^;O;6AZK1
zrnYQ|d8odGn1gxuzuLBHSyN#xIk+(Orc<_l0JR-RyS*$EEiX&S*IX%uI`8R{+N4qn
zLWl;jR4j~P)ee8q0vV^NjUa8ejBT*VoRO?lFLl&b{WG1I_3vp9 at 7%Vb?I(tnGpn2?
zY|RJ&Ac+W%J at y!Gy6GmII&}(B6d{TtsHB}?4XPA!%N}cc7I<rOy*&hIdrtjtE{SG8
z0pd8u*=Ii!7hn7Wj7Gv?<B^x at n2Y>*9rxdVKfdveZ(wb0O{+`pvE8|NT3&ofDuW%3
zMmT=_IG**aXU$07T}(?dGj6->HvHPJ{Tgn)^;Set1b`8V^}%gbt1{;kUZf|R5Cmo*
zNn*VD%|C=+_=W!&XPj}ypzB?iqT)Elr#|&5eCR_T!e}(oP6;{iX}BtLraFLPq?bN~
zBuQ}W*fCsx{q=b3Ti*&PW#tg-l(6!bx3{;kwY7!ucnl#3+taOmC8q9=qDl!1gh at QX
zbQ&WP^OI_F^F#jMt*tFgr_+qE8N{Q#E^h3v!T at NR{gsO~*X>p&lR>je2m&jHpeQ9=
z7D%RyC|VKCo}-;aq^=D_U{1hF0jvg>Xmn9OH?#^NvJ+QfETgPXfDp7|SbL7}WU-_w
zi2(*wl0d-D&|YC!snA9sCV&aV0t9lqJ71OEA)FJXryMH?B1D1^2^jsehENA}0%Zo2
z0ze{TQaRnNXm4*ZETM~A$b}>#(u~D+#&=1Yu$ETfXHZ?0-65Vca$lF!o~0DeWv!c-
zmQu+Kt*z*8kE(^)Uvhe5=7N2>98fY9(>Ws`1|fkEQNa!SssgqI>{F+$qhg=-hER|C
zZg}5$WoA$$Adni|LpZ+r6d?qd8A1pMK~T)OauB>dlRHJzv!Ut9$A`^#Y`$&#&WYLG
zCFdhm$(e}2N`ZvqEg at w@lV5e`C3PI_ciOczp4&3|p3=5A3_k76L(;G<djGxWl?hOQ
z%6zZJ;}OQ=@mv^g-REXHonktj7IrIEnGv?;7uI*(n&wJ(SoE3WQ1m<G*nHdeos;_d
z7JHMB>iv{ya+zeE+b|jI=7*Ixk~@$}If6<Qq}*fvFsqW;*HytJc6KJ1OeQmHZ8~L5
zw>eFRhN+HRvWlXpkhCHZL4i}ro>vC<Jy!%33 at b^hDxq-H;v_4D&CN}`@P(J+(4o@`
zh80QCe}kk(lewsbZKr?w+AdZJDcALTs)Q=FTah40DKMSx;P|tTSKO>!17Ka>%MZsm
zj&bIhXX45$UkO1`5no3GteY*(*wYjB-VgH_oB6%Aws|J@&t^Zj(QA4LrP7vCF-|*t
z2**x8mfliF!f8*?bUNj&Q(JiCkw>tzvxD4<k03WkWc+7kQfjlnEelCaw!Hjz^BN$`
zXj%foEs4*I)@%K5tD|-86 at w{bCRupIkt2t3=2>SIQdS*FpdOH#`%jtFB%NVZV^h_P
z9qYu26L|2!2P<J<l}#6F-Kcpksg)+f)03$mLyXP)J?}Z;TAj^--vA&Zfis@*3>-Ri
zXoj9T!@P2|23mQE?%Sf2$_}Y+hE-=oHVjL*HR^=9qPZ2_xyGhS-ALy0VQ5vz=Qd*A
zSKy(svF2UcaKf0mD#j1kcHN28#nX9Jc5kVh3+mF94GqY)mtA#uTc%{Plep^QeI-K|
z0J0{gZrg{D%)bu+Thko7+|c;Wchk+23#3S>IhbehZF7<RA9`MO$va1Da2=QI67!oH
zZR at -(nqYmi*hX#lMeOupz&3N#hIBfl#A53=)7H19H8C-_wyXF$6KrGf6u?2*_EvIP
zq*^EA@)BqgE<S875|+MKT;YXe;|mr(qwHxioH5NcwC~D*cnLx|I;E_E`^c>q0vTg!
zxM_67r1F)-+K?ne&6CX>EV_i+Hvv1;c at Y$BUNyeL8Q2^d;t5RxfNYc!I=tmuZ5=Hb
zKb7xjK8&LM<ALk9nJ?cyb3^?N>t-XVx~heJ>=!}iidx3gG(U?l?vv;E=H36MuwmA^
zQlHm8bgk1Tl}xLNK1?)egh)<D;duvNuu%t*&3U5P+R3mBh>x23M+|1FOfWgLX)|t~
zAxz6Y&-A~xY^L_8>b0yRC(Of6ViTD_&`#a1bt~2*TdO%TBda;r`&g%^Why3LA>&?|
z<zQ`Vr3cp+>z`q=G1}G6I-N+9uMDvWF#5paRCV{c3Dn%i^vO_v{X18JqmI+2R(}rV
z+Vrfg8tuE*<RMz;b;I|(jnX-trC^aYTU*83tz+E^8kp}bW0htsXp6NzE+fNYpK;fv
zw6?J|T<B#^%!ovV;};=2Ci|yZ!ouDvzEH<Q!`QONN!Ql at RtamCVF@7`{bAaqBpa2}
zL~vdHSTkw{_aFD*>K+G>UUowvPo_6BU#X;>BngC!iUU)pNfWI|r4%NU2_Ap^aZDzY
z01{R=(Yk!+>;B-|7u%eOw)NYFdvvuOqzImobPgOifHTfGqmXvG=FsF++V-AF9enc1
zC-Klj50wzf4s_=-uS3}5mS#=oI3E98rPZ6|D2j0O=usRzbO;Kn5=EgiE8R~krynVV
zz&F47O?>#nAI3fR+*1&42!^#A7HdBhg`^^SPbL#wbImol?z-!6<j9f1)~Jc8DW&k&
zfBo0^z2E!2O7L|Ex?7dyqda}xj~qFIAN|oE#kJR73n8Nl#Ec0^qp)ECDW3aHH{FEW
zZ@=Bhu*%bMDBWmPh9{f2u%$>TF_}zo;e{8 at _*S_(=ei^j(24TVM<2zFH{OVijg1w<
z+D8oQ=+UEi^2sOD;Accm_EgEtkdegN+B&2hK}Jz(Nnk3jJev|g+R$c|@TqqO+nL`j
zd1t6>wx&D3F2RI+f=OX_w`!g37XYY~WK at zsMlwx0LZVd~a&hD}`PJ#P5Jgep=`7`_
zPzkw!>TX#3E)z<CtjA9C?s#nXxhL1Z9kTyJeW&NXR7xR|5|NY;8N^UMM`2r$DG(ro
zATm7n6qAT4y$>L2-+*ldG)wpvPHHpXaq(SUx+~x=$ZYE?+pKRa^Ru at 4n)}<vdCLCR
z$7a+2?zw6nTVq|CtBRlqF(*(lgO$5Sb60p()9?B>M3iA-Mc_P-KyGrUhP6lgC6tL~
zx at mHDzHC5yU73#?5O8x_w(ITN|3SWE{h-XyLIfdBVo<KlIb7VxoQTWYnVfL?`A+#V
zIx4Q_OL*0)gvFKqamQvSs(zQ}M{9nTxd=EAXj2{av#0RA)5d1o|L(bJ9$T}BRWeGV
z`kMROCw=W$<-aL&BO%T8f at h?1ZrMe|oL#xIQJSyLS1$E;_{jxeRyK9oFo`Bw8>0U~
zzteo>W*94(J={%ULDJMHSrFV%r9#Lv3~%;X*DbT at yZSTsJw3@JJ(AVf+WOx$?`@J|
z<vZfqW`#4u3He^zjv(#-XTpYBRnP9#bG5;S_MRZP2i>C*m0&W{80N&K|GMXSy&s<Q
zRWdC*n(4ZUlpxA-!Eu53NFb;haW5-&kx4|Q9>nAa&PGA|Z?gZ`w%znyp7FW<%rs(`
z!1yL`zqXAT$8kxl`JD4?Z|cm-G`1n=b0`;Rmo>E=>+G7=1dtjd>JZu8zH6Nu%0=MH
zTbuz%>Nmu?n~aI>BxQ!MBuNm*2>=1G0*Qbp=Rk#>CvO;$-FJRM*-32MPS+O|f>BBZ
zfwA at pV&}}8zuJE`j;$R`mFGrVzVyYO^hCbWZp$}h*+<{+nyp+6Rtj;P7 at b4AiX<Y8
zM`N6G&bgROrih|Z2BE5j>C}U#_AtY0BYX-hVYxX6n=K2}3gxRy$<;b`c6M<3>8CFw
z;fRzHo12^Xp6~e{tc}+-N;BUqbIaI7U<qp;49n=C*%GYi;=IW%^x1-RT%#GX8nYe4
z0umMD at Zm!^aNs~QL+r{4ki-c;{`lj#?Y7%-^5jVniS%k&EW4v8wL)72k+9mXkhyPz
zj{UddZngUwu2-R5AA^vn1ZSOj7B0N-LX6i(PHLbJcw0RL<DPr&!L7G`8zVVxp5r+j
zP(Dm6nDlNrAhHb)<CcGt<rvufT?mH7tS}x+oPYlLIOm*m8fmR9e*jIVQ`U)y@|%;u
z6wqbx4Uw3#k4?d*{t%w~LwNsN*U4#4!kifLccUnBLjUvyans!!gb+xQ1WA%W%8}v5
z$ew0akrcb5G_8{!@T at zKHcICC%Vi=}@@615_6k>|(jgg^4N7Xr4PuIq>XY)UDQ3^8
z?kWXAq5 at Hyzn`mxT?S#F7(SCb0}(+=StRnUI}f_hj7tFbsw at Z7%5$OS|FvRndDOHn
z^!aW^A4z7BL^kiXL$v1`{9Tu%(xkZ(qtR$4 at VO4|*LG`Df2RMp?VFtGbOl}8(oBdv
zmo~rI(0Lm?be}%<k!a^JZr6R##;i=VCqv?Eo1DE|{7zh at i%<k%6OLk=P;?&sHaXkb
z7-daZ?lzKT*Zg!zq&k7lq%{YeRMWoe(I=CWk5nE?jk0w!@zoA|5lei>MMQ|>cm`Ug
zu8ja%5{gh9)Rep+wDb{j;#^PhK5Y-;FJ#d#Q!2MbjHAg`(FBnjV%)3Ze^AcDE~p<~
zHUZFb5r~tkGJnEY%|ZXRcS9dtzMJ>BoA^wUB!y(9^CDvsin at f=HzV(|GrncXTepb$
z(v9sp(r8=y`H&}e4lARJ`}G^kd9T|L`50YPXq%jWZ5fShku=P4oc+gbyEaWGfE>9a
zNs_|G+A3kyiDoY|E0e8l8JU#}N`fo1%Dvp{#NsoLZT)FdLGzO|KUwwl=-PZk*@xQv
ze&#`UE at N{=!FA1F*+es)&YX^GQ}0ugc_2UFW|*E*it}5-As1{_mPhTX<7bx;C9}ls
znjE)j6Vy}F$8nswGYG_S?941zWp~qHPID%thSsb(`G?!v+jTy;n%zBEQbv`7rYVfa
zW2~*MA&NvWHOo{-PN+G9noK4*b?Q_tG-yS4`+;etG#6>mQFe4E0pQL%@5EpH#b4mz
zhac9YtktQvcNtcS%8?`rmtA%l-tv|=<G{g9<1JkuHMHKYF16io!wvY;KmAi|Y;0(4
zujp=1Gb_c|+}y+)-}FYj{ADjqu at -n%y)@dem>CZ}^bkJwv5(=l+ioiiU&N!;?Cv#U
zK`DkONdl!5rqdX&d)@1B;NYee<LRS{>LP!VB>2|1zJ)*j<3GmQ+FI5I11ueLPOi%C
zp}#bi at W_!Pc)<%U#>-#!GBgG6cis|88R5Wz1BI9-ga9kKn&CZG>V&YfvjZWbLLHn(
z`?<6wgurN&;<>M{ua)S{JlcCXF;}Hf_7jz0JYEBlC_=KD%n2=iSOS26Qk)_+6hK(^
zNh4Nemz-~T*gs{GmZ%~)EP`<snC?0f=!)?6mRLpA%qt|)KQlQFEa*^{0j45jQUYZ{
z>eW%Vm*@saYRNEEijhS;!%W()x^2)L>UGp_ev%|9gPS1$mE**64NqlN_JCZa-KC^7
z$DBY!m`O3$oi(S)-ar|NH=rI40c_U2(VFYGg`{G~>4oE1hn^F5sFOQ7(#(g#*r;rM
zf?6jk%i`p+z9DIWJlDgAzWS{Hko#efJ<PCjaBY*evLqA+4_KN-FSNl*=YRul%YkN_
zAI&#^oNbOa3_K?;-*&%i!Z~9%#$q70uCR)_eIk9gfOad?2Xb7?p=e=f`VP_F5c?tQ
z9_E%Hd$aa$q92*&`zyVm>mr&?=d3kkCg8A&q+)aZZO`fpU~8sntH1u9RsGa2CtXwh
zZTzIQ&zOaPF|DT$x`vClc6v+6P)PzoY0{HaxKD~p!lrSv#klq4t4{M{xl5I&nB{Al
zQ|w2truk~^e*k)&X-_rNPMU-wGSXF(eXCFjbI;?_>sYPS?>$zMqzsJ#(m1XrJS<nq
z%0*?&6JO-s_3In!TB2M634xXEbgvbm(O}{gl2klbO7VU7J%F!#<tsRG;)Lcns+><w
zlkVBeWY=<vyP#j%ZZP%){CCM-+jky($4L~;V5>j(xzELwS6+$r^>L%x=5~^*8K~R5
z&L&^1n{K)Z|MkCq4x`Z;2<eTX;t5RY<!s08J3lUKHBW?G+dhZb4 at 2A-6GasoSzlkr
z%U<>}Ty)VzAW{IR5@%{c(q(4QWHMzTfGAq|UF}b)EAxCOE(pgL)4j`vm75!M=TU%W
z)PhynA9SZwHR!%{brCbPlrt=u3RKi=yIPe!S8{(RT`gm#!vC%hrhA*HFNBzZk*Np4
zhK3eim1Qp6Nnbh~QT|No5&AZ`M0;b?y2HhWLgx$tk<zCx6?>7zHS>`4;F<>@gi7eE
z8o8)YZ8YQa%%^RadAFs{5PPML=kH2iq?FosN16*3xQ&ldpY|4sW#3h=sV!fXuwJK&
z|CSA2y$^b>E1tg#Bet1?KI`B^AHG0>A@@rDUJfEzr!A9|pSd;czc7e-CKMPVw_#rf
znzwCx!O%Aeg(>q&6XR=3iW1 at y#6`jjA>9q}EVN|l+poTRstFIP4KW1J?;BTTpW3vj
zH*}28$zN}Gl~Z8(5BAV>*TlTKY^b7c->Ckj+ej9`&erdJ#-N+6b3=2#cKfQD{fLab
zC$WDL+vVMOA#mbdCDxFPV4gJC=kRNSMedaLl`2=W;=RpW58CO)r^vSo?g%lU;fUFK
z@(1o?2=%sncQ%kCJ>6zU(AS1l_ruCDub4 at rH!3ay$_s({%}Hnzz-~8#3~fGX%Z+K%
z7pZTpN*IJH15gWaHDAu#Q$A}7-X~- at ZybIxm$8o_`p-PeQd7p#9M@&ziR_w7uxy8#
zSbN6M7PF at HvFxQAbKkMqe^;(sh`BS}fRa+oEAzpsG-W6;*`b;xC)@YRF!~kU?RT2v
zMu+8Ah-9S{9)0vNeDj;%#EBCp(iaI3p<!yt5BZk3SwhLB7ajt;ML+e)zmI*!?bd%y
z)oZo4rKeyN3B+-lDe2sE&&7*g^g?WGtPe_@^>kj$j63hV6JPt<*C1t7AUE{1J~Xc>
z4gB4%5V1VQR;R7D{a}r4!x)d(@cidrg!9fjAEQy!XwNc2Bqxc&?YG~KU;p)A$1S(q
z0x2b=l;C9eIkQzKL)RI6Gwy;uru|3?cw!>L&dv_r@|L&YdC$85o0}VhsX$FOFJ{K)
zKmU1r at Pi*Lpt%(*2&_WH_Hs#7f+L5I;QH&Y$Ft5oZ-yrH;Cy46ubg<}IL2f$NgvP%
z9C)jRWLO2(+mbM>HdEEIFf0;WK)Z}aBb+*QsuDdvr2WK{d3bw!yJ{y{WzE^Mg at _Qx
zF~*}b&|ZiLx$VoA2Bi=s<VPIG7>~yQ5qJWldQsjswX>&+;}<$qFUP0M%adG%O&#Us
zN&v$u0kYuIoN4*`Vfjc{<tZ8!v5a|)Va4Nll{IINaVj0DLsW7{<jl%ey3geAOih3Q
zD}rK$NJQ-?rlmARb)>u5H`-+>liECo+c!7qW%>J<WA-b~U|=#BY~kSq>hqrdZ>6|6
zB+E2k0I?0O?W*i9hNUWhPbK}NvS+LrR)Nl_Qqe5Wo at 3f+T<{jQ*&nIMhgp9l)^NKC
z9kyZ^e4Lg^df5ei1QA%N!dsY?0<tx?m6UA!ZMxpeALXEth5uIO&_=5y6nm<0Wj!;5
z5Gd!Y&xM4QBR%Q>S}dsb2F+H+YRtbwHI7Qu>8~`9?|pdHaEbfKnc5XeS(pKG)vSJy
zgz)xm;hQt3YVmjC27j?t+0_h-{ph5TVdZv&C=#hVLw at 2xbx7tm&>-gbNHoYJJ?XUS
zsXrHi#ksAvJ`UagGzVa6bkA)^Qc8%zp3v?K(-%oV$Gl=L?WP5+5#{ENm4vltv_Sw$
z!%5R^l}f2f5?>oyl0pc?ag3dv36dm%jPexq=6qq+5i2}jP(WR^na9mnRY)Y~KGwe*
zy8p~nBpMlwMvVxMHU>~1jIgG0jz*)@g(k0u0q_b)a!*NDrEO@&53lZbWog4AoPPT0
zxc1uD;>9oiUdSjy95V=$nGG6JEf_-D$(;|0?Cmn4R36*;5k!S;iy1WpPCc%UgG*UL
z$O?f>CKJ5)#V^)y{Qa5ttewite1%Av=kepm at s4-AqtZUD7}g%NVO6E50|yS^`0?Wz
zfS;;hzIX1sBuO}q6Fl|Q(@=?m5QHQF1SJ)@jxb+j%)U%y=(c?sR at K#mE85S{{b!^S
zl*s&H7{J<i4TlaL1VvPluxvwanx32duJn_Y8Q9v|!pV~-EBORg3~R45tn`L at V`CHR
z>*E=Es at Tz+=qQe3*1bztWsl3}`ppc|n>kht5 at c<|GBG7n)*M|8D2cI at Dp$0(|4OO>
zaqHpM7 at A`Q|8KDXd#4DZ!Gr4R4bHK>z5#0k_g}XY=@OpSj0vBpue#rKT2^lgxzXma
zDtqUoB-D{Qn(3?yj#=6;A6xau7R!0QB83~1^#|Rzg|Rj9aQDQdPRzp*iD9r6>AGpG
z&1Gm<>bX+iz)2`VwLLUm7;`;qJbU5Yw=%4@!TO*n4wXE?rr$O;nR=qnwp+8hRBH2H
z{`Y#$wLVD`T<e%;@=O<c3NbdDHJvxJs;kdU$z*Mw*+BpFY1<WA$YowlYw98hRT!2l
zar-X(vfC-zu2x-{`aI^s2UEQ-x at uSMKoeoQ_BSMC?=pb!`NAa+O(%W!a$neK6CHK>
zVd-L9`L0cH^KR6nIp}+#+78iPXB{<w&nAi4#(w3)lx-xXwhb_s`B^XxcJ*)QIq<E&
zZ@*l9`Xr#Bm<w;`5-eqJmB!6NE$@(Loo(+?m{ZOK)nZ>kO~hB3m${|d->1K&T46U9
zLVysVMer(PEPrz}e=*JwG~(K}ucQTA`tNSf+T;|++Zk94We!{vgiwm3yaLLw3m9Q7
z#?k7%u6LKE&)K_ql&4C{*h0o^j=0cjd{sphS+`XIHPSe*tFjlQg{n-(I%ic*3`^=9
zr8K4~2#UgPq&aGt>>wx3I2ka*2B~)jZDOH3maPQC{5F#rMLc0?5AX}QaqVY{eZ_?X
zA=jhcEuf2bj|pN1VAzi)9on<m5A#NXu3$B=0w9p%@Z~p#))z<HJ5TdSu4T}<BZxdG
zIRwp;<%|wJOCI8LXC3uumPI*eyUa0ZeT at K4((oLH!gzhXz{Tn^(A(Orn#6q}2-9g&
zgk%sAq!f#v$9b#|54>+|X?foJvbI;^Sb<p;^q{-bbX|VQC>r65U;H9|>6bo;n{U1a
zYinz1RDY5LS*<Ff!TdPZDi>YzoaB%)IV|?u-u8C<%CCG7XKZX#L~@^bX!CT>VQk`9
zWl1oAk9_1K_|S(wRKfA4K*osWu`ux5Xwp8VeRVGmP4h}?D~@BFe){S7`JexJyyG43
zXtZGH%u63znwO9XLP!t^2og|9iklRQY?$XMeEOI|$n(41ym>@+D;z<}5uzv>%x<L<
zVcvcms|?a8!uIwyHa9mlbye&!mPK=<Npjc^G&h>(8X#i{k4?pYb^6Rr6^%(KO6 at ka
zCkT<HTvBQkAhE|vP9Qn*Xois7Na()It4ozkr72|T#-eKQD*$4#qPx8(+gHNBa*5gp
zTTK?K8%n^vH120bHhWIO%0zRe6e5utK1n-aZF9r*Rm1amvO1t!=?1u>y}ib->W7&w
zP300--IKn_<wb%Cl!1LlkpQa%iU3;WhudS!3ILK!l2%Zxpg74A1gK6mu8T3Xg+A%9
zGUd%+)#jD=a>c6lFyE^A<K;9^O5V+`4f?+;T#1!}$m|(dB?8!cOpDV50Qr at 2Y236|
z^ISr<OhlKfggV-3sX6cptYIH8t|rh(lSHroR$*8<bS}VyBX+tCFdxu<TUdQD!!a#A
z7hqy}8(f#RT(R79#*{KjQH-rA4P1yYl%Z*6X#9QK`a|?%=&{s+Dswu>*Pn=rguY!j
z)RI*-@;XV9PPmkXD8O~9-Y<&3L0a*dht#{gOhS<)NhKITCn6hY9T#7%s+0yKnU}rp
z^OgQr?E;!vruswlW!Uj>&AnwZnPl!Y3?c;~BBR7L!?1)PNEzYSvD0zJ8D|tp0hY%d
zY2JRh%Q@~cSEN4z0dv(aE{>--dhA${G}i|&$+a&jVNxN at pLNz*MF#2=j6VsmUxucc
zWvZV8^kdlZ=nN}K5*$8!7 at M1$Ssn(_nG>MWvt*j^Q%^mGyY9LhCr_R%LMMb+rnJiY
zOt@;$YkZ+vW|>||ILyGYV at Gkp^PUGe>JG(f!gTj>e at LY(!h;V!fV=LxyYK at eAwVkG
z9W*nq`a1=z<<|-8nC_#|2<M%5KA!Q6GYVImu6zN7`p5}0GlQa)rE^~vm3bl)cRFn5
z_AmY4KH!0zhug16Zr_$P%X}L3P;qVPkme<WQ%}?aBPmlmGRToo(78t9&LT67^|wf?
zeS>s!46s%t&W51vP?CndsNOO+wf^Vp)_iDF1wB1g!%+HSk=;7_u77pzW`DDek8c?F
zOjr<TAeyPx&uCwJ=S)cY*s|ATXC(Xp03ZNKL_t&)w;_Vo!>fJij9TeBG|lVj?CRzS
zQ)mtVNX(>&FBf76ako*_Ynx~qW&_za;4%-xp<6bK$BbF2sOdL-s8k;}*{d~OSI+L5
z2w5XdSdXz*S)Lsz_&U{8LKlCv?y6~~jrQ+2fPTtebnTPguGB(j8Iv{QXh=fb?REOp
zze-iLY$^v2!esldeF(tDd6uCeoLx(BhGj~oxnfqsN~w#L02j-YTo~4FV^)h~SfQ9z
zNP3l_3EBqNW>uDJbMH0@(UhU6m+fd(mY!bISVC~c__Yj at z^e2+{e0#<<YDDgpOtOL
zGVi4>-Rn0{tFlOXEyJ;L)Z6?wr+Sh^v7UvusiM?ArrlVv!BU%{J?vk{sX&XH&0M~~
z^;~YcYe8N8UgRNRG6%FVA6IXAQ~mla)?_k86s5tmahzZzqov83vwtW!jSFQ?{p<4I
zQ;1|Ymlk~wNMsu$U+^?AmO-p)U8tuSr`FEq^{$Hlnwu6ikN?xLh5D#=p<FV2kTUz&
zLa5?F&4?mkI!zEorKMv$9)V-Ex)fQ+0ftPP(%nx0Ac4rDD+)+<%OaIx#PJk6J3D0~
z#HcvB&-hMR--GV~zCnnS1W6Jj_Y0WEs1&Qpm3g9)0zWDTzDuWAKoEInmD}9h#OCJa
z!lW^ml1r9N-{rXQlgXr@<@_7{@TG>BwN)8leN~1as~B8!HkLBN=H at 1%$bBs&z_|PF
zd+^bZeiYyN&UdoKmw>7UtLjdNzP=Z`Rrfx%wT+XfP6Amh-aJO7t1!$ARti#%FpZ}f
z!^+ij|2C%6DSqT1{|NrOH@~TsfwZY$ee7L-`?voeZn@<aL?Y6hmb*@D^BJmG;l6wC
z!@c+3TXjxV*;KLniQZ4TSlO(YRV9`%iX>k3s_(<=U;lalBS`6%ol7z^9(m*ueBu+I
zz%94jk}@lx7Bo+_aHIXhu)qLB2_sE8W|O7b5_+C|l6f>Sn_RVg;)y5m^2=V1XFl`n
z&J^@bb_E|*F8}^xANv^o<-hn%jK}L4;;oHyWb;4sQzV7XiJS#|9|qH<cvQ2g?_af0
zAt}~oG#cT^kt2BRYp=!ndIXb)zKOPEZU-5U$5>liD;O5BD5xTIp0tH99iIVc-!rHP
z9;Q|Z6nFEkYtjYR7Mkj3FvcMK&ENbj&OZArV`?wko4Kxco9s^;8=KhNJc#x64ecP{
zMxysS2<#4n5cQY#ng*u6#7v8tm^FpndqS3YSL5**qme`o&Y>fS*wBou#|AMo7>tOc
z-u+*eb(%@i?D#DS%2W;%i9YL6R+&B9FXxNuNFZ9)@0XRkT>P?*BvE+fD_=Q-t?nv8
z`8wDN5=Gj2#SCGDNcIbsE at DBgPBhp0saAg$Ff at a*K+6x_%LDQ&rXmNS4%}zkRzudD
z@<AoYSuGRGF-(S4D&1Tz*8;n9qlV=vng-Tt6UbGl7Ja6C4%AfZBrE3cbzoP5Ov~D)
z(-^OL%{7I%Ua^_gm{o}UdNWK~aRKBfG9yzx2)hz&%x<$vBq~tQZT30Jja&};gU;xS
zy`xh3mx!|TR%FdHO^l7jz}!m1TFb(@gYA6+pj4VlFwN9NWs(s_0leU3!)heLU4rS(
z)^F7VMA at N!Rp9mzMcLIXTiG>2OQIA++)W{{Pdj`F?|$!3XIa06(N5*ctZY2dbJcnz
z8H8yH<OVW&th;Zalu?L|Tfu7m<T#=E=~4O}a(+QY<&C at b@=zZd?^9GmOJQ2gT{cs4
z5aplz23*-Cf1Q!ADyL#ia&fVl%ryxnYcw-p6Y1$Gpj3kV%87{rl9GAWH~{fb9g=|v
zJCkkv_)q?mP6@<Cl5(|SvF7pIbx at MmxCb_06kN0l10<r<6{fhF>{w^c#%+AlK;yHt
zu^cIA^L{lUiByCKc9YPv(3}z!z6fnloTh+sv{R(^ulY+?Ja{_{j#c3U#mqqk&@P1b
z)MGow_SP0ufUp|^VQYH}kDqwF^E+FQb^U!?mxm-tu(PvM_K*Afj6_jXAehdD23gyl
zS>NM0$<0 at lP0LWm+sMj$wSCk^AC>uUsei7;kN||iP)Z<CapU~h%(Y}@M3KP8#s=2c
z*R!lSso=Ks>fk(&6Lz!TxH3e8Xa_JOP7=K6dtZd>uDcG$jvWKDvc3T`adgEBXP<p`
zC3&Sw3NMpymdhdc!WX^}Z+rXOAf<$iqF$C0l>rytefK at M^Nu@^C{+wRmoQ6dj(Un#
zrpYC5skrR`+<kdvOCPu at Nid|8SX&#XCKj->J(PBKCj7ty58#FyZor8Xk3&kCI at fU}
zFV7r|ECb8@*nNwhFI18!oO$LmaP`$!7aqbx`nc6&7j4^`LH+FbZaSS}I-NR8 at +N6b
zDTSMEx(PSmd~+pz8F33;4opMV_P at F<hwPYY2(15kj9o7mUwkoM@{*TeJRTK3bG9@|
zah!0D)t!3>8x9Wd(|pCS`j;f(N;V at Qs4?(4R7_wO!)j{Fg<;jRLf5~u8A}r?Lw<o!
ziLdN|XuDuT(5|QRrrYM6PMQ*`n%2DtevTrMWl&K?kYZYyCZH=j+Z4 at P!s5N^O<WBa
z%^`p);SMYsK@#Ty6Qna0pA*(b8nDfcSTA{k*u0NQDTwUSq-o=`8jgNk9C2r$qANK4
z&3*K7^qmKTs at pa5LnLQ9`GL~pKGO-2+?*3kWxg4uErsm(2LifqES&~AUmE~dG;%$8
zgPt(Jg-N*0t6h%5CY7X%*@Qr=Yy<48GgQqSI76F5(vORcv1&Z8?jxf%yTrt=&%f at k
zrZcM<On-~<$UF<MQBo$4+duBNDdx$sLLhMtbJCd;)71&U29Dadk5<Vo9dOe_#9B7h
zQJ(|dp))jdvXu&~=bV}}mE~9O`ap=+GvnCOg=|7;Y`UtRmk2q}?_KRAL-gNA#P(Sq
zTRT)RsbN7UdYe7Z#$U{bW`;nsSVm^$I!4_-S&yW!6$EBNbBe6HwS^u!iG(k=9#Z}3
zQ~$g%#JjTO4%NqbjLipLxjq+l)kBv?LogHDx!-Hp@;2kvpUvi@>=#Tg+fJULCpc97
z%h=DpebQqW>$i5MP3oimg}`19G5<PY_f^~VxL6aWduW>J1GTf;C9hE5+Ss$CZqRMg
zE$6|l7hT5?_4f~VG1sf#f-SO-%R~oFr+OZ}QMb|V##CR+EN#uplvBXVq!17#BBPTR
z^@>>ywgGjlrJPZ5&Ewwn#?2*kW*#SVNTS!7RvgEWQVwp~STU>i5=BvQ!0JKvHuT#>
zuQZv&JQ_t<l~vg-jA~W(1|2j>zg<Pfag2NKy$2uv_{Z_^!;fectWw_OMPvYeRfy!F
zF(L$Ve=DUD95{Fo&%59PtgWqOP;vRD_wPp>Pw|E~zG1G+BX8^7?|u)Sdg^HqL?`UD
z%d9D-%DI`zS2z4PRg&QNvyVeWD<PoHpmIF@%P+qiS6y`##^bSbJu->}9(w3u{QH0Z
zm-zO#zm4+Na5c#pm8Z}$NtRCyUD)G8G0hYYn*`O-OuWlePd<ga at 4d^)9l*!^qwTxT
zf9?zT?suQaUu>Pz;c at cA`i70hBhV^2PnD4?1tI|{CC1}*eBbwdKSm=vKBLo-)USHu
zI4;jB74557y|!~ZMMuyw<``lne6GxGuX~du!DJHmu3ztCk}&?!Kl~B==|}%vWh43o
zKkJtPcCmzcPDPQ;X)^aY4OM?V9+DGA9P>);tsVT#D#iOvQWhf|98W8WR9B^qI8oq^
zGgFp;f(_Sr?ohr2GA4i+s{Xu=IF51ERj*!<nk`Z+_Y4L`m{6aHKpH}&^_UfBP}rTj
z!LR--^_nh)r$Bp at VwSC#RYg}1rIX0EWm%Ov^GY{Ydt~L%^G5EkD-8uQw|fz=vo*mr
zuemyieZp0m$Qe~9UONvwSKMdZnrV!SG!)jcxBG@!5o_6bNYC5R37ylJgu?!W--m)M
z0j%OIynsp&eKMaUu4p`Dn@*ZNW6LSUger2<P%2%0?@L~c3om at 0GwMQ<qo%FrbE#%3
z5R!s{GDIs(wAY+Ez3;ven=q?L&}uKuOjBuA0g_VkC3i#*X at 0nx^eSC)Imsph_dxh1
zSH|NzirR-KPo2d7_RoLS=wWV)*5D$A>2-)2qC%U|eb6~Yk2!5R6qr|gXNK`;*^mgC
z4LI9N%08gJQ6(%0XczFTw)~I2U8hES3l;X3G`$yvothR#)c3HaI=*&BC`u(b at 4WM7
zU_jak$8;LDg$bGJ+S!?4XJ;q48l7Xh=XS>~+8_^2ky;EhDY8jRvI$Fi^`&KM`G!39
zluP}vreX3v1Z7UtIi#$VG6nQQvI{tOH#SorNgyvtQi71B%u59wM;m-kong4g{$=_8
zG+&4`vLVro#{Jj9wO{Xg_q%ZN<kKJ$MPd&hMy!|VG{HB%@eSN?!wr~BCYeuRej{3{
zpG0;Cf;l5`^?5}CXEUO^3%&a0f#f#Y at z_(g^|yT^MC$EcLRtBr!jhSB^ypE%`qi(-
z@#DvfN^>W#uG6*8;QKO{dTQ|SOpxnYnvBUPLZBa1e5|xnD2`)Xa>*rl*Sp?@!-o$A
z9d8qERGSoKlc++^BHr{|DTQ~v`=^5+V2NUU>XV<sq0<gwYimn$wV3rG%^6KDiKU0O
zvZBc@=F-%b3yt{FR at --NbwrUU=78BA_pIx^Ts=+_E|S|wDRIFC7i5{B6r#v6o^Udm
zauf+D#gKC4ox6-hsZ;_UjUvRcDo%74{PPe}pe;PeyfDJ_HYSs45j$AMtCf(_t|1_+
zGCWPEG+bJQXBq$OAt-YWm@};sbJ=XCa3QKt at 42)&M4dx!zGf+<Diuf>X%YbMIe at sn
zB|U7Zn43J1zb@?!FZC~$UR_KbLylFS^K>ml%^A6>ve?c+0pM3whC+<?6=_}H_f at Bw
zMAW`l%58W|LnBz$+b&H^)eOliW at WaciNdXbi}`c4vDv(9%iOx`RBaa-J`BZ`CVls`
z4bo`!H&vtI@<6V5ht#46W*8PV<n_|wWro-sp&(`3uH5 at FL6=0KeVAlh9VWX=YB;79
z)0&~5s_oB*E^IRbb!{x0wtb)Z(-RpPeTe!^ZPhW{^0i{NXZFR~D5bb5A6(u*-wnAc
z{UrwzQJGRD4c!-8RbYtrO*Sm0)Kab4GVGfn7@`l&*0bca8S6VGEE_dzb($}O^k7aR
zG0(MWlZ1!vkA8^O+pQ-#FeO!)$NczY%^s>BO~L5(XG2^_G$DZKc>7)7ndWYFb+SvO
zESKLG(U(Q_XOZo$ioG;k*W!HFQZTd81(p}#>duzGEn9z9TJu6BP?z7amrWdOzlR6e
z-`s4r2$df)HM(c1W(yBqp^0NO(1tWI$t)&o=C?&HcthL0`nXG>N9KJq>C#^P)SfZs
z)?;*bLB0YndacFfR|14gnX&_SwP|mpHt|_QyU#QcC(Mabh=f=vh(i~}U@<K8$j}Dw
zd9-blzO2dUUY_Oxtbj&S$x3@%g2PWglpH0j>2!+i?QPtD|ARPn>ZF#XRSkM-_+ACi
z(;gDCk4h<A^!(>z^T6gp)uf>%hORmDi959ENB->8sV!`6Z-J9M<RtaUA|gyCQ#|>^
z<9Pb%rz-~eGz at Kba<XMj)T;L@$&`vXPB0otoN>l8aQ4|}LWsyYE>|)GU;EnE at qrI~
z0Du4Ye-9~ThU>mE%7kJXlgR|Hz4o>Ew}0?&=SnPn99!!*U9Ku28B`EgRnJv at Jb3T`
z4jw#Ud{4><fB((D$9?zR2O@#5f9>n|@|VAi6DLlr2zEfNRb at AmYin!xsh|2OTz~!h
zu(r02C=y1xXaw-f2~$dm0|yRhdBjAe$!hYEFqlYH^_mRtndNx<pip~VK=<dVe^))t
zR3&OZpRYX2%{k|sgQLfeVr at J|k|<nv-E~-BTOZsORA(-}QUAUwp$V>LNSBAEc1(YN
z#+lE++ur{6%J*OT;+OCXzwnE=^Nu^c=*h?H-G8j+w!=u!+?vGKWo-GJ3n>uCagj(R
z)!+zHMl-G|T at s^=WK_iY<Pa)R6d_48m^z|H_jz|_MYH%!IUF8QBN74wCaCXPJ#GBG
zT7P>f<0$pEb3!SA$RKJwkT9K2vA({J*Z<&~@XmMsC|>xY7h+>$W1- at B-+El7E7QC4
zGDMq*zs-;B%71Vre)*Sw5kGz1dvNO1sgA>~PETAw|F)$wvZq%!TAmFM_NbFIR7x)Q
z>TKIKW77^M%JJ`0As|T-NGTooMT1I+%yBFYc%~|IsrR)XDM1H4D=#0 at s|{+Jn>NzX
zfF0Y(i<$s8jaBM at p$4XzLmyS=lQ5Y~aP~9L#=G8q9e((K_(wQ!;DFUep2r6EO$**f
z6<n4K)3$SS^)*-Hs;jQTfBsMZr4{m|POmxaG!=h0T&iUBO1;=sRzElI6`TFgRA*6N
zmS_cy?5cZgW$QVdXlhiCGc2+Y61L27l?(1nBFg}xnukuVQ-YHHa`RMp*J;a4E$b(k
zP8UNR+2J&u#<<{u=iyiW*I&k~UiJNmWHh4|&3oh4)iYb>*_ETvMylEk%&Muc at A!vr
z!^i%^e?%mr4vD0sg(}U|ko|n=wd>=c_1E2OTK1_!+pGZ at 5(ET9YHrDMB6uQ6OB8t(
z2qYo^0&$`sOfbOQPp)MHFY~E0pAznnv2xT+|31#vk+-cB<Gl0E#jpMIU&TN8zANXh
z0{N(gZ8vpYYE;*z-%ZS_US9gLmqH~9JnBAs>-3~c=SD}?AP13ouh{K}hVK;5^wG5U
zxufm0kEHFJ)XgN%KN*n(u}G!52HBv?CYLFc3Q8#`l at yrR-~^#PhMMc69`)ILPlNO^
z|7Bz20N(pE?=G0tZrZG&B%?NCyN|tVQOtcbk~nZ^Q-f26B`uH at tx<p-)PFy;*J-Z9
zr|nWwPgI(uIZ<)ySxTBvO0c$j%3OgJ0>u?$qGCv~LLY5BLuye0SN*`N at sIz<AK7)x
zO1D$_G7wkw(ZnEaCBq>Z9y8<M!Grjn-~BE8>_2-ywzjrbD5Zh+O?ru^DzH_>UUGFD
zWlnI~X$Nu9MHk}W!9$Qy1QG&Jey#<}>d4k-!i5kJQG`fD7>`FdaPS~D*4H8B2=96C
zyLJt;>Ov9lG0fY7-L*N54&g}ZYs-4$o8Ev^r%vLJ{_u~p>^s`#GAej0_xaiRO#hqb
zh+qa-Dag?X&wS=tMgB(DC8V9n(>$Ff_|Ah5VP|Jrfbxr()(MTth$?y5s7QmWUuRYq
zmJM|+ksy^b=xjJbM2KY0u*Nue at F3RL*P*+FgpUMhMr8D1QbS$<=ujoLemWrzxk`In
zBdwk)a*`yt<M!K;#7T#|?ZU1M`^UH+LhcdU`d$0jwmw2*Sm_Mq at q|Z?9KkcrJQI-+
z&Y@})CtFM;AV?r(Q=-}GW}CpR?|UxaaiFyfXa^dCX@!ugbjA>(&vigH8-`_L=(kZ3
z8{1<95p*hZ!z~M=7eRJ3Ib<TjK5hH<vu)4vER*AmpjoNZw-W@`+!<|9OeG<LN>n!K
z4CYLPQ(W>^A~YxFr3|8?l(2|Pj?CZ+R=m!uZ2=- at l3^&r{MG6=B8%uMZtc*ZrUpAW
z$1<ydb;cCZ+uR53w9A#k7dpG1x-=9+W at Zpq9VWSnCKI-&NiOTCke`CNe%9)--4CA9
zS_nQ`&b=xbRMrOp0))tTLzP*z;l34FbBH9eJQP*p7F?=)Mo5mFP-sS{%895#NZQo7
zm^1amlj=l;JX1AgT)X)c<cv~?^7q&t6J}w+bp4sivM|>+W at UQUT0I0ou`1TL&p7L9
zGZ!>fI#aVolmt|Acy`hxRTp?hy2uX4%3jPQlBQ=(`+*vLsJeeMK~FcKmfG#v)HO;(
z(d<D0N|`{d8(sBFBX_eBvCY??)Zz-z at 8Z>PB#?!qQMsj{m92Eiq(Pr&O($_5^|uLo
zoJ}$Yn<Vls^T>dhXlw%Jb4Q)*m0YFMLc|?TUj~M?%r|*9DuT;Z`fhe=T-Fjwy$oHy
zFH(h%KiM*w35K{i4Y5x{^f9$zdEC&r+AVy1bW9UwIyr69Ev=Z<u!l*=I(%s+WPg0>
zUPK61$o6gQl70N?eAZO|O`6i`wB_V;5z%cqwat}y*CcgK+KO52Ey>E}dl$x6zx8aQ
zr;r+nuNrLHi=q101((z1PuC~WM3;Y{Y#K0;W;D+iQP)d7;c}bOH0AZS)=AAaF)OaV
z;!*oY>ceb^kS*gY)2g?-Yxw4Z%*|F6#)#_eU)O%?l4N>kJ#X8KRBfZm*k_Y3Hyi(<
zT{L8ubB^Xbn#MaUD5?Z0Dy1N(uQNs!;J{bHYR-IYs<VZ2i~Xe%hHy9Vt<R;+5LvT<
z%(Wmx9uX}lmaS42(f|+2!>_14e2JMIgZ6zLv4(Kqvh8OZdoz8<H5C&XbK(Myx^PgB
z+%UXkl1!nX at buHCibhjU_q_v=Jj%jp_M1xRs=9aC6hbGN=)(++b`B4qNqvk$bE0bU
z5t>mo^M5PGbTYxolP6cAu2zyHK@>?aQh%%{5*UxiSYKaHg(GISTSAo(?!Nm@{K=pE
z-?;C-2M~z}41z$iCniiOg-b5E1V8yx{}VPhH}?&r@=2!Ar7nfAWp#PG+j_b;O3;d-
zpqzu2ZRWuETcJk*PdxbqKJ%H+;;%mY*;U{)sMvo|B#Xa~Mk8Ex)m3=Yo8E}E^>wqe
zwuxayQG`byeGH%f{1<WSEw`oMWh5YIZ!oMRQF!2i2l3{&{1Be=oagKdwXkA~w77}0
zos+gOnIRahZT-3J3K0+?n)|*i@#4?K55D0CannuT!bkq~zsCCd2KI9 at mpng$$dF%>
zB*EI+8qPWA94LN+SNNw)gA~)#i8Je8O2i_lJ;NmtM2PxJ!>ho}x7>#R_TO&AbDr~@
zeWMoEnbwTW$C6ofF}$Jr?xfN(fvGg|&ihc(=lIBxBlyK%`bFGx_dWQ`XFdxlM;`lu
zy)ZJ{RP8YHVNOQVyjH1AJW1j#nW~!gi*#h at A~m$j3?+~N2n{i?McQ-y<HAS1>Te*3
ztljBkiYK3Za{meCJzWEARKi86yOn;|Zjl#-ouALu+S(W&{FM)uaemJGfr9LT)@OY*
zJ(|_xh-RNfkt|~XrG%8Sk~_ku$TT36GO;Z+xGPqOTCmMi%y(zrT*eS}yeEWz{Y5%}
zYzCPX&O85ny!0h6*}v9=nN;p}z<a(3qC-kJ%MQbw_w9R*pO5#v_ucr7fB9S3+}LbX
zBb)XE7g=Y7GirmLHHY+lO8JduFWD;XSK*XU_FsR-8oy0qRivhm<2XY#R=ws|Krsj^
z3kFU=NDv7H5&|S>_D^;l={8st8KoQR)c)jPU;Rvd)lKyL=U;@2FL}YBYRod1Hr24p
ziLWb>MSfzM4Ab>L`TM#bPySmyb5p(k-GUjP_w%){dkrR&X~W!^_d_{9u4`Oou@<#`
znm_B>dtLi7RpH9O=Dhzxh=N&BZI4MQK|+Ek%5p|TP>Kp6Q;=w+6Vo4=`X?zUH3gtR
z)D30tj1uT&kMchY%0?L*n;W?NidSHBb93K@=JW;b8zRr3&&}K-RX(5b9XWg$%n9n)
zOhW*KP)i*_H9~6FVo~TgDOg{k5-=EvD&0Ux_&ZHW&MJx`S)gZ at B4$|Kw-wv3cU!En
z*|M at jhYsR}FS-<~GCyf<RnmFb+S<a}`Z_oiy5O!kAyI+Uk&#4<xZJ0e>{INN>_!5>
zbebBaAAkIDNGTCT5r&{UGlnw--z at nlys^2CB#C#;$-EaNxgpisF1y<@&BdY94&m78
zNAR5ozmsO7+J^@hK}$oJT}W(CwxHU=ciQH4vOVRepMDyD_jiAXr=EH$)f1(JQpq5T
z$lRjF4N#<%c)=wvz`5t1yFzQ2gPpAFw;-EfmmqKK?CjugZu}cOe&X?c=SZ5{q6t6(
zRr&q=^Uucx7hHfSiYnlTRy;(-s*>zj5P=6`BDQevgNdm`*l*JLUMl$wQz)3{K^ZtW
z^$**pDsp9Y#4HSyuU%C#S0P?OO=23guo%k*ncIO{ha^BA=EPr>#i^W2e^aPCvo7qA
zwB4tHQ<l~CdKVOpn}nsx1cU{nq8vvW1@?vRe^E!p at 76;#0BqxY&1qFv{A#6gE{bQ&
zS;Dj3r_9Q6Kilv1`mXM)*2`*ghWb3`IR>k(=5P^B&sw=eyNESE0$MSxT`gU;{kC+>
ziWb*)We>OJJaFC5_IsTS2aK<iacdewYB at 2e$5<9B at vNBDs_Y|LBTGq-<}mgqhh^78
z$NB1FSx&Vsc;wxr>U8zLH<DznjW(NtZz_2k9B`L!T-x;Qvv1!*)2=UFxYQj2>wVty
z&@=}!MCEOv8$-sF*=8MHW}A$SSX_tYbscZLjr!cxPrN!@ux$`^69jgbN>|5FuZQ5Y
z*{<|H+vLwP&9h4qg&}Cyc5JrvGz7zG>vJF4x1kw*ePq*yXcE~>#NDVbcId4kOYYyY
z+in1xn9wpxetXRh)`rI(%D-zKLEs^^qNal^q=r=wc=kmAVP=Rr*X$=!mKYN{w@;z3
z?V)yka-l7I%J>y?Sw7}f{}Y-q?$$MG%gW<lXS1s3<%bnzp#4K^`bwr{M~)xLmbR#q
zuCDeCMN~s4kqDhSYMu;uQH;VScb_e7+jz-0rL+r?S20AA>L`k!RGNT7scN>JwyV^p
z`I2!Q<HH~RH~7*Qzl_m%4Uz4&LaUTjHn_Gvu3+>OPMoci=1LvSU5G at 4AA9GI;j&j;
zwonzMZ2?>fxhsF9%jOLY-sfvSu}xzYifJuU8t+;=Aq4KY<4)Xm+X4I-1Ltiew9Xuz
zxj1ulz3Z;KaND=P){=2x000=yNkl<Zow___j^)1nP at E>|U?^OA>81FgANnC2I&`Q2
zTWDGi(_WEDlHlf>Z^b7+`Dv`Jt!G^}K+6z3^RfAFD!+}A0+~fogtN{*8<)M}vbjrH
zwuxt5)Zd|`v`~gx-~NTVA@#{z9x|_AsI~a)XFrQy|KI;bwjT+C)ZF_snM|;=vlFz=
zIG*Cs*SrR=fBoxm`0!y3ugiYjWGbqq*vnE%Ey>}m*y58wvMQdo%2fgCpUq(XsZV|y
zKk<`4j<e1>YoYd%P~V5dv>LL{%QVL}nDwC#G at IK}Q`_6yJ2-LT32bgov-npP{D3D*
z_$V{NO1pqk?)MaLFVlJOl`nr4x88ai&N}N%_;}XJ(P#uho<KFT#5Xdm3}=wsqt0`2
zuv at PSQ-1-E494lFpMkT^I?Ib7`=}Db+5?CEb~naby0}wxsU7p^V|&{f+%RXEky{RW
zpD>#I63ouPLr&HqD(Y9&eU0?DXPkKkjvP7SJ=YRouu8xxNmao at 5F(RK2tU7A+aPIo
ztvi>_ib=?lXh<pXp7*}17a=aI+rg^r-BO0f*yKU*p-Y!N>{ov!+$Yz565!~Oqd0Wv
zphrInh6R8aLNJID<e76q4S*d_0rw%$>{SM(6L#*i&czj1Ty9hYhL$#VZNRQaKYhmP
zoJ!tMzim4<4!X;*PRt6-2?z>808qlXDf0Mc=ly68vf>@KqZ@(J<T8XKM~`4_ZOw_7
z=xZTU4vtDrx2|Bx0pzM){JhEDmZ%s%_=eYG^T4K;Y8Qgp%-e&y4|57(^9pqf>FSMc
zo1MDrz3_Sb{5MUi?PUH+wA=G5r2iF?Af;~8a;Gf`Fp?yJVpVjoZ%QD2cDA>7Fb|B4
zy6QHa#yE7^L2qK*mFNJ0m{wo)*|iSa at 7msTad<XGbS#VdpJ${goVt5vl5$~0VcMzZ
zSIE;+z&UYhechxG0+(ER366c{D4u-sNkoy%n)HQqExG4(GQrPW|Gv!ejRxZ4%_T_^
zTz1*ZmrkwP>mY*5mUz`ix?FVoNfKjwdmE$C2vVlWNFB7eHp@~foMai8+ZenM0+EO`
z^x>{sezVp?8l!580C3q4l8EsAulj!6apxVl_uhL`uXiF)Plm;uCb#&x_x~KElnZAX
zi?C1Z7AdXCD|#Mt<Pu!X%rhR}x^1e>8 at wsFI<yVXw9YmG&h=;S`<eIQ at +&UK```b5
zJn_U6ne(V<Nxav!A5$hV9*^;>ANp0i?%LONe)aK>e;j}C2Y-;dI^`+lSy&1e)!_AM
zyo2$043(sgqvP?|Nt&$$#qaFw at OV5Pj3||g3+XD&F1;#ywb&pgtcssx9=d*08%il8
zNm8VhAEG2l;vK_DN-5Sw#3+h-hI^<=$5L(!0Aj_k_5s6cliF5gc^G1ww|{={D5VOf
z<qK(~w<m<ictRN;>B<zP-oX%<H at Z<x2!TW;nPcjTP+U*f-3XbpSEQIwbH9i+v}v==
z<K734%OuF;-{zMHI)m~G&W_`F#*$Xa01bO|g&ZHgOqZd*129u?#<f?B*iG;|b>E?7
z9_wzrU<i%-)KvH4e7Vel_Vqs1Rr$IUrZX>BWRN;QW4#_{c$vCnWfJQ;ubZjnkXG{m
zO?^B2q4L)!VlSy3CP2UX8Z0Xl*sX3LI!)y&i!BoDGBe!za~B4of2T`GJ_lD@;J(is
z%Mh at qjo(uJo$^OtuV~#)vh;~GJ5KL9V`@5yd{1oCT()_9y9NRGrI`>Ch|PFhXjr$w
z?H0+suCCRk7*}|pCc9JLIMlju(Z}acHVsraw%KxX*OS-PE7~NUF1wo4C8 at eVtJq4r
zT^{6pyvBVugVBr-ppLfj*o>uqSai8bgp`8%7QLVKwQrJke5E8?+A!^L(|4}(BW<9O
zLo%y2an*&emRapEohV%d)U^R^)}c<YZR^p-0Bt?TL*SQ%uEWO*zDeR;#!NF^>z?<y
ze#2MCRd-e0U7(+a#J`iXr$3jDVionS!IIwEld$T;qMRH1GHREA+mQC35Od?gB>NJg
z>ELvc5M29PSARl>=ggZn>lufdV3WI~9sM04#4MvD`+Yye{K+IqAOs<bY<;B2>9r(D
zin^OJ at AO&t-C$#Ax_udn0r}W%hG2RjzY77d*Lu(uXauPgl7^%3u47j9Hk+7Ln^{87
z{GP-Khy*Bd;S00uq0O7$=F+Tb%_RUl at W6xk*0*lO(@#AOqSSFzQ0$??5g4OPN at MIy
zw(<72ztw6&=cT4CnrZo{9!)ByO`bm=#t?Gz`T9B8NL#jZXHpN-&|J!39tlDao<4aJ
z58Qu0E`0t)OD)0oq5USNRs4qZHa`*(zIoG4xaH<su(r0Q8TRc^T&lN>3547LD~3`r
z&N=rSTzcun*xcM`onNCGpCk!?=}TY6&-~2wxbNQk5k(S$!pU|jQCdy&4>Ub?>==Ig
zcYX_3Uvu at s39!!eUF`xkeK*-ETwFkGleTu{`17%iw834s8NzM7?29 at nMLkJ9Z3rO3
z6Hh!2DJ2dZJh*TsbNu*opb}&*1u(!U(7=0YnEF5Y=}+Rh&wWm-yM&3hWRfHx03$iZ
zXtb7IW41CEc7mYD`!nxE6nPz6+dH`N#=phY*Id1L*pMFhShi|Ws4>n1;LxUyA^Op%
zrT{pcLH90&WW_mLID-|VDR)ke%g!Dsy*5zf{pu&^c5l{@iof`UFXDm=p6j(vqCDvV
zr5MN%-ObFTISFOkA2{Gb*TVy>>Ze-$*{MlH*gCa^uYdg;m`o;1C#Kg8rEPy)RYy}D
zKJ#z#3$y97Pk&wd(XY=Lnl at 4D)Xd9c8%_6Ox*tub?gb37^M15-0_{^j)g(1h at PhyJ
zAOCZwf0wClncoPqzLD50VG#%(AjVm}Z25NI`b+D?p+l$Pnrp5uAT5?r$_gbx43(hP
z*NeSRe_Y!1>vNv;1gT!g0RX3h7ExwQ&r<K1#31t7FG|@Go at f1fBAbknW&eEZ+urJ=
zHB?kWZF)dRASjy}HXGL65>e>yTBf`AOmxwdu=Via!}x)#uUeXubEq7HtKzP5l^V;k
zF)M(O+I~fGn at Q&F<!zs`+`itlUfqu=uDifhKk#brIwdl0s5k+Tr;|1h$Tg`%F3!4s
z<Ek at P6H%l_RUrhfy6RPU_Op*K4<YWNfaX12s0X>t<zP!PqcnlJ9kJK-cppA7Olg*>
z&+&QZKdZoW_o026Bnd!(l&L#Ik|deam^9lAtT$)LWqBS1n1kDAYHkz}UU9`MmT#{t
zxu^cBEWSihRA5u3bRvQs?+Zx`lSx@;o_$8)km{up<}b%_j5v-l8jS#?xY8lY>8GDw
zGA;@^Aq~@`$)E%vk`m*QTv7k3>^_Y(qh%o?&6d^wpi~tXl6F<jznxs`Y1-i24_-zH
zfrAGR;-xQrDUKdJiqU9<NJ<d<PEU#H9>+1Rzy5keQFilaGMWx0$q2%Q7hbfq1UV#t
zoU7M(U*v;j%S*Uas&*YC&Z1jC{jTfq=}&(Kx7>2Gmc+$JHsWkgrdF}z&psd5UVAOp
z*Vh{vQ$BAuf9qTL+Sk9HwVf-G)X`2e)6G9qD#3*pURa<S+X4etB4no1Devs;;E5-m
zz+^HhuMpW*$!FuglO)0M=RAAqnZu$_(Jr+yRQ)!A*Imzi+jE%%Tkq!(eVzxiVge{v
zF=zmLkw)XW3aPtrw86VH)x*qq;)y5l)KgDYz&r_}<hwJT1k at tJB*mJnt*znMv11sG
zM$QKokRgsX0>ZPU7}Oy?vQnVJd$b>b-(D2^+YlQ<*I$PsF?qAwdb-aLrU#~bo2R==
z{fonsuZd4gv;XAWysBFDD9z2%-smf;kT^Qrd5+l7#IS69<T~RBt&Q2U>*xv(mG`*<
zFQYHI(2V6&_+s$PBzFy7RE&iyW at VD5Y~uxe>mO2*YZ}YEz6)K4`=Oxwpi?1DapvPi
zT=y2|jy>%VB%j-cHE_$ELFLG)u5^*_XT6SsHbI%Bn59as*wvbEG8q6xT#*3#Tslcp
zS|-k;*z*H~xX6n}TJR20`xR+%{!sNW+6^h(hg1QZAZWT$WSM-p+HjqQ?)yAdW>a25
z*SU6O-mQV!;386lNDraml2LJLPc_-0ICE&{tiH_s-YU?T2o>9KX{;B$?4~9ZVJ at 7i
zNK<jy$czb;h8793I#{|;No8Z_G?%8_L6tR8w|HiuaZ{719C!oxNF(#eief?xZDK54
z;&Bt2WYgSrJ@=7V7Qw7+=)?xi))uSFW)qn?M!6@{%wdAsrl!U!Sd-YYXc%XWwCiG`
zi!Q8iwDNeSN*~QZ(u`{Rx{7KGFsb)hHZCsNN<g-=N(~tA;qak+RDqD{mM{FPEwie(
z<1$v8&Fc#B;UX0c{avU!`dl>B)p)PNLT|tBbZKcHY70m51s|9dX4ue2vlOf2i}}#7
z{;h1wPd0=^GNi4<7AAM7adh2ynNF{ez<Z0Rr|-Nj16qUYx-}iVzI$d__FD+ok)ds`
z(g&K>H511W6WGRxnn3dE%ptT&*p{iL?W7BlrN(wlA+zR$*mO2yvU$JHxV`N;mW<1`
zO`l{DLka_3lBccq;7doQ at 1?6cGcRUklA=Q8zYDDrc5Ngt`-r0yVtXqTN_FVFE<>U<
z*o>_!vryl8 at IjSbrV@&Ax~SV-b0GCRe@*GB>m1M5iEtjLL0^d=bRR;vE3AT}hb<LX
zo<OO+=1IrPR@$_T`fa$+xFrBgCKH@|`lN=1MPR7 at lUau!3h|w9om$!0*ucR<2N$w{
zu5;OyV{lcLOPZ*cBuVhp6Hg&-h|SfTbh#C*_?J`Ln0)BfcmAq-RCkF=;uHl2l)8Fs
zZf;<6b2Cl&k-37{Gc3jU);Dj$Z~o?Q<M!L{L?j{r1QIGZ5%@@Fp^fKBoZzi*e=Gjk
z&tAW)q?bjy7VPCRR5ISY&O7e71Hb%>{|oNF|NezaaEqYVTuX~+3=l)H!e}J%wzs_n
zKlaXd;=q9e&ftI&MA+Hc!CiOWg>QfR+mKQMOkl)8h{5L+^No44J at M|i<Bnaq at mIiq
zyGIqv>%H&3`|!mteG&0AZuRi?O;Xy|HX2IWG_ at y$fJz9=3M7E>c!b9u`);uprEo)2
zk$L8d@!A+tN{mP23<{?IX|R+MR+1n|lBKo}&GV*i$UcT_yU(?H*X`&~MJa`Q?!E`x
zTiZBr;6M<m*=0`+1;y>s77;;463hw-Cx{}MqBX$YW~i^5R7xR9RFPbw3^Q2V={02R
z8xi5*haO&P2`gkg-jEW+P*>Z1#@6;;TXKpa)U}<R9o%#GJx1`op>Mb6N#AX4#c>QN
zBSa)1L>6P22}*f>NZYl~<gqm1NeGdK7H}RT6>cED?hv6>LL$PQcixGI9(ovOopt7(
zvs=yE)-{Am5 at Kv^w@@Y|iqL&Nb!rRW_`AP at l#!KFap*neE2W2JS|zLwD=iaG{teu2
z%te`|n~@}Ok+wb!e$Ik0LC&eSnux*mn{q%@{I5PiR)1=BoH%g;fAQykJ{Ps1FH!hF
zrF4bbn52w8hk$AQ+UB4Om&tZ)A$;6I+6VKo-T2iT at rBQS0i)5Vo6bY;DNqr3?J_Li
zeQum<&fwQUP%0_#+-+#BF_9{W(nxAjNK}jw$u#yyY556>7Ll~M95L%Lp8of)#Sj$X
zFaGQ=arHIV;Q7zLXzr at vJdNi~Qi+e+)Ylg2A|<#okWlj(k`9t2!Ta8OJ;tLo5TeEG
zAD!kG2<@bhKqX14{s{t!G`^5o0W6%>LoyhNN}yPQA{5zk2;*X$Tp9SB?Kv95WM2tD
zXS$R|)Zcd7?f8YC{{Y^1{d;iv6_;aueSM)SU+4|w5)B_(YUyGiE*B}bYT&ZK73Buv
zM<00<4?OT7jvhHOgWxdleUsDt!V1NOV^*SKBq~i|MjD!_Eu9s3SV}2OC(}%nWJDBU
zfnwD>4j+8wh8u9pb+_V!zw*oY at 89~C)TLvA#f19lx&cE;Z!X!Q=fNa=P%7pfRgi!G
zhky7-7>~zDRD%6p@`N_|<;HY6?OadOTF}nU4o|03JoeaQh~v0OAuS-5hOtx$qJKSl
z9Z8~a^w<%ccKEcp8L7KcsoPx5`#{3DTxN9PCN<UJ5 at g(^61qyDzT at _Rf^H?Utd2(?
zehjBhox&n7qP;xnhv)~D^rV!+=H at 2OIOB}YId7s#nog%&UoZwELNv&U?JB~%yjR^Y
zqFAIZR}E$cMO2E>b6{E~oNZJ5p$)?df!5H(ux#5h#h>~}KrVh>zT at s3r&EG+E)sFF
zGWWqJF-KpUVcl(G-nWYiYGxjC!N?Y|qri062T~YbK|r2;BcQ0ytV*QhnGK_6Xv6Kj
zdZfK7jrG(HH%mlmegIMG{Md#0GD4s=gla2PUwy~p@?Ik>QI=Z0$R5?&gvP842O|~G
z!W}nbmNakkU8QZd-_JJf*|uH0kd>TK<w={{5?wSJ-Hi@&l;<MLuDgl6_iv6>U9!X4
zsxoK)th+SKwmqBPt*jUItUpxN(J46<P}Lcc4#cd6j9c4p$POU^C-oFr<rc{NhgzH)
zi*^eC#THt#I0T#M)eef>j?O#ZGwj7abqa&ytdFy<G=lY07~4_73ufk=?H7^iwdMSU
z8^m%$okdoS_KwoPVwFiXaTT*|-4#MHhIxMHDy6mEh}!l+XMSlm7%J$?7P`7fW7kA$
zt`d72E!%w8)pm$J!fuZ>t&OkWpEM^kD5Z{2hc?fo(9tJ|jFL8H`Bm|p3v6j^vMP1f
zp4qA at 1FD2w?gcJ>QbWbY^@&iJho70RYeXBv>4Se>Bxo?vS{t1=iTV{<w&{;;+adbs
z&~}3$;7c1s1ZmNYu!IKtNpZ{5NLH<SbaXDZr;vU`p=0>EPD|H5^c`!P?~cu8Xv+%I
zWEgjYdZwVeWSH-UAnvfi+opAtD{Q6t+nh|Q$TIZDw(W}g)YI2#$T8JJSxkLy$_?qe
zsaB<Z?QNv@`dSpXg!)VMbl>$w4t-kNN*+GRFMTJ}Hf{PMn3YK?Xj-><s$=s~Ielox
z#l6B-C2UIVwJLT}Ra1f(7jzb>e_*oOFLFVa1tMceRnW!&Id3d|A3IJTB#n9JCG_>q
zuS=OLX63#v^(<CR at 3m&liQ^cP$rQ}0H1yYQ=4_UQoh(mb^ky2WZ3ZG4VPj)saAwvw
z&DWv;`kI(j=sb%<)KTxFi?o#c4{dF2SC9vmu~ZD*a}Kl9+fJ0q{+%Aq<M9}4>uWQH
zc$+np0C4~P_v164`71o~$fFRHV)sOXs*K1J!gZdUJG6Q at UR%RY{KP*UEMbL9PQtd|
zhVbk1wME&kM~L`CS5NmgTZ)ael)rb^U3cT-|K$@nb?Vfvk!<F=FKhflDIkgj6e|b<
zF1zeyxbn&?F<x6UW`sA<m?R=R{P4s0=tutyw}1O~jK}LxN<r*%Ntc<iy}gasz5cbh
z_~I8VjSAZ3*05XD=a5pBkJr3y2vJk{!sow$4}bXoEP{AfrM;+x5y=Qi5 at T&`geVfY
z{E91_?N>ksk*rh-F|)HXfl>^mxb$9iICU4Xd4 at y^ICbh2{`#-}UtE0g3s%O}Jyd-C
zt%wNs+;cDf!(V<3Cr+Gb4J+Bt5>~zKNJvbRDOf2aNsO(nQyF at wfP!*M^Ofu5DoIk@
z9HmkXG&5wmo<j55*iHQk-S)=D27co=eiK*!z^n0sOI|Sdh4vYD2(*TfeeJ4$-e?Uz
zw35HOv$KPb{^>{Ym9N}@@p!zn2bizqI858wEw*APC`6GcpLujoupT><g(RQ{&h at +|
zDOAe(*2xh9JKNj%;UE4HeCE at i#lsIjjLBp&mqoAtafRV%`eSM*R9~B1VQkv4>7(sf
zY}>W99hS^$f<OD{pW}Ca`(G81$IC83E=SuLEo9-jL|Fi|XZ^C#V74lyI2%Ry?sre%
zpZ=2{$7Qd0IbQk7EAXuIo`p*<xdfNK at Y2B~%4P9%pI0B+{Lx%<@!3kLw$LWu{q70;
zn~(fo`0d~Noq{G-Widr+fHGAnZ5P6;3{`Ufw6A>m27KkqH-MRO#TA$1-~GuSVSQsg
z2-E6Qhwrzc-3ffutf5pA+xK!LhB_icUdN4J{TuxL?|&Gd{KO|AgxFWvn**&#0j<MD
zETjKgN`N3xhD8>zJ+$Iib>h__l)w7b8}Ylp`>*hG at Bi5#&@QeX?|lraA;M!^lakIG
zbG?g^7MC>|=#f$iA`(cF1fTuPXYuj>=M%W$hOgrO`|nSaf37ZFJlK`C7R0^j+8F%2
zTAKDvAcVm0|K9(B(P)JCzVAIjBrKa7&k$}6^9Jx+bb^S+_VUPnE>G)+A9 at 5I_`nD7
xxzBwLL;}-kT!cNXn3d<;=WMG3Nx_z`|9`P9iN1+Q495Tf002ovPDHLkV1mv;aWMb@

literal 0
HcmV?d00001

diff --git a/modules/opacwebaloes/pages.py b/modules/opacwebaloes/pages.py
new file mode 100644
index 0000000..435cf7b
--- /dev/null
+++ b/modules/opacwebaloes/pages.py
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2010-2012  Jeremy Monnet
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+from datetime import date
+from weboob.capabilities.library import Book
+from weboob.tools.browser import BasePage, BrowserUnavailable
+from weboob.tools.mech import ClientForm
+
+class SkipPage(BasePage):
+    pass
+
+class HomePage(BasePage):
+    pass
+
+class RentedPage(BasePage):
+    # TODO, table limited to 20 items, need to use pagination
+    def get_list(self):
+        l = []
+	for tr in self.document.getroot().xpath('//tr[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl07_COMPTE_PRET_1_1_GrillePrets_ctl00__")]'):
+            book = Book(tr[1].text, name=tr[4].text, author=tr[5].text, date=tr[6].text, late="N")
+            l.append(book)
+        for tr in self.document.getroot().xpath('//tr[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl08_COMPTE_RETARD_0_1_GrilleRetards_ctl00__")]'):
+            book = Book(tr[0].text, name=tr[3].text, author=tr[4].text, date=tr[5].text, late="Y")
+            l.append(book)
+        return l
+
+      
+
+class HistoryPage(BasePage):
+    pass
+
+class BookedPage(BasePage):
+    # TODO, table limited to 20 items, need to use pagination
+    def get_list(self):
+        l = []
+	for tr in self.document.getroot().xpath('//tr[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl09_COMPTE_INFOS_0_GrilleInfos_ctl00__0")]'):
+            username=tr[1].text+"_"+tr[0].text
+	for tr in self.document.getroot().xpath('//tr[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl10_COMPTE_RESA_1_1_GrilleResas_ctl00__")]'):
+            # if all the books booked are available, there are only 7 columns.
+            # if (at least ?) one book is still not available, yous can cancel, and the first column does contain the checkbox. So 8 columns.
+            if (len(tr) == 7):
+                book = Book(username+str(len(l)), name=tr[2].text, author=tr[3].text, date=tr[5].text, late="N")
+            if (len(tr) == 8):
+                book = Book(username+str(len(l)), name=tr[3].text, author=tr[4].text, date=tr[6].text, late="N")
+            l.append(book)
+        return l
+
+class LoginPage(BasePage):
+    def login(self, login, passwd):
+        self.browser.select_form(
+            predicate=lambda x: x.attrs.get('id','')=='aspnetForm')
+        self.browser.form.set_all_readonly(False)
+        self.browser['ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$TextSaisie'] = login
+        self.browser['ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$TextPass'] = passwd
+        self.browser['ctl00_ScriptManager1_TSM']="%3B%3BSystem.Web.Extensions%2C%20Version%3D1.0.61025.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3D31bf3856ad364e35%3Afr-FR%3A1f0f78f9-0731-4ae9-b308-56936732ccb8%3Aea597d4b%3Ab25378d2%3BTelerik.Web.UI%2C%20Version%3D2009.3.1314.20%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3D121fae78165ba3d4%3Afr-FR%3Aec1048f9-7413-49ac-913a-b3b534cde186%3A16e4e7cd%3Aed16cbdc%3Af7645509%3A24ee1bba%3A19620875%3A874f8ea2%3A33108d14%3Abd8f85e4"
+        self.browser.controls.append(ClientForm.TextControl('text', 'RadAJAXControlID', {'value': ''}))
+        self.browser['RadAJAXControlID']="ctl00_ContentPlaceHolder1_ctl00_ctl04_ctl00_RadAjaxPanelConnexion"
+        self.browser.controls.append(ClientForm.TextControl('text', 'ctl00$ScriptManager1', {'value': ''}))
+        self.browser['ctl00$ScriptManager1']="ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$RadAjaxPanelConnexionPanel|"
+        self.browser.controls.append(ClientForm.TextControl('text', '__EVENTTARGET', {'value': ''}))
+        self.browser.controls.append(ClientForm.TextControl('text', '__EVENTARGUMENT', {'value': ''}))
+        self.browser.controls.append(ClientForm.TextControl('text', 'ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$btnImgConnexion.x', {'value': ''}))
+        self.browser['ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$btnImgConnexion.x']="76"
+        self.browser.controls.append(ClientForm.TextControl('text', 'ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$btnImgConnexion.y', {'value': ''}))
+        self.browser['ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$btnImgConnexion.y']="10"
+        
+        try:
+            self.browser.submit()      
+        except BrowserUnavailable:
+            # Login is not valid
+            return False
+        return True
+
+    def is_error(self):
+        for text in self.document.find('body').itertext():
+            text=text.strip()
+            # Login seems valid, but password does not
+            needle='Echec lors de l\'authentification'
+            if text.startswith(needle.decode('utf-8')):
+                return True
+        return False
diff --git a/modules/opacwebaloes/test.py b/modules/opacwebaloes/test.py
new file mode 100644
index 0000000..d105c76
--- /dev/null
+++ b/modules/opacwebaloes/test.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2010-2011 Jeremy Monnet
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+
+from weboob.tools.test import BackendTest
+
+class AloestTest(BackendTest):
+    BACKEND = 'aloes'
+
+    def test_aloes(self):
+        pass
diff --git a/weboob/applications/library/__init__.py b/weboob/applications/library/__init__.py
new file mode 100644
index 0000000..463e89d
--- /dev/null
+++ b/weboob/applications/library/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2010-2011 Jérémy Monnet
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+
+from .library import Biboob
+
+__all__ = ['Biboob']
diff --git a/weboob/applications/library/library.py b/weboob/applications/library/library.py
new file mode 100644
index 0000000..f73fc8f
--- /dev/null
+++ b/weboob/applications/library/library.py
@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2009-2012  Jeremy Monnet
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+from weboob.capabilities.library import ICapBook, Book
+from weboob.tools.application.repl import ReplApplication
+from weboob.tools.application.formatters.iformatter import IFormatter
+
+
+__all__ = ['Biboob']
+
+class RentedListFormatter(IFormatter):
+    MANDATORY_FIELDS = ('id', 'date', 'author', 'name', 'late')
+
+    count = 0
+
+    def flush(self):
+        self.count = 0
+
+    def format_dict(self, item):
+        self.count += 1
+
+        if self.interactive:
+            backend = item['id'].split('@', 1)[1]
+            id = '#%d (%s)' % (self.count, backend)
+        else:
+            id = item['id']
+	
+        return u'%s %s %s %s %s %s %s' % (self.BOLD, id, self.NC, item['author'], item['name'], item['date'], item['late'])
+
+class Biboob(ReplApplication):
+    APPNAME = 'biboob'
+    VERSION = '0.b'
+    COPYRIGHT = 'Copyright(C) 2010-2012 Jeremy Monnet'
+    CAPS = ICapBook
+    DESCRIPTION = "Console application allowing to list your books rented or booked at the library, " \
+                  "book and search new ones, get your booking history (if available)." 
+    EXTRA_FORMATTERS = {'rented_list':   RentedListFormatter,
+                        }
+    DEFAULT_FORMATTER = 'table'
+    COMMANDS_FORMATTERS = {'ls':          'rented_list',
+                           'list':        'rented_list',
+                          }
+                          
+    COLLECTION_OBJECTS = (Book, )
+
+    def do_list(self, line):
+        """
+        list
+        
+        List books.
+        """
+        self.options.count = None
+        return self.do_ls(line)
+    
+    def do_ls(self, line):
+        """
+        list
+        
+        List books.
+        """
+        self.options.count = None
+        return super(Biboob, self).do_ls(line)
+        
+    
\ No newline at end of file
diff --git a/weboob/capabilities/library.py b/weboob/capabilities/library.py
new file mode 100644
index 0000000..7881f92
--- /dev/null
+++ b/weboob/capabilities/library.py
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2010-2012 Jeremy Monnet
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+from datetime import datetime
+
+from .collection import ICapCollection, CollectionNotFound
+from .base import CapBaseObject, NotLoaded
+
+__all__ = ['ICapBook', 'Book']
+
+class Book(CapBaseObject):
+    def __init__(self, id, name=NotLoaded, author=NotLoaded, pages=NotLoaded, url=NotLoaded, date=NotLoaded, location=NotLoaded, late=NotLoaded):
+        CapBaseObject.__init__(self, id)
+        self.add_field('name', basestring, name)
+        self.add_field('author', basestring, author)
+        self.add_field('location', basestring, location)
+        self.add_field('date', datetime, date) # which may be the due date
+        self.add_field('late', basestring, late)
+
+class ICapBook(ICapCollection):
+  
+    def iter_resources(self, objs, split_path):
+        if Book in objs:
+            if len(split_path) > 0:
+                raise CollectionNotFound(split_path)
+
+            return self.iter_books()
+
+    def iter_books(self, pattern):
+        raise NotImplementedError()
+
+    def get_book(self, _id):
+        raise NotImplementedError()
+
+    def get_booked(self, _id):
+        raise NotImplementedError()
+
+    def get_rented(self, _id):
+        raise NotImplementedError()
+
+    def search_books(self, _string):
+        raise NotImplementedError()
-- 
1.7.2.5




More information about the weboob mailing list