From 0f04ea5496b4d4a3497cef827d15afed2cdc41c8 Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Fri, 2 Nov 2012 19:38:57 +0000
Subject: [PATCH] UPnP port mapper using the Weupnp library (untested).

---
 libs/weupnp-0.1.1.jar                         | Bin 0 -> 25422 bytes
 src/net/sf/briar/HelloWorldModule.java        |   7 +-
 src/net/sf/briar/HelloWorldService.java       |   7 +-
 .../sf/briar/plugins/tcp/MappingResult.java   |  32 +++++++
 src/net/sf/briar/plugins/tcp/PortMapper.java  |  10 +++
 .../sf/briar/plugins/tcp/PortMapperImpl.java  |  82 ++++++++++++++++++
 src/net/sf/briar/plugins/tcp/TcpPlugin.java   |  14 +--
 .../sf/briar/plugins/tcp/WanTcpPlugin.java    |  56 +++++++++++-
 .../plugins/tcp/WanTcpPluginFactory.java      |   3 +-
 9 files changed, 192 insertions(+), 19 deletions(-)
 create mode 100644 libs/weupnp-0.1.1.jar
 create mode 100644 src/net/sf/briar/plugins/tcp/MappingResult.java
 create mode 100644 src/net/sf/briar/plugins/tcp/PortMapper.java
 create mode 100644 src/net/sf/briar/plugins/tcp/PortMapperImpl.java

diff --git a/libs/weupnp-0.1.1.jar b/libs/weupnp-0.1.1.jar
new file mode 100644
index 0000000000000000000000000000000000000000..2626a76c0284e8ca9e42bf5ce111ba1afb7527ab
GIT binary patch
literal 25422
zcma&OW0Wp1uqE2IZQHhO<Fswtw!iK^ZQHhOo2PB-wDHcJckiq>@6MVv`H|F0cC94!
zrz(}5D9M6?!2tb7QEg}7{~yACR?z=id2uyidT9j-My3CRK>?}!gT-M7hxPm$)&>Rw
zLi_*1<b@TaCB#+L8000w;-_E+nUKU^f<8t4i3;5I3wbYP3Y3(#CjoNo>7~TdI$u7j
zc|_o8E_2(G;2NA*B!c;folW3V;t~^+Q%wZ(0mqwrEr?g}R9Zfvk<n>w!8Lf}tc@@b
z&A)&5aNHM&vhX{Mv|X@-F^aqE7Kh^;fh+u~pUoSNY<MKFL+fdZPs$Okz@;ZHweMY9
zC>}#T-Lo*Ha86Whw8|Oa5TEf5I3s)nuDRgbEvMdV0VKgRAKQQuPsd@RmWC$r{?~Sa
zfRz7#Rss9BT?c22|7no_jzIWNgol}{gR`@lz3cx0i~8TNZjSbj|5E`9Nb%qFo-33G
z@MJ(hGG;(Pu>TZntxU}9UCbC<JzaD3>>Nlt62BFWB=0`W?1YN+6q9;nDWLKjj<NOl
zT1lsPvGEYvQ^jO^mM%2jNA&;H^?6rD+o~k-CxbSQZ<;5M829k~6{-Dld^D^ZdwDsm
z_+skCR+L<OzS;l!do;Kxc$oFk@HVm{ub=XKedlXfx7~fy=xs6g^He5??V@bw;nu6&
z_WX1J*H=XR8q-sm)AX`p@{zqVtFNxtF|D0xW=MH#Z29e}K-&0VlbH70TVnM%=5ALP
zU0DhF?6=a4^=4%n;O*o8y_EI1`{Qa)cq3{4d32$t&XdLIet99k(`s+EHOUZ(kd-3a
zHJ#Nud#ZOy7nie?iTlay5m!NA*Hwxb<GVjOx?$FG#!*|mV%4r!-Q=8-Mw``^-czle
zg)aX0Dpl0v+a?_GJm7kBW31a=Tc>N#48G>O_-g+=r^j9X(E4Nl#@muIy$IM%Z-av(
z`8LbGAzxViT5z9q{FHs&du=94;62d_FLYxU;c7Dl*5WSc$85vyq!|N$`mQgoqe`ze
z19LVVJ8nUb<2eyy6G_tUP!aTpPA|Dm#z;TQuf#yWg14)xbCYjzfxZg<d$HP!?>=Qi
z)Yl>6`7547t<`N6>5}h@Q1|?zTIqeJ#Q=Zz)a-Jyq`HM<f8xwy%w|J#)tCol!C_|}
z01suygEQ*;^ikll->^=dgN?kg9*<Cf9gO}Jg_r~?19gL)Yu5%Y4XdhVmu=N*pSV=b
zYo-Me1uN^&G_q!Uj6>qkHiOAmyH_-QFUxKCn8b2tPm3e$>T%s!iTlxAYgr)P>zW_v
zK0x=Q;%1(h^3M8If>PiI!K=~i59?lOngmEQxDHPBz7kU8sAF=yt_Mh~1!6&@s{LhQ
zB=#H2H~<g0k@{mT3L_!+>l!3zeJuW$a@$)WZDZyt1m$TpL9?vyrT-R&)<l=RC5Z|h
zPxc(yVs}K%RIdnb5-H)Hq9K;u@Cv(Yvc?mNXpz-@P*9=04T-CzLswdS3pe2H*YC#F
zK%dJiX)s!p$?@z+bng7c+{*D)BrS8Qh8VJ|sMOXsQo?DMo$9%rdzDX@YYc{fK{CCb
z{$*JKSiJkm76=L{K{CAp)C7SMEcH<_Xd!TgkVsvo3_jQms24gghf8a9i>woTMEJ+3
zV3d8_HaSf#4JM8_lOXK|7WMQJw-}A)H2Q#{Q?<^>x)#ti4Ci$|${E4AG>UrELWJke
zq`3H$FjIll$w~7W%{SFBmr5gHYitYC?fKcGDpU4G26^F!3H^Z;I|;sgWSw^tfw`FO
znGuSIMB223T<0kXwQ3gSVo}Z&mVj+x>bQ<VgRb4inN}jLuh|L+ePnukiL7MJ$`Shw
zNy(-=6nyG?8cicI<q0c-2SVGeSIt2RbGin9ap#yn^%;OV)$>uwW+okYMz5ac3M^qH
zc(BCnRNIn3Y~;&fkoWB57=>1pa`FmKl4SAS5bWj`>u=iPBWA|o-=)0R^WOYsa!?(r
zbdrJ&)88T-K4e`X@&gc&cM)1cSSZ%oK~VXk44M$;E@FMKY#f&t8K;^?Mbw;eNFr>$
z^v87_Y1ZkK9&+1Zh#7WyRh;sdt?r_yTJ%4*igR<0cridxhVP(tLc8ZW1j_tL{HhHJ
zJxh-~2GwszxZFT(lQ2VEWkvyYLKaA}*fSrbKAx#lk)##9ow23y%Lyr|H8GmnESN%?
z?!xV*7*&x?9>L+3w(w&;O$irl>*cR4SCNhgw8Fj=WIJ-23av)HCIK*aC(#mDD;ze%
z;&9L6IS5s>slGH4M|@JSSytkf2i?wtcBT*L=;VXw-`2we-}Cb{TeavfAKA$gM!DPz
zq7jXjVM@k0`{i+!>*0tlH*ovuo!aiO*u$B^#t*zMVc^k!h{D0?9ZYnL$^vEOr@Hk~
zC2V@mI(N_bfG!Mc_C-v1`J40bKjK6kMp*4zUxU>m&N$<vC<ll=ZfA%Y2biEJsAMTD
z-cRe}=F6wSP~Xu4N#iIn)6X@oI%&qg8z;y;bSpe&C(2n4h>Vco`a?jw_sApljQ5`b
zjcF*Wv)r+ebK%gz;6T9}E^n#G*i&ly6gXliKhQ#$p3RWRUL91O<j>G=mkS#}BF*KI
zRNRV|Hi)4JL^Tm8h64h{ra*J`i@uQ6Px{n@$;isZnBgZs7HP@O$v1!sAjwy@UeKzB
zb)+<vY{>5qvmtFm!kLrxEg7~Ej=Z4NOtQ6MQ7bvE6bBTlePUgVqv$odzQxpK8G`m6
zh)znOjK~X|^$WTFpGLyCoTS(}m!MdE)A5rB6sA}<;6sT-L+n_$s&`ta#CDxiMQqt-
ze>^yGChexkJjU#7yPkg97@T2;%l`68GM?cpY@V`ig>(O5$X5&HC9hSllY7#Mrs}+K
zQga8lz7q&Av<-(ZKCVR}v5R8)3vekS3=n*hsD1#d*2fX~x}Zml90@{GwG<RnwwbtJ
zG$)fF8^0;Vsjr&cOmF)8`mX}fqAaO~zl({|Rju_#zwn6pX7cFs#?w{S%?f&KVfA1I
z@L<YC#GHNiNu!5s5NjGs4}gkQ<9%t74t{0A>D6J2el&Pf&|H$WKj|W5U1~<GR?xh!
zFETuMFWBvoKy}`N$`;l`jI0C?(im<Bjguianv9u!u|*F^BVdAQvcw_f3Jbw%iUG9)
zdKyKg;0J48vbd+2ozSZbNj)Fa>465Ly3I5gqsqW$F)z27MP{OML3<&yYN^o(X-0#s
zBuQ4D_62#<xy0g7tQ%v7LJ0)4QUxI@u{Z7vs<^`-yIB`|5wJ)ANIBDD+aZaLY=PL(
zz?;E`A?U4wlEVrz6y}U0>;iji!XyQ^(-l(I`ZHAXPAK@51!7PQwBoM#qM=mY2xk>=
zT`WNjwbLj4%h)4`VC0r6@*oR|_IfS!x`Gx#>C3ZK#|S{A3)KbkrdI%x+f@b;^XQ|$
zciH^hN-*5Bzo9UM1`+r&f+#Ge&&(y`{aN=^T}`uC8j=)UowYW~QvADTr*1fLds!dw
z?_JdZF&7$_4unAQ+4O0dH9MqO5|V<RhwOoSP5BEJPFKSc3a+Cc+zZL0!?W?!%H}of
zYp2(Rq1$`l(8Lm`8N-F0wBS4MUK@mqJir{c7MMP^eWT2Pg9xSYM<n%*X>t_vJjDeN
zc`R_aOg9zXUL{6#Vflz>2GCE7=}nM`3O+-l1Tl<k2ygeh_Y<&Lj+w{uyIdyrj1=VV
zky>T+XVG;o+*!WmY-KV#+u@joM+p0;a>{UIrmY8AC9S3!W|v!!!=*?zY9M@LZl;g6
zrJbhxr==eJKf0SSTUk>Rw$45-4t4frPltcfCT1dnda}3YN|Rp@Ur`Z1U46JaGIe9`
zU`_m0%Fm7+#c(bGj`0ITPZU^bRDb#*hN^lb!h<BSgE5NJTE$zT&e)^*z-yNHC}tT>
zelAmOEiET(%R21;lK6>rH0LO`lp7}A8(!UYX6DFLX3+`AJ1t7^3UcFSI*sN>1(>Hy
zr%r7;y-JpOiR|A%H*e;G0dKa)wsjKiyTT@bfYuRosi+Fz05djmkcM~AlTJWDlQE@(
z7x_AqgUHU#O5CBH=JV{yXL6&PyA%fn2C*aZBvy}4<un8k0aM6cV4$fFVpQ7amRIJ&
zk^SKYu$c#(2_=px5a5`ELi|ePR=Yks_Z*3!<X;wZ$zfSMrh{%s6j9Q+F)p5Nx&tZ2
zEG6;zZsPRJj++9^0vc$Nc05K|v+UGARHr72X@Lu9LTV0>jAhXfSc~sdv+W`9hb@d(
zP#n8V38F1AwK^`KF5#}vC0XFXb^&xaq1Zye*w#@XfA<m*E%NFD7((i|lGC%3_cNF&
zU;L7u#YnYwy6#%gd1K*Pz&ddqs=Sa`;xgN1IAwH%qA#LPVNdAE<`1Ts7)^bj8NXxd
zJm;73x0%kHI8lz4V`}$7XERGl0-?+c(Ns}$L!$hOU6zPS9R2y~goH;mtf{nhMGuPV
zlXOkq;nj#FHHxT`plT3#B^+Cl>}%AX0G<95q~uro)oduZ(!M)7zde#*jD=QP;48`T
zG8V2B25Ew;>vc@8$wwMajZBPIbd%<S+DphTEf4G{gW8PD<O_8b(-VHUMyq6`KOB20
z9k}@|d}i1#NWTWlxUDuZqOKeNeyY0W&PM=s)tmtl$<4J0t#tDj{W1u-$j@<$NFK?C
zzY3ho4C?@Lc)c1lKoLXrb>+*Qeb9B8>WAE|ZN9PFix|a2zpR$FCay=;mf37K+d(E+
zy0h9?v+UoX-#@CffgujD_0+SoiRAn;hs|5AZt$4(q-mkRLGO_MTiBT;o_LH4>@BeI
zHtX+Z4;v!-fX1dIup|_wZlI)cbcuZn?L2uBck)`#xun=LHY^wUSN(!XRe8b6N6N$-
z2n!)pR#8O=YGUKsdyQzS(3@y=UUR{;1bAvd!D51KOwUd|tDy?;_;+3_w&X(|R>{^M
zt_D`@Z)+N|yu@Q@W5s*Br6*=_?O=J8<r@CsTAY$kBum|4b!VCsDswVA2YdU4c0xX`
zPn{1h=SKFEx8hx~9E4+&Q+yYQD`s5G-E&?XF(1$pYJHa{wAi32zV3bb!h7yqSy6W0
z-x6Hu4#%thkz^)ZIOZHkLI`FE4pHz0M}@eWOvc^&H@YG#U!cZNh)AjnD(wI#SHGw&
zV+#sL8Rcyh7F7+2V?+k6B)OJAx$I|T{jouLS;jdfdy@Sb4651dZdQb?=OmPZvcO?5
z3#O~V<v>#zlO^V1^Rb}V1>*Tjc!IL2&-ajZEi?E4-MV(g;WXOZ#D~~E;a(2LyvjO9
zeERQBSr{j@Dou2w5IC7D0_pk=FeLE|(4sAOMLfb{G#5D-%#kjYGpu_dE+#3<#-l)@
zay)JueQYCv=1QZ>gkp5U-^<a|0yoyRn#=Y>$`FQ-(kmvK^V~TUZ^36!>%8LUDCyp-
z{Q>T}U3D~>nSs?4gCILP(!IYqLecthA;_|qcRivhj3rcp+Hc2OVXz&PzdkG^AK$=G
zHa5??IE6`!_mLNjvJa6ZUYihUM@Y;^^8DN`TZ$&wJ&3zF*Zp{ka;KOXfNf`+3ukyY
zq*l@>H7t@gF~-ZvsiRvdAm`5Jx~a`#FYstAKg0Gahk&+p)ZAgH#%KNff14kM6XsWY
z-}*AO3lD==1%u~9&6mM%bWyIA^9=JaCP8_bBnt`ECz)6IXHoHkJ>>NWh_B{UwQDuC
zJ<a!~31AX9EZ!$^!8I+8(Y)t|;Fz4w*Z}PEI{;9f-XG&GmYYjm6+L$yb&nbXEpyzQ
z6DyWnMZ_#tV-9DTiy<#9;QHqItKB9p<6Mw^j=H_ab}RN_O3+%2`5A6zdHVzKZS>P;
zL&D1^5HcO&Rq)RnHt0{-<y05bhJY<599VQGoKZSZjuJ2Lkz7_NPm6QFs(^T{tP`CT
zm3=LF*zpI>LEs@)(_tq<p_()TpVvJv1ghoS_<*^r(+X&#t!27aO+STTT>_;SsV=Gj
zOES0AQ_efnGkUsncpmGA8u}jz>mE~Z8ijdM2V@5&fP;g^NlStT$px8Enp7OzCvx5U
z2SH5Yn{gTSMT+-9``*1VB4LCVgAM_as{6>91{LYiCM&)fh&{1L7!lWSwb10vM<Sc^
zb*Te-)M&TNX9I)`ssovxnWZ9j*zX%H6|^K6NC>E1AB!jaD(8c6t{XsfG!gJsrCOaw
zBc)(R8J#sIZtjL`Lu@edWDX;VC8c@AAFWAIp*x*n>~2OusEoIg<}-20;}*d>n=!I}
zBcgWGLQ}EFKYR*{8REhNEM8{x=TK*-Qj{|+)J7KpuIjsW6~a=p)KG(jJ*ao^$aIc7
z!Lm0l=fjJmL98)n`m_4o@}a#ycixU&b=Mj2Q8k;z>gJvSLEQp{o<5@!7U$s)cK&{i
zfDpV#XR*a~7mCxG<Nl*xx{dQ1NX;MMmuLsq;_9-GxST?^O0BeiaGkGYfua4lYOf_n
zyXx0a2N{u}L@kyh=`BmGlUF+G76zvN%6E;6g+YZjJM7Mn$vry9wxWxb;$b>twqQaO
zUDGJ5f>VyEe++60X((z9?2%^#y75lbcv%jQ2T>LU*gc*wuaQZEE$vM`14~Zp?0MtT
zXgEbKTXb^hjCDLl5(!FYf<<bHc7Kqf^hW_AM1-}j{|bu@w6<9QZ{`=IW8r&DL~HK8
zc)6&-wWBAX2H$zOsX!m9DID4Wk5vf?@bi<QAp)5cJCR0gYKHBgLv42E6)E_|xz02f
zs2(O_*o&Cou}fk{zx1XYxEUjQ8e!;$9dj|O*f?0nw-kWsptNX)f-W^}%q3^TqlsAQ
zddEr`(57{2%f&T2&^qXkmm|b+Y6-f;#H;$w%5>Fb;sutHBVL1gr+9s4$&Y@~hTSsi
zB-4xRLQW*!+s45A1b3Tc?WyV|nJwr;J$B|_of~B)pc&z23RF~j2msW?+cyos1H&Dy
zD{TGLsE&~kvW@kGDu_42n^7VdA4Vx78jBex^405w@#n%zou%zOor~{tVEcW!g$pfQ
zSxx7RmC0@NMrYccA+nnppkr6FNyU&_h#izkaYWJM6uNYp@!RmO^Cgn3R%~c9<t#aL
zy~Z)zR>b<oWjA|R{Ti;&kb(Wj_Cd$UEP0%cEA{fifS4zIVF$vYA)u%Zw?F-DNh8Pu
zM>)esyvM@BfOgu`)|zd>`;jNm(}bU&=5eLZu~Lu-B+TcweqxcnF`keVoI<`r{6}!$
zd`aAQW4fvC>x!8J2r`j3yj~W=MOlEjXH2%Ru;w(hl|{uWTFXrtC$8z0<oWO5Nv45{
z1e0}Cy4oGL+S7;(A!k~{@tU_&4rqEksDCPjSHIa@&np$9UcQ69@bQcVjuXesb4QXE
z^)=rPh-9}3!`QA%=rMfQg@vu)0PO*_-l<dkiz5hf@qhsFSfuqqjrEx>bOUAHY5Nav
zp?047JTeT4zwC)*HC0ED)N?J*kQUp|YvRTnA7luqIqm4l5E?;rGXQ)>m%9>BMSzxj
z@XD`1?wM3huzvR$;cE&6`j+7-UheXH&s@lN&J?g!D^wK<WQyHpRN|L=&KIBxAi~|C
z=6*=$RP+rk3y}&T`vs{C!y{#%0I1#mn-lgc|N5@p(+vynxIT{i*zE|xKlPm){M}IB
zGfv$Bqw3Y7qG^G|4cL$s$peY>gtm=qelGbRzK#uk%R50}o{}EG?SEqQTwS$DQZ3xY
zze!|FB}7(N#JV;web?(WiHhc<A4#4Qb2X;`qexmJ8VuWJT3x-~)6xtE*$&PA$&~W=
zUo&ASZ9O>9jX;4Xi$13ggOR9FEUOgO)39ukQv)G0b6238NE~_$S@K&=*P}sq-5X?j
z<B;q!FtUSiUzCn*C7Hi;GxlA?-^+^VPjJU(wtK>0UVLDnz$*=k<)qXhmVrJh-kvr&
zF*30jZ03a1E5|6Zi7io^@$4_sPs;;AjPe5>32u)edgdn*Wf_7Kv~kHj59wO)X00%{
z2IRJD3hi(l))ktw^Pw+Lj>|U315I(rOtR7b>a(zFjW0Xv^3|gupL)v{vA3_$X{u-c
z>45V@>}mWK!HF0$h8OM`d>bWOV=0`Rp4;f>^|s1g2qqpWwZvjCF!K%S!rdO#{@7&1
zUFUj-LLVyP_GB0Qxm62N>oJf=9@i+Gfq=l1#X{=1`IjyNUEdzQn4=a+v9b&LMKOzv
ziT^QC)j9We2T%1wPYe1ORW{>G5{DZzDOO*UExuXdN|$-HHD<g!`DIMi^x(FnArn`C
ziv@qi(o&I=uINB`n2q@wx>JVa+jRI>?+Ta!L5{=_=X<y|3U|i{ob+LR<{fDJce89q
zH@=^HGy%l9gsOpXccyG6sx9}Wx?S?uq<T1fhY`nYnYCurMO`g}UcmrT_Lo+q!Sj3e
zxx?l{+Zarv7raV1-i+miL>i1y!G&XO*u}REnAc)oheR#+dPui4i>k9`fb>GLL!Vi<
zagt5bcpI~5vHWPuo_N4lgvF{zjzz@;%4K7pMc!J}Y8nV+<_Q~id^cwHLN|*0i{B!D
zrh%2OCV^~2v73Mx{?87j3%MC)Y%kjAkp1iIlhF)?=da@UooNq;;tseDc(!=-`xPMa
zxUdn;TQXWSdWh5>fD1PiFU}mZmFW#*0)Yfh!P8qI@l%(K%E9(}sR)iLUK8b7IR9`x
zMR#KXJ{TnQnc4CEwaZ_aQTUk+aUrH_o)!;dPHrHsohwm$UaR{X8<Gg$wVlh`Y4gLq
zrE;}SXMt`!8T>!L?ZGh3o9hf%wY<6vv;;OMhwI3g%GtKhX1_){F2v?JskDY;){`JH
zP`-W^s)C`2CwV~ppfO#bC5r*Tj2!Gz7l{msc+68wD`I3kZ83U`@VO<@T%izfN!jpz
z=tmWOgP-yu&#c7Cj_+#6GzqZ_jR<ZK0aZv5(U%?%gOR=Hj=u-@0(=<=0NFV<j^ir*
zID4tR0at;4Fv)%#CkawN+Q=T17AP;Tp-nvYiHR<|DTTBh4DDYJXvf64?ZXzFzNO=r
zJRHF!<8ju4=gjNuGmCJr?m%p7D4tPwV;VUjx7vUAh;-$ppFYU|B;*+LU=}m&T$GL<
zG4ELFbl7*zv`-(q;WsAl+=JbN@op&2-!pE>S_ZuVre!ZUK8h_}cjBZ06#G2XScRm1
zNfN1Z&1Nor2R*}0Oezj{iZh?IZ4RLaLcJR%`}&BWZ8q6IY|Xwt!6BsQ>3%hQZ*lOj
zP|GpTK9xnryN(Pzo!~pp8@$`OBL+ut@n36DB<MFU*vXLxOpsT0j<}NTX*jjMq-$qR
z!o5{S($Dp>8TOTL1L3VG>@n70zq+HSZF;Gg*eV3hafww@S`Zux>3maUo0afA)q0jL
zTb=NaJx)IH&gsHh&aw}zUk44k$cSyO>;5>8+{y907D=FWh$<5Aks4#3Lh@g1L=P=h
zRh8vuJFr9&&wsoWx8>N(LQtSc)poE@YEcnMmI+Mp?ozA!%0@#Wa;AL3ldRvcCMfae
zK3c){4d-^&S6{1D!M`C2@%xvKL&`7);1Uok|HcX-3uuyzZV<B0swE0@TSQ~9n?6$0
z*nHjEI-g%0JdW*`V{xnDdOc&Uk;BU-CMrvt#$0APq}cDFO?@-*lpF9o_CAqhXa|t4
z-CkO!p<gR7Xh~T6dx9cqD0N!q<Nk}Q6ZCx;M4|~&JKzMBf6a|BZiZh0<dHB#pMaSn
zL6na>rq=mPgG>y@hLix6QiOyyT($GBBa)vmZz}mb<r0!L7Eg6HnnW2y6VQAZO3^Aj
z=bJ|+;-{jY4{EN-+O~iAXuWlA4$coPCffOBG6@fr{X&ix5Zl{A#4UdyUdYaCALHsI
zH!sgDdEAyhlc{>_Wgmmw(6YF<cao<$JWk%$lA7riS-7Dl|8@co!D7EL=xrM)+tqhP
zitJu8&i+<auF|$Jb<EnCPni2vq_-<=<s2z+6)8|fVki1_?3oX8H|1|E4agdb)c_1K
z(>CKKs>Dnzhz|}4wtv~#*t<mEf=fv4dKy`Dl?)#z9iV4W**%>}ZLd|yH+k>A<{Z4(
z<1)D2g-sHssZ(FAQEo|1tYynvuF^60hg_W`rwxPD<o52MQ71Zkap<P0k(S3RRWq&S
z`wlI`s?6k=5TR9}eOu*O)HKdT!QV*d!lieKYLY9oSRvZ78YQ(A7&ZkYTuS<{9NwX*
zqUzO)JZ1*?1@1~5k%g3+p77#IfBUYj`M!$E$42|zC{GOh(M%Vc1uDkOj1P2Y;AeoI
zOTh~`hUK|R5tXs&I(heO968$|>R_vBj6_G!!NxLhmlBXCsQDdZ;v5!aqs&h_Z0j1A
z2)><^$ATokS_Vh*0DYoa+}-kI>ljR_6lwD}VU*IRWv>Vk<SMU%`=`e>zWY_1m{R>I
zSp7QJxfhg#Qoqxp$m+be{r$qt2pBl9S&91nr(i!6d8Z1N)rl|c60ey&{RQtU*()c4
z^0zO0f8Uqs{4f~Lac}3bg}c=3Yio}__X+tRs^a3J+~T;n8pNg_iM|g7tAHfWS$u2!
zqXOX`TqlxHt$9S&*+S8GM)-0}V@)g%)yPUF>UwA}q31ld0)!tEB{Zi)#nF3jf<H)p
z{6gMEY9B08G)9X9jBM&d+0|tS<J9o?Y7s2*;;D60pu38~lUV?Z8Nu!cu`}m!R}|36
zw`gE&uOyoa+~_4_+Fbklk|6JrU?Va7d(_Ph>G^|{5yYIb$eQj2`KL*^(4C(e{T)+#
z@E)s)P1(!4fxj%L7W~k3qS5VZ)Qt6EzF8bs7{Js)#0R-A&uVY{6{`CpahlOb1#qOJ
zt_$!)JFd!0icp>BU7Zl+fAY&i0HC?F{q!fCkR}>eiG0RelM2F)%phIJ4N}rJP=YfZ
z&D4DHWhzK=HZhv^eRDP6j$sx>d^F_v;cZ<`e4Japk0{)HWg(<JTk{ZXZPEJNJF$H+
z5g2Z}#v*gJjm`}x@QI<$m+O3ceI{(Ynw#H_E-5B&#G3p3jKtsESUxO#*x(4f^RXQU
z=*HffKR=G$$MuX{<xz^we%XfJC*yv2@np!`3*7m7N*VLK-8q>H?&urDmwj#yC$y;!
z5pH%ZxN>0cZgrhsGbT^DDpD5t6uuAp=S~ak2uy=u*0(LpU_Q1@%pCW}Q}Qjm5_+ie
zxj9)`nItQU-KBqXb#%1*w;x5&?JU7@wy|dBa7YZ9w@qUgnS5Ol{kt?_%SHLHH!pfg
zzJ#WaN@J|0Xu{PF*5X8&WF)ASRCRe_>gnnsL<|dJgKY5O>G;Vifv3{>`DTK7L~^i-
zRxHYb6`(*u#wT^R>Dv~7yXL=se`hg*UT14fJFL1Nv3-Eep@%P4zabQei*x+&AHC}6
zZRI?KEyOVRlTg+t$B+)YbpOYarR8&Q%r#oe-XYM<pWt9mYI(G8@0HO0&K@f6`vcVO
zBofImd;t=LjVVch{d-za(b9@1CnSXMj`Atud#?`w^=DJDi1DF(9Fw$Acq&{|QYDJW
z|2df3I{+4;dn_-5jwE#5$dNCtNU;d<@Iwm7)5;Ir%<%Sh6chCm_A6&Ne)cVMoE5XJ
zSSTQ%A9<0{6@|C3X&4S5%*_b<HzfOy=UaY@I{A=R?z0WyWNuGykA-j--i$;lb?Hxl
zVCjN6PcN~515F$Q13_uA238PbWabB?O7lb<9!z{5x))0iTql@7R@K7MyU_(Wog+Y_
zmmI@b2BY~~=*FSWycqPb33w_nM>pdmA|}DxJDp9SJ;4?2c8tx|^=&G&MPZegzdesi
z@k}#)fQm4P&)#$|QPX0)$8Y$uI0fHnnVNb9`@`$~7&CnZcaUwZSAT4P-9qj7i>+g0
z@rB|wX7|0bUPEJrcd|=G-X;lih;PRjY0N>;Ic5SvbNR_Hruz@;4W2Ofk7-x;LuRk;
zMIDh#ui_4#gg+#4Adp#mP!Heuzz3z255keLa>fK{dPrI{->&E0wH$#wd|JsT3MgOX
zZ>z7?2%Y_Rl?OEXK0C?W?g;{9{(+B(1WtdtH|YvEC)wQ8f{y)^rt2rYr_!>0Oj~zt
z{?hb*kL=<E=sPvO2!TABIFOpZ`1rHgV4hBc{2e$}_OuAq?Z*Ze3O0T|s<Qg+Sg=CE
zpKq`T$$fEMA}~LzA@s_@Nmi$1u?eYnq7*fq53P88)c0#WKd$`-^HvX<ADG`bXF&x^
z21B4X#L;qMS9<LlDN?D1XN31p(E+t@;6ahOH@@fZxV6y|Qcvn)&k8}U&~2mPr~DVo
z)l~a6OHUnPO`=c&eA`~SL(59`aXRqdGXe?gN3*{}MF<G{Q@vvE7}!c}IQb~U-|SsI
z?+U!xKJ0VH{U@fj_Kt7$Jb7k)Nxu)@f%@(vU#C6lN0WTI=}&y(>3SKKSnu&4Sjpxk
z9bLHOntt*svDSZ11F8n|3DKC#1nO#|N)~HJQe8j`_~_vqoZH8=HOU*KawT>ilGnTv
zS;Bpa@2xpw5{g`^+}ZAyck$rX2HDd$+TY<M$6Dqg3N(m2&XNqkPP5?78g3pbzhtQ>
z3+mWztRL|sOiu+aVxqAxX19Wum1{i?P^nmWfP2-ttUE+^vm8-R%z9y~#;Z=gE^H(4
zJn$L@9v*%KHPPySgrb)`=mJ|U{D7Wqv}UrJ=2s<PKPgw+R1eHr8VH+4G^3X$Jf){F
zYdHXHGw#oYm6Lr4SKJ+|JdAg{3~v)>b&${TR1;sKV0{2bVd|#mh&!|{+q|OZfDgg{
zA}vAv57N>!;wabfKYr0LGY}BP|DI+fY2<3=VdN!d=KhaS#9(4;<l<73>E)}lk`g$V
zNPem1?`})pS`<ph1?z4sc?CAc9CuAe(rR)rJOCX;^W0QKBrBpAZ9)V<S`~sqqO#c_
z4r^p|ms?K*G-6QcY{=+XQmgVz&(FH1FXp=JCO<v-sy|##6ZUr9eBE%L=K9>o>c8JK
zPy+8UeTG2J4#056zw~Q7dG!aOa%G$igg7SQQu_4AslqtX5L}JQASw)<6Wr~=*=J}8
z333mEvi};9X4kZEvf`j**R46$I(3|wn<&V}I~g6~-y4Eah*!FknoV#%Tp&n~MTa3M
z+S3J3IM&u9o*nX5IKeaqCD4o%><7<g>uiu7I1woy4YSuR-ZN%kP-e>CyN6+LGl>bV
zA>hK>;?gQL><XrIbm|DkhpAO^BxiI)OLnJekA6h$=$i_ua*D%Md=Mg?GOK~iyf?k!
z4ofENWFCLxQ7C<M??k`a*RzIsX0gf(zVvDZ1mmLdsSnf#e{CZxGhGZ|<(3-i3hNDo
z21|o;(s1SPQGi48d-CKCOk}{=pM260_;aMSwmVe?pHj8Q*_=8%6HuPgdIkk!KD5W6
zZO`&yx;R5q@^W?jPR_~J9i2GN)*YB&P^djRqEYZ4o>+m=AG%tj@yx-k^EiZuLf{YD
zv)e%0#(IhfNfZc>Bq4}?nh{kRT(~hLL5m|oyU_MEDc8|q##%y(rf(_jCjs+dA+U$L
zSUx_Fmq59<^gMpR2rZNohofEQuuc?{bj~@WZ(WYndMbT3UpQu#E!<ctGD~HcR1+)P
z#6`49%)K+zsn6?N`8Fimz`ar+JJiN2C>Go-3d>^e;U$R1=EX*hvEiwq<)FY&^~%}@
z=jUH8ApMP77-<O|5Qx&0GptNSVI%uocUS=%oB4~qPXG;?90%#4vXU1$TYg!bwk4D#
zli63?QSX-t^`lJAfM?{Tc@b-afY_8qtJtC6H!wYN+!*v+UaYwB_sBpf2NIqwh7Uz3
z^S)(0r46q&)hb$?WAZvIZSci1vp^F(23d>MpHI|GazTvP%kBu6hLh6odILoJhrIR8
zMqSuvOD7x^JcNrV1esMx68=pJFgO4ShW*9raAzlOK&(<_#Jh=+otaN@5AUX8(yj1W
zHIAJ$<W7=Y=-~INp{;&PP5d57!7wDXf#s2PpgWoaiI^VgeTvzSVJDWjpi5{eX>5}#
z1d2AFl!*BUhN`<I^s2f!7`qZ>k~M|tM48DzlojxNARh|*R<#qFRONuZDEX{mx8hvx
z;(D-T0)z?dv@(n)P7!~ImAcmOLi*J;y0_z4p|>$Pqgr-};)Sz2EI;9ID}yAd;j2yt
z8TuuzbVF|LRkoySiE&%rkp1G(lU%c8*IK!*Y|3QIub{KWpjEpG49l+{BbMBo@~d4!
zCJAB5az+$Whd{^6pBO8Gy~ULu5=SE`&c9`Up#mB+yMK9T7vUeZB^8f4`Dq*PQ?MLM
zG2vM%e$+atudqn!<6WIwC5)nip%h^(+Nl%W)j@}Nsm<tSoSI^yHE6`Bu9Px)nOiFv
z-&>Mw;**myTs6GcMm0ypr?28)z`N<(O@k`Lq7X$TH~*+HrE2-x@VAgRD8tTh<x5ZC
zBHb9rWyi<1W?CZto<V2vy&%h+XX$UJN&WlK54f|^+JpoA`Uq8}irWYXWzrBxs->bY
zFgx$nrO+J35#^%S(%gSV>pz=vjI}4cs!B>Y#$6c6q)>G{m(Zu+j^?YK7n6d-Pt|6g
zGl~&u#Fc51jC{>kBmAQwc9>ah6rHQbIB|g~NWCD*&OA3*?J3d5{@Xl3>T!LGZ#oCs
zk1nN9E<w0<>tcD=HZK0@%3E3^z?-s_LO;)(4V3GTiW8+OIY+#>Rsn`iU`^O)v-yYt
zA4QiLT>>`x@3<AS8hru6XUmx?S)7&SYIC%53-y?#o)aVLRXccV4>pc=x*asOo6QbL
zS5+xJJAK56B`@#pEU^t_`O&Txabn~Tvk_;P*D@Mi*tLa&)fm07fRMG0Ls@i(;jC@X
zrs%f48mI_g1JCx*gSvW*vfTqa`)<7v-a7@D`)Xu4A{1E)I4aH?jeAN@OvFB&k-P(b
z8eOQ<N>4`mgqQs<n(VO^$U9+l!odjj^??<Yr%FfU6hmH0&B2c5;j=Sxv{ELO5y?Ac
znBvk3F0i`f!$e7LsDu?l$xu~JYo{DEp1y~A?g$NnHKn79+h48uJ?=(27JmlECFt?u
ztW>RZ#p+~R=IV46i4}8p>pbe#-b3E;E>1ix5F9dL{bxQ4`kbx3S?Cw>uM3WOQ9_Ka
zg-V&iKWK4Tgz%KvmtWQrljKXk-%`-@)H&{IBmT5Yjv!+kh`y%dzEr+)3G9zjs{6v|
zE8koBhTH0+ASX6osQadN$zClM3S@qA-?%J)P=8mwJiaeoesR$JP&F(}nTp&{C6-zn
ztTu>@oNk=y_xqV9U0se(Tf=h}lAVoO(5l>vZ_kCx(-wnhCAd*&s&ZA@(0s!g6q=-F
zmWanZk*`+0vMin$jI3=-aXh>DhHM*2K*^pp2nP$LQ#3ras`XnpJaDS}#)!rC^>>|B
zPNG*-y>jT54Zhh{h{wFW??cfboyS!=a(@1PnlFWC+W?_M-yQIv_Lhq<rs<8iRrPK8
zMc}@GmUKd5tzY|B5_L0)$_HHOKJ69QOMJ?)H}lUcF+Q?ym_6Txm7=699|HhgCq-LZ
zWj`gtBF1rA0k|lEa(w$)>!vyMU7PLUWM;ziLP5_E77n)AlMm<gr3zP2<=*5|Y{Xz7
z4XuiP7Qd?Em0D-E?w*t88$(b!!`=PL3~KX1_0fpi$Z57*W@OHDXO8;~UsO)}a}Kmr
zdV_ZTedF6-k;S%kOpHbsTu{Xb*QXhlt0O&G_P;r?{UhsEy0&w1wa?&duybF9FM)_0
zx6!nkEurvK6g{d7M7pNP+H?e`VeeUrU!<%bSq`0l>8jTTnVqXM*1kwOV~Vb<M_tF*
z52QUDp)_+IWBOw&Z-0aah;=huK}heIzk<BNkxSLg=+pkto71K_EVeJjUD646ot5cO
zkt3(-m6{MpHY_3_r$sXoKSj<$G;Ajurzc-Uq>dxP3R2{n0WWqy9j5(VWP8d!NCn~V
zP~gmQ<8GTE3H4>+i4#m&o(wjeC<AiJcsPv~V{=1Y#@kbzse=;N(uBX3M9i7JcTV}6
zV(t4(HEEqME_(8UvXki6e#{%~;YynqnZF~k22q27to6LLT<?JaN$p%AaZ;`{@JTVi
zeBpfETwF@2-7@@cnQ)I`8P6a~A;rpOwqm^+!^s-oO_AXhe8PRyAKa#3BL3JE*;JV+
z7~9Ut0#wypEmO-M?*t$Hdq1uXE4L*AA|bgYxdU!ky3&@z24{q$^2(r(CoU}2#+wdj
zf&I{@(9^NrM`7mh9QypE47hPZKx1vXa)Bi^x+ioP1MV`YSBkBcJqpR-ovO&gC>QBX
zcVZf{UE{pGtl~3?@T>CVWoWQE0bXHIw#*12BPPi&=1W^`cmYAoxrYOE^lIb9CXuOp
zI&LPRVERv`#UBAJkE-djqXdtHT&Pjh_ev#WemppxeLNs6NQ7R$@}s?SoukvNH*j<R
zf(!%GldYLgW7fXmX^-@`67$}rX-3w^shLk0)?Kp`%}j2+Fp|E_Y6H>-QlPg6k@LUi
zaf8^7GdK{wN^o64Du~BGJ$s=7ugocGCP>>*oXYWztnzz%(05QchlQ<K&%s4Dt4K%i
zAudq5^gcv=E#{2vU6#gXU@&+>?22nw#8h|?ZeY=POqa-1JCKLmxWUY#O3tKc&Lwu7
zRKL?&S5jYPw?+5(H?>ZRdpEmTGQDlLs<m2{`R%bL3BsHtN_5pG<7C3h)v!|T3t0r3
zS|G4Q&n09y2Yz9Z&Ez0N3~kgywF=>$*M~f{rn<JqKeYt8vJgErgcSQx+Xa*%NrD~?
zsf>r{lv5^fI>4C2ou6p5$APh>`n&ON3){F0#c<oxvkm6dXMsJV;$$iM$?h>w?X9PH
zOQ(AsRw$Ae2sC5*>J2dk6|*n+Ad#~_ae^gZWcwJgxXD$xyy>1`-KsV1`Y@3nV5W?o
z5vR9Sx)a*g;0K*cg=UpAffg|ArU`<uR_r}@NbVtVM6~Euig@BwUjCk5E}n}LSlqF_
zLAF`Wq<2}Q_dmySdHWO4N6orbK&><dlsDyrbvo!h?ur#ZeQL#(ecmkzH;^d6Y4t@_
ziFeI!4t1ik|0{2aYT4`5X@DK<uP9UA_@5n!yoVzKE`=w=0Yu+PB)WCjIIwv&O(6-b
z(|fOH5tp<&Lo5uKt|O-ynft6PBODK}&UPcGNhyzzs#<^!NN+GC%hy=hyQ*FwSKyWt
z<T;z-`i2%$*y7fJq=u6864;)=St#V5sV5Z2(9j)AY(M55mM?t5P}?0?=N`4%zSYwp
zD;IL^$oU=K>L9EqTzBNm9ZKr}Z99zqNb(*#+!CoT(9ZDn9Yf74#!cwUos1`8T{z;M
z{VURKL_%nez9>dV2HjtRc0x3sN&e>VkUffU|3Xi!hx0U`g#IF>aSce(K~YDmbQvlc
zpYkK566C@eP(poJpNbji6i@61LE*6<9h@IBKJmwnJ$;rCi+=fSi~goNJSwpsh}^PW
z3?!d2E_4FVpwtX;7cAG0$XP@0#M!WhRsV6;fR4Obsf*!l@rSPrt|><3-Ko3i{qVD9
z?h)x~BMYGb*&h0KNNpW+pDhW)j1c*z7IQ+hHP5Yxy-=Hh<8I1Z0vw04O5OH)Mrmz>
z0kKz9wL}f`0Zx%{)i|#uO5db)SpK4XG=20&uK`zp#I8S$mKCyo$eO%N9MwjHf}AP?
zCpE9iZ^Yt)P{dI_tdKX5;_X)}95HrbmZ_@6;{XJQ^j>df`Z}fE+U219p%cA*J#LU3
zulnf8DvFyR)TI`NJXSq@KR}Cxyj`bf($Z$b>Zwec;;ihyn+cz2#=K|R_-DkCcmuGu
zWWGXiOqWo40<l#V>`6x$xuJ@^u@EBxjX{)bh#Xgz)qS|ged5nNtWe8T+$|RIp%TvX
z;R322aq<YNufeC)u01=WK3(q!8HUEX>%q>)bBq_5hR(2GT1OJQ->$p<7gHE_U3a<E
zd;Xa%fu}X(KN!{I7HtgV)@5^6$Sth0%L)#faq>!k1Snynx4S*$C)uR*7;Z0IXRfDq
zA;DX&7=3(i{FJmWU2cKxpu9IMsJE+}ePsHfq@87SCg8Dx?L$#S>>)52zz{b^f5G*m
z@ex=%QBRL(K<%;o3cJoXg0$^NC%aPz3^Q=W#NTV^f^OZR5q~CIPHlzadi~^;@7oQ<
zDV?X?0VBtjT&9ZOkd1kEBXz)P2=^$d2;l$bE^c?Bw`Ll>RZQ4bJZxIIBj)B8h1an{
z>p;fh2;0@T)Dv`SW)8R38lJ^jm5`|v2^7Z2kJ-{J-i$B=U0XA~;McvKTwZhXb6e%>
zIrmbSjO9(av|;_rq<(EN0L*I0Fioodcd50lM4iGIQx2dgzqo;wzx4^HvZBR=$hq{k
z4pZZaP(5NdpKv;a(H*JgN}Mg(HmvT+yd5NQ)fgJev#XXCW1OQFHJqZc&E#uKWB;ps
zN;tY__vwd~YR6ZfilGFj$RVK9p^to!S?v+}bMh&WQ;9IIJHv|p2^KN3rl}_}_O7so
zERw@H{E37Jk&m7}2>QUkJvaLxPAR&rU#&ZbZ`clPZ=2eE%wy8kMbUTFqV$hh*g1o2
z0h~aXfyLW3OvT|R{O4-1|0108B`ZXVz*Ng>kuL8$*%%zHi#cC*LxiMs4BE^A)3p)e
z^dNHi(AWq;Jlm>_O_6|K?8S^p@jR9&uA5qu&7qVkuEegToi9XQ)<T~k{+A#~89x9a
z@o{A3Cz$Qw2mf>D(+M>01T{y{=DEl*^ZGilF3G@a#@XSxtSy<5fTH^j)0H_MB5F%`
z2N3)jbYlZ8wT<w=5!9UwYMK@44EQOK08z1q^fG{XkmQ!Cz&|1ddE<f{_o5irQ~{K@
z0~AY$0+K@LT0(p!i1JQ>xOc(cJg6h>A>Tw`9$N6k+Cn}Pg?cA}or9ns2vq>iyyI&s
zfS=zXzqf?H<%j|%fSnVeAL7u82N51LsmJq<iO}5veaPb;+(NBcL;;DxWVS>Izk@&1
z@W_lno!a}4$LD~Z8=xO{RRG2K#X>L-n%q*02r6PkBiup^%);N2Ff6kODm3748VLU(
zNDv)!3%REg{m_DMSVG=Q3x88U{u469h>~3bb*+PaDZ#PpL-6Rp-@5Qj`w>_|gv?KX
zHmm~Yhgksf?f`3Ss4s1p#t8%!St1wbKwa}-u41AQcfe3Fk(V>Tn0H(m%()p4EQcae
z7KX(Vl3N2Ni4hXJIb@m=5RQk^u?^-VE3D8KLI((@at1726Tw28DkA`B<p3bm<Jj(i
zK(t{}NbVtoMHwQyf6L4u3R3~xy8}>*i7N3-yYWrQgIrI5Iu^mGlY+CYAkUM6(WZoF
zn?tI}0spajli=9IVB6LZuo5D2XTXd*Qk;<YzixUVyw5)M>5kVSR>|iX_76khxR+{T
zt`BV`Yi;)-WcD3;wJrpj>O93ZEJ9ozI=hp#<<yM~Ke<v(WG;@tB_|p*?!i4bF~dSq
z82>S=`7^0sy<qHR=b28`_bIV5hhn-n{Vci2Q~Lr9yrI_FkS`~gpP>J19*|wcJZ=jd
z2uKkQ2#EgwA`d8KWN&I~=KTMr19Q}6T~*DHzQ5V*9HvU>3xt&CK|rji;%carl&Gv=
zM^s>_OMVe<mj*2D&B(XEls4~y?vhXm+^HL&FYlr9KX5_v5oi!3;Bww<x4Z5yhS4Ul
z28g`db2G58W@H4MWWAmCJx=v$27oEW>>Do|Dk85MGbS@7BT#&>xndNdeXzS)aVf<@
z&e!Y<pCDR!{u&|;;~GbRsPbkLOMkHjOn<P6WxUu#G7A>(E1#5xbGgWh279Rt8J)C3
zM08XUkN64=A)kcEg{R}0Imb?z$Pq9OqlS5^<mYQ543nrBdf5!dLnKIX8f`5)hg1}&
zz}a)^dJSV)s|jR*$&gT+*|C^qrw7*k1uz?e$qz+C4AtT{6&|HHOafcML}Dc2rx^qA
zN_DeLG^TqL4NC%^P1SQic9aU!W>Z^7={8cMU!=N*&X~!|<i+5cmg-GD1*@JqznCTS
ztykB1;i}eta}cjU=kROK5d0iD+sh1LLmryXGed;HGf?}e)Viv{dr|XJD4DYCagZu-
zJtA6oHY7fxm8Ua6ys^Vem@dYV)0H8Oo%c0+y8t-9702OfxE3AOC5BTtfT^B5BDA%C
zT}M5ko+Fqs%$1UXmo^tNSj7xQ{l-t6VZM1esL0eF%5be7Q{}lC<iYniB)}Kmu2{0E
zKutfC%KD>Y5?^&_#YYMxle>a(poKrT?-lfydaKfd<cr0g%jOMcO(o!>$^P#L?xskT
zC!bNvuh8DP$Z@5?ix}}s8@KNMF&lH<okayoI_&+{)iso0KOdboY=jhbjs{KL83laC
z12A~GJp7{PEK%Pu9(|R6L0bt_NLFJ>%^}(4<N;fUd66rLyPRH5ylOS0{N`do4C^mR
zYPas`3+_pN)&m}WBXwnolErKd0j(!|QE8Q)$;tz%LFenx3Xq=C?6YGnd#;rtwYsKC
zCOm5gwSZkE3l>BH)MGe>GtcA+9l0Iz2ZUsg4Y$AY0%Y%=vG_awRuopn!EudqQW^HM
z6~@)7?FF=)t4~s&e4gToVtiKXjiki&hS43hg}2hjw&`Fe;w88Q*XrdZTKU@s>?>)N
zrroq|V~O_mD5b+fT(T1tUekD{Y+a*rLH)j~a_PYD_KB^2pI}IlxV0G{r*(_)VK4%7
z8M=zt=OP_bnl$b<I6ZzPSyPg%Yk9n@RAb^aP87|CH|_J-5zJ1k{F4wfo(U4eEZTnT
z&DcG6cSV#FL$~@)?|4)S24Kg+33#}X_Qe5u#V<&Vh`K>gM|!~#()xxo<eq)1WfxHl
zVgd_1JYB%zuC<}Yvt{L3zvXkr%(r2wq8^tH2K?4VIA)zuyl6z!^WRY(Kp`0h5BbMC
z7)a)PFphgck{%d~9I>?fW#1@EcVyY*WV=9V>k<90G%ME3f=^U5jc9|=WUPrMii+*X
zj;X0bC1?t$w?fU|?Z)EihO3Sa$#<~tthi%)LK`+Uiv#V5BX_2#zM*3plN=N<oCG}N
z&Y!Z?UuI^sVMkY*@NgE$U>vc`>Km{S_GK4R;PUZ9)cz=|>kx%dXzEzhw$AF><!o$@
zYAgrmWJEv6P(hB|Eju~*k;BA+c)*uHuF`3FgPWx>GhS0`wmB+@Wgs4Q&ZTw5O5Z##
zVcn-FIv4;(opuM$uVWUu&Z^RPdb#3idUZ<Mb~7bP9HeLU1r~bMR=l^CBODZA`x-SB
z><m&dG8-B5HhW3_9qGT~E3RpmUbQwfsXq`=ud9~0=J;m`2gc>NzLtkG95s|tEe5gk
zDP}`m;MtwvW~Jq;3367As#WIF+APUy<OHwBiE2jVn;|`xPA*H;)AGOEV>vdhv@LHJ
z1iFMSuW;;|46HJ~6p+6MKVBgTq3{W#VSLFdnMpYIOctV>3Smz}qZEgU1klUwGPpvT
zu?D=Hkn>_LUqwE{8Ak|TWj^ETtoHiue;)>yq3n8F-+!Ia-Y@_0Bq#fmpy5wWc3pTI
zA}MW078gL?r5<+u1N^^wiNB&LkDdSi0kHk|oS*9d>?N#ROdQ<*%R!WAdim<Aqkr48
zusX1KS!G(`uoTGRAW`a+(JL8&NNu5^Oq-*^m?`U<>n{}~XK*=C$SVn<0fW;Ng3!x~
z!vLc}fh4CcgMgqTy}+9y3yY25zts4j&d6r6p-$eO65eiKZ@bJr<hb1Wob(~yg4gTP
z-xq-Eu={RCfY{OxR<uhDS@=4dQ~_+*eODnFTfOhOtppj5co=J64j>p?y&C?+;F{e~
z5ZaH@<G8;n#WQ+3RUsM-+p(-uAGssDM*xtCJtnvHL~fq<WnUW;PIpL$d`dj>5Z$oo
zN55X9!y$|P>ah@sbz+&XP#SfHh6Y({jS?b1D&Z`L_2CmNJ(nYnJ*Ol7pGK}SDvmAd
z;u72;xVvlPF5Ni6B}n7$p5PGN-D%tj5Zv7%SRfD}5S#!>2n74cym`aCyv%%a`$u=J
zRcF_!RdvqY_w>2j{4x`RQkZQUS?#j|+BM|1jX*`=x-s4|#7}DEwUM93isP$BN8dA2
z>u%<4Uzd^Zp*P|q7`!*~{c(5(hB=2mxX&sjM>D~FK;l<leW-IeQJ`6CRA*L-HynjN
z5b{VmQ_m6{D3_YP>Y{_ME^YF+-`y7hv#bxA%#%dRD1r)jhI15#w+cMW0;*)z>bpV`
zrXY%;i~E)I+hNGuq&Bp=crhi4<2E*+k{^=#6K-57TsZrx78IPAf(!Cl`q7&f*V!dW
z3`?$(ELfmCh$>-~p^E+@O;JfUIVhbp<IaeC!R+gh(ySN}=hk7&GsU4P2y-W+tbLqc
zdy%OY4Zy0zE1Cb`E8bX86F1AehQ&ZMTIQ?;wf&5(Wo?N{(G%WqzL2bsg}G*Jk}@yS
zW`N8}ooOUGC(5#XS^K#<-5C>*C3KmIKsS~Q3d>hT%4w9SPXb|mrF*-QXY=%_Y6~Z>
zG+=}^W9bQ=J;fDLFYt?eS8dI0KEuRy#rjrWhObFOp=jDbBpV;|l9gGIW3wBX7uZZ#
z&oj%-sb$HD+Lx}~pY1N(!yB(SdSboHa7oA8#3Nj~>5V2fdm7YtjgCHZ56^WUkkBx3
z;c$KG{z?2jp_TxX*Tun#C-y3gtJPd*J-DpNwZa#LKP!2MEZNU2tI#PH#Rs`zY?QT<
zo0vb7k-Ke*r;rcV(0MD1<1;s{hMC%~yd>Z<_Sw0snI+v?)&xyqQocUEFrgNXQAG|~
zES&C3E_>z3vTUUwxD1?V9Z#;L$n??yn)@*fU_)_({_wsrT^cFU^C%O0QzZ8e@<Uwo
zEO=T$qX7`kxW>W!fg%f83Z&Z6@yMv%W-T-IpzR<vH@9Zyym%bs$C|SyvUz|fN8ar=
zSU)WIp`k7|?M#ERmV=O1w1VB>iJYbSt2(@Q;0t1{qL$`_b@W|zn)jK;va0pg>*(y3
zf^TXMkhGVOCi-z?AhHmfW6Sd+?7Y~#O-;1g{Y!w+w52JV;Q(*9@iNAoRzI=ei&xM0
zFL~GJ&xmidhCiSBlD>>zCold^-vRl^+EKGPEqE8yeQ?PkTKLiNvORX(IW+d=h7#KS
z{2BX=zR4NoSXAu&M)%W;!-?m`<uHbLOldXm$BI<_87}vMNtaXO8V+tdDaDaDEta9_
z69og}bd#r<viAckL8D4lqLu25W?oNlNJ}F_E<<n+fy0$;OudyjK8n*I!$~X#YjmKS
zX2qw23dJjTUX>J-jOjyhphs-GBxy+{5RXEus<EcxnYea%lpKCpXqz4c|FA+2wG!}E
zq=@5tfSI80G(R<qZwlg|nYvnNXcDNDo{v6JADdOd_Q0o@1TasIp*y5n=DU!gk$PlD
z+(2;rBeg-&&|_S#XGrHcow+{0dGJ()$@3yZ56(|9<MhG9goGS89lKA1x$}^kxJ$C_
zz!Ex`cK+?=j)ECkrWr_6V7tsuWys3xybmfE+I3nE#u$}ul^v*KUs5=_Ku4scvSQ<E
zYe)DKEdHXlk;&p5Vp$|r37oqe+B1s-=I`$GFtfkO;<M$fwk0WlQj2uW+2wKI#_``*
z$~G7K{yzO6+C&ul$EcM&zH}mNKVn8|u%?D>E~9>LtG~<F<nwA(ysDhe#xy;2HoAA9
zlC{o|v4CYK12S5RsrjjFQ^I2ub%%6og6mAMuyWXYO}$*l-1G>*XI%VL>#WkQ=N40Q
zty!p*{Ul?QhPjN$z8s`6Nl#OUl4Kj-HByzQC$XK#3tNvCvtfjOEA-LN{b7#iyB<ip
z8=I!fzEos?q4b&RDUrI$d*qI|+ON-61gYtQudbXxp-nneHt6mS6O?hSdSG)OR(egQ
zpla{)S_Q~XULJwM#cSnsk<rC2X)f~`&ViN=%P(c7h&TZ4?VZ9<2WWu59?5GRH|(#F
z(TN$V)~>$I*J28bySZX-owbRwMV=o=Eu}`$-iX+4#ucGJH*WEqc8;h)uLwBE4R5!=
zXzpb<tPjRHV#c-~J7c^oN*30ZpWc|T!EHdCs3s1sAeQS5<HQw(Te{`@o&j+kfzIwr
z(k@8Wv)hoLKJL{O$g1uG2&5S#YdcZy9A;OLhi4TE+kexwqL1w#mq_@KCUX|V;`S0*
z=nfzW3|;PTl^mlB)4ddW`Z}G!Bc{ktst3>Mn6&?<PH5vo`>4-E_Zh-_b3NfGasQqi
z8BKrPvl<q3&+4xe-|eLG?3lh7$E8VMSbu|Nje?iNKRFBQoYQ?qc#6Nm-Coziwm~Z8
z-cqJaml|C_cZ7lqUv`S+j?ss=Vay*3iJ{&&=}XB?xLq|j;g3~cj`3s;X$oj2mI$?X
znQ)kA5{?wi-JUFb0e9jwJ94MJ7c+#lw`sZ$7fFtVRpfTe>xIs~VOSwQsb+2^&dt6T
z>h@8xNk@+!mt2Z>A8>OhMnHQ>ky)QmaPo15?kiQ;mwF=D2s0GymVnNvGfH5y6Y1P?
zAgU~9h@qdXNG!@3D%(~@+Ub1M8MbJoHp4BiK}Dn!Q69FoYSj3Ga5G+uy5=U6jdQW!
z6YbT_?m+S7z>jCp2OGr$4@+NInPj0nAL)&v0ZC~Smv2ucov7XC8PMjr!>DpMi)s+G
zKlEYE1JGkUgri=Jxz1*G&UeR&w?Xk!DhLU~Fd*6)xx-ZhvD|2Fu<V6mx~zwY8|#8C
zE$p1yIOWMZ!WYqn>be8S^Wp$Al{vyHA8)#x=dsd2tHW3;9I@s%sg7mj{gIp`B4K8N
z&z5D7$g&2<>OfR`=q(qUD*;hBx+I<`Y#1#!!<Ja<2-8TW(Ap+Fy!_cR8u;``?A~yh
z!>v=R$YNO8hnCJ;NCr$t31`4_?~7i7Q~5lNyQBuM&mMbdT(0LxpPX${L^Q!F)uQ<`
zcW%of4Px&&fU7pDam9_7&_})0cCKE4s2!-5+!yPygDnXL{7H_80LNag_mN4?#8Jb?
z((|O!134|Yo|{Q6S)A?RLMJ;1{zozD2f@i%#oOVhgsb!smuP(0Q4EOheX;ysp!@rB
z7Hxd;qQzS1Z4u#X1v(00C9l&)^Ejf&>N%;3AInB`$8iVoE-Q!#M!<%uY;ct-t_>^>
zUZn2>mb5;D-}n7^6=Lf+Vmis!LM*$#gI<#TbZ7nP{Oke3FniR|p4ikodNq*!!5NQs
zo@B)FlPy)d%8%ZZi1me<uZpb8gLN1Kh6V8PMlg`etprE3c&c5V82iF%bY=jnk0}5$
zP5iOSpIlQYh^OCTu&dvVpK_xxUq06yRm`4|Xra5&8r<_6yT~Hf=0be3>~kDFPWjxA
zZ{#!6bx7qs;$Qi%k6345%7dEKCm1Lw%HQ)}MMq0bH)}iBKPn^s2}&w`;+SC{idFOR
zWo{(J;YA|Itb{>|sA}wZ=nUGgH%b<h7n7^+SjEtvV%$N!Om@~g@Z9El&3!#J!QEc#
zIL!{_QCA=#!x)7-M)ZuQ%9uB%iKhaU=(Vfc;<}iqF++OVO(rqACu<S2|7w#5kqhfI
zslv$^nI}wdzF@97a$W(C7UG;oG>4o^fAmQi(0-+c^*dqm53M-Lcjr^(9z%_Wv*=;|
zn|Y^Q)O`u-0YV}tt0pA$N#}iJoK@+$jzs*DK3(hv)^OS<ngW~2bg@>li`a9~CQRR|
z6$DmvRz6ADh}{?5wpx_{oJ_5%58>~`NmeM8PRzj6EOQ0arBeO4yi{F7^yE2`eLOaT
zpX#Pma|5R1?<M!XvJZ-L;oh$X6sX-t37eSB?^SC4_yGr$r-t>ZW>AmFUf$1!kW@>0
zWKsnSQ|GO`fNPI}aDx{ZbY*g@MDdOB;m>tfoJHAcr1|I1$zJK7AL$>{F%r}fGLP4*
zGct6CBB-(XpU<0`H0KLbUIh%Sv0t&hGaYEXLI3MBy{W6=10p~{Q9o3^NPquKl}xN1
z{&=1#TKY~nOGJ0dEc%D$!SzsPuz@>TU^p%Lr-{q&NvMM(>`-W=0w7>k(s9tXp}D8|
zN7YOt7h6}AOuG1W*Mb~TXznm;htJ+4zIoS)6JN_!{P*0>b5iV%>gD&AUA69CcHO&l
z-G6vFopyhHy$j{>kzEiK^^j0PtDlo}I3bFvwuq?zsqDg+5IyDQEzayYC&5T=L9$^S
zo2!JNyoFN;HVc{=kd2|BOhT5krbw!lvB{Kx&TUzsbdwRy96n=yW6w!#_Ovlk1g)zN
zUa%s4jx**9P^4&+2#tW}MyFrqC*8Hf6~og>JtQBqP`7+dJ^TfRigm`PK`cisO9i8t
zVHZyCVkMUJh`=h+GY>NYwMB+;CbgavV30$SWVHU2Sp#Rh1-{a+@7#`dDJ8+U?*hJ!
zt415BJl^w7cpq-mX0V(loMm;N8l0#S7<-v90k9ndrm~hMPr&CMC;#XRNYyTkN<nMR
zFnGtB0->*KZq`RTa#7!J$(ac8m9~~yWpB}V@}^0RF1%V?S)V)nVXu5dVb7<}L1T>V
z6v#Yd2lKash4lUw@6<s32@+hB#WnObhPfD!U7Z~_4>A&4w?cEgC6ur#U}#}avn&AY
zNU5&8F*yTN$zdM>8n?%iKeQukb%wfh+WAaX`@jRNDt#K6=6s*&z<%GnV|d}PLEshp
zZ2~@(V5SJbsu|Ca%YO=EM1%H0CB3ID`cSmEYS?hP>T@P<q8}{cX=32>Ep4?9yA8Y!
zraEVI4OC8^O2I+0+rCbM$;;3+f_8YV_gfa=qihy9wGN97_YRW{rKXP1H}HI@?Vpl0
zo1-ks6U1P<hlF5qin@TTRms*1%b$6PK;Bm|fu3h!JqOP^#iKA`^iT4k?7HtL;*(P1
zdwO{3t0T(~bWrAk!MLA^T0+KQu46Te`HP&sJwyIp%yaB)u9@-CX=<f$EVnU|yF}RW
z8ak_lQ7oSKRP+UNohW@yAs14w>te278<YRsHzC+=ZTcuUT(leLm$(9|Dyv^B;ZrR-
z^iFt7S%oI_WxkmAx<_^a=rTeewF;iV<At20S>Jl0NU`$%8$cums$WDLs$VoSOl3pV
z+x+rv+xb*WFK&K8j`*=11UYWI)MD{DQHOe|SI_ac5U<~6%u@y)Q+lkN@4iy?XjnG8
zh-+;M(;PlT7Fw?Mu5z#I$y`MxMNiV7<h|eGs73IaidUP$#r~j|C{ZG6zc}39ZM*Ka
z?hrRvm*bqahVLkRv_b%|sNbuO2~;VgtL^3{F_m8HwbOe`fd-%*pP&*E7APD#x5wn+
z>t=_tB*!7%TFMu;Q&KnJO}pL-Y<59+m;V7jUE{ho;01GgwrWu~ztD#vZch`E+!X4r
zD-a^Ii>)gdhH)nbO+2hW=v7|a-*JmCa16)A;*socm_q&W;4sxlUYWEvWN}u%h6?4P
z#ZX63>&MnUg7w-ceZe&kx4m>wk4u>F)(;fiY_E5r&q>4ValfPUFxjob9K)?uOpUPG
zpcNnM^K5;=IoQFsx)@hKUx*oq3#)})l|^t-b0Lip*cXja>iA075w!+ysAO<Aw@|nB
z8d=i+sO2tRJyE6C@=Gi+rnXctVoP(#n8VSg%{-JBCdS#j$naSZZp`3P#5soPmD2kZ
zg@H^9tSh+5QiptV2COLc6#&XHP1>SK{UNm-&>)yhfANMWT0^Pb!rAlWSxDSYt8SxV
zU~WWp{-~zSiZ3-K&mvyNAdpGx8((<jg5l&dzaaD>owuvl2ZFT)hjfeT<dKJ;1`TiU
z^gk?cMftMz0|)qK+UL%mU#$`9lXF|v?_*ztgk{y5j4Rm{oA|z6x)C|MQL?MNN*}~f
zrZZi&&WjjqHIlHTS|p7WlC0;&0)=cTy9asW=k<ogZy}X0DfmP;dM38|wzOyXInWm|
zHe50Mi0^%|?uxO2Od<_^>vW3bSQ+khD8ETcGK44))V;;fMe&0fb(5TMNGxHHUm)xy
zb@)96I~*BK2QaGLdr&h)NWBuh^K&sSmf!{FlUlt?c4|^^YStP1kWYw`GfAFlz!_Ea
z9sdvsc(Bx)NI;RDRi4>bk1TZP(sdFCLnxSZuFGLtuuW@ksa__>D5P|0pIm;%hn_bh
zKBd6%m%<vxSivYeEEH7B!$idR`$<Uop>b5p#LnIPm%m>0Rd6J5?@HD@%nh+55`46!
zL266wl2|g*gA_4A5wmFpq~n?9o@-M~UEZJ@5jrL{>~EupFO$zE>=@HbB^6)0PWkOl
zTuqsKTwhPW`3yC+kqS?2sb7b;JMXeS0FQ#e<}gTWz&GpIJD}TyT2^djIx~P5hMzYb
zWqmRjWO9AUeHSED?<TU#h7kqMajO(fbCzC2v8@gsUHtfBAtO2AP&;aJ1ar`eby$tY
z4{-3x8yod_@&)QUi6ze+Ox-Vs4SP8j9I`=?$}`^vrG>?q3mHWZk@1)rTpcszYF3sc
zq^4SV!*b6kDg@a>QF*#?!e8tuvZVQDUE`@pORu%^4OKb;rgm;#rc_}!+a}5}(|#Ct
z{IrJ<QDJPd?rP)LOOy&XHKabzBO@4VkQrZ^sIAEf&ZVE*LQ@H=c{xbYJsaA9R7`xy
zi!<*7x=fKByS>k708TPZpGBk<M=(Hh-+O`W6nirWMnyn~Mxm6NxkWo?NSkfCsCLmO
zf%G>OG*P@n18TbO-4<v(s>xRw2W^XBwe9VsDq~2kEUonOV$MghS}e>6mxw%S-#m{q
ztfitNrfxAY!{sMx<9D_ujIDAw$Uc>1T4<%rJzq{jE3H{jPU`25@z6jyub^CAG+>wP
z*QqfO%CWS*$Y2;Z<(^wbRr~HmIEP83?7-2vPFH3mO8TBE7|wJ#!_k9fi^E^T?#B#d
zPYw;SGumfK7UNs4TW}rv5#*L_WztHehlwQ!?}sS$w*(Jsx49J{_FgFttd#^-yY*6r
zR}l(8+!lG9Y|cIrd2VrI4YVS9RQp<lGJ`UMHTyF9tK9Ky`E*&C2G}=WcZ%K!EtLgb
z^+eGYQ2}IqjA?CMO*(`%*3fRWrsm`0R5j(D2Ppu&L&z58gwK2(?`0q9%KO%N`%qDg
zK`Rwpeu}*RyyZ3AN3{=Kw^1XggmA^U+1y=JSwkv>uo(uQ2z*k}Kpf<(rXaR2@T`E~
zRQ9^Y!~T@y?|Y}U`!6@qVoq7ry8DqkhT%l_u){{yC4vu%Y0w(TN()!qnL#lPz`Y`F
zMO%7jV47x-)XGYOvh5=G%U`0-Mk-}1^MT6qBL2syQ+0H4Q!;UKvUaePad30-{(}a_
zB!e8^ienC2zU5IME%j~+RW~XYPQ<qXdOw*5S<6TVMC2Q7Y?V}QY^^M=>`=BihdgZ4
zb%r2fK9di)gz{q;h(3gjTCh4_#d&hwXMBjQzPY;o$PdNR!;8klA!`gbmBbQnK%q<1
zD(~`Y+vRBuWRnSY%>{;y<gG&sm2r<v`qs3sM&^dTLyu#tC>ijZ(wB1U<&w92nSpiL
z7w!l}Ib`F_gQQhsUVUiqQ*F8BU55?cTp<J_W2~-mieM=5w|>A*CD5tqr*Q9gsWN`m
zt6JPPMA3TW;Dm71wsYFPs()x8oR7}4YM*hD$;cuoHwr#oJ}1hqXfL!E{usy%M@6`r
z`;jQ-Hjr7F!id7AYcg2xLyR-SI^gs86}VWI2duNdikNa?>7wJ>ZK+_EQemS6=<c@b
z;L?$yjuMH^iNU|^HNZc7x+Y_JyPhPwoHJ?rV%j9pfYZ@*F795*wr#a=P@8q-M@z?w
zciSs;GmaW5d^b`Tnxgon0&#U3#)M?bY2!~~>-fQacRnZ8j^|oXZ!h<4E(=O2CCpA4
zC6f9g`ulVuOgSTq8B+Vx5oMFhaJ=*eMmW%?Um#x4vIqrKn83B5DU|g~_|1KfG{#0Z
z0dv5I7a_>L>E)L{awCTHfi<i}VdSX4U~9e2pFf&squD;gnEk?V#8Iz}=bm3`x17?;
zNjnmcI;S2)q8*GnN})1iHXN``6>lw20HyFERostu1T~ukDq}Sif_jcEQfn$M+s_~M
z5)K$|LbTn4z1{c}tb^bkoco58A{1#m8k>eTxI-i8**pa!(YA<>=s*B2b$kUj4QsI9
zv!ICzi8-zj`maX=0m)SH09tujgsTcTKqbQH2!+_}7iI(qNnkdL$d`MlKi4*Y7iz|M
zm{$HJ)NF6!VearR0pY)&O!W7Ye<xJ@s~9xJe>3wm|3$S}@j<mX9rK6i@Iwf`ebAAn
z{~xTK9PQb>?CsXHW*y#g;QD{o*1?IZ%;}3)#XE0^u`UY+n)R%11KyN}o9Q<vp;F$F
z4lA#^+4s{a3D1NxwTg;<zr0-GFXuZTOP9hZj=#8_odbx_LLj{IioE8ao-thT-Bo1v
z1{}Q{7QnyGFUBDgf!`74#63}Q<a_12raYZF&a_3f(VpoBKN~5h5<+)_QF<Dwa7;>$
z8Wo46RXDNb8wO&^dk`ok`0~k+&mD^@1k8+Y5~`NcHSroDn+pK~8fC(To)_rKpMX~^
zE>>1x$K^Dd#L#on1%IE1fWJHqKV&ltqW4Nn^Z^AxXsa^%LDAZ>;I+(*v>24)C(!BT
ziB=7LZ}O44D_i!qr4<U#pB&N6ML8h8u{({enTS#L6pk}^m$~|y+97PItQCqoHpvrh
zHFGN2;Ixpd0NZ02cBo>EV}$O~9@w^fD=w!5%?8u{@FRYG!6VA(_TYdF5ycrI_Brfj
zDLCeRiZVjuHP-_V7h8dbbtbylY2LW!o5)*DdmZ_-dHY)+Hd;g?unWpJU%;1xO$EM*
zkHy7bX7l3oBlAk+ns`|GRt{X=3W`OVoxA1WnF(Fyu4P?*ic?xKzN$~G@ldN<Sny<a
zc~90Q!Muj6fvvG$?>pnj&iww9B$MmaCjxbW(<~dB5S*mMb=I688j#*Jz2`Q9ZjB9D
z?BqkAg?BMaKwr~^Cwsa2-BoW{-7p4N3*}Eu_n%tb&&uh&2^5l=oHhfCLp8-00Y4c(
zba`ePPFRxl+#rXWZ8LgPiu5oJXlIc)@w)=#jDj>2UwL>bn6p7yo0Bk=FB+B001HtL
z@(aXfiRN<`wvxZP%kHG6hy-`s&#`xrUchSTkMAG6rLL+tOe!#M?wo`5qh_$<7e4WE
zinHj?kwPo{cI@^N`}#f0H4^`R?#yPph1^NB4a*Uz{tAYox6IueTr|6f@n^LDp_k5L
z<#Gysh=B(IZz#6^F&3O$9G%Qv+^o%AH9S-%L99R)1tm54if5-vETGAc>gbG0nn=p5
zsvJCO99+#@91UE28crT)=nqF6JR3|PR;H<m>DRn7-1FSqK=v_q)>FlLRu$G!b|&B?
z^CpmmX;cxU$Oes)iocEL1pSa*pkZ)f|FaPMgVPTK6Y5yv=l8#|&7;}xh2ejm{BuA8
z|B?d!O(y;k;qOZ7Keg8X7(XwJ|4^R$LwWtt)nC=we`>EkS_u5p;@=b8f42Rp#r|ju
z{+sPTbKIW*zt?8}69V#&YT~~swLjkH@3&_@8jjQcai5P~|KrNP*{u01=C7?@kC<-(
z|3BtmRv*7Y|Jon$2z@2?U!nifE$}PquT|H7Lk0d8^{+M9U*Uc&_&vf+D*hJkvHbTd
z)UV67M<{iT-$MO<5%(+Xue|gTc0}v9u)k-ikFbBA;D54#KgQ3XDcAkCX#JBL{P_z1
z-S{Uvcr;%8yYb^o`QLn?_!H$H83Rr4Z$3Q2{EIvM=@b&w@7TkifRI4Y|A6*SF7fE%
m@6+%jsJ7w%@8VC;$E2(Zf`3@iLqTCbd^jK4D-n%;9{nGtq1E{S

literal 0
HcmV?d00001

diff --git a/src/net/sf/briar/HelloWorldModule.java b/src/net/sf/briar/HelloWorldModule.java
index 64a3d8fcf2..a0fa22c7f8 100644
--- a/src/net/sf/briar/HelloWorldModule.java
+++ b/src/net/sf/briar/HelloWorldModule.java
@@ -1,13 +1,10 @@
 package net.sf.briar;
 
-import static android.content.Context.MODE_PRIVATE;
-
 import java.io.File;
 
 import net.sf.briar.api.crypto.Password;
 import net.sf.briar.api.db.DatabaseConfig;
 import net.sf.briar.api.ui.UiCallback;
-import android.content.Context;
 
 import com.google.inject.AbstractModule;
 
@@ -16,7 +13,7 @@ public class HelloWorldModule extends AbstractModule {
 	private final DatabaseConfig config;
 	private final UiCallback callback;
 
-	public HelloWorldModule(final Context appContext) {
+	public HelloWorldModule(final File dir) {
 		final Password password = new Password() {
 
 			public char[] getPassword() {
@@ -26,7 +23,7 @@ public class HelloWorldModule extends AbstractModule {
 		config = new DatabaseConfig() {
 
 			public File getDataDirectory() {
-				return appContext.getDir("db", MODE_PRIVATE);
+				return dir;
 			}
 
 			public Password getPassword() {
diff --git a/src/net/sf/briar/HelloWorldService.java b/src/net/sf/briar/HelloWorldService.java
index 2eec307890..6dbbb30790 100644
--- a/src/net/sf/briar/HelloWorldService.java
+++ b/src/net/sf/briar/HelloWorldService.java
@@ -3,6 +3,7 @@ package net.sf.briar;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.logging.Logger;
 
@@ -55,8 +56,8 @@ public class HelloWorldService extends Service implements Runnable {
 	}
 
 	public void run() {
-		Injector i = Guice.createInjector(
-				new HelloWorldModule(getApplicationContext()),
+		File dir = getApplicationContext().getDir("db", MODE_PRIVATE);
+		Injector i = Guice.createInjector(new HelloWorldModule(dir),
 				new AndroidModule(), new ClockModule(), new CryptoModule(),
 				new DatabaseModule(), new LifecycleModule(),
 				new PluginsModule(), new ProtocolModule(),
@@ -77,7 +78,7 @@ public class HelloWorldService extends Service implements Runnable {
 				LOG.info(pluginsStarted + " plugins started");
 			// ...sleep...
 			try {
-				Thread.sleep(1000);
+				Thread.sleep(30 * 1000);
 			} catch(InterruptedException ignored) {}
 			// ...and stop
 			if(LOG.isLoggable(INFO)) LOG.info("Shutting down");
diff --git a/src/net/sf/briar/plugins/tcp/MappingResult.java b/src/net/sf/briar/plugins/tcp/MappingResult.java
new file mode 100644
index 0000000000..f558a8d731
--- /dev/null
+++ b/src/net/sf/briar/plugins/tcp/MappingResult.java
@@ -0,0 +1,32 @@
+package net.sf.briar.plugins.tcp;
+
+import java.net.InetAddress;
+
+class MappingResult {
+
+	private final InetAddress internal, external;
+	private final boolean succeeded;
+
+	MappingResult(InetAddress internal, InetAddress external,
+			boolean succeeded) {
+		this.internal = internal;
+		this.external = external;
+		this.succeeded = succeeded;
+	}
+
+	InetAddress getInternal() {
+		return internal;
+	}
+
+	InetAddress getExternal() {
+		return external;
+	}
+
+	boolean getSucceeded() {
+		return succeeded;
+	}
+
+	boolean isUsable() {
+		return internal != null && external != null && succeeded;
+	}
+}
diff --git a/src/net/sf/briar/plugins/tcp/PortMapper.java b/src/net/sf/briar/plugins/tcp/PortMapper.java
new file mode 100644
index 0000000000..5bd226329d
--- /dev/null
+++ b/src/net/sf/briar/plugins/tcp/PortMapper.java
@@ -0,0 +1,10 @@
+package net.sf.briar.plugins.tcp;
+
+interface PortMapper {
+
+	void start();
+
+	void stop();
+
+	MappingResult map(int port);
+}
diff --git a/src/net/sf/briar/plugins/tcp/PortMapperImpl.java b/src/net/sf/briar/plugins/tcp/PortMapperImpl.java
new file mode 100644
index 0000000000..e990cb2e38
--- /dev/null
+++ b/src/net/sf/briar/plugins/tcp/PortMapperImpl.java
@@ -0,0 +1,82 @@
+package net.sf.briar.plugins.tcp;
+
+import static java.util.logging.Level.WARNING;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.Collection;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.logging.Logger;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.wetorrent.upnp.GatewayDevice;
+import org.wetorrent.upnp.GatewayDiscover;
+import org.xml.sax.SAXException;
+
+class PortMapperImpl implements PortMapper {
+
+	private static final Logger LOG =
+			Logger.getLogger(PortMapperImpl.class.getName());
+
+	private final CountDownLatch started = new CountDownLatch(1);
+	private final Collection<Integer> ports =
+			new CopyOnWriteArrayList<Integer>();
+
+	private volatile GatewayDevice gateway = null;
+
+	public void start() {
+		GatewayDiscover d = new GatewayDiscover();
+		try {
+			d.discover();
+		} catch(IOException e) {
+			if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
+		} catch(SAXException e) {
+			if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
+		} catch(ParserConfigurationException e) {
+			if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
+		}
+		gateway = d.getValidGateway();
+		started.countDown();
+	}
+
+	public void stop() {
+		if(gateway == null) return;
+		try {
+			for(Integer port: ports) gateway.deletePortMapping(port, "TCP");
+		} catch(IOException e) {
+			if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
+		} catch(SAXException e) {
+			if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
+		}
+	}
+
+	public MappingResult map(int port) {
+		try {
+			started.await();
+		} catch(InterruptedException e) {
+			if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
+			Thread.currentThread().interrupt();
+			return null;
+		}
+		if(gateway == null) return null;
+		InetAddress internal = gateway.getLocalAddress();
+		if(internal == null) return null;
+		boolean succeeded = false;
+		InetAddress external = null;
+		try {
+			succeeded = gateway.addPortMapping(port, port,
+					internal.getHostAddress(), "TCP", "TCP");
+			String externalString = gateway.getExternalIPAddress();
+			if(externalString != null)
+				external = InetAddress.getByName(externalString);
+		} catch(IOException e) {
+			if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
+		} catch(SAXException e) {
+			if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
+		}
+		if(succeeded) ports.add(port);
+		return new MappingResult(internal, external, succeeded);
+	}
+}
diff --git a/src/net/sf/briar/plugins/tcp/TcpPlugin.java b/src/net/sf/briar/plugins/tcp/TcpPlugin.java
index 603cba44e1..f476aad47b 100644
--- a/src/net/sf/briar/plugins/tcp/TcpPlugin.java
+++ b/src/net/sf/briar/plugins/tcp/TcpPlugin.java
@@ -91,10 +91,11 @@ abstract class TcpPlugin implements DuplexPlugin {
 			socket = ss;
 		}
 		if(LOG.isLoggable(INFO)) {
-			LOG.info("Listening on " + ss.getInetAddress().getHostAddress()
-					+ ":" + ss.getLocalPort());
+			String addr = ss.getInetAddress().getHostAddress();
+			int port = ss.getLocalPort();
+			LOG.info("Listening on " + addr + " " + port);
 		}
-		setLocalSocketAddress(ss.getLocalSocketAddress());
+		setLocalSocketAddress((InetSocketAddress) ss.getLocalSocketAddress());
 		acceptContactConnections(ss);
 	}
 
@@ -106,12 +107,11 @@ abstract class TcpPlugin implements DuplexPlugin {
 		}
 	}
 
-	private void setLocalSocketAddress(SocketAddress s) {
-		InetSocketAddress i = (InetSocketAddress) s;
-		InetAddress addr = i.getAddress();
+	protected void setLocalSocketAddress(InetSocketAddress a) {
+		InetAddress addr = a.getAddress();
 		TransportProperties p = new TransportProperties();
 		p.put("address", addr.getHostAddress());
-		p.put("port", String.valueOf(i.getPort()));
+		p.put("port", String.valueOf(a.getPort()));
 		callback.mergeLocalProperties(p);
 	}
 
diff --git a/src/net/sf/briar/plugins/tcp/WanTcpPlugin.java b/src/net/sf/briar/plugins/tcp/WanTcpPlugin.java
index 69bd3074e0..9b2cd234fa 100644
--- a/src/net/sf/briar/plugins/tcp/WanTcpPlugin.java
+++ b/src/net/sf/briar/plugins/tcp/WanTcpPlugin.java
@@ -2,6 +2,7 @@ package net.sf.briar.plugins.tcp;
 
 import static java.util.logging.Level.WARNING;
 
+import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.NetworkInterface;
@@ -33,27 +34,54 @@ class WanTcpPlugin extends TcpPlugin {
 	private static final Logger LOG =
 			Logger.getLogger(WanTcpPlugin.class.getName());
 
+	private final PortMapper portMapper;
+
+	private volatile MappingResult mappingResult;
+
 	WanTcpPlugin(@PluginExecutor Executor pluginExecutor,
-			DuplexPluginCallback callback, long pollingInterval) {
+			DuplexPluginCallback callback, long pollingInterval,
+			PortMapper portMapper) {
 		super(pluginExecutor, callback, pollingInterval);
+		this.portMapper = portMapper;
 	}
 
 	public TransportId getId() {
 		return ID;
 	}
 
+	@Override
+	public void start() throws IOException {
+		super.start();
+		pluginExecutor.execute(new Runnable() {
+			public void run() {
+				portMapper.start();
+			}
+		});
+	}
+
+	@Override
+	public void stop() throws IOException {
+		super.stop();
+		pluginExecutor.execute(new Runnable() {
+			public void run() {
+				portMapper.stop();
+			}
+		});
+	}
+
 	@Override
 	protected List<SocketAddress> getLocalSocketAddresses() {
 		List<SocketAddress> addrs = new ArrayList<SocketAddress>();
-		// Prefer a previously used address and port if available
+		// Prefer a previously used external address and port if available
 		TransportProperties p = callback.getLocalProperties();
 		String addrString = p.get("address");
 		String portString = p.get("port");
 		InetAddress addr = null;
+		int port = 0;
 		if(addrString != null && portString != null) {
 			try {
 				addr = InetAddress.getByName(addrString);
-				int port = Integer.valueOf(portString);
+				port = Integer.valueOf(portString);
 				addrs.add(new InetSocketAddress(addr, port));
 				addrs.add(new InetSocketAddress(addr, 0));
 			} catch(NumberFormatException e) {
@@ -79,9 +107,31 @@ class WanTcpPlugin extends TcpPlugin {
 				if(!link && !site) addrs.add(new InetSocketAddress(a, 0));
 			}
 		}
+		// Accept interfaces that can be port-mapped
+		if(port == 0) port = chooseEphemeralPort();
+		mappingResult = portMapper.map(port);
+		if(mappingResult != null && mappingResult.isUsable())
+			addrs.add(new InetSocketAddress(mappingResult.getInternal(), port));
 		return addrs;
 	}
 
+	private int chooseEphemeralPort() {
+		return 32768 + (int) (Math.random() * 32768);
+	}
+
+	@Override
+	protected void setLocalSocketAddress(InetSocketAddress a) {
+		InetAddress addr = a.getAddress();
+		if(mappingResult != null && mappingResult.isUsable()) {
+			if(addr.equals(mappingResult.getInternal()))
+				addr = mappingResult.getExternal();
+		}
+		TransportProperties p = new TransportProperties();
+		p.put("address", addr.getHostAddress());
+		p.put("port", String.valueOf(a.getPort()));
+		callback.mergeLocalProperties(p);
+	}
+
 	public boolean supportsInvitations() {
 		return false;
 	}
diff --git a/src/net/sf/briar/plugins/tcp/WanTcpPluginFactory.java b/src/net/sf/briar/plugins/tcp/WanTcpPluginFactory.java
index e4ed87284f..f976e22cf5 100644
--- a/src/net/sf/briar/plugins/tcp/WanTcpPluginFactory.java
+++ b/src/net/sf/briar/plugins/tcp/WanTcpPluginFactory.java
@@ -16,6 +16,7 @@ public class WanTcpPluginFactory implements DuplexPluginFactory {
 	public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
 			AndroidExecutor androidExecutor, Context appContext,
 			DuplexPluginCallback callback) {
-		return new WanTcpPlugin(pluginExecutor, callback, POLLING_INTERVAL);
+		return new WanTcpPlugin(pluginExecutor, callback, POLLING_INTERVAL,
+				new PortMapperImpl());
 	}
 }
-- 
GitLab