From a5b1332f95065d8ebf4ad372d93c342d1bad8b94 Mon Sep 17 00:00:00 2001
From: JigSaw <JigSawFr@users.noreply.github.com>
Date: Tue, 5 Apr 2016 14:52:35 +0200
Subject: [PATCH] Optimized & Fixed FADN Provider

LoginCheck, New Logo, Optimized
---
 src/Jackett/Content/logos/frenchadn.png       |  Bin 25425 -> 39306 bytes
 src/Jackett/Indexers/FrenchADN.cs             | 1951 +++++++++--------
 src/Jackett/Jackett.csproj                    |    4 +-
 .../Bespoke/ConfigurationDataFrenchADN.cs     |    9 +-
 4 files changed, 992 insertions(+), 972 deletions(-)

diff --git a/src/Jackett/Content/logos/frenchadn.png b/src/Jackett/Content/logos/frenchadn.png
index 960e0368023781a16f262792c9b75821e03266f7..4bc6b8d9d8b9307e67e0ce8a3d9f1688d712e2a7 100644
GIT binary patch
delta 22754
zcmcb3jInDolVWFppF1y?6c+;n1FxrtOArGCqaXtVLm~$o0|UdygHwM`R1{}&%A9D`
zr)s8~Y+z=tU~Z{rXlib5Vy>fLWMF8jZ(yu%Y@lmoY-M6#Wn#4PZ9fyE>Ev4GCIJ&&
z1Je*g6DuPND+3d41Eb0OEM}O3p)5%%iH7E>W~L@-y2j>7rn<={CMmi}X+{RR$;Otc
z$w`SxMn-8Sn{TtUaS)|)vLT15u$is_hW%%G{TNLrJF**0{=m*Pc@B^L=Ba$TObV73
zZkC4TCZ<MC#zsb#MsCiohOUk-mToS_X6EK*hK7?1*%c-q6bPLBkCjW)t|GTUFC{a@
z%GA=$$->yg$;HCO%+S!))XC7*+116(%*E8y#LU9gVsat7*k&QY1V&~fbK}XSLgq}C
z=9||E<?FL_nQhIVtmvdyA2!?5#WAGf)}FnU8**=l-uphg*mSq$?=Roy-TuD*;$`6~
zA%7<~j*|%o5`-TK1Su{oJoWTO-^O4*v(#08+LNcBHoLK7l9z#*;S_5PVP_|v8)6bI
z8*>yn7ruM>_5HWIFTY!+m#>~#{H%ZHwW{CmwqK7bo?HDiw)9m=_4>4Rmd9o4A4}i=
z(Z+H30*9i2Q$mkoJ*Ogr!7&kg|NTp*^zW(vWqf(Rf4$v*%m4HK*Z%sy`S{H8GcT{d
z*|_Y#-cp^vZ@&C}_T8v@Zs>Q7r7qdAbD}j{rwE<@d?70Qp8LO<f25Y3xBa{CkKB?e
z8cXkel+;vp;@EPnV&3-?=~ILH=V;g0*X91KPftH@|F>t^`t)D_fBt{gd-;v2-+x>A
z^*4WCjY{r0`2FuAyXD6Ven~#5pKo{l%l)+V)n$I?rKkU~{rUCjcjLb||IAu`-qiYj
z+Vg4Geod@2s{XtAv7PO=%jZ|UtJz#!a_@fHdDH5(pZ|rGoq73RI(foo;m3vXp~q*H
z7hV<*Hs#PeUcX-YLuGSB`hsV=ODeA$oxiXvCitf58L4lTZspe=g!sPL^xWWl!kO72
zm!Gefn!f4didzL~=8c<rSHGE)TEBX>dg}F%tq!M;-FX^mvU8eR@t&N;Ym4|^%?qFW
zQ)hKqZFsU_?Z(e)^;dn*R0*g4&)>vxnr%te!Slb*6dp_dR{UA)bp0Ep!kK4M9|t|>
zHIr<Ax&L|G9h+pM^U7<h+cw`jzlYQA^}(~BS(fz&m-%nDe!9mpa%;!3^_#QiO}U$X
z_gIkm`e(Ufq1WTe->kBHnRVxsS&|~lrmRJwk%u?U&74;qle#mO?N(`^>BeiN_X1`L
z&ar)#bK=UAs8==(YP-+vaSayts=wM>8u?;|{-&F<=dTtQeB@jGF1f7lYU{4h_xjw|
z)13XLZ>YV+Vfs<+RZrmD^!TS+?K?{Yzn4drHyND{OHb%~t#p<z=BnQdDX%L#mw&cd
zZsn74kI(S^!fQvTeHL4MdYy58<IWc8(vKhCeD#q&dGmMCOy<vK;?w8eD1CRPO7`=y
z`t5mn&%Rsa^E_{5FHH=;xp`K5_nFT=vEtQ}eOJ7>8CtotG<(4Tk=U3en<igvj0ojE
zq3W0Y=$GkH)>V6&wcey$JGzGH>#C&hR^>I{qL%$PdwXuW<c62;Ka0J$DX5luaz^}`
zjl$-0&U3^MO{)~V{9xPZbrEgn&q&{|d>p&Y;+50kdZP_HG~Weo6Eyp{?zGePO~1=O
zzUdcE6Ls5hrs`_sja_$>=2ch4oQ`EbFip3^Dt`sv9c#T`Z-wShtJKkJc)h39Vz<QW
zLu+<<KHan;ZU3uthWyzx_g-7|_)2e}@b*1AF>601#T0f_K7Lg7R<CV|-k;2_xuyrN
zJxg<p-K??h=9FcM^**9<51HDgEiI4Tvp6!~{L!^Kr(@3SIu?4}PQNyCTGr~>CrT~+
zg5PA!`?&J3(yVu9N-H8lGYq?nuQYzuyXSgyk-oJ5^fm5xZ&k=72X3znZQZx|hVM-G
zJ1ojmkF%z{()qLJP4DT#Q$K`D*;eGFmv?r)mg{;gaYky<rjMGRr>s(|FS`0<);ykd
z58l}9J7<%VAouJ+Q}G#Vx5-noB0WO3R-~V|Jo|Vh^ODmxcHst_J)IsEPGU|y$s_*$
z@X^KVZgV_an;F^uYj+CUGv0mKYhD(u(^`K#)qDl>;g}QVrQf5sJBP_G*2;c7D^;_*
zJJw*<OV{veGc^t$TIDp+NM{k3vPN~iU#LTotXt62ty9ikzWMq5yIY}gryr*X^-s<%
z{P^b8hU3eAbQG5zQ?-3r6`X2a6U%ksX>sY!k2jO2GN!C^Ta%}>yC-n!=}56fp{@L-
z9#x{#g2d<f7zd^Al>2<{rPqYn>~i6f$9Aom>g~1NQzN`JbBgV1tvM%5kE}8Jq9?bj
z`+I%7xSqM8)+U}GYc`!)_hh|R`3BE9<uXz43VD)+{a5mxUisK>$FYy0Ec+fW*%50b
zv3aJ#^vCCnjY@rPMouV|(w<eW8|t=;%V+-dYb8$|WUoiB@Lnv}uK3PtPVwC}F=lSl
zCwT6PI;>?BEF9GB{pXs=)vF>$*DrFP{!rUjuIgq>ZvCOjn$a1d$ChPn*ZExb%4z$}
z<WSu&YBPfFnx5tE?PtETdy>@bDJC-QomQ_IcN-+dKKnHJ#J3&m)?c#Pq_#0Qvg&H-
z#+|#8N*8+0&5kz<e9d8|*L@=O!fA(tTHE*QT+z7gxoVS!-tLck&ie)5IQ^mP=I3jz
zGNEx-bp&F!a$ZS|sz0@-XV)2zneLHo?xtrQrlyw1%nzShSbR2NS4EQEor#-1PAI)r
z73bS>+Ao~-SZHH*srhrJ6`_sAzP(YgwjQD%!k@o87nd&UQ8}mJwCcOkRMp)KTQ~1N
zAM|APhqg^u%J0@r7uDXC6c<{&`z2qzX@9J-i|;k}yIXfXlJ?!S^8JB&mzYfoq0`oK
zRb&NeKYrzQ^`Y{*9}Y9Q<6JvdD``xv-KQt~<khe9yVIwi-@Pd#wqRam_aW9ZB`43B
zF8mn&_C%@6;Z<9TA`=(9o>g$y<khoBkC~ROt5FVLvs!Pb;^{k%(>-4~ebRa?b7ptu
zbsdk;v_*PPRz>lICeB)|xMHzM_|BvCr4sH}3s3KHn;v^nwRBcB*XHwCR>j8oYnEqz
z{%o^W>+r*%3z6<S>tz~huQ_WSZeQh5w{FdKHMxH8YwPurUphT3Xf>+|ce%l8QM`1^
z^hz_mdtRXy0j0K~lFL@<9NH57t}<?;gw1(vmgZ&ZQ{VsY7nqwS9`J8}Wn@n#vq9|P
zr1~C5&95hz)~#~X(muOhS?lUm{+(gl&duAe`L<@>jew~Wb2jZrd!HI*aboGCJ!{(1
z?`<{nH4Cxj57)m}+IRl*jMvBZ<@o&7`d(6|xZ};1byo_-|MpcT9{OT>ZudSlj+#)(
zUtb=5x8cA4J#%Z+(eDO4oJ|bpKXZi|Ci^7Dq-`~{sXt$RoX>7|@_DIgHA%}ey=E;t
zQs^^DMa9!e#I-djJXGT0B*PV4Ggr;~xaa(t)AvFuxj*-ufAiz2Ve;uiuOg4`x|u!m
zo653Y$GOj~&bF*QrE`sOf!-C)>4qB2>t<{1-+86^>}>A3yNh&pUwB+(^h&KHvf^Qr
z;Eo5Jz8zLO8#xY7sBdj$t=fA}`M&jBzC;PJd+vEMY2uBq-`UPRcXluTQjtIrL%Dv*
zUN@fh!;iE*g&tYV+bw)9Eo7Ovd*lhrxw<n`*Pjdfyz7DO=Xr0pw40t6)}DPruhcPg
z&yr;i3WfI^D1A6JbwOHh{?&8#{+lkdp3v8hUlC<r8u!Hd&`c|b4O&m@L#CZCcl>_(
z(3Dj%Rly0{&Z$<nr=>irWpQ*^emOBQvGMEI(reeQMa0La*VfLxdNs6aZ(O2B5wn56
z=<3debK@d*em9isx3sZYa{vA2?c0yPd#CsN_ir9H=C;F%fg%%^y^Q&LF0%Ooi^!Vd
zr>nE#UTrB|e&0Cv$*EK7&m{Nms$Nz9m~-cqsI$>KQrRwD-K@uaa`m3co4y7dwJ6g)
zryYHGUGdfYp#1^j=XXBR)@xhtmv^ys@AZ~nHro52|F)a!*FJTs=(X$DEz94@i0j2X
z`1AAg9Q*oty}i6);o*@H5eu$ni6)+zT=8_F&#YxWYQlYeeK&63PA)E<T>brB;rn~G
z@9x*{KmYC9H|1UOr7CLSX?c-aHF7JgUKg6q><B$oQM&TS%Yd@DX&GTQyG|WAYb^Bn
zS>jyvn@b|T6gpn2%t;D2)SYf{;^<<1*09*Dq?oIdXWem_Jolh#%Sx;Bdl+Y%Da?C*
z@nuOwTwGdma`Wlw`k%jC_WyjR`25E`Q|A2rar~k1{DyjVeuZHE|5<ydH3pwP{ozWm
z%Kd+D_xvo4KfZdo-^Lv~JXT+=I?~W{JbC$qbE%7GnA??#G`wWBc^^5o()2Q$qh{;-
z-&>{Kt{$4d+#~*}<hjFcv(CJ)yt(e?@70I$UkUO0u4LY<n0495|8nV@-S0#$2YoC3
zxP0};LdMUt(wbMX)yCDov9!Kvdw%iNtc$O|S`<EFnXVuI?C10O&;P!!x7W9;>G=NH
z{=9%h{g=fngw+iqk3C!cNr<V(k&lh#`}@m(kEmC?>ovFdx%d9*Lx-3g1w`b$-|bcL
z4B8T_aac3$V_)UF{F$e9m#X+)jyl<v*-$c1+>p0QZu)|V>04KG$1XR{53PUsrShIf
z=!}SP^T$mur%K+lVh*|bFZtSQi*=g~Uf=zxr|_h3lkVpOhpe<CM899Xd*(~twIj1<
zP49eJwtLOGbwv*kvCgag78zIb(bew9v)L;4KPTtZpWa^ZCHKBt(L<)H)T2@p)vx3&
zzS7Zi{6}<j%lf^?KI#8c%C`R~{HIa=Ut)d5zsg4zYJHEH>`(r_zvD&EIpaH_H~T7u
zPnfn^&(@t;o40w*T_XpB^9@hi)|`2;v*Lj7l}oEPv{^--TlKLnX3l!fvOxE{8H?tB
z>QFa2pK7(P`?E#Xn{~~htT)aUKVM}t`{wzIdG5RKrWF=W3|{V6`1F+My!wBYb_E3v
zUxMwA9<Ja2Wx7P|6XgV+dj}amy^H;~dCwA;aw{JDZ-$G?_s@PIUO%yS|L5|G`~80<
znh!P{K75!d<*e;Q6JL48%Jj~-&n6M44_w)_Yq8bSZL3a39J5)cbY^O<M`~ifw%gS$
z_Pwj0N2kZ6YjTCM*86(NuG-^uT_^qOteK|E>TVvr-YOT`U4L<^U5xm1vy&-1Ry2km
zom-h@#vXirj^*L4+1D!`-m$zg|NrNlf35oud{``h^#1M5799csLZ@srk3CWT?=AG_
zZLZJq!~gjIFnoH@F!}!v`Oj~@*UCpnN56Udwy>bULB!Q1FvL>u)B)$|Nn2m0PpM}4
ze60SO^s33`D?a(mUh+J>uwF8p|Jv3y2ftcgyBj^Tu;AvF(>#@z#RPpd|6G1Q^Vq~c
zS_e*VU9?^&_DR!Z6Gq0@J)XhNM%k^04RoAlZcab{>B>~?HGdE3Z}@tMo5%i>;GR19
zE!)_ZBnh!QHhi(!V%FgJ%#Hiad8dSBa!xb9)*p8fViG()Bd-77_j>!i^8XU&)&E@g
z{?WCg-8K~;8s^TGWou@feDaB)(5*e57H1de-e&y#{fUi)qD$l9Cky8Xt$MJ^NBGGr
z717f%Pp$rB$DO{gt9RWxlSO&wc9@y1UOh=y*?rfilvPHqzSWOq)N?d<$NjgEy*%rI
znE#>BHB6UZ?P}S{SF+EcYOmbu*RSVT7PqZ-s-N)hlfLnvkMiy=f=ZrRydL`=xE)q3
zlu=yTK80ziNtASpNXAlwhUY&y7=x-R>fDx#GimO9Bob7m@Tn-fQ9yygRBrMdyR#3E
z+Z|gu|8L~E|2yrEe|>#DGAb%5KfnL*;lt%$iq4A9&yJYhd}iPK%X!;B*3LKJ$=n*%
zKZWs0$_|x!Pp%j>-{46qnmhD1-}B7du)O|!{k&xhpR;M2cU-<c_y2y)&pZ7@bIX>O
zdd{6Dx#i}DbFGsfCxxt@aU@<g!%s%vIymj9{PcV8cAa>wlYW^mL$B6<nJp-(Z~Sxf
z{H6NqyF1p$x%#PXWpm+ZyfkZl%}?$nhZ*-CbzSn@P{P+^ay`rW&lXaAo>LcHj&$JY
z-ypl`Laak}>+|ZCL~hMg$CAs(9{iSj8#db{dBe8bxrg$mKXkYE`egoJ?Rm}oty@jS
z#Km8hSg|;M=qNXM8+zt&cbcW}&!5q2#om_9Ub<9OOiZjx|NeLGIG;%>J#Na2G?I*F
z78Dd5D6mK|nkjJn<Kn#f{AU-RJSY`lY5h1a^>x--?qlnMR{gN`6xwp_=*IMJrsZG5
zmh}clo<4U|YU!>@du#vV#pe0SvvZT)P0F+HGk+KKGg{p|YU-l(%u8yguQ~Df+us61
z7Cn(P@h>~xS)?|d`g!PO*=`*@y-oY}_5Bq8-*l2&-{QXi?#mCKPTzN?dA50d#lM-$
zU+8_2=s&(i+)CrJl4tO(drV&0lT2Jy1wS4XT)a1TidRPxcb5{&ye|{xsrZJn{V21r
zuu9rrf1o@5yW+mI+}<x|B-OgR*W~7H+O)}O{dMhE)iDLDDowuB1eROLPMbC@A~N#f
zkxpUO<nqeOnPt0u1y~q-)P&m(E3&h**UQMri2OM7@83V`L$kwHyRN>f)i+o8Ytg2A
zUk;rKzP>Yja{berD-I?ER5)DT>az17PZPua?;mUTEAadEyPo^d`*_EX+A6;%-_5P_
zb~?^}I(<iyRH>2py4S1yJojrIzLqj~w*}+B!r9*EmxZjZkkEVRGPgBHXx@~UwPBeZ
zT#8+f>UYJhKmO^H(X(T`kKX_2`;+q3Q{;Sdesy<iShqorp`5?RBZ;-Vr&4w=Gg}d|
za5Br%pi3&QOJ})gUQ$u?6+U3#6%@2o&~3pMr<Wp)4;I*ONDP`aY0WyJ`IgN)O1tk}
zU0s}A`HErR%`Mq++FQ14IdXEcx_siRc{YVj20SlItk$fnU(3{#Vf66BhY54<#>&}L
zIIO>}T`>7h_le7!_Qv%uU8;KR+O-=uZX{Gz?le$Kl&}+8_JmEv_cD{tJRh|lH)XbF
z#=mv*7cT}e7GGSUQE=w{%F8b=<ZXXhV%56v)cn%E$10wOQj8LfW{NzY_3c>N;r*G;
z)7rCtetfkmfAtQF&GlDrulsyo^=9DpCE4HhmYNoSwtIiQaZ;%0Y&{zx@m?SCs~^==
z%)+<lZws+ES9)7EJ8ygU&D+Yc@#}e$i)0>tcrc;FCM~zL)xvY8&#?@i%t;HT98BQ#
zn6>O$gGR5JrNT-9jvD(DYAYNVR)#InI+&3iu#1~JW=92MBG0bdu4~uTAG#+u_xb$g
zSF>z|q(T~NQ+tl>xlvGBI<@%uxsPXz&lmjqlDSRpPV(n>zI?yiZ7O~=<Sl0p+OT7X
zM}A^sp~%E#T~DWqp85ItNZ}t3kIPwGL22#E%3x44%zL_C;jb^5)22^fdoe0TC8sqb
z*B~l7U-xiik@BSFo4<eme)HbF`n2lm*>~^8mX()VT3IQ1PC7I>DlRUqvU2B#3%l;V
zQ&x<KyI>)~Bf-PgbNn&W{*!xW?D3M;;5nCI@ZiOZj*A&B0*g4-r``R#O6&frH%njN
zKXt9MTc}R<_U)|(A1B_L`8dsE)r>+thTiUDj<GzE$7Kst?><rVwW~a2aO8+#N?vaL
z-P8O`@9yvS7wUbfw@y57k6C_on%3E}^tB#ak1@DO2dy<a&$s2$%@i{Uhm|60P3Ao}
zmh_LfYvH<n`;2Hk9|4C+B6256B7)q$>YqOH#AfExr>TB(t&Uz@9bWmq`u^$qA8+qJ
zI<`9g;hUMpckbVL^u6x=_uSmT?cG7wl&^YC)H+&kUjKS~;n$hzFTVf&^82q+@Rl7r
zA`BYz=h*W{6+ZqNe)IOth4lpoGK?19etRiv>kW&IeS%FJt|sQz^2U2PDMm)crG5O8
zxh`hknTrVr-rnB6v-mmR_jh-b%gd)<%xIZ1DR2AfW5?K*`_E5HPHz7CwRGCFX<Yd#
zT}pj@eJ{TMe)GQm{pS7q<0Tf}5q@1_RbnMubKgBXR>bk$n>QP_ZvE=9!;DwXK2O?5
zeCGLG6Yg&f$iG+FzgXzS?k2<1nh9F|i_f%Xt-AAf#|`gTsft@mzt{fH<v;Rp7nA*i
z7Yoi87#x^mGqF;NE4gIi+(0c?X=aX=F9w-i*SJ#G9K7H)Sw+(;yQThMTG6tGV-~)a
zJ2xi2_so_~N?mzBW?O>U-$*vC^RpWq1vYHhaNyQ0spseCKcAUC&vE6H@O?ij&&{`P
zog$aN=ijv2_~nNaY>sI(e^EK6vBga1n@-^Sb91drcE|Sh^%)%7uw~1UmzS6CEPE@(
z{=0h5r=RDGUSHE)7q|D=w|8>u_kXNcJ0`K~F5g-M6<?vKw`PvoM>1|tbC8&jc;IAk
z`i~3k_GgOE+sC)Ket&=e`G*eziY(sV-gB(W`@U{9y>>m!b8<`j_jg4F6)h9wPM_8;
zv6i)3Yxb{Gc#duLG>xu~$2%CVi;IiDEVJ@Buk0(#$KQYB)~!eH?(RM+@%&-$SDnzc
zj`bFP`g3;qq)hg`r)pJjP)&QY@o~)s#b;;j5a^GYQT@3@eAWxAD;qhUA3dzcuk9)P
ztNM4xn-7Iji>ErJyQu_nt>p>gvbpcB6fm!yLq*NgQ>pn9SB<Aa?WHRUOBEMSec;)j
zVe{}#YxkC0x|dWc+tm$w-#-zq4Rc7p$7ZNoJt4VXQCvUn$<6fnPv`%6bN<5HEg$|i
znCIVFcK?0xrzci{lO`?e3KMwnTh8mZhyR8hSCVsc*D_RozFVJ}+1cC6dv3n{`QGbs
z$IP1yI6l<Oe|tBU<-zZHu`>c)w0R6OPd%*2S#QXbTVW#k`P$dlH6OX-AK1RHmcRcu
zzMfxy-w!2iZSDFu@82_T*tV@Luxq;gf6G2LcOEu(kC&f6tzK_DtLH_T_=~dLKZ2BM
z=l_4U|8Jb#r{4P>GRN=itexHb*S1W~E}@{}M1sYm4=*NY^hxlvsbrp7>OH;V@r=cb
zm5)6(eEe}o*oKuo=bx;~e;jq~;V!-Y%cTpib(}dJwZnv`=wryLJ6r12Sd7GPHr_M|
z4Q)-G>;A~5V_*Je;orM;zKI#!nsCI7$8)M1N3+9&pOe=9=D%6<LE!%P4@=uWsI0uG
z(s}5!$}xvk!IN^*h1r4@drsy^Wl=Zxdstbvaq7aapZD}d&PfrAIoIo<S6%S*l&IXD
z{pauAzHYg5m)k0y@^^RCc$~IuldBK1=GmOny5)}`PkXz&>nh9VQ!D0$w|H>h)%$xl
z_8UKc;H?`vp>r;r<5_GtD=Z^;|KgJ@imLM%7K${A9645$_UPmc{eSn;Ev;-G`2TzP
zzf(NEW@0<Pd{WQDCnqP@d@Hv<y7#uZg$xhJVX@PvSNFI(t36iCG)b%XS6*9xSbYDF
zde*uJ?DZ24A9ntC^8BCpJs)44=4n&DwQ%jEx|dI<bI&__>XuafxB7ooWo2bI?%jL#
z;ll;a`eM!P<(*71za(}ZU|BbB_vvHrb}tEdUG}Z=7Vo-<(>Zo`r<y#wmA1&Q^^a#n
z^7-$UHWmp+Hc7d)b1nP=JC#hOCNB>#KL70B-}X0o_3tiZ|6HJ8D)+>+hUrqs#4J`f
zWkD6sE_Ic-?T2^U{iv(*-s_%JaQ(u@GX>A)^oOlJdg+poy5F1!hg!L9zFrCbbH@IU
zW>_`%mn!Z%JFDkEyeRm#j6IPh*IvP_$-|$cx#7U%BazP*-F_?7mYC=gwN~u(>C<y8
z3Yn65nhz^)EB{{4aj4;8LCRsXT<2XEK65rVxMZfBQ#5Szlv!-Vds}JiD&F$^J5QGX
z|9Ag+{@)+{pAT{CPgtg@efspD*Z<%DR}GtG61XL5!{+UWGfbQ^dqpOhTxD6PGGWr&
zv%U=5wr}52`B(SR$(EB9F1znOOURd>ysTxdn8e|upT#5N<Lh0z4yM-kny`AsUOo2g
zs+sM&FNwj2X2zE%Z+?(EHT#Xz?$XejqP4%~PS-9MEzW!;JC)C%>EHv7scNhjy;Bob
zUb;4+C8(gnB<1N7&A2}w++VcVUDQaL6tS<##6ZHo;}S>a0duy+JnfGK744+O^*-ET
z-{0o9`)}Wm-KR>|esWrN@JZhG)AhG*NiFxE|LoDx?wI=5x^j1R9=-KR$t&~S-QE4~
ze|l(Uv@-@yYBJRMmQ!Wcm29Kgsg~TNpkX9q=`nM8S^2i@lD+P4<YhK&+jp+OU`yO=
zPtLy#imWSxSmyPgFp!(8RnjKPy08C~N3B|@&zBk7<7!*$e{%0X(EsN}KU2hq;?Iip
ziyzK7nBlYhcB+Mp_|*L?gFHC*J%7x3@Y&z$Fw4CC{a#6JhYQ<^e;x^JQCAh3?f82a
zf9(nn&+t&0-J4?NtKXSUV9Ry#%N7y}^<v!Nwau3A_qsDr%Q`im@67x>W!tGsvHp*q
zdY)97wPEwm2>~}e?fa5LrmeaX)y$a85*;0F^Syqn{1fN<9|Wg(ali9?)*>R2SGbgI
z%SDcR->yx$)O+dX<z#DXHcNron}hu4*_{0O`T5SOuUhuMFaK}wd(iyl#;tpa_4)mN
zyIa4oth|`9l*6_^Ok$BS^SkOv7c)XC%pC<pUVb`y)HN(D?8l+!b^J?3AAgj{<ym}D
z!r)qig2yA4^Yz~q{U**!6LR+v>YX4^#W-(@O60@%Sxw>|O!pse|9?0CW3By<W>9^y
z_^|V~ZQCS!+IWs9U+YP<nYCc5+6UWg5u477Y$`T29~yR-zb`5&IgueUaS0d8kw6!l
znF_rJHC{``?JZlYux@Io)Ag-PYhS$&R?oa~h2hFozEID|T@v-;$vm4p5B74eUgz^~
z?V25Hd@e6I)f85HZz*$R?9=?ovW~y(nh!SoU8_57*WK-!w<E8q+RwYz<tejy%O<DY
zcdK?U@Z(q_z%es;t7_1V_fB5Bf2S*C3U7WMwZQasYs|iynY+v16+HhXEhciU&3gO$
z3!iGmta76gxp^vXNX=LA45(ju>I3UZmB;>1R$eOGefH3yrlX#>a^>#qb{0A6;+gdF
zU#6EpMa3cIKA{%FId+w8;`{%-7Myo}?QZ_cr^kHr?$w`oSis>X{L5~keAJqg4F;3W
zvVZ^4KmQLuLr$Juih+cYOkXZnSSDL@qTxO>Q8u^8eSMyy>-T-)Dt~uJu}gVMePG6k
zh@+fxO%73FACG!Z=i2r<=dWMre--goQ}H<)HD}z~A{iz-#~}ahNwwWKbsC=Ex^Zf$
zd*|xVwWogVm~i1$l#p3%K@i8W$AX!YHr$9#5xU8=WzPGFOEhn3s7)5!yEIj-%Jy{9
zS+xwumwoq_l^iehnN%xkukJZbuFP0Q@2g;aWnpYz_!E^4{r_LbJ61J(xmmO0<bwwd
zOOMK}4B8T{J8hS(jb?ya@C0$m#n%&z13iPT+$*t~dq{Yr<eJ#Bvht732ilw(```bR
z&|#2mW0e1MqW$OT`nT&pDc65pU-)omxnY;`yS&`bx90Bt($B`i5#{Ky{PM9`Vb06%
zKAO6|hPA$d{rmgHp@%HyMZDVm#lTJQhuwsgYc+GVH}xJcZ#!S}%Kp<+{aVJQrjs=`
z#Yr)(G?^!`rFMR|xL(n(H<50O1t*_;BFl6$)pqgo)Vx_8>R11+KUZ<JFyNF&_PQrQ
z`#ZBsWd6Bc-mz{~#0oFn)2iR*_)eV~yL+|zr0=zsRu&6nE9yP&C!0v@>5Y7nw@-e<
z-rdJP{bI|0{n~8vr1-<aPYz!(Et~bP{@j~0H&>>goAdC~)6;i$mUh2hzrRbMDew66
zcWZCEOy(?H-5VygCDB5%S^Y(uZjay+E!U--iK~03l=&0~nED1+?Un29?zY)c-v9Qk
zY}xnUb1W(+<?TMI$kfBYQa`t>Lu69={Q7xMpQi468NIJHZ2Rf{e<%7s{5)Sj?_kD}
zu>TFMVdC~5GOHEmO_>(1tn&TcJ>|aScX#)muCP(-6Bets?Y>^It<O!m`ND(Ljf+p1
zHJz{jb-85vbk9puPO7ApnmVX(D*19Ob@%=?XLkXkBFo{26E0?igy@`Ky>Mo3eOBnz
zO$%3+zl^%}-fR7eETOom4>eEm%)9cWG}p9J=4_J{bJ*0Rb(@crPTTWt-(rij^6YMg
zM#se=S<aHFC&MKIRz7-=ab%@&y5-J|fjSRlYQAjJuYY#>^aj@JCdKEr%stoh#CO}L
z;<MWhpZF;a8YBPo^z@%=`G2f3CtY}_C*WVN_U7$70aecCgB<ZyJZ;Q*c01bLF63=}
z)3;7%)#9yceT$remtKA;!j@85IkTN#Uf`(Uu>*&krkgD8@z(s<vgJqDwK+DGn|7?{
zum5ql=6U_k_=2C8SpDW$9F#b$(7RTAAx~qztt9`+41<*V`uXkr@&=tsOGLID5-XfC
zVVRVFMLo+t{~7)3)AvpZTYYpx{ef@Sruk}D%grt0mR0A-<*02mX`8(Ke8PeU?N8=;
z#7ey565LU@Pw#6~xo-byJ^i=Vk2fW(vN{*a`Q0o~syy;csLixpjVrW#vM!a_s8^^K
z`qZblA5}=06#7s~*}yGXAY-xTB#GX{f|4V%*Y7>%xIez0VfNg<tFI13EZTi(*@DyU
zjt<N3CMITbu6Ox*Hs$)RJ$qul9JMTb#1iDi9p^Xo^z$lthD3==ufNKjJaK1N<z(}?
z>dp}9Y1OuI|2}yyS(&u)Iy28oub1+?H>_ofe(u>)>Y#Oc6^G*#m1(aRmInTrCVY0<
z^yxcmUz=%hm+o52xA<ZG3=2;VXZcoM!zyp>HS5;e7WK>jJ=Xv6r2ikWwF(IqGM7Ht
zoaosWD3r*uHjE)^<L=FeFJ2T}`2O;#tRlC=oL);k4jh&W%oUN)QFoPIl;NYr6L(|L
zRX#xnA>R*6+x1nPq|e3fi8v7u<*#1nzJI<^S!VFo+Hj$$smros7k}M#zW(~$^1QNR
zt(ODElR_AcN>APME#MXBwp^bXB+Rz@^l7cmUdx^PjvXxUm=(3Ov{}<;V#v}jV!Pht
z=YMMT|30%vS!k&M)2+8=mxLEMa5rB()>O}=wpdWzf9^y6zZ319Y(iiC<G85q=^-x0
zW%lCWK}Ijlu&^*WLGDwlLytc;^wO+9WT3<KNH1o`fvc;-f4<!RzuriSC(^!fQiV<0
z=YO_VZ~5Mau`ku#T3wScVOR4PqYL3x+t@ggyP2k{bv;(n7H&&CxN=AJb2IDRyCo7M
z;@%W)sqgR;<>t;+Tj_L^^SNH!qcb~;bMo?xX8PQ?apS?u<@2B2y2-tv`hY@^PMNp|
zPrXZE%G9^TydvkHuQk8F<o<p2z|3cJTbF!PbZVY(iD^}wT5ZB6t+csHJqMj1{g!Lw
z_#nWM%W;UopJPj-cli3El9G@YOV4CWT$?g2V47;?t>Y{GGIr(&uRHZ<N75X-<25@g
zq(XPsU;X$j)GBOa=IkZ8tFr`VnfYDw+PHr^`%1O5^{Gr-4|1I5zj!MxValbJ#E!0H
zzINtCDvp`Ht8y03y);c^X|K`;rkeAI6K>qR=UQQ=)3KQ2{`WVF&K_6(5P9=f+Vh#|
z7QB02$G&&sIQZ$4(eK~CTO%%Hm^^y%qNBN)`PbjNK;=yvHy+$s{Cr2vPowqwziH*~
z`DS$Kb3}aP!?ou3>KEM2Q%;$YC?ogLV_~1l>b0&07v62@c-(TZpkoS?qDr8Qu@v9^
zbuDIXQ>Tjl`u+RP{`&sC{}|`yT@SkRSR%e^0T0uKTLnLFg>JcKQ}bhjMW3M4hJD+P
zC8aZ-=U5_s>7}m1qLz;tbC#Z8`|#}+tC;%FzH)haMJ5s(w`}P!Y&%&|-z0GD#X`}^
zD$9i1%(PWhqdc7K6$}le`Xi&F774d4+1D>1bpF7lV{GF3@y`w(W@nX~ls(bpE%)0^
zme+GHtz$8pZW``(s-#!rPvt_F;Gc(&KaDXF%qrY^C6vW1JaF2s=|*jb>*lvAq}a$M
zZ`rivtBLLoVGhSxT2s8%ZrEse^nZQJ1c_wtKfZpEqH><AX1E9+3Y+~oeBA^U&VBL*
zUP66+-#9mAe+|3-A$%IAQQFBzkCfzp9AMv3^pxvw-ToJMckkbS{@gh}etEkm2b<Y@
zjwc^7cyeZ@am=2IiP_iJedMqI^gqEyW@F(ik;Mla{_c$p3%h1%Bc-%NEu*!k-$eJ}
z#d@w9pQNv*F3%db95TD8q9*Gv!OJ$sqO>b+eYnKd+2;2){qPbg&U!3zt07GDP_u=n
zZg+^bUfkYO_wLF4t($M+o6CK9tErk>p~^yilkR!#B8E=4CkSW?96RNIZ(nKm+_|!k
zEDlbV`>3MUDH^BtrKO=_(j_h?r~6Es3s-S838dDW1j;Dda?em-dG1iy!Cx~s&#|a%
zx_-Z6?!}A{5B89+A2OSaudH0Kvn-+@c6n*8e$3ad`xh_lKIL_lQMdH${#fg^yEpxb
zQTZ6VK}P(+R*?`{e~B;rk#R9k3JNBKzRn7n6=j&_uyk5x=7u?45t;|~^xjH7zFc(M
zhn99D&B-o?GwXdKVj`Ygnz~wI?ajNlpBB&mk;}*bODAVeijb?$-fvRX5=XwiZkhkn
z#QpZ|)(7VvJeXkO%egytk;Sshd4(_UM6w8^?{In7y65LJ={^5mg@34>zjdnUy^5cy
zOp+7SzC|5YNGbfua(&(0huV+NN87av$?&qT@a!^R(zID3pfZ_ras9&ydE33$UqAfW
zCM-Ps=b7c(9c~KfXKWQX)s|<)?ap*Ry)t)d_jJ9&ii#5%CR$UDJW^3K(zN;@aYT7h
zij%kRdG5x*HWS|))dl=pG>?^<$Se+G<xmlty6lK&)2o!MtY9|VDNOO6PWCFY?mleF
zEKHI=bk?qIG;HO#wCCS(U$goxMthccrfukIe|qV|YOPHxj4S#(giL)4cO{AVRyT!x
z^nWE$UaFTgbJCT<3dPIo4<BZBYgV3C#jP>5AuQp{?ab)pH+kM+Cd;;}rk#9Kwdum~
zH18b7D4E+zCW}oIw;!HqynN!m^WOXaTh@J-|7&vk`MF6kJ5Sxar>A@Wx%tK#{`#Lw
z^(SfgPP#hdh-Xij*qqpm?U4~L5<dL6U|zpjcO!pO)7)Q^|Np+9Y$R3m>PqI7ltUE;
zF3O&lX84^xo^iNXf6x5ydwy5u)qL7~!a`L*=<QFJmn@AbHd2eXI&mLNvC-`D5Ma^K
z)&2P3UhO0k#ShF;i2+Lv^=`@u(Eku&S2?M;UR<x}_qp6h7J4o%W##3PJnd$mQ%#&I
zJeZX}-|I2s;B=G_kUz#!=kQ9kWvzfe_m*u%tn()LTxy9}dPGY%;vf^FlMqL<zRJAk
z$&Z#?*e)7(;H2?#$uuRm$tRb*cyH`K;lxqx0?u+d_Vw98CE?4oU!QXSw7TojDVN^a
zCOcMTG1o^dWsJOL{=_2obnM1iZi*6Ziw`r`B+lq@e_`U9mGeq)HS3}+hc<t{a!M|%
zSN-i0bGOBtdHmElJVFnt%u5OC;JVLmQTj|~u3vlMtWBS<&3<v%xv6|__uIwJZOx2Y
zJc4WaHeRd9^qQlg_SiFQdvf`YlNmf(N13mkpZC}{{<CRM{qf|ewPK)2_wV-Kt80F8
z&sPqeHFasKS^hmIF3&YVHRqMTFdtj_X!gFZ(VlJ2ds1Ayowq-ItowC_Ot0b1b^Qm!
zl(J(5&P1&h`~Ca(oxR1g_x@w7d$IXibW)AMhSu^^r({={q-Lg0ZN2Bj81-z+PwDIH
zH}Bo*`v1X%u+?Wj9b&4#_~U?`eX@hs5|JNo#a3QClG*d6cA8j~51S#A&fU9{T{2rv
z&De1)<MqM{JI4nLCr#NVpD^VsOY8H8t%{rlPiHRY=GQ!b=FI9ut;63|8SGI1Srn+X
zCOLO{YTl_n_0xHKR(;vt$MrhO@BONsQO6xE{f^sB&w99O`n6gA?&)<WcAM0933w^@
z95ZH{DcbItYp^oOM#@m?*2(3QS}J4=rT9FBThmn*dmed^;b7D`(?#&2${~Iyz1ZDs
z$08iQyp!FNC%$o8-vqh0e(ekHE_+?cVzpKE^Sr6j6C!7GZrRxF&Y||$@cjM{c6xDp
zPJl*%3l4tLtNU$U-#qtiZq;7bMF%I;-<=z4(zfmW<MiZ`e=C<)-sjd=n4<JWQGj!w
z!4gUBawDn5Q#T!0-(V6Pb^3McySqCNpSz|OIA_C#3yZgJaF}(()px=dm8eX=`PRn^
zEOZ#ImhJXkfBo^fx6x%h$CIZ`pBC{(XThZ-X|0=hyf3_(u!Pgyy<KJImIe{IOc~)e
zxyJnZnKq9t&TaCXkS4l!ZCJMg&&8E$U!0s213kMOA5_~p?mqlfJKVy?CdEQVEOPzJ
zQ^nJ_8unX14N`ivYvQ!rU%m$X;yhnuL)z6jr|h~WaAoOix$nzj7}g$7<mXcCSlsdO
zpQ2NCiIC%@2a?VD4$Hb692j`|-M*-EPW&LDeNdyVvtCRi>POt{fR-073MJg<w{ZA&
z`&~%POr6R-U2mb`m+xgS^K*subQO2!+Gs|+C^25ya6{~srnDBPW{$sfGNXTdRm;5o
zFDlpPRsIqzx+%W@1FPNdm;M{e4W1nN#Kq1puQX+mbXx^m%OwSye>c9@@H<Lux{$f~
z!dr#QET*#zWcunojlP;r)hfBDZm!vIPl4mcty@d>@9)1j>z<SN++|A&lZ@5&xxcvG
zbGh~ObZ*O|b9`q@D=yY;Ps_{{oUGz<m}8S&l91#2>&%K0eC!K&*BYpNsO<^+F|S=;
zmCbim=*3&ge!(`H95vDFQ+Qe~9Tt~k)0RsWSTo1w;8N{yuH37c^~y$TGvc?c+@<ql
zm&+lWM@zU@uE|`sHEZs)n{4}Yp4;m&KC_UVb8|~>=nO;e()G#<uQIwGf4xK9Qi{hQ
zv!_qVXOcjLP@`gRu+8F+6Q`Np%=>)z{@=S>4oxeq_pRgku;j#*JEd;(HdQYXV0u}-
zX5E?vCOP-^9sT!g*-@RAEl<=n>pQNrxMbgY%jcNY8P_<WBS0u^UWfVy``>ordT}~s
z<x556|8I?d`0T88%+9i@2A((G%3t7hR;jFJIlD9a`VZ##|Lg|G4E%!s#7)0(`}k?A
z-<9+FFL7z=JQMiExcK7^g~yC<-oBfpV(2;RQr1>awL-N|${$<WO=g`->R*2UYffW*
z>ywf{XWRLA*1zX_e3HfHU{U_W3Iioip_CWRQyPxtZ(ZZFWP_5wSLUL^7Ox;Cf1#>L
zg(*{?*}N1y&UyIcjH`af+ooF`<X82|?ECiXn!+zeCl9gd(=xW-Ze37(&VOdQ%`5@+
z=cy@u&Gj<vs{+K&nF~G5D!N$eTX5>r+0V0nh18o0tz&Lo#r1lY*`BOJl_%rpslR;x
zUU90EzuJ#u@7gkDl&5Z6qPA3E<+9!T&TT$#n{I4Yx$)MQinDE#XBuu?tGedW&$Hq2
z>Hi;eY(8&y{Ncrh44Z=zzBZj6HuC2)qK>8PUdhV-cUr!BmCQqF=k&iU>i+X|PTjEo
zyVC#T$^Rd23)HjidHpH%Qae8<D@S~k4O8PJA%CvAzt`(TnPci7^M1Rf%O;(@WxDu;
zjZ5cM&uf=w;dnVQO=ZKMsVbc1dH1(Dd0pBht=_D-Z^Oc-tA10r?B<TCeWeMSPuzZc
z>E)LN&(28JeZK#fjlJ61rSQzj-pOB54*dJZyrd#pD2V%DYj$}3jkoU;gJyGbFKO=!
zF3IYhdZs`}vLZwAqMKotlFzCS%+9m4Y8WMYyRIrL{`~YytNG!FiD%BN*))fH=WC15
z$Dge}PhC3sbjY*Vs1v(Rm7cL)X73-i-fR8g(9l}B;I9@&oq8sf;zqNz54>7dzVgNU
zcS=(ZEzwM|O%9mWpAgb@;$HpkqO9hV87@yQIQGBv7MV6n&fhKL<;IWm#3T0AND8WN
zv5sBMBmbi$|BjlSl#tDTxl0c(7`bn(TAI14Lp|AsIsSLAyzZ5&k1U>r|GTPR{QjWx
zyt-$R*Lo83O%^@=d8Du_q|2c~LG|zL>p!p7*G<k45?<cbdGUnb^ouG=Qa%Pw^-+5q
zy`~6y@M_gnH|FN%7JWVz-J>qpy;pAa>C-B|**%gcaJ;_gaq`hCEpBe^5-Ztj*RDmx
z#=3f))Q<nvbX0xGgHt<;J1%xyyeJqa(Ii;maqZlkXM6Sc&7c1}{r`+Yk;`1pVbjAt
z1R2Z>yzc2$zVi62bj~KHiU*#HOcuUnH9J$!$iz5LKX7H+ni(H1UG^8R@QB+xd%EzH
zRL<1~+m}h6UiHRPcIFzc+ciPDd9~A9Z>n?$PP<yj+n;8C|4UjdhiU4Us_Dg^nv#6(
zK79Niw<>ljha@!yykuYE$+Gh7p`OW8vZw3ayz6Xr#p)c-#2_wzk9`mM>w3P|zi=*z
z(w$v-vR*8q=$Xm+|IPIWvghi>e_mWaGjRX>nF8J{r_24828CU_CfR>nM^Eq5%lm&t
z=Kp%~UZGj+{5(tVKLwLb`V2g{Ii$O%RWcp9u*o)5WN~ooa@J$hd)%)r{r*SbVI+?u
z$80U%N!y=Fo6Fm!)R&7VKR9wrO8r{cO<Nn4i);%+10$>JKdxNOFvp^>>FSvUf1c(4
zu`<73(R}u;Y>oYr?vx!{yG1s6yiMW>pI1F?>C;rXd-V+>P4^x#adXGE-EN=B*L`5g
zEdH9m*Ne;3C;$Iq{a;Sew&uLLA=l)JFxz@BNiBYJ&YE?0f6rLIc(-}xOszX>eSR(C
z+!1-KbXKhXI^IXGKlInDSsng2`GEDazc&7!uRR&8LO1=^oBQZ_X+%ELr>c4G{}=S9
zn^YMob{?yU>}|VdmSQLo(AFt1$GUu7*trc;1Xqj9dtdzYmg$}Y?&+nLm7LWz?_|WU
zUB4L{|NKg)aKR&%?Rj?}-P>FJ=IvX<nLeA$cw%o&=8Vc-r19wf-`n-4-_`%K^WXnE
zc1`k*{|^{fic~muv^ypW+;Ujuv9$f1M<mnCrOBcSAOB2CZDcyMS#(q5^P3me8Ys<P
zQrPsqQb%9cF~xabnf8_+Ee#>kdNF(1ZbT_H{Qmy_bN2o}r|;~mo_=>RqjdIamFVgt
z&4&BlFYY-wok{h<?ftK<cNRXbS|%&Bx&Ff22i0<gBI%-s<eVhzKApXPL_GeN(EOiw
z|F@j;s4vV4e&rN(Yi}UiV@`o<0l)8>O<y1P^xNFq{VhhRXBWh<bk4d~7<%@4W!%5Q
zf_+*s8_${jSf@9Y+wann#4C?YSjuHNrpJ6QWXb;hx3)w0(M5)(rgGa9g|yB(SoN}r
znfYC;e_1AP{apU2p^~?+Uwo#J>zhis^C?qzuHW}dOMm|#BlG-wOYXm4Y`pK-%gf7O
zey!SaJGbt8x&6`lUr*FIciYa}Uor9H+-ja<%D48qzVQlT*_n8uD<XS|V9QFzrGoqX
zAGEuyRP^F8+Hxu<%<$fF(TD`IdfOfK=cSBU=9YDz{HIv&DI>h)_6iF(iDn+=xIYir
z@BKT|{2M&0x9`)X={GEG7F>V3Axq`e2M);_QDTj`i$7kuzV`&X-492*f9vb7c3Efk
z&VQ(=7098oPe6bzruvm8A6xshS8_*ZI0#AS2JbzVa`$^qNG6K}=iPfs(#y>%eomdv
zZMf*>r~2@ygEn0CuCgfx=L4>ER@wT^2uc;m-fY}2yg8INNmd~GsqKzk)$8U6iF@T=
zW$@PYoVslP?!!L{8ahRlIC5=$+B!4Va<cMlO?dq1=<!>kUD>BHK5yR8d2N;l$2B9X
zZ@tpy6>qm*-%<FO&E4Jo$G-Ewep#J9eY*AC%ltpH>knTnI5L%cdPKdC$aZsc!$j`K
ztP+_kA2y0dU7C~MyjX=*Qk6sb!;*viHd8`;grZYku!sE)QJCOlB*oXAy{G!OndhR3
zm()e%PNuZ@iJaP8TPd=k=9kEG{TKyLp}6|LrvKj0|8M#4@%um3Zj(9Z8a(mY?r!eY
zvEhi(LQ&cMM=dyhy#IIP|A7R9`UhvP-&gSsn()B8|D!^Zkm`?l2P86dOCs$vuimzr
z%j%~5dZs4h#%n)LE!beuaZTxP1<&c%ua{&-wX}UcH1qL_O}p1^*V^;m;*pF0qQ|K#
z1q)T<O%H0l(sP)WnIhACHT-+QsvFza>1(RGA67j4&o0ZxiKAIi$iK?Nf6_6|j}=b!
z0>9q)2d$fH)jNf0?K~Uf!f7uiZ!fR;@PLtD?uOUp*4EZV*WbQ+r8WQmpZA|{onC+8
zRmqOBZzjKI&z3p5ap|3OHZPC<iBmYvtADkbVs=4jMp;K-*TV!CA>Ru^HT!c_S!}CC
zGZz^&zO`izQ+xPu?{AG%j%Y>3Nhd9|7s}r(S$)5rOVIJe>G)ql@pUg%>mFaXKX-O}
z+;NGsPB)S~f9XhgYO#1#g(=+P50Hravn~G-v-}?g{k>mOx0P>WSbaf`O*dpoPQ+4H
z&8DlW+C3$2Z<+e#%vo~(ee|0X8OOAiPIj2JmTfK1z7HK+(;nZ6<m2b>{_;-e?%zU@
ztFJ$}O}D)JM5_K&)yG|KY)c>dOlGtAtdlJIDLOSLW|ipaONUb5>|UjFaq^3QPb(+w
zZMM6sk~l-HXR<^~?xDBra&^mlPi0)`?2L?ye0Y*eVcPy<j|~scG<ovqk<#6~?HL|l
z*Z-RzpJX9Z@a+m)?1Q}h{hZNDf}#{ePda$*`^sM5u=VQIMMs_VcGTDWe&$>EZ~oul
zynUr}Tl3nxxx0T<sCae>is@fEWgr>N_WIg2HFtOBEoLQAvP&8(goOQtRxf<SJ<0RP
z-r43qSML8VY*X=JLUS`SOV_mL!cv@phdi{j*Cz11-QcQWduFEap9k~*2%9l~DG;7`
zRkw0p|9j82$%1OW2K)Ty99c83K8F3llasuDb8kJk7Ja?*@)Q+62~E!go1k2WiZJG5
z5eFA*`^Rd(cz4;<_%p-VRX;6u^DX<SczO2A!rvE7zFv!6!hWjY(9QinkH-dl_Ing$
z7jxBdeICQ?M;fL4J2EFunP|7{etNRWBi+TF0vt;_FB$4yR^xEWXmwec_Vtcrm3Mc&
zG2@Bw_oj1;&Nxq>I#twfzTMfS-qS1IUJbAOJT;snN>^{LrEh)p?8O#}9MRh%r#&}z
zEc#Zf|KWc9|L@FUYyuiyzuw>7eR}=h+40FgZfWbZdY9Z*oSf)1Nh{?+qgjuu+YzI-
z-R18LY@{Y>9L>7nbd=L`Q2@v5hZ#B57r!)EE7#v%bm_WO<CX<_t1_zIWjbqfa5hh9
zRR0nG?^67eOG{5P+}TyhEPvXcGfMFi$D)UV60PbsK}#!M?JO5f-ny}n>!s(U!mf!A
z9$)^-WWu(T<<jXJ`w|aK&A$HP`|nnjB$?y=6VAkNN5qOH2ghA2yyhnS$~pGN)cE=L
zTihQ?T?;AvR=--xeJ9hJ)P>Wv<$_B6-!CwHK2u&(l3D$G*^N7QQx$4ko-g+0Iizmb
zWZ{?j({A@)yYu@##NCpV{$zh#d;hmRq0SO*b8IRnaf|DL7P<V}KL5w=9ydX0bw44g
z9Ul{fAOBu5?}$XBJ~Q8?De}Mey-zoq`Qehc{>Gg<JEu&#yxhP3^Sko>(lZO4YR+%(
zJu%g3waEG7-xddQ2Bvft6^ax-{#E+OLeX!_*;_tJNmG>$9VpUO<9h2kCD6sQ>(a`r
zQ_o7CbWJ;2W$EPgZOOy-f2aCCP0at}#^82X@%sIWW)r_PUlu)Ae8eK_?s5K`@wY=0
z((nC^F$@czUnQled*5BV!@1s3X(OBZ)opUeo0mS7^FFP;=hv;(GP1Ha;||OeocXTM
zWcJiGlfCEgw#GDEj9hf{jpZwww~q^!pE_{o=GW^Q)|Z!T^o`VdwZmnTmh#hCm-UP*
zE}Q(i)3GGe>-EHdW9jb`<TqB%U+Z~fiL?M$^GBQ0S6midV$o#z>v`nTt66Wag<Y!u
z^lA0O&L@+1z&BukR%2-E?>+K0JkFWp<jbw5+uq%KsL}P}TU7#!(U*&H2R6t5u8XU9
zU;XpSa=W9`_y0-Vwrv|nQ^V%;^GpR<$<2Pdb6b0l3s16e%j*5`*6F%i;uN(`HJ&!-
zy!*RcXQ^={DtJopt1r2c<F_V<aZbI!p>GwQK|KZ>Ci~VKvzp)Dzw9!XPT{)SkM#e%
zh=1lR|4ZQeySvIf&X-gk9y}|pGMTecq-CDFiA?0<XP!$g{@_+jKR;jl*el!f``cSv
zS^4_gUYNK_`z|qE_<ZqF2gwhu$7ga+m*{JAJ%2YQs%T!@i9*&{t2JJi=Bl4^>6KGo
zR9|p1NzPlYa9&7a@Ux8A9}kqa#FRcxt$e%d*@?^dbK5Obe;-xhJoH^K^4FEmw#Rnw
zzH{qlVsyoekj1PLHPOG7L^K6dIoDoI6$_sxT^)1Wi&^|tW@cmJmMC2@F|mlKsHD=;
zsqsIj?{_)=Ju)K7WjQDR_Oc0%9;<lwJr~>()pNOiiv1t={muHdFTHD?YR5mk8XljT
zo!wow`)r2EqU*13e)<<D?tja#bOC2gbnBX<N6vBQ9?&S;w%zg-XeRTP?)+)b4d)zL
z66Kt=*(mDNnI8=k#g0s^c)%)=Y3eL;LB6-*{`Gp<`=9sTKmF>K)cl`k(r5UneW|i_
zYi4X-tLwzGw|>FVU!RQb860vK=7@G_c)sz%>yOu>^A}D@dVEFGYVNww4C7N}_b%Uh
zwWC6=?#0b%B6H1V&z_x=n|ty7clki$>{+^Nv_2O+oPFixO1bS5w&Y#bV@|%G=rWHb
ze{tu&%&C)RcC$a!S{<L}@Jw>&orWWYJ|eDR{)?_V^R-JRJU6tlseiEbuU#WYuIj4i
ziwz|v_RgOo!`C)vPu0w=KAf*tPoFliL&ecgZNt8Q9hbu1^=`SH8~5wd^c|mXy>6Lz
z{MIL-?Rj?;gV^*l7MduqF8r|b*SmC!;%7SZf8Tjt@p|p{9i^{9!;;`-rO)5p-MvOf
zfAN+@ck?D5(M)`BIs3PU=*0Ro+sq}`T-@FNynFwLuR1!KgJ-q3t=O$xzDpvxIX5o6
z`x(~2sr~K^tDIZ(dV{l3{&Q|voZOne?&DVZ9}MxI4{^)L$$fh1Uq9>a-Pj&O9ew@9
zlV)6dB_+#}W#RJ6ZevHlT!xy}=f2%3K40|yo^4rKS%BBZJ$ue<|MM{a`NO}zW$IHS
z#ivH_il5)U)^v*BO^fPTv(58AeOSm^v)oe2_iN2_$;M2FtvafIcC;OOy7{=Kc;=f<
zlbssZFQm>3e>h3AXeGzIud`z0HUxF4cy=u6_*ii!!N6h7`p5aXiuXUuT{1~6PjCO1
zaHPomfQNII$f*=3XQvBX%zbXj^Wvh@6BoX&SD9P>=HqvpCkYMPx3a#kuU~lBu=ZSr
z(L?V2pFP8F$6BrK?s+_A?c3Tt3s{{dWpNxfb3e>@{|CGMv9;0LcT|2>n>~9r>x>m!
zpMCf+VeejBv+dh-&dRQKwDJqKSuC+kaAnYoE7yche(Z43JQug?#NoHOdlV9u1ijdr
zd2(Iqv0szs)lc!bfA}-gAA<$EFQ{@jTixZGt{?yK(Npg^HkCpzD`WQ8&6PIK+pu-(
z(Tf)agS<fd>LMc_GRyy#*!zxYZeF|J@@7AwM=FZGqPwfBS>Bp~`V7_8)vm^CjnmJA
z7LZ?xj?t<5%)vO>(`Ent^z7`(&CSm1;`g6>_AITj^USAu=T$#EOJg}-Ih=i*k{Dyd
z6aH#%_Kc_3D~0-Rzgn;N^wlKpdZFuP+VTeZ3nr^18qF*yDLL}*pPkKjnTM;_PpUaC
zpZNb^?YsNC{PbTe=;6O{&qyn{WcsD!5}f;vpZX;=@A>UTd)7}A<aFM1H#TbaY@c<p
zk3U?~WoveHJl*$r#@)O1u^&{W=0|Y7d;8{6Z2Th8wy=N`4%#0o?-##czJ13D>HIx`
zZ+7i03ZJ#C=Xmn3zjnKK@3#5<?)lDNUoLNZ>nd_FtF<Irx90rjQ{PrD+P&pOyWJn&
zmc$d<`uopR*tl^q9!m07dYvuZ;;6`Rg)6#5T#Vze!1>QJeAM2&dsp=TAoIKW`}@!D
zt^UsSSj<(>QNTc|*W>b(&(F_q-m&Y{$;s-GQBjA!*Q!nKeA>jq$S-H3!P9uI>d~4t
zYeZ_RrcIxox&3y=T1mck85x-k`|m%$x3~Jv?(+V-ckep&WZdcqDGgY&XnA<+jn7UU
z%WN}FxtyKP@v-on)T*n(D_66WFzTIlIHOhX{P5D@V^gmiNjsn0t-dyw|K`OEP()Q%
zOYeI*`^Deh{f=Mk|7mX9X14R=vC=CBs)E96jOK5YRZ#s==OA-*P2QTqcYi8(XY8A`
zUSYxCsp~How%yj&{<8na(M2041)cijdMtU}zTbD(tX=o$r``LX2?w0=8SPJ(RLnb`
zV34rz`r~?#qjwg!|NZ+{>D&3^hJDF={QNg>-Fo!t>1mtKZ;I#G)z13*wNy+@Y>h{-
zjChpv<Bv0%oumJhJ-f4W5p(>#R{igPir#3NSKYpSyH(smf(JBKUS7Wa$0^Y_Q#Z9%
zS6c47Hf!->Wixa0?zYH68Dj|^@VfW+;@_v1KbPjIX9ES^=FP!hjt9=vc~oGr<o^53
zn>PnbOsI_WxVk6DDZb#O&aO7a(qC%6#<TS9b-r)PpAvcNF^AQ8=GK_sc{?5`ALr~}
zCVo1>AR#}$|M&Oz#lMy19|o;%{a!u)=<c$q-Ou%lEaoWeVbEmN(oVkaCNBGYo!w^<
zb-y_k?Fnav>(4x0<a}E0?cZPPmH%Cke{}Gh+3(-KSyvl{v)#UbKV32V#@=0f&b)f1
zbvI93QPp#ffrQM$DUZ(0wFb?$-@SV`sa!nL)+g`F@yCX@XU_Wb@1LFa>C-x?QmY&U
zxzsY7%mmVRmkG4B?Cbxs$Em{7T*)i*l8NS?c^1ZMfg+-AnN#XJm7o93FWz+hwq|Z;
zSl8iZW-&3bO&eT9;+|&M=yg<7ez!mWnJc-xqQF6*O^iLT%c83@>Gta94<0<2_)Vbn
zZ{)J)WqrOoB^q{3$%$OL&im-^J@c+^ey(x)RY+&G@BcUEjQ-Cb%KCbLdwnl@so48l
z9miFlT35@uu5Q&-{&ehcdwtBW?)r)M?0>n>`F*>7_WNI#>!o(?c8>Ydaq^sI(bK|!
zQ&P(3zt8XZZISKZBd{Pm>_y$D$!qK?4m^zi|N74VGwEHj#`$k&?0$Mo!tJpk`(I`;
zv0Y(C0@0n)u7Zazo=B4WYj^nK1+6wuPXU&r-}kUSFDP)4ap!4gc4OCmvpq_oe(BRz
zm5odPt`-seaU?Khb>Gq@w=*B7H+cqCO_N9$$z0`eX^P3#AFh*BmS~+d@?G`gX45gQ
z$-ZUw($R`6nIgs^>^<$y#}+Ftl#e*qvF-TmBZiq}e|M@+Ow%fue6q!WgQHnMbB$Kb
zq^R>6U5njQ1fCb#r-?7}Hd~w{y!P}b8@>99SFcRZ3frv;lBsdOKXX}PD>wgQt=`b5
zzEh_9?&jD#C9vl7g-?H~<<5z?J?S;K_`R|J<DHwE=loj!f68C`&*>gv;hc*k9!YH2
z)E0S}QGiJ|=vcF(<F6{E%os(3pr+@FEek%sS{?Ie<@}^S&h|%M^UD|g|5y9%`*-=y
z+rA6Sv+Bhk*6sISetDxr%M=fvZLg216#5uR8A|r9$yvDN?AFk%=s>TQ(8$>ly5aXf
z-|#g}6u9NIRmUXIOYo>5*Y1q92`XEn6uIASTg!CrSbV1IDv`jP%lj-h%w5)*yL#g5
zhKyeRil9e7!)!DHwSp_QuSz==QJ7)OcG>L3m9}M3nHM7KC$Bm4BV+A>i1jBv+i3SJ
z>D6_*q?Ns#^HRjoe~}MAYOUXMhI`)i+bcZ(de3!#J86~fXQvqL($(kQ%jY|rEM2QG
ztHm|dZLwBa_N||JX1!slty6<oJAOPk$h<Cof8N3E_FtFZ_@Q0TTKDGojX&%ENqoGu
zOEg2wI4SkkvdX_@vkPa{E8WVyt?;s9+T*vsuSsojJ7T!^d~IKE{lD{)HHXbNe4qFI
z!?or1XPepiyF{LBX(+g-oN6F(;oLgcwBAKlYX$f{9;*mPZJYABPlUxWf%~4#{cmfg
z3a$M7dV|%b=9G>p)1()LbOn_?^jpNaGVExc*blkI6OS*syik^9n#iPwo>AHL$0l<Y
zx=lX6S7Y+a^{3Vt-8f&z*LvV`*m2X)Q>!-q-uG5XLnTW3k%{Vu+LldCEb~5a7)+a<
zWWtogFLhq|LydOQTvI9Sc}opvnsxar1+Vrr`YQ9fA#ghHCeGczEM9NQ{8f4HSHaSg
z)j_BJU!9s8rTQfJ`0E+HAD^XW#T;o{^(&?RjCI-6uk)^pr_4LP<W}yreV?r@KX&?W
z_^`f?RkrO#Tz}aOr)8XVvxGES*9ZLx5zOeFt};VoneGAaN$&gps2ubT`eSl*_UEU|
zyA*ss_U0B&$jiT2{nk{h?rZqVzjw|X{^)z3@VWnA;Jz<Y*MB&5TEEy{Sn<@y346Zx
z8nmhOtzA+d|IfB-(>HEmHP4tWe|&;(OK>HgesFTel0)AGZ!Ve~bjxtkwXgo6T|q0C
zZcBgnUuBlajJDKrt)7j0yH2u9y|hL<VN#|3WDPZ4n~8f^H5)dBUO3hzS2=I5*za=f
zu-y4G|5{$3;o8w;_5Z{n*57uS)gRg-dnfYxZd_HsRB~-$KzjY(Nu}Ek`mEkPeeKj$
zzFNmU<d%Qg=hv`0i@7|~z4Xbs%GamYGZn;0REGZfwQI)u&RxNila@SwcI`8d@4Ma~
zM^!fOTJrw)=K5*N?^iT`mj7?j9REwzXZ2Ag1F7De%`5J(9ycqxq!#QVKIy>sO?H}6
zJx{0JxVM*0+2x=OYooej&+&SddFQispSAEcNbLTw_kHU7{J*+oRkrtPzKY(f_{;n5
z?q2Wudi&FIDLJQBPH;?DbP;jgrl-o?dC1_%>>E)t@|O2L2z**N*R(b0rfo(JH|Ij$
zsHoaYGRYejWaMnt33OSM6WcpQXlaepT-oyu%P(*AJ>Q#KJyV5K!up-(v0Z1K>kW4&
ztYy6H*~Gb~JYmbpEh(vC_g7quN@&@3VDq(^Zx)@K@@2E)Njvt4_lF&3wdz={7E=4Y
zd*j-VA6j%=rgJI3x{!43>HE|w`BavzR%SmQy9kF)bd;0}k(j9VX19^{FALtiv1^Nj
zkIg-8c$z0#ZZ<z#bJFt*QO0upH}Bqk`fO`<z0KF-|1Fj;?x>qpbm8^Iyw-gEJvqlu
zr=IwfSKfam#%JZ8?l)^wgw5w0Y&6qR;SArzTB!Y@Q>^Mu#@Vye<DY$78=dn$XY=mu
z#~s728+NX_;J+`rYM=kCWk=V|Ny&`XT)SxZQP!lOsX}au^U}prC$^qg7n<1{#+Avk
z@A<-1o>N)%bDr%keph?M^N@<L(YeD7CY~8vqmFDmyJpL#l2zAkeLH%#W!>Tvldkm`
z{<yjI_rCu3x1R+UPI1U!_x3ftbZuwg$sHP%QsD|ln#WgG3xz$=G@U84=;G1hj^NuY
zJ!{ImUhg>@`tw|kjPHcXnbzVqPb@rp)UsE2&Y!h2>wW*`)#ifr)$2YR&62y`YWw0)
z&D?)Ed~VO4s4Nv(e6i#2-`aQg_n&{g+|O1?<IcIN+kWZ1Y3FDA%S>lG_w%=V=Bd3p
z$t4vPC+_Y2os*xxdF$4r@7}F@+cSOQ`eniMf9~AF^I?uT<E1ZeBjPoWM)<ASlX&A)
z0pDxiig`L#S0$M@PGUKxwRrZK`U4tMC#h*p*3i1NrE=DdZ<5<2+$7khNngqmm2-ag
z_vwS2IWMQ*Dz0u-yx6GsL44-hzSf85`;?86HCxxd{aAB<)uGg|T|2&?v9R0Zu=(+m
zdu?BPjNVSjDW1Xm`gKJ}|L(dN@qO8+C#&66n*BiOU*Vn>qi3;mt)gN%>x8vm97>&8
zKYjUp-J^QS%bvEW#QRusW>r_ue)=?3Onhxn*y^i`F6Tv>+xB0*U#NRaYr*uA#`(|f
z#0)EsNu2#D#LmtR+PloM;^nDJH{CpTGR_I#G*AEBorEVhyEHmDnWFphD`m<KK7Ff}
z)A4D=v5Y*HMViW!;=Si>J-Oc5%W;<4H3N;m-|GKQ2~|4%y8cu81nEU8ee#_8>6Vf^
z8Bffw-nYX>Q}@^>4sj=uhtI7mL?Tx#-u!E>P4|@k{LscZnuaF6yoVlFJPR$}#S?9*
z=V4<$XXWOk<BW;3p6r`lAr$(*{N?4q@;^0<&v#eHO_?sf^y$=1Ys0z?cwTO~?drAN
zBK;W`x684{`V%p)4~f>#Ua@TI(~ujocH)woy5e>&pD5k?Cu++z*2b(^4@~C1o^PhN
zIdS%^L(E-gd<AZ#h1`6<S-2*Q|5$>w{mY(o;dGuWGQuZ&LloBww5fQe9WY8Z<BfQw
z6Fj;8{LF)1H#dG*a%RKQ?Tmg?#pTj0x~6R6cxZDzDey8|*cplXh3?MY$->{7m|lcN
z**@}|mdL6ny(nAh(9;>EDi^d;O{ag~vCj5>=|#WSp(dS=XGMfe4{P|WQzluxK~H2=
z^@7WCj(+FQu}-i(zxZz6<KO$1mi(@p=vMp0BJ%mKq(mRx88HXks^YF4QkX0;N6Gx=
z(dArxZgsjp_0}%i!Lxah>E?P>w$QVOmx<T#?R)mHPu4j2flZU-%KbSLpUa)t^4!oi
zy=buvo7oz{hy-JP(IC^Otu~t`FN<8=^=0Cf@<f+sTb_JaX0!Z_;FM{X#lKIgj5(H)
z>$`lDQD&L{=Hlf(8;&2{UAEGse63r((2`?DcHW^LpZNk8X<gXz&Mn5EYm-Ug)%wcU
z9_ghX#ld2)_uNgbdgw2oY$GS$t;^1ESfS>M>A5}Jro5}39Y596G2J&NS!d;`eb+_0
zO+&SUWBt2bt#~I)YpvY;@`To>`?qfj#I{)eEZnQ}RD07hziE>fZr-*)Y<Yvb^Yojo
zQ{vMfGM+6;+%(<mveFWbu>W(?S1)h4`lrUIUU^@r;E`qGKTBqq=T<!Ly}u<qD)iC^
z74ERrW-qi>RbBqDTxWKO>&_Y5SnF;o)!k9s|2anW`aY9T?mJ8OEj!7q!(F*5>GaF>
zHOtT0HlOJ4j=k%b6S&0x^Ox+8H_s$^DCVT4pAt5l**+;*iz$$y<MQsKd)h8sK9+c^
z<IL*$Gmh!iryX8&Q)2%CNuvYB-)t^x-j94cqcZO8p6AxK>q3))Hs8DRhN=3C<cac@
zlF!GozwKMTadS=0vsTm4%vf=o4W|xFue=lb!*lYwsiC%;V&5OsPky*FDD!lW<J9yE
zDqmI>9bT=ICcI(WnY-(S@0`7R_a&#bzH|`VGqK&bWbQ^z{W|Mpefh1IM~%4Irlqc4
zwS(jGb)(%YK0iKZe9Kk%?VG4&yqDKB&bB-MWvgGc*5>mCw=}}uuDX0a@s{!F-Wy-G
zKL0=8?)aWJ4@)F0Ur+VBe|wMBOf8<pt1|Mf=ByDa&f8=-O;z&Mm!Q=jPHTx)@8^3{
zIcJ}~o@M@ZyS?jpclI~yU6(whRo|al7UbuD&n9H%S*A0_Zkzcl=FND&XU5i3%Co;R
zoXS!^CDj{hJ3I10SykawPC@^6?#<878uny12dH`2)ULB>nOQ5By1OD$bshJ=3DTb*
zrv$Is!*@OHww{xFYSbFvUmvEe?e*%tx~t&W(q~IwS)_gpn<}xkd-wMpY-{!QtYS*4
zPrq+2>+N67w^`}J=Ia)(V}0}|-DEY^pOYoT9{w@qndGEM|0O*?rszMq`TcyG!B3|-
z&wbB+_Inn4-G=S?mxyyx6C?Qx%>K+i8u^Tq$+tQ#^!tsL{|~toO%^)rSTkSkbLzdQ
z8RljCx~-p_V%C&Cu&L`-<+?k2I*rcC=w|=8yv3k?y_U~PBa76~1EIU$ud%k7%{c36
z{+YDH%gP_C<vKn$4PDRt>{)C1=RK1upFaA0EN7nLEYpzBd-mKs8rQz^%<SElkFOJw
zC_j2R%}{mvhsAy3PqaD%&D#5e7hG?-9lG6bPL$h}g+Eg_h6lend{pWB)u%GsUxr?0
z4^T4-zUH5Pty`nM`{n6Fb1QE&c}F~+Ww-uQK+JAov%=0;vA~;;R(?)fedyw@3+qoQ
zul{T`%j9_3#h00v^tZp;7i05Ft#hJLvhM7Z=vTkm%|w}sR3C*z{@5g~tDR95RBGiL
zRb_T?+N(o{RwbJ~y)#8}^)8>#tCp*8X@;~Wg?_g=pD``btMucaEzj%2MT6}70`<7-
zV|hYvRuvuOcrEgO6;EJnYyMT6Y3nBM(n~AyO_vSN-sH3PR;j@376ZNa`j@RTPetTR
zYF)AGy_U|w*4r1BWL-`*+?iljnjH3hPVBKGPb)+AuIHMQH_L0SbbYx0W6zaOWz!eW
zp8YekXwoK=#GC8h2x;$P*s(5iP5mzEyd;NL40h8?HmtUO#WiJDQ}O4d=T^V!BP&Yh
z%>8fCb~p9&io=Slj%{2i9{AL8N1MoT%kACbk*#m9<T~kjPTpi0B&Otf-SdH0$;`U-
zt3A9zZ{^OrG2!(STfM|}J{xzRYY3H;x_<KUth-r8k*Dp<z2{i*?R&KAbeQeyn_|m+
z>&pYL3+(h{e!I%xUh2iGlDC$XuuM<3^|Xzj&Y^t#{SxiA!Wi#&QhK4fXVm1pCl_Da
zIkj~6w$mGD_s#7NTyxm{)SfoA19MJSge-j?YqQnp*{apy)pvGY-*VxzXUXE#uk;^h
z#k?{Ly1sAMI=O_YcITCS&-7={jM2NIDwaFztfk(u`iHxWZ8)8uKH}TGp?db4MS6N`
zUq8weTII8R!|XR5dPjCXmb$-8GhEzfxu?;BlUwE0uN2-r(r4WMJh!3r;i8;fKb}|e
z9q%kX{phvYmg4KNSFbvlaI&vz*s-jzDzYLlEoYV3Ya2gLN$agye@?$E{Pypa#(m$-
zGO2qeTJfLxS|578{!!rv>FGV*vTENf7)mGqwpsT)<k{B~$9tFWlj5B<OT%}!)V9iX
z3Bk^R$8<Fg>z&%eJKZy4+4{)zme{h3M&Ucxt#t@p`t|XL&{Z#fq&|K#>)g8F@b!yz
zO>WNVdpvV`==9xQ3TA;?*{=@nYFN*3>FVN)CS4oOfa6O`_OIOjMCpEg{G1%$$%Z+T
z-s@{WUO!tS)l~WOx`jE<S52;5ar<mK@12|-kDUxkPO|KjSh1_?`m)3#+5Sa(!k1Jg
tKR>iLtBHT-micS580_-z{`t?$z*AUZvgoN;9|HpegQu&X%Q~loCIEb%+DHHZ

delta 8806
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

diff --git a/src/Jackett/Indexers/FrenchADN.cs b/src/Jackett/Indexers/FrenchADN.cs
index 58238ce2..db57edf3 100644
--- a/src/Jackett/Indexers/FrenchADN.cs
+++ b/src/Jackett/Indexers/FrenchADN.cs
@@ -1,966 +1,987 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Globalization;
-using System.Linq;
-using System.Reflection;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using CsQuery;
-using Jackett.Models;
-using Jackett.Models.IndexerConfig.Bespoke;
-using Jackett.Services;
-using Jackett.Utils;
-using Jackett.Utils.Clients;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using NLog;
-
-namespace Jackett.Indexers
-{
-    /// <summary>
-    /// Provider for French-ADN Private Tracker
-    /// </summary>
-    public class FrenchADN : BaseIndexer, IIndexer
-    {
-        private string LoginUrl { get { return SiteLink + "login.php?"; } }
-        private string LoginCheckUrl { get { return SiteLink + "takelogin.php"; } }
-        private string SearchUrl { get { return SiteLink + "browse.php"; } }
-        private string TorrentCommentUrl { get { return SiteLink + "details.php?id={id}#comments"; } }
-        private string TorrentDescriptionUrl { get { return SiteLink + "details.php?id={id}"; } }
-        private string TorrentDownloadUrl { get { return SiteLink + "download.php?id={id}"; } }
-        private string TorrentThanksUrl { get { return SiteLink + "takethanks.php"; } }
-        private bool Latency { get { return ConfigData.Latency.Value; } }
-        private bool DevMode { get { return ConfigData.DevMode.Value; } }
-        private bool CacheMode { get { return ConfigData.HardDriveCache.Value; } }
-        private string directory { get { return System.IO.Path.GetTempPath() + "Jackett\\" + MethodBase.GetCurrentMethod().DeclaringType.Name + "\\"; } }
-
-        private Dictionary<string, string> emulatedBrowserHeaders = new Dictionary<string, string>();
-        private CQ fDom = null;
-
-        private ConfigurationDataFrenchADN ConfigData
-        {
-            get { return (ConfigurationDataFrenchADN)configData; }
-            set { base.configData = value; }
-        }
-
-        public FrenchADN(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps)
-            : base(
-                name: "French-ADN",
-                description: "Your French Family Provider",
-                link: "https://french-adn.com/",
-                caps: new TorznabCapabilities(),
-                manager: i,
-                client: w,
-                logger: l,
-                p: ps,
-                downloadBase: "https://french-adn.com/download.php?id=",
-                configData: new ConfigurationDataFrenchADN())
-        {
-            // Clean capabilities
-            TorznabCaps.Categories.Clear();
-
-            // Movies
-            AddCategoryMapping("15", TorznabCatType.Movies);            // ALL
-            AddCategoryMapping("108", TorznabCatType.MoviesSD);         // TS CAM
-            AddCategoryMapping("25", TorznabCatType.MoviesSD);          // BDRIP
-            AddCategoryMapping("56", TorznabCatType.MoviesSD);          // BRRIP
-            AddCategoryMapping("16", TorznabCatType.MoviesSD);          // DVDRIP
-            AddCategoryMapping("49", TorznabCatType.MoviesDVD);         // TVRIP
-            AddCategoryMapping("102", TorznabCatType.MoviesWEBDL);      // WEBRIP
-            AddCategoryMapping("105", TorznabCatType.MoviesHD);         // 1080P
-            AddCategoryMapping("104", TorznabCatType.MoviesHD);         // 720P
-            AddCategoryMapping("17", TorznabCatType.MoviesDVD);         // DVD R
-            AddCategoryMapping("21", TorznabCatType.MoviesDVD);         // DVD R5
-            AddCategoryMapping("112", TorznabCatType.MoviesDVD);        // DVD REMUX
-            AddCategoryMapping("107", TorznabCatType.Movies3D);         // 3D
-            AddCategoryMapping("113", TorznabCatType.MoviesBluRay);     // BLURAY
-            AddCategoryMapping("118", TorznabCatType.MoviesHD);         // MHD
-
-            // Series
-            AddCategoryMapping("41", TorznabCatType.TV);                // ALL
-            AddCategoryMapping("43", TorznabCatType.TV);                // VF
-            AddCategoryMapping("44", TorznabCatType.TV);                // VOSTFR
-            AddCategoryMapping("42", TorznabCatType.TV);                // PACK
-
-            // TV
-            AddCategoryMapping("110", TorznabCatType.TV);               // SHOWS
-
-            // Anime
-            AddCategoryMapping("109", TorznabCatType.TVAnime);          // ANIME
-
-            // Manga
-            AddCategoryMapping("119", TorznabCatType.TVAnime);          // MANGA
-
-            // Documentaries
-            AddCategoryMapping("114", TorznabCatType.TVDocumentary);    // DOCUMENTARY
-
-            // Music
-            AddCategoryMapping("22", TorznabCatType.Audio);             // ALL
-            AddCategoryMapping("24", TorznabCatType.AudioLossless);     // FLAC
-            AddCategoryMapping("23", TorznabCatType.AudioMP3);          // MP3
-
-            // Games
-            AddCategoryMapping("33", TorznabCatType.PCGames);           // ALL
-            AddCategoryMapping("45", TorznabCatType.PCGames);           // PC GAMES
-            AddCategoryMapping("93", TorznabCatType.Console3DS);        // 3DS
-            AddCategoryMapping("94", TorznabCatType.Console);           // PS2
-            AddCategoryMapping("93", TorznabCatType.ConsolePS3);        // PS3
-            AddCategoryMapping("95", TorznabCatType.ConsolePSP);        // PSP
-            AddCategoryMapping("35", TorznabCatType.ConsolePS3);        // WII
-
-            // Applications
-            AddCategoryMapping("11", TorznabCatType.PC);                // ALL
-            AddCategoryMapping("12", TorznabCatType.PC);                // APPS WINDOWS
-            AddCategoryMapping("97", TorznabCatType.PCMac);             // APPS MAC
-            AddCategoryMapping("98", TorznabCatType.PC);                // APPS LINUX
-
-            // Books
-            AddCategoryMapping("115", TorznabCatType.BooksEbook);       // EBOOK
-            AddCategoryMapping("114", TorznabCatType.BooksComics);      // COMICS
-
-            // Other
-            AddCategoryMapping("103", TorznabCatType.Other);            // STAFF
-        }
-
-        /// <summary>
-        /// Configure our FADN Provider
-        /// </summary>
-        /// <param name="configJson">Our params in Json</param>
-        /// <returns>Configuration state</returns>
-        public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
-        {
-            // Retrieve config values set by Jackett's user
-            ConfigData.LoadValuesFromJson(configJson);
-
-            // Check & Validate Config
-            validateConfig();
-
-            // Setting our data for a better emulated browser (maximum security)
-            // TODO: Encoded Content not supported by Jackett at this time
-            // emulatedBrowserHeaders.Add("Accept-Encoding", "gzip, deflate");
-
-            // If we want to simulate a browser
-            if (ConfigData.Browser.Value)
-            {
-
-                // Clean headers
-                emulatedBrowserHeaders.Clear();
-
-                // Inject headers
-                emulatedBrowserHeaders.Add("Accept", ConfigData.HeaderAccept.Value);
-                emulatedBrowserHeaders.Add("Accept-Language", ConfigData.HeaderAcceptLang.Value);
-                emulatedBrowserHeaders.Add("DNT", Convert.ToInt32(ConfigData.HeaderDNT.Value).ToString());
-                emulatedBrowserHeaders.Add("Upgrade-Insecure-Requests", Convert.ToInt32(ConfigData.HeaderUpgradeInsecure.Value).ToString());
-                emulatedBrowserHeaders.Add("User-Agent", ConfigData.HeaderUserAgent.Value);
-            }
-
-            // Build WebRequest for index
-            var myIndexRequest = new WebRequest()
-            {
-                Type = RequestType.GET,
-                Url = SiteLink,
-                Headers = emulatedBrowserHeaders
-            };
-
-            // Get index page for cookies
-            output("\nGetting index page (for cookies).. with " + SiteLink);
-            var indexPage = await webclient.GetString(myIndexRequest);
-
-             // Building login form data
-             var pairs = new Dictionary<string, string> {
-                { "username", ConfigData.Username.Value },
-                { "password", ConfigData.Password.Value }
-            };
-
-            // Build WebRequest for login
-            var myRequestLogin = new WebRequest()
-            {
-                Type = RequestType.GET,
-                Url = LoginUrl,
-                Headers = emulatedBrowserHeaders,
-                Cookies = indexPage.Cookies,
-                Referer = SiteLink
-            };
-
-            // Get login page -- (not used, but simulation needed by tracker security's checks)
-            latencyNow();
-            output("\nGetting login page (user simulation).. with " + LoginUrl);
-            var loginPage = await webclient.GetString(myRequestLogin);
-
-            // Build WebRequest for submitting authentification
-            var request = new WebRequest()
-            {
-                PostData = pairs,
-                Referer = LoginUrl,
-                Type = RequestType.POST,
-                Url = LoginCheckUrl,
-                Headers = emulatedBrowserHeaders,
-                Cookies = indexPage.Cookies,
-   
-            };
-
-            // Perform loggin
-            latencyNow();
-            output("\nPerform loggin.. with " + LoginCheckUrl);
-            var response = await webclient.GetString(request);
-
-            // Test if we are logged in
-            await ConfigureIfOK(response.Cookies, !string.IsNullOrEmpty(response.Cookies) && !response.IsRedirect, () =>
-            {
-                // Default error message
-                string message = "Error during attempt !";
-
-                // Parse redirect header
-                string redirectTo = response.RedirectingTo;
-
-                // Analyzer error code
-                if(redirectTo.Contains("login.php?error=4"))
-                {
-                    // Set message
-                    message = "Wrong username or password !";
-                }
-
-                // Oops, unable to login
-                output("-> Login failed: " + message, "error");
-                throw new ExceptionWithConfigData("Login failed: " + message, configData);
-            });
-
-            output("\nCookies saved for future uses...");
-            ConfigData.CookieHeader.Value = indexPage.Cookies + " " + response.Cookies + " ts_username=" + ConfigData.Username.Value;
-
-            output("\n-> Login Success\n");
-
-            return IndexerConfigurationStatus.RequiresTesting;
-        }
-
-        /// <summary>
-        /// Execute our search query
-        /// </summary>
-        /// <param name="query">Query</param>
-        /// <returns>Releases</returns>
-        public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
-        {
-            var releases = new List<ReleaseInfo>();
-            var torrentRowList = new List<CQ>();
-            var searchTerm = query.GetQueryString();
-            var searchUrl = SearchUrl;
-            int nbResults = 0;
-            int pageLinkCount = 0;
-
-            // Check cache first so we don't query the server (if search term used or not in dev mode)
-            if (!DevMode && !string.IsNullOrEmpty(searchTerm))
-            {
-                lock (cache)
-                {
-                    // Remove old cache items
-                    CleanCache();
-
-                    // Search in cache
-                    var cachedResult = cache.Where(i => i.Query == searchTerm).FirstOrDefault();
-                    if (cachedResult != null)
-                        return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray();
-                }
-            }
-
-            // Build our query
-            var request = buildQuery(searchTerm, query, searchUrl);
-
-            // Getting results & Store content
-            WebClientStringResult results = await queryExec(request);
-            fDom = results.Content;
-
-            try
-            {
-                // Find torrent rows
-                var firstPageRows = findTorrentRows();
-
-                // Add them to torrents list
-                torrentRowList.AddRange(firstPageRows.Select(fRow => fRow.Cq()));
-
-                // Check if there are pagination links at bottom
-                Boolean pagination = (fDom["#quicknavpage_menu"].Length != 0);
-
-                // If pagination available
-                if (pagination)
-                {
-                    // Retrieve available pages (3 pages shown max)
-                    pageLinkCount = fDom["#navcontainer_f:first > ul"].Find("a").Not(".smalltext").Not("#quicknavpage").Length;
-
-                    // Last button ? (So more than 3 page are available)
-                    Boolean more = (fDom["#navcontainer_f:first > ul"].Find("a.smalltext").Length > 1); ;
-                
-                    // More page than 3 pages ?
-                    if (more)
-                    {
-                        // Get total page count from last link
-                        pageLinkCount = ParseUtil.CoerceInt(Regex.Match(fDom["#navcontainer_f:first > ul"].Find("a:eq(4)").Attr("href").ToString(), @"\d+").Value);
-                    }
-
-                    // Calculate average number of results (based on torrents rows lenght on first page)
-                    nbResults = firstPageRows.Count() * pageLinkCount;
-                }
-                else {
-                    nbResults = 1;
-                    pageLinkCount = 1;
-
-                    // Check if we have a minimum of one result
-                    if (firstPageRows.Length > 1)
-                    {
-                        // Retrieve total count on our alone page
-                        nbResults = firstPageRows.Count();
-                    }
-                    else
-                    {
-                        // Check if no result
-                        if(torrentRowList.First().Find("td").Length == 1)
-                        {
-                            // No results found
-                            output("\nNo result found for your query, please try another search term ...\n", "info");
-
-                            // No result found for this query
-                            return releases;
-                        }
-                    }
-                }
-                output("\nFound " + nbResults + " result(s) (+/- " + firstPageRows.Length + ") in " + pageLinkCount + " page(s) for this query !");
-                output("\nThere are " + firstPageRows.Length + " results on the first page !");
-
-                // If we have a term used for search and pagination result superior to one
-                if (!string.IsNullOrWhiteSpace(query.GetQueryString()) && pageLinkCount > 1)
-                {
-                    // Starting with page #2
-                    for (int i = 2; i <= Math.Min(Int32.Parse(ConfigData.Pages.Value), pageLinkCount); i++)
-                    {
-                        output("\nProcessing page #" + i);
-
-                        // Request our page
-                        latencyNow();
-
-                        // Build our query -- Minus 1 to page due to strange pagination number on tracker side, starting with page 0...
-                        var pageRequest = buildQuery(searchTerm, query, searchUrl, i);
-
-                        // Getting results & Store content
-                        WebClientStringResult pageResults = await queryExec(pageRequest);
-
-                        // Assign response
-                        fDom = pageResults.Content;
-
-                        // Process page results
-                        var additionalPageRows = findTorrentRows();
-
-                        // Add them to torrents list
-                        torrentRowList.AddRange(additionalPageRows.Select(fRow => fRow.Cq()));
-                    }
-                }
-
-                // Loop on results
-                foreach (CQ tRow in torrentRowList)
-                {
-                    output("\n=>> Torrent #" + (releases.Count + 1));
-
-                    // ID
-                    int id = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(1) > div:first > a").Attr("name").ToString(), @"\d+").Value);
-                    output("ID: " + id);
-
-                    // Check if torrent is not nuked by tracker or rulez, can't download it
-                    if (tRow.Find("td:eq(2) > a").Length == 0)
-                    {
-                        // Next item
-                        output("Torrent is nuked, we can't download it, going to next torrent...");
-                        continue;
-                    }
-
-                    // Release Name
-                    string name = tRow.Find("td:eq(2) > a").Attr("title").ToString().Substring(24).Trim();
-                    output("Release: " + name);
-
-                    // Category
-                    int categoryID = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(0) > a").Attr("href").ToString(), @"\d+").Value);
-                    string categoryName = tRow.Find("td:eq(0) > a > img").Attr("title").Split(new[] { ':' }, 2)[1].Trim().ToString();
-                    output("Category: " + MapTrackerCatToNewznab(categoryID.ToString()) + " (" + categoryID + " - " + categoryName + ")");
-
-                    // Seeders
-                    int seeders = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(5) > div > font").Select(s => Regex.Replace(s.ToString(), "<.*?>", String.Empty)).ToString(), @"\d+").Value);
-                    output("Seeders: " + seeders);
-
-                    // Leechers
-                    int leechers = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(6) > div > font").Text().ToString(), @"\d+").Value);
-                    output("Leechers: " + leechers);
-
-                    // Completed
-                    int completed = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(4)").Text().ToString(), @"\d+").Value);
-                    output("Completed: " + completed);
-
-                    // Files
-                    int files = 1;
-                    if (tRow.Find("td:eq(3) > a").Length == 1)
-                    {
-                        files = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(3) > a").Text().ToString(), @"\d+").Value);
-                    }
-                    output("Files: " + files);
-
-                    // Health
-                    int percent = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(7) > img").Attr("src").ToString(), @"\d+").Value) * 10;
-                    output("Health: " + percent + "%");
-
-                    // Size
-                    string humanSize = tRow.Find("td:eq(8)").Text().ToString().ToLowerInvariant();
-                    long size = ReleaseInfo.GetBytes(humanSize);
-                    output("Size: " + humanSize + " (" + size + " bytes)");
-
-                    // Date & IMDB & Genre
-                    string infosData = tRow.Find("td:eq(1) > div:last").Text().ToString();
-                    IList<string> infosList = Regex.Split(infosData, "\\|").ToList();
-                    IList<string> infosTorrent = infosList.Select(s => s.Split(new[] { ':' }, 2)[1].Trim()).ToList();
-
-                    // --> Date
-                    DateTime date = formatDate(infosTorrent.First());
-                    output("Released on: " + date.ToLocalTime().ToString());
-
-                    // --> Genre
-                    string genre = infosTorrent.Last();
-                    output("Genre: " + genre);
-
-                    // Torrent Details URL
-                    Uri detailsLink = new Uri(TorrentDescriptionUrl.Replace("{id}", id.ToString()));
-                    output("Details: " + detailsLink.AbsoluteUri);
-
-                    // Torrent Comments URL
-                    Uri commentsLink = new Uri(TorrentCommentUrl.Replace("{id}", id.ToString()));
-                    output("Comments Link: " + commentsLink.AbsoluteUri);
-
-                    // Torrent Download URL
-                    Uri downloadLink = new Uri(TorrentDownloadUrl.Replace("{id}", id.ToString()));
-                    output("Download Link: " + downloadLink.AbsoluteUri);
-
-                    // Building release infos
-                    var release = new ReleaseInfo();
-                    release.Category = MapTrackerCatToNewznab(categoryID.ToString());
-                    release.Title = name;
-                    release.Seeders = seeders;
-                    release.Peers = seeders + leechers;
-                    release.MinimumRatio = 1;
-                    release.MinimumSeedTime = 172800;
-                    release.PublishDate = date;
-                    release.Size = size;
-                    release.Guid = detailsLink;
-                    release.Comments = commentsLink;
-                    release.Link = downloadLink;
-                    releases.Add(release);
-                }
-
-            }
-            catch (Exception ex)
-            {
-                OnParseError("Error, unable to parse result \n" + ex.StackTrace, ex);
-            }
-
-            // Return found releases
-            return releases;
-        }
-
-        /// <summary>
-        /// Build query to process
-        /// </summary>
-        /// <param name="term">Term to search</param>
-        /// <param name="query">Torznab Query for categories mapping</param>
-        /// <param name="url">Search url for provider</param>
-        /// <param name="page">Page number to request</param>
-        /// <returns>URL to query for parsing and processing results</returns>
-        private string buildQuery(string term, TorznabQuery query, string url, int page = 0)
-        {
-            var parameters = new NameValueCollection();
-            List<string> categoriesList = MapTorznabCapsToTrackers(query);
-
-            // Building our tracker query
-            parameters.Add("do", "search");
-
-            // If search term provided
-            if (!string.IsNullOrWhiteSpace(term))
-            {
-                // Add search term ~~ Strange search engine, need to replace space with dot for results !
-                parameters.Add("keywords", term.Replace(' ', '.'));
-            }
-            else
-            {
-                // Showing all torrents (just for output function)
-                parameters.Add("keywords", "");
-                term = "all";
-            }
-
-            // Adding requested categories
-            if(categoriesList.Count > 0)
-            {
-                // Add categories
-                parameters.Add("category", String.Join(",", categoriesList));
-            }
-            else
-            {
-                // Add empty category parameter
-                parameters.Add("category", "");
-            }
-
-            // Building our tracker query
-            parameters.Add("search_type", "t_name");
-
-            // Check if we are processing a new page
-            if (page > 1)
-            {
-                // Adding page number to query
-                parameters.Add("page", page.ToString());
-            }
-
-            // Building our query
-            url += "?" + parameters.GetQueryString();
-
-            output("\nBuilded query for \"" + term + "\"... " + url);
-
-            // Return our search url
-            return url;
-        }
-
-        /// <summary>
-        /// Switch Method for Querying
-        /// </summary>
-        /// <param name="request">URL created by Query Builder</param>
-        /// <returns>Results from query</returns>
-        private async Task<WebClientStringResult> queryExec(string request)
-        {
-            WebClientStringResult results = null;
-
-            // Switch in we are in DEV mode with Hard Drive Cache or not
-            if (DevMode && CacheMode)
-            {
-                // Check Cache before querying and load previous results if available
-                results = await queryCache(request);
-            }
-            else
-            {
-                // Querying tracker directly
-                results = await queryTracker(request);
-            }
-            return results;
-        }
-
-        /// <summary>
-        /// Get Torrents Page from Cache by Query Provided
-        /// </summary>
-        /// <param name="request">URL created by Query Builder</param>
-        /// <returns>Results from query</returns>
-        private async Task<WebClientStringResult> queryCache(string request)
-        {
-            WebClientStringResult results = null;
-
-            // Create Directory if not exist
-            System.IO.Directory.CreateDirectory(directory);
-
-            // Clean Storage Provider Directory from outdated cached queries
-            cleanCacheStorage();
-
-            // Create fingerprint for request
-            string file = directory + request.GetHashCode() + ".json";
-
-            // Checking modes states
-            if (System.IO.File.Exists(file))
-            {
-                // File exist... loading it right now !
-                output("Loading results from hard drive cache ..." + request.GetHashCode() + ".json");
-                results = JsonConvert.DeserializeObject<WebClientStringResult>(System.IO.File.ReadAllText(file));
-            }
-            else
-            {
-                // No cached file found, querying tracker directly
-                results = await queryTracker(request);
-
-                // Cached file didn't exist for our query, writing it right now !
-                output("Writing results to hard drive cache ..." + request.GetHashCode() + ".json");
-                System.IO.File.WriteAllText(file, JsonConvert.SerializeObject(results));
-            }
-            return results;
-        }
-
-        /// <summary>
-        /// Get Torrents Page from Tracker by Query Provided
-        /// </summary>
-        /// <param name="request">URL created by Query Builder</param>
-        /// <returns>Results from query</returns>
-        private async Task<WebClientStringResult> queryTracker(string request)
-        {
-            WebClientStringResult results = null;
-
-            // Cache mode not enabled or cached file didn't exist for our query
-            output("\nQuerying tracker for results....");
-
-            // Request our first page
-            latencyNow();
-            results = await RequestStringWithCookiesAndRetry(request, ConfigData.CookieHeader.Value, SearchUrl, emulatedBrowserHeaders);
-
-            // Return results from tracker
-            return results;
-        }
-
-        /// <summary>
-        /// Clean Hard Drive Cache Storage
-        /// </summary>
-        /// <param name="force">Force Provider Folder deletion</param>
-        private void cleanCacheStorage(Boolean force = false)
-        {
-            // Check cleaning method
-            if (force)
-            {
-                // Deleting Provider Storage folder and all files recursively
-                output("\nDeleting Provider Storage folder and all files recursively ...");
-
-                // Check if directory exist
-                if (System.IO.Directory.Exists(directory))
-                {
-                    // Delete storage directory of provider
-                    System.IO.Directory.Delete(directory, true);
-                    output("-> Storage folder deleted successfully.");
-                }
-                else
-                {
-                    // No directory, so nothing to do
-                    output("-> No Storage folder found for this provider !");
-                }
-            }
-            else
-            {
-                int i = 0;
-                // Check if there is file older than ... and delete them
-                output("\nCleaning Provider Storage folder... in progress.");
-                System.IO.Directory.GetFiles(directory)
-                .Select(f => new System.IO.FileInfo(f))
-                .Where(f => f.LastAccessTime < DateTime.Now.AddMilliseconds(-Convert.ToInt32(ConfigData.HardDriveCacheKeepTime.Value)))
-                .ToList()
-                .ForEach(f => {
-                    output("Deleting cached file << " + f.Name + " >> ... done.");
-                    f.Delete();
-                    i++;
-                });
-
-                // Inform on what was cleaned during process
-                if (i > 0)
-                {
-                    output("-> Deleted " + i + " cached files during cleaning.");
-                }
-                else {
-                    output("-> Nothing deleted during cleaning.");
-                }
-            }
-        }
-
-        /// <summary>
-        /// Generate a random fake latency to avoid detection on tracker side
-        /// </summary>
-        private void latencyNow()
-        {
-            // Need latency ?
-            if (Latency)
-            {
-                // Generate a random value in our range
-                var random = new Random(DateTime.Now.Millisecond);
-                int waiting = random.Next(Convert.ToInt32(ConfigData.LatencyStart.Value), Convert.ToInt32(ConfigData.LatencyEnd.Value));
-                output("\nLatency Faker => Sleeping for " + waiting + " ms...");
-
-                // Sleep now...
-                System.Threading.Thread.Sleep(waiting);
-            }
-        }
-
-        /// <summary>
-        /// Find torrent rows in search pages
-        /// </summary>
-        /// <returns>JQuery Object</returns>
-        private CQ findTorrentRows()
-        {
-            // Return all occurencis of torrents found
-            return fDom["#showcontents > table > tbody > tr:not(:first)"];
-        }
-
-        /// <summary>
-        /// Format Date to DateTime
-        /// </summary>
-        /// <param name="clock"></param>
-        /// <returns>A DateTime</returns>
-        private DateTime formatDate(string clock)
-        {
-            DateTime date;
-
-            // Switch from date format
-            if(clock.Contains("Aujourd'hui") || clock.Contains("Hier"))
-            {
-                // Get hours & minutes
-                IList<int> infosClock = clock.Split(':').Select(s => ParseUtil.CoerceInt(Regex.Match(s, @"\d+").Value)).ToList();
-
-                // Ago date with today
-                date = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, Convert.ToInt32(infosClock[0]), Convert.ToInt32(infosClock[1]), DateTime.Now.Second);
-
-                // Set yesterday if necessary
-                if (clock.Contains("Hier"))
-                {
-                    // Remove one day from date
-                    date.AddDays(-1);
-                }
-            }
-            else
-            {
-                // Parse Date if full
-                date = DateTime.ParseExact(clock, "MM-dd-yyyy HH:mm", CultureInfo.GetCultureInfo("fr-FR"), DateTimeStyles.AssumeLocal);
-            }
-
-            return date.ToUniversalTime();
-        }
-
-        /// <summary>
-        /// Download torrent file from tracker
-        /// </summary>
-        /// <param name="link">URL string</param>
-        /// <returns></returns>
-        public async override Task<byte[]> Download(Uri link)
-        {
-            var dl = link.AbsoluteUri;
-            // This tracker need to thanks Uploader before getting torrent file...
-            output("\nThis tracker needs you to thank uploader before downloading torrent!");
-
-            // Retrieving ID from link provided
-            int id = ParseUtil.CoerceInt(Regex.Match(link.AbsoluteUri, @"\d+").Value);
-            output("Torrent Requested ID: " + id);
-
-            // Building login form data
-            var pairs = new Dictionary<string, string> {
-                { "torrentid", id.ToString() },
-                { "_", string.Empty } // ~~ Strange, blank param...
-            };
-
-            // Add emulated XHR request
-            emulatedBrowserHeaders.Add("X-Prototype-Version", "1.6.0.3");
-            emulatedBrowserHeaders.Add("X-Requested-With", "XMLHttpRequest");
-
-            // Build WebRequest for thanks
-            var myRequestThanks = new WebRequest()
-            {
-                Type = RequestType.POST,
-                PostData = pairs,
-                Url = TorrentThanksUrl,
-                Headers = emulatedBrowserHeaders,
-                Cookies = ConfigData.CookieHeader.Value,
-                Referer = TorrentDescriptionUrl.Replace("{id}", id.ToString())
-            };
-
-            // Get thanks page -- (not used, just for doing a request)
-            latencyNow();
-            output("Thanks user, to get download link for our torrent.. with " + TorrentThanksUrl);
-            var thanksPage = await webclient.GetString(myRequestThanks);
-
-            // Get torrent file now
-            output("Getting torrent file now....");
-            var response = await base.Download(link);
-
-            // Remove our XHR request header
-            emulatedBrowserHeaders.Remove("X-Prototype-Version");
-            emulatedBrowserHeaders.Remove("X-Requested-With");
-
-            // Return content
-            return response;
-        }
-
-        /// <summary>
-        /// Output message for logging or developpment (console)
-        /// </summary>
-        /// <param name="message">Message to output</param>
-        /// <param name="level">Level for Logger</param>
-        private void output(string message, string level = "debug")
-        {
-            // Check if we are in dev mode
-            if (DevMode)
-            {
-                // Output message to console
-                Console.WriteLine(message);
-            }
-            else
-            {
-                // Send message to logger with level
-                switch (level)
-                {
-                    default:
-                        goto case "debug";
-                    case "debug":
-                        // Only if Debug Level Enabled on Jackett
-                        if (Engine.Logger.IsDebugEnabled)
-                        {
-                            logger.Debug(message);
-                        }
-                        break;
-                    case "info":
-                        logger.Info(message);
-                        break;
-                    case "error":
-                        logger.Error(message);
-                        break;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Validate Config entered by user on Jackett
-        /// </summary>
-        private void validateConfig()
-        {
-            output("\nValidating Settings ... \n");
-
-            // Check Username Setting
-            if (string.IsNullOrEmpty(ConfigData.Username.Value))
-            {
-                throw new ExceptionWithConfigData("You must provide a username for this tracker to login !", ConfigData);
-            }
-            else
-            {
-                output("Validated Setting -- Username (auth) => " + ConfigData.Username.Value.ToString());
-            }
-
-            // Check Password Setting
-            if (string.IsNullOrEmpty(ConfigData.Password.Value))
-            {
-                throw new ExceptionWithConfigData("You must provide a password with your username for this tracker to login !", ConfigData);
-            }
-            else
-            {
-                output("Validated Setting -- Password (auth) => " + ConfigData.Password.Value.ToString());
-            }
-
-            // Check Max Page Setting
-            if (!string.IsNullOrEmpty(ConfigData.Pages.Value))
-            {
-                try
-                {
-                    output("Validated Setting -- Max Pages => " + Convert.ToInt32(ConfigData.Pages.Value));
-                }
-                catch (Exception)
-                {
-                    throw new ExceptionWithConfigData("Please enter a numeric maximum number of pages to crawl !", ConfigData);
-                }
-            }
-            else
-            {
-                throw new ExceptionWithConfigData("Please enter a maximum number of pages to crawl !", ConfigData);
-            }
-
-            // Check Latency Setting
-            if (ConfigData.Latency.Value)
-            {
-                output("\nValidated Setting -- Latency Simulation enabled");
-
-                // Check Latency Start Setting
-                if (!string.IsNullOrEmpty(ConfigData.LatencyStart.Value))
-                {
-                    try
-                    {
-                        output("Validated Setting -- Latency Start => " + Convert.ToInt32(ConfigData.LatencyStart.Value));
-                    }
-                    catch (Exception)
-                    {
-                        throw new ExceptionWithConfigData("Please enter a numeric latency start in ms !", ConfigData);
-                    }
-                }
-                else
-                {
-                    throw new ExceptionWithConfigData("Latency Simulation enabled, Please enter a start latency !", ConfigData);
-                }
-
-                // Check Latency End Setting
-                if (!string.IsNullOrEmpty(ConfigData.LatencyEnd.Value))
-                {
-                    try
-                    {
-                        output("Validated Setting -- Latency End => " + Convert.ToInt32(ConfigData.LatencyEnd.Value));
-                    }
-                    catch (Exception)
-                    {
-                        throw new ExceptionWithConfigData("Please enter a numeric latency end in ms !", ConfigData);
-                    }
-                }
-                else
-                {
-                    throw new ExceptionWithConfigData("Latency Simulation enabled, Please enter a end latency !", ConfigData);
-                }
-            }
-
-            // Check Browser Setting
-            if (ConfigData.Browser.Value == true)
-            {
-                output("\nValidated Setting -- Browser Simulation enabled");
-
-                // Check ACCEPT header Setting
-                if (string.IsNullOrEmpty(ConfigData.HeaderAccept.Value))
-                {
-                    throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an ACCEPT header !", ConfigData);
-                }
-                else
-                {
-                    output("Validated Setting -- ACCEPT (header) => " + ConfigData.HeaderAccept.Value.ToString());
-                }
-
-                // Check ACCEPT-LANG header Setting
-                if (string.IsNullOrEmpty(ConfigData.HeaderAcceptLang.Value))
-                {
-                    throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an ACCEPT-LANG header !", ConfigData);
-                }
-                else
-                {
-                    output("Validated Setting -- ACCEPT-LANG (header) => " + ConfigData.HeaderAcceptLang.Value.ToString());
-                }
-
-                // Check USER-AGENT header Setting
-                if (string.IsNullOrEmpty(ConfigData.HeaderUserAgent.Value))
-                {
-                    throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an USER-AGENT header !", ConfigData);
-                }
-                else
-                {
-                    output("Validated Setting -- USER-AGENT (header) => " + ConfigData.HeaderUserAgent.Value.ToString());
-                }
-            }
-            else
-            {
-                // Browser simulation must be enabled (otherwhise, this provider will not work due to tracker's security)
-                throw new ExceptionWithConfigData("Browser Simulation must be enabled for this provider to work, please enable it !", ConfigData);
-            }
-
-            // Check Dev Cache Settings
-            if (ConfigData.HardDriveCache.Value == true)
-            {
-                output("\nValidated Setting -- DEV Hard Drive Cache enabled");
-
-                // Check if Dev Mode enabled !
-                if (!ConfigData.DevMode.Value)
-                {
-                    throw new ExceptionWithConfigData("Hard Drive is enabled but not in DEV MODE, Please enable DEV MODE !", ConfigData);
-                }
-
-                // Check Cache Keep Time Setting
-                if (!string.IsNullOrEmpty(ConfigData.HardDriveCacheKeepTime.Value))
-                {
-                    try
-                    {
-                        output("Validated Setting -- Cache Keep Time (ms) => " + Convert.ToInt32(ConfigData.HardDriveCacheKeepTime.Value));
-                    }
-                    catch (Exception)
-                    {
-                        throw new ExceptionWithConfigData("Please enter a numeric hard drive keep time in ms !", ConfigData);
-                    }
-                }
-                else
-                {
-                    throw new ExceptionWithConfigData("Hard Drive Cache enabled, Please enter a maximum keep time for cache !", ConfigData);
-                }
-            }
-            else
-            {
-                // Delete cache if previously existed
-                cleanCacheStorage(true);
-            }
-        }
-    }
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using CsQuery;
+using Jackett.Models;
+using Jackett.Models.IndexerConfig.Bespoke;
+using Jackett.Services;
+using Jackett.Utils;
+using Jackett.Utils.Clients;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using NLog;
+
+namespace Jackett.Indexers
+{
+    /// <summary>
+    /// Provider for French-ADN Private Tracker
+    /// </summary>
+    public class FrenchAdn : BaseIndexer, IIndexer
+    {
+        private string LoginUrl => SiteLink + "login.php?";
+        private string LoginCheckUrl => SiteLink + "takelogin.php";
+        private string SearchUrl => SiteLink + "browse.php";
+        private string TorrentCommentUrl => SiteLink + "details.php?id={id}#comments";
+        private string TorrentDescriptionUrl => SiteLink + "details.php?id={id}";
+        private string TorrentDownloadUrl => SiteLink + "download.php?id={id}";
+        private string TorrentThanksUrl => SiteLink + "takethanks.php";
+        private bool Latency => ConfigData.Latency.Value;
+        private bool DevMode => ConfigData.DevMode.Value;
+        private bool CacheMode => ConfigData.HardDriveCache.Value;
+        private static string Directory => System.IO.Path.GetTempPath() + "Jackett\\" + MethodBase.GetCurrentMethod().DeclaringType?.Name + "\\";
+
+        private readonly Dictionary<string, string> _emulatedBrowserHeaders = new Dictionary<string, string>();
+        private CQ _fDom;
+        private ConfigurationDataFrenchAdn ConfigData => (ConfigurationDataFrenchAdn)configData;
+
+        public FrenchAdn(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps)
+            : base(
+                name: "French-ADN",
+                description: "Your French Family Provider",
+                link: "https://french-adn.com/",
+                caps: new TorznabCapabilities(),
+                manager: i,
+                client: w,
+                logger: l,
+                p: ps,
+                downloadBase: "https://french-adn.com/download.php?id=",
+                configData: new ConfigurationDataFrenchAdn())
+        {
+            // Clean capabilities
+            TorznabCaps.Categories.Clear();
+
+            // Movies
+            AddCategoryMapping("15", TorznabCatType.Movies);            // ALL
+            AddCategoryMapping("108", TorznabCatType.MoviesSD);         // TS CAM
+            AddCategoryMapping("25", TorznabCatType.MoviesSD);          // BDRIP
+            AddCategoryMapping("56", TorznabCatType.MoviesSD);          // BRRIP
+            AddCategoryMapping("16", TorznabCatType.MoviesSD);          // DVDRIP
+            AddCategoryMapping("49", TorznabCatType.MoviesDVD);         // TVRIP
+            AddCategoryMapping("102", TorznabCatType.MoviesWEBDL);      // WEBRIP
+            AddCategoryMapping("105", TorznabCatType.MoviesHD);         // 1080P
+            AddCategoryMapping("104", TorznabCatType.MoviesHD);         // 720P
+            AddCategoryMapping("17", TorznabCatType.MoviesDVD);         // DVD R
+            AddCategoryMapping("21", TorznabCatType.MoviesDVD);         // DVD R5
+            AddCategoryMapping("112", TorznabCatType.MoviesDVD);        // DVD REMUX
+            AddCategoryMapping("107", TorznabCatType.Movies3D);         // 3D
+            AddCategoryMapping("113", TorznabCatType.MoviesBluRay);     // BLURAY
+            AddCategoryMapping("118", TorznabCatType.MoviesHD);         // MHD
+
+            // Series
+            AddCategoryMapping("41", TorznabCatType.TV);                // ALL
+            AddCategoryMapping("43", TorznabCatType.TV);                // VF
+            AddCategoryMapping("44", TorznabCatType.TV);                // VOSTFR
+            AddCategoryMapping("42", TorznabCatType.TV);                // PACK
+
+            // TV
+            AddCategoryMapping("110", TorznabCatType.TV);               // SHOWS
+
+            // Anime
+            AddCategoryMapping("109", TorznabCatType.TVAnime);          // ANIME
+
+            // Manga
+            AddCategoryMapping("119", TorznabCatType.TVAnime);          // MANGA
+
+            // Documentaries
+            AddCategoryMapping("114", TorznabCatType.TVDocumentary);    // DOCUMENTARY
+
+            // Music
+            AddCategoryMapping("22", TorznabCatType.Audio);             // ALL
+            AddCategoryMapping("24", TorznabCatType.AudioLossless);     // FLAC
+            AddCategoryMapping("23", TorznabCatType.AudioMP3);          // MP3
+
+            // Games
+            AddCategoryMapping("33", TorznabCatType.PCGames);           // ALL
+            AddCategoryMapping("45", TorznabCatType.PCGames);           // PC GAMES
+            AddCategoryMapping("93", TorznabCatType.Console3DS);        // 3DS
+            AddCategoryMapping("94", TorznabCatType.Console);           // PS2
+            AddCategoryMapping("93", TorznabCatType.ConsolePS3);        // PS3
+            AddCategoryMapping("95", TorznabCatType.ConsolePSP);        // PSP
+            AddCategoryMapping("35", TorznabCatType.ConsolePS3);        // WII
+
+            // Applications
+            AddCategoryMapping("11", TorznabCatType.PC);                // ALL
+            AddCategoryMapping("12", TorznabCatType.PC);                // APPS WINDOWS
+            AddCategoryMapping("97", TorznabCatType.PCMac);             // APPS MAC
+            AddCategoryMapping("98", TorznabCatType.PC);                // APPS LINUX
+
+            // Books
+            AddCategoryMapping("115", TorznabCatType.BooksEbook);       // EBOOK
+            AddCategoryMapping("114", TorznabCatType.BooksComics);      // COMICS
+
+            // Other
+            AddCategoryMapping("103", TorznabCatType.Other);            // STAFF
+        }
+
+        /// <summary>
+        /// Configure our FADN Provider
+        /// </summary>
+        /// <param name="configJson">Our params in Json</param>
+        /// <returns>Configuration state</returns>
+        public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
+        {
+            // Retrieve config values set by Jackett's user
+            ConfigData.LoadValuesFromJson(configJson);
+
+            // Check & Validate Config
+            ValidateConfig();
+
+            // Setting our data for a better emulated browser (maximum security)
+            // TODO: Encoded Content not supported by Jackett at this time
+            // emulatedBrowserHeaders.Add("Accept-Encoding", "gzip, deflate");
+
+            // If we want to simulate a browser
+            if (ConfigData.Browser.Value)
+            {
+
+                // Clean headers
+                _emulatedBrowserHeaders.Clear();
+
+                // Inject headers
+                _emulatedBrowserHeaders.Add("Accept", ConfigData.HeaderAccept.Value);
+                _emulatedBrowserHeaders.Add("Accept-Language", ConfigData.HeaderAcceptLang.Value);
+                _emulatedBrowserHeaders.Add("DNT", Convert.ToInt32(ConfigData.HeaderDnt.Value).ToString());
+                _emulatedBrowserHeaders.Add("Upgrade-Insecure-Requests", Convert.ToInt32(ConfigData.HeaderUpgradeInsecure.Value).ToString());
+                _emulatedBrowserHeaders.Add("User-Agent", ConfigData.HeaderUserAgent.Value);
+            }
+
+            await DoLogin();
+
+            return IndexerConfigurationStatus.RequiresTesting;
+        }
+
+        /// <summary>
+        /// Perform login to racker
+        /// </summary>
+        /// <returns></returns>
+        private async Task DoLogin()
+        {
+            // Build WebRequest for index
+            var myIndexRequest = new WebRequest()
+            {
+                Type = RequestType.GET,
+                Url = SiteLink,
+                Headers = _emulatedBrowserHeaders
+            };
+
+            // Get index page for cookies
+            Output("\nGetting index page (for cookies).. with " + SiteLink);
+            var indexPage = await webclient.GetString(myIndexRequest);
+
+            // Building login form data
+            var pairs = new Dictionary<string, string> {
+                { "username", ConfigData.Username.Value },
+                { "password", ConfigData.Password.Value }
+            };
+
+            // Build WebRequest for login
+            var myRequestLogin = new WebRequest()
+            {
+                Type = RequestType.GET,
+                Url = LoginUrl,
+                Headers = _emulatedBrowserHeaders,
+                Cookies = indexPage.Cookies,
+                Referer = SiteLink
+            };
+
+            // Get login page -- (not used, but simulation needed by tracker security's checks)
+            LatencyNow();
+            Output("\nGetting login page (user simulation).. with " + LoginUrl);
+            await webclient.GetString(myRequestLogin);
+
+            // Build WebRequest for submitting authentification
+            var request = new WebRequest()
+            {
+                PostData = pairs,
+                Referer = LoginUrl,
+                Type = RequestType.POST,
+                Url = LoginCheckUrl,
+                Headers = _emulatedBrowserHeaders,
+                Cookies = indexPage.Cookies,
+
+            };
+
+            // Perform loggin
+            LatencyNow();
+            Output("\nPerform loggin.. with " + LoginCheckUrl);
+            var response = await webclient.GetString(request);
+
+            // Test if we are logged in
+            await ConfigureIfOK(response.Cookies, !string.IsNullOrEmpty(response.Cookies) && !response.IsRedirect, () =>
+            {
+                // Default error message
+                var message = "Error during attempt !";
+
+                // Parse redirect header
+                var redirectTo = response.RedirectingTo;
+
+                // Analyzer error code
+                if (redirectTo.Contains("login.php?error=4"))
+                {
+                    // Set message
+                    message = "Wrong username or password !";
+                }
+
+                // Oops, unable to login
+                Output("-> Login failed: " + message, "error");
+                throw new ExceptionWithConfigData("Login failed: " + message, configData);
+            });
+
+            Output("\nCookies saved for future uses...");
+            ConfigData.CookieHeader.Value = indexPage.Cookies + " " + response.Cookies + " ts_username=" + ConfigData.Username.Value;
+
+            Output("\n-> Login Success\n");
+        }
+
+        /// <summary>
+        /// Check logged-in state for provider
+        /// </summary>
+        /// <returns></returns>
+        private async Task CheckLogin()
+        {
+            // Checking ...
+            Output("\n-> Checking logged-in state....");
+            var loggedInCheck = await RequestStringWithCookies(SearchUrl);
+            if (!loggedInCheck.Content.Contains("/logout.php"))
+            {
+                // Cookie expired, renew session on provider
+                Output("-> Not logged, login now...\n");
+                await DoLogin();
+            }
+            else
+            {
+                // Already logged, session active
+                Output("-> Already logged, continue...\n");
+            }
+        }
+
+        /// <summary>
+        /// Execute our search query
+        /// </summary>
+        /// <param name="query">Query</param>
+        /// <returns>Releases</returns>
+        public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
+        {
+            var releases = new List<ReleaseInfo>();
+            var torrentRowList = new List<CQ>();
+            var searchTerm = query.GetQueryString();
+            var searchUrl = SearchUrl;
+
+            // Check login before performing a query
+           await CheckLogin();
+
+            // Check cache first so we don't query the server (if search term used or not in dev mode)
+            if (!DevMode && !string.IsNullOrEmpty(searchTerm))
+            {
+                lock (cache)
+                {
+                    // Remove old cache items
+                    CleanCache();
+
+                    // Search in cache
+                    var cachedResult = cache.FirstOrDefault(i => i.Query == searchTerm);
+                    if (cachedResult != null)
+                        return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray();
+                }
+            }
+
+            // Build our query
+            var request = BuildQuery(searchTerm, query, searchUrl);
+
+            // Getting results & Store content
+            var results = await QueryExec(request);
+            _fDom = results.Content;
+
+            try
+            {
+                // Find torrent rows
+                var firstPageRows = FindTorrentRows();
+
+                // Add them to torrents list
+                torrentRowList.AddRange(firstPageRows.Select(fRow => fRow.Cq()));
+
+                // Check if there are pagination links at bottom
+                var pagination = (_fDom["#quicknavpage_menu"].Length != 0);
+
+                // If pagination available
+                int nbResults;
+                int pageLinkCount;
+                if (pagination)
+                {
+                    // Retrieve available pages (3 pages shown max)
+                    pageLinkCount = _fDom["#navcontainer_f:first > ul"].Find("a").Not(".smalltext").Not("#quicknavpage").Length;
+
+                    // Last button ? (So more than 3 page are available)
+                    var more = _fDom["#navcontainer_f:first > ul"].Find("a.smalltext").Length > 1;
+
+                    // More page than 3 pages ?
+                    if (more)
+                    {
+                        // Get total page count from last link
+                        pageLinkCount = ParseUtil.CoerceInt(Regex.Match(_fDom["#navcontainer_f:first > ul"].Find("a:eq(4)").Attr("href"), @"\d+").Value);
+                    }
+
+                    // Calculate average number of results (based on torrents rows lenght on first page)
+                    nbResults = firstPageRows.Count() * pageLinkCount;
+                }
+                else {
+                    nbResults = 1;
+                    pageLinkCount = 1;
+
+                    // Check if we have a minimum of one result
+                    if (firstPageRows.Length > 1)
+                    {
+                        // Retrieve total count on our alone page
+                        nbResults = firstPageRows.Count();
+                    }
+                    else
+                    {
+                        // Check if no result
+                        if(torrentRowList.First().Find("td").Length == 1)
+                        {
+                            // No results found
+                            Output("\nNo result found for your query, please try another search term ...\n", "info");
+
+                            // No result found for this query
+                            return releases;
+                        }
+                    }
+                }
+                Output("\nFound " + nbResults + " result(s) (+/- " + firstPageRows.Length + ") in " + pageLinkCount + " page(s) for this query !");
+                Output("\nThere are " + firstPageRows.Length + " results on the first page !");
+
+                // If we have a term used for search and pagination result superior to one
+                if (!string.IsNullOrWhiteSpace(query.GetQueryString()) && pageLinkCount > 1)
+                {
+                    // Starting with page #2
+                    for (var i = 2; i <= Math.Min(int.Parse(ConfigData.Pages.Value), pageLinkCount); i++)
+                    {
+                        Output("\nProcessing page #" + i);
+
+                        // Request our page
+                        LatencyNow();
+
+                        // Build our query -- Minus 1 to page due to strange pagination number on tracker side, starting with page 0...
+                        var pageRequest = BuildQuery(searchTerm, query, searchUrl, i);
+
+                        // Getting results & Store content
+                        WebClientStringResult pageResults = await QueryExec(pageRequest);
+
+                        // Assign response
+                        _fDom = pageResults.Content;
+
+                        // Process page results
+                        var additionalPageRows = FindTorrentRows();
+
+                        // Add them to torrents list
+                        torrentRowList.AddRange(additionalPageRows.Select(fRow => fRow.Cq()));
+                    }
+                }
+
+                // Loop on results
+                foreach (var tRow in torrentRowList)
+                {
+                    Output("\n=>> Torrent #" + (releases.Count + 1));
+
+                    // ID
+                    var id = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(1) > div:first > a").Attr("name"), @"\d+").Value);
+                    Output("ID: " + id);
+
+                    // Check if torrent is not nuked by tracker or rulez, can't download it
+                    if (tRow.Find("td:eq(2) > a").Length == 0)
+                    {
+                        // Next item
+                        Output("Torrent is nuked, we can't download it, going to next torrent...");
+                        continue;
+                    }
+
+                    // Release Name
+                    var name = tRow.Find("td:eq(2) > a").Attr("title").Substring(24).Trim();
+                    Output("Release: " + name);
+
+                    // Category
+                    var categoryId = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(0) > a").Attr("href"), @"\d+").Value);
+                    var categoryName = tRow.Find("td:eq(0) > a > img").Attr("title").Split(new[] { ':' }, 2)[1].Trim();
+                    Output("Category: " + MapTrackerCatToNewznab(categoryId.ToString()) + " (" + categoryId + " - " + categoryName + ")");
+
+                    // Seeders
+                    var seeders = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(5) > div > font").Select(s => Regex.Replace(s.ToString(), "<.*?>", string.Empty)).ToString(), @"\d+").Value);
+                    Output("Seeders: " + seeders);
+
+                    // Leechers
+                    var leechers = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(6) > div > font").Text(), @"\d+").Value);
+                    Output("Leechers: " + leechers);
+
+                    // Completed
+                    var completed = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(4)").Text(), @"\d+").Value);
+                    Output("Completed: " + completed);
+
+                    // Files
+                    var files = 1;
+                    if (tRow.Find("td:eq(3) > a").Length == 1)
+                    {
+                        files = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(3) > a").Text(), @"\d+").Value);
+                    }
+                    Output("Files: " + files);
+
+                    // Health
+                    var percent = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(7) > img").Attr("src"), @"\d+").Value) * 10;
+                    Output("Health: " + percent + "%");
+
+                    // Size
+                    var humanSize = tRow.Find("td:eq(8)").Text().ToLowerInvariant();
+                    var size = ReleaseInfo.GetBytes(humanSize);
+                    Output("Size: " + humanSize + " (" + size + " bytes)");
+
+                    // Date & IMDB & Genre
+                    var infosData = tRow.Find("td:eq(1) > div:last").Text();
+                    var infosList = Regex.Split(infosData, "\\|").ToList();
+                    var infosTorrent = infosList.Select(s => s.Split(new[] { ':' }, 2)[1].Trim()).ToList();
+
+                    // --> Date
+                    var date = FormatDate(infosTorrent.First());
+                    Output("Released on: " + date.ToLocalTime());
+
+                    // --> Genre
+                    var genre = infosTorrent.Last();
+                    Output("Genre: " + genre);
+
+                    // Torrent Details URL
+                    var detailsLink = new Uri(TorrentDescriptionUrl.Replace("{id}", id.ToString()));
+                    Output("Details: " + detailsLink.AbsoluteUri);
+
+                    // Torrent Comments URL
+                    var commentsLink = new Uri(TorrentCommentUrl.Replace("{id}", id.ToString()));
+                    Output("Comments Link: " + commentsLink.AbsoluteUri);
+
+                    // Torrent Download URL
+                    var downloadLink = new Uri(TorrentDownloadUrl.Replace("{id}", id.ToString()));
+                    Output("Download Link: " + downloadLink.AbsoluteUri);
+
+                    // Building release infos
+                    var release = new ReleaseInfo
+                    {
+                        Category = MapTrackerCatToNewznab(categoryId.ToString()),
+                        Title = name,
+                        Seeders = seeders,
+                        Peers = seeders + leechers,
+                        MinimumRatio = 1,
+                        MinimumSeedTime = 172800,
+                        PublishDate = date,
+                        Size = size,
+                        Guid = detailsLink,
+                        Comments = commentsLink,
+                        Link = downloadLink
+                    };
+                    releases.Add(release);
+                }
+
+            }
+            catch (Exception ex)
+            {
+                OnParseError("Error, unable to parse result \n" + ex.StackTrace, ex);
+            }
+
+            // Return found releases
+            return releases;
+        }
+
+        /// <summary>
+        /// Build query to process
+        /// </summary>
+        /// <param name="term">Term to search</param>
+        /// <param name="query">Torznab Query for categories mapping</param>
+        /// <param name="url">Search url for provider</param>
+        /// <param name="page">Page number to request</param>
+        /// <returns>URL to query for parsing and processing results</returns>
+        private string BuildQuery(string term, TorznabQuery query, string url, int page = 0)
+        {
+            var parameters = new NameValueCollection();
+            var categoriesList = MapTorznabCapsToTrackers(query);
+
+            // Building our tracker query
+            parameters.Add("do", "search");
+
+            // If search term provided
+            if (!string.IsNullOrWhiteSpace(term))
+            {
+                // Add search term ~~ Strange search engine, need to replace space with dot for results !
+                parameters.Add("keywords", term.Replace(' ', '.'));
+            }
+            else
+            {
+                // Showing all torrents (just for output function)
+                parameters.Add("keywords", "");
+                term = "all";
+            }
+
+            // Adding requested categories
+            parameters.Add("category", categoriesList.Count > 0 ? string.Join(",", categoriesList) : "");
+
+            // Building our tracker query
+            parameters.Add("search_type", "t_name");
+
+            // Check if we are processing a new page
+            if (page > 1)
+            {
+                // Adding page number to query
+                parameters.Add("page", page.ToString());
+            }
+
+            // Building our query
+            url += "?" + parameters.GetQueryString();
+
+            Output("\nBuilded query for \"" + term + "\"... " + url);
+
+            // Return our search url
+            return url;
+        }
+
+        /// <summary>
+        /// Switch Method for Querying
+        /// </summary>
+        /// <param name="request">URL created by Query Builder</param>
+        /// <returns>Results from query</returns>
+        private async Task<WebClientStringResult> QueryExec(string request)
+        {
+            WebClientStringResult results;
+
+            // Switch in we are in DEV mode with Hard Drive Cache or not
+            if (DevMode && CacheMode)
+            {
+                // Check Cache before querying and load previous results if available
+                results = await QueryCache(request);
+            }
+            else
+            {
+                // Querying tracker directly
+                results = await QueryTracker(request);
+            }
+            return results;
+        }
+
+        /// <summary>
+        /// Get Torrents Page from Cache by Query Provided
+        /// </summary>
+        /// <param name="request">URL created by Query Builder</param>
+        /// <returns>Results from query</returns>
+        private async Task<WebClientStringResult> QueryCache(string request)
+        {
+            WebClientStringResult results;
+
+            // Create Directory if not exist
+            System.IO.Directory.CreateDirectory(Directory);
+
+            // Clean Storage Provider Directory from outdated cached queries
+            CleanCacheStorage();
+
+            // Create fingerprint for request
+            var file = Directory + request.GetHashCode() + ".json";
+
+            // Checking modes states
+            if (System.IO.File.Exists(file))
+            {
+                // File exist... loading it right now !
+                Output("Loading results from hard drive cache ..." + request.GetHashCode() + ".json");
+                results = JsonConvert.DeserializeObject<WebClientStringResult>(System.IO.File.ReadAllText(file));
+            }
+            else
+            {
+                // No cached file found, querying tracker directly
+                results = await QueryTracker(request);
+
+                // Cached file didn't exist for our query, writing it right now !
+                Output("Writing results to hard drive cache ..." + request.GetHashCode() + ".json");
+                System.IO.File.WriteAllText(file, JsonConvert.SerializeObject(results));
+            }
+            return results;
+        }
+
+        /// <summary>
+        /// Get Torrents Page from Tracker by Query Provided
+        /// </summary>
+        /// <param name="request">URL created by Query Builder</param>
+        /// <returns>Results from query</returns>
+        private async Task<WebClientStringResult> QueryTracker(string request)
+        {
+            // Cache mode not enabled or cached file didn't exist for our query
+            Output("\nQuerying tracker for results....");
+
+            // Request our first page
+            LatencyNow();
+            var results = await RequestStringWithCookiesAndRetry(request, ConfigData.CookieHeader.Value, SearchUrl, _emulatedBrowserHeaders);
+
+            // Return results from tracker
+            return results;
+        }
+
+        /// <summary>
+        /// Clean Hard Drive Cache Storage
+        /// </summary>
+        /// <param name="force">Force Provider Folder deletion</param>
+        private void CleanCacheStorage(bool force = false)
+        {
+            // Check cleaning method
+            if (force)
+            {
+                // Deleting Provider Storage folder and all files recursively
+                Output("\nDeleting Provider Storage folder and all files recursively ...");
+
+                // Check if directory exist
+                if (System.IO.Directory.Exists(Directory))
+                {
+                    // Delete storage directory of provider
+                    System.IO.Directory.Delete(Directory, true);
+                    Output("-> Storage folder deleted successfully.");
+                }
+                else
+                {
+                    // No directory, so nothing to do
+                    Output("-> No Storage folder found for this provider !");
+                }
+            }
+            else
+            {
+                var i = 0;
+                // Check if there is file older than ... and delete them
+                Output("\nCleaning Provider Storage folder... in progress.");
+                System.IO.Directory.GetFiles(Directory)
+                .Select(f => new System.IO.FileInfo(f))
+                .Where(f => f.LastAccessTime < DateTime.Now.AddMilliseconds(-Convert.ToInt32(ConfigData.HardDriveCacheKeepTime.Value)))
+                .ToList()
+                .ForEach(f => {
+                    Output("Deleting cached file << " + f.Name + " >> ... done.");
+                    f.Delete();
+                    i++;
+                });
+
+                // Inform on what was cleaned during process
+                if (i > 0)
+                {
+                    Output("-> Deleted " + i + " cached files during cleaning.");
+                }
+                else {
+                    Output("-> Nothing deleted during cleaning.");
+                }
+            }
+        }
+
+        /// <summary>
+        /// Generate a random fake latency to avoid detection on tracker side
+        /// </summary>
+        private void LatencyNow()
+        {
+            // Need latency ?
+            if (Latency)
+            {
+                var random = new Random(DateTime.Now.Millisecond);
+                var waiting = random.Next(Convert.ToInt32(ConfigData.LatencyStart.Value),
+                    Convert.ToInt32(ConfigData.LatencyEnd.Value));
+                Output("\nLatency Faker => Sleeping for " + waiting + " ms...");
+
+                // Sleep now...
+                System.Threading.Thread.Sleep(waiting);
+            }
+            // Generate a random value in our range
+        }
+
+        /// <summary>
+        /// Find torrent rows in search pages
+        /// </summary>
+        /// <returns>JQuery Object</returns>
+        private CQ FindTorrentRows()
+        {
+            // Return all occurencis of torrents found
+            return _fDom["#showcontents > table > tbody > tr:not(:first)"];
+        }
+
+        /// <summary>
+        /// Format Date to DateTime
+        /// </summary>
+        /// <param name="clock"></param>
+        /// <returns>A DateTime</returns>
+        private static DateTime FormatDate(string clock)
+        {
+            DateTime date;
+
+            // Switch from date format
+            if(clock.Contains("Aujourd'hui") || clock.Contains("Hier"))
+            {
+                // Get hours & minutes
+                IList<int> infosClock = clock.Split(':').Select(s => ParseUtil.CoerceInt(Regex.Match(s, @"\d+").Value)).ToList();
+
+                // Ago date with today
+                date = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, Convert.ToInt32(infosClock[0]), Convert.ToInt32(infosClock[1]), DateTime.Now.Second);
+
+                // Set yesterday if necessary
+                if (clock.Contains("Hier"))
+                {
+                    // Remove one day from date
+                    // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
+                    date.AddDays(-1);
+                }
+            }
+            else
+            {
+                // Parse Date if full
+                date = DateTime.ParseExact(clock, "MM-dd-yyyy HH:mm", CultureInfo.GetCultureInfo("fr-FR"), DateTimeStyles.AssumeLocal);
+            }
+
+            return date.ToUniversalTime();
+        }
+
+        /// <summary>
+        /// Download torrent file from tracker
+        /// </summary>
+        /// <param name="link">URL string</param>
+        /// <returns></returns>
+        public override async Task<byte[]> Download(Uri link)
+        {
+            // This tracker need to thanks Uploader before getting torrent file...
+            Output("\nThis tracker needs you to thank uploader before downloading torrent!");
+
+            // Retrieving ID from link provided
+            var id = ParseUtil.CoerceInt(Regex.Match(link.AbsoluteUri, @"\d+").Value);
+            Output("Torrent Requested ID: " + id);
+
+            // Building login form data
+            var pairs = new Dictionary<string, string> {
+                { "torrentid", id.ToString() },
+                { "_", string.Empty } // ~~ Strange, blank param...
+            };
+
+            // Add emulated XHR request
+            _emulatedBrowserHeaders.Add("X-Prototype-Version", "1.6.0.3");
+            _emulatedBrowserHeaders.Add("X-Requested-With", "XMLHttpRequest");
+
+            // Build WebRequest for thanks
+            var myRequestThanks = new WebRequest()
+            {
+                Type = RequestType.POST,
+                PostData = pairs,
+                Url = TorrentThanksUrl,
+                Headers = _emulatedBrowserHeaders,
+                Cookies = ConfigData.CookieHeader.Value,
+                Referer = TorrentDescriptionUrl.Replace("{id}", id.ToString())
+            };
+
+            // Get thanks page -- (not used, just for doing a request)
+            LatencyNow();
+            Output("Thanks user, to get download link for our torrent.. with " + TorrentThanksUrl);
+            await webclient.GetString(myRequestThanks);
+
+            // Get torrent file now
+            Output("Getting torrent file now....");
+            var response = await base.Download(link);
+
+            // Remove our XHR request header
+            _emulatedBrowserHeaders.Remove("X-Prototype-Version");
+            _emulatedBrowserHeaders.Remove("X-Requested-With");
+
+            // Return content
+            return response;
+        }
+
+        /// <summary>
+        /// Output message for logging or developpment (console)
+        /// </summary>
+        /// <param name="message">Message to output</param>
+        /// <param name="level">Level for Logger</param>
+        private void Output(string message, string level = "debug")
+        {
+            // Check if we are in dev mode
+            if (DevMode)
+            {
+                // Output message to console
+                Console.WriteLine(message);
+            }
+            else
+            {
+                // Send message to logger with level
+                switch (level)
+                {
+                    default:
+                        goto case "debug";
+                    case "debug":
+                        // Only if Debug Level Enabled on Jackett
+                        if (Engine.Logger.IsDebugEnabled)
+                        {
+                            logger.Debug(message);
+                        }
+                        break;
+                    case "info":
+                        logger.Info(message);
+                        break;
+                    case "error":
+                        logger.Error(message);
+                        break;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Validate Config entered by user on Jackett
+        /// </summary>
+        private void ValidateConfig()
+        {
+            Output("\nValidating Settings ... \n");
+
+            // Check Username Setting
+            if (string.IsNullOrEmpty(ConfigData.Username.Value))
+            {
+                throw new ExceptionWithConfigData("You must provide a username for this tracker to login !", ConfigData);
+            }
+            else
+            {
+                Output("Validated Setting -- Username (auth) => " + ConfigData.Username.Value);
+            }
+
+            // Check Password Setting
+            if (string.IsNullOrEmpty(ConfigData.Password.Value))
+            {
+                throw new ExceptionWithConfigData("You must provide a password with your username for this tracker to login !", ConfigData);
+            }
+            else
+            {
+                Output("Validated Setting -- Password (auth) => " + ConfigData.Password.Value);
+            }
+
+            // Check Max Page Setting
+            if (!string.IsNullOrEmpty(ConfigData.Pages.Value))
+            {
+                try
+                {
+                    Output("Validated Setting -- Max Pages => " + Convert.ToInt32(ConfigData.Pages.Value));
+                }
+                catch (Exception)
+                {
+                    throw new ExceptionWithConfigData("Please enter a numeric maximum number of pages to crawl !", ConfigData);
+                }
+            }
+            else
+            {
+                throw new ExceptionWithConfigData("Please enter a maximum number of pages to crawl !", ConfigData);
+            }
+
+            // Check Latency Setting
+            if (ConfigData.Latency.Value)
+            {
+                Output("\nValidated Setting -- Latency Simulation enabled");
+
+                // Check Latency Start Setting
+                if (!string.IsNullOrEmpty(ConfigData.LatencyStart.Value))
+                {
+                    try
+                    {
+                        Output("Validated Setting -- Latency Start => " + Convert.ToInt32(ConfigData.LatencyStart.Value));
+                    }
+                    catch (Exception)
+                    {
+                        throw new ExceptionWithConfigData("Please enter a numeric latency start in ms !", ConfigData);
+                    }
+                }
+                else
+                {
+                    throw new ExceptionWithConfigData("Latency Simulation enabled, Please enter a start latency !", ConfigData);
+                }
+
+                // Check Latency End Setting
+                if (!string.IsNullOrEmpty(ConfigData.LatencyEnd.Value))
+                {
+                    try
+                    {
+                        Output("Validated Setting -- Latency End => " + Convert.ToInt32(ConfigData.LatencyEnd.Value));
+                    }
+                    catch (Exception)
+                    {
+                        throw new ExceptionWithConfigData("Please enter a numeric latency end in ms !", ConfigData);
+                    }
+                }
+                else
+                {
+                    throw new ExceptionWithConfigData("Latency Simulation enabled, Please enter a end latency !", ConfigData);
+                }
+            }
+
+            // Check Browser Setting
+            if (ConfigData.Browser.Value)
+            {
+                Output("\nValidated Setting -- Browser Simulation enabled");
+
+                // Check ACCEPT header Setting
+                if (string.IsNullOrEmpty(ConfigData.HeaderAccept.Value))
+                {
+                    throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an ACCEPT header !", ConfigData);
+                }
+                else
+                {
+                    Output("Validated Setting -- ACCEPT (header) => " + ConfigData.HeaderAccept.Value);
+                }
+
+                // Check ACCEPT-LANG header Setting
+                if (string.IsNullOrEmpty(ConfigData.HeaderAcceptLang.Value))
+                {
+                    throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an ACCEPT-LANG header !", ConfigData);
+                }
+                else
+                {
+                    Output("Validated Setting -- ACCEPT-LANG (header) => " + ConfigData.HeaderAcceptLang.Value);
+                }
+
+                // Check USER-AGENT header Setting
+                if (string.IsNullOrEmpty(ConfigData.HeaderUserAgent.Value))
+                {
+                    throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an USER-AGENT header !", ConfigData);
+                }
+                else
+                {
+                    Output("Validated Setting -- USER-AGENT (header) => " + ConfigData.HeaderUserAgent.Value);
+                }
+            }
+            else
+            {
+                // Browser simulation must be enabled (otherwhise, this provider will not work due to tracker's security)
+                throw new ExceptionWithConfigData("Browser Simulation must be enabled for this provider to work, please enable it !", ConfigData);
+            }
+
+            // Check Dev Cache Settings
+            if (ConfigData.HardDriveCache.Value)
+            {
+                Output("\nValidated Setting -- DEV Hard Drive Cache enabled");
+
+                // Check if Dev Mode enabled !
+                if (!ConfigData.DevMode.Value)
+                {
+                    throw new ExceptionWithConfigData("Hard Drive is enabled but not in DEV MODE, Please enable DEV MODE !", ConfigData);
+                }
+
+                // Check Cache Keep Time Setting
+                if (!string.IsNullOrEmpty(ConfigData.HardDriveCacheKeepTime.Value))
+                {
+                    try
+                    {
+                        Output("Validated Setting -- Cache Keep Time (ms) => " + Convert.ToInt32(ConfigData.HardDriveCacheKeepTime.Value));
+                    }
+                    catch (Exception)
+                    {
+                        throw new ExceptionWithConfigData("Please enter a numeric hard drive keep time in ms !", ConfigData);
+                    }
+                }
+                else
+                {
+                    throw new ExceptionWithConfigData("Hard Drive Cache enabled, Please enter a maximum keep time for cache !", ConfigData);
+                }
+            }
+            else
+            {
+                // Delete cache if previously existed
+                CleanCacheStorage(true);
+            }
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj
index a50663c5..c0f290a0 100644
--- a/src/Jackett/Jackett.csproj
+++ b/src/Jackett/Jackett.csproj
@@ -216,7 +216,7 @@
     <Compile Include="Indexers\ImmortalSeed.cs" />
     <Compile Include="Indexers\FileList.cs" />
     <Compile Include="Indexers\Abstract\AvistazTracker.cs" />
-    <Compile Include="Indexers\FrenchADN.cs" />
+    <Compile Include="Indexers\FrenchAdn.cs" />
     <Compile Include="Indexers\TransmitheNet.cs" />
     <Compile Include="Indexers\WiHD.cs" />
     <Compile Include="Indexers\XSpeeds.cs" />
@@ -226,7 +226,7 @@
     <Compile Include="Models\IndexerConfig\Bespoke\ConfigurationDataPhxBit.cs" />
     <Compile Include="Models\IndexerConfig\Bespoke\ConfigurationDataBlueTigers.cs" />
     <Compile Include="Models\IndexerConfig\Bespoke\ConfigurationDataAbnormal.cs" />
-    <Compile Include="Models\IndexerConfig\Bespoke\ConfigurationDataFrenchADN.cs" />
+    <Compile Include="Models\IndexerConfig\Bespoke\ConfigurationDataFrenchAdn.cs" />
     <Compile Include="Models\IndexerConfig\Bespoke\ConfigurationDataWiHD.cs" />
     <Compile Include="Models\IndexerConfig\ConfigurationDataBasicLoginWithFilter.cs" />
     <Compile Include="Models\IndexerConfig\ConfigurationDataAPIKey.cs" />
diff --git a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataFrenchADN.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataFrenchADN.cs
index f41af8e7..518151ee 100644
--- a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataFrenchADN.cs
+++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataFrenchADN.cs
@@ -1,6 +1,6 @@
 namespace Jackett.Models.IndexerConfig.Bespoke
 {
-    class ConfigurationDataFrenchADN : ConfigurationData
+    internal class ConfigurationDataFrenchAdn : ConfigurationData
     {
         public DisplayItem CredentialsWarning { get; private set; }
         public StringItem Username { get; private set; }
@@ -16,7 +16,7 @@
         public DisplayItem HeadersWarning { get; private set; }
         public StringItem HeaderAccept { get; private set; }
         public StringItem HeaderAcceptLang { get; private set; }
-        public BoolItem HeaderDNT { get; private set; }
+        public BoolItem HeaderDnt { get; private set; }
         public BoolItem HeaderUpgradeInsecure { get; private set; }
         public StringItem HeaderUserAgent { get; private set; }
         public DisplayItem DevWarning { get; private set; }
@@ -24,8 +24,7 @@
         public BoolItem HardDriveCache { get; private set; }
         public StringItem HardDriveCacheKeepTime { get; private set; }
 
-        public ConfigurationDataFrenchADN()
-            : base()
+        public ConfigurationDataFrenchAdn()
         {
             CredentialsWarning = new DisplayItem("<b>Credentials Configuration</b> (<i>Private Tracker</i>),<br /><br /> <ul><li><b>Username</b> is your account name on this tracker.</li><li><b>Password</b> is your password associated to your account name.</li></ul>") { Name = "Credentials" };
             Username = new StringItem { Name = "Username (Required)", Value = "" };
@@ -41,7 +40,7 @@
             HeadersWarning = new DisplayItem("<b>Browser Headers Configuration</b> (<i>Required if browser simulation enabled</i>),<br /><br /> <ul><li>By filling these fields, <b>Jackett will inject headers</b> with your values <u>to simulate a real browser</u>.</li><li>You can get <b>your browser values</b> here: <a href='https://www.whatismybrowser.com/detect/what-http-headers-is-my-browser-sending' target='blank'>www.whatismybrowser.com</a></li></ul><br /><i><b>Note that</b> some headers are not necessary because they are injected automatically by this provider such as Accept_Encoding, Connection, Host or X-Requested-With</i>") { Name = "Injecting headers" };
             HeaderAccept = new StringItem { Name = "Accept", Value = "" };
             HeaderAcceptLang = new StringItem { Name = "Accept-Language", Value = "" };
-            HeaderDNT = new BoolItem { Name = "DNT", Value = false };
+            HeaderDnt = new BoolItem { Name = "DNT", Value = false };
             HeaderUpgradeInsecure = new BoolItem { Name = "Upgrade-Insecure-Requests", Value = false };
             HeaderUserAgent = new StringItem { Name = "User-Agent", Value = "" };
             DevWarning = new DisplayItem("<b>Development Facility</b> (<i>For Developers ONLY</i>),<br /><br /> <ul><li>By enabling development mode, <b>Jackett will bypass his cache</b> and will <u>output debug messages to console</u> instead of his log file.</li><li>By enabling Hard Drive Cache, <b>This provider</b> will <u>save each query answers from tracker</u> in temp directory, in fact this reduce drastically HTTP requests when building a provider at parsing step for example. So, <b> Jackett will search for a cached query answer on hard drive before executing query on tracker side !</b> <i>DEV MODE must be enabled to use it !</li></ul>") { Name = "Development" };
-- 
GitLab