
    Bd                     l   d Z dZdZddlZddlZddlZddlZddlZddlZddl	Z	ddl
mZmZmZmZ ddlmZ ddlmZmZmZ dd	lmZ dd
lmZ ddlmZmZ ddlmZ ddlmZ ddl m Z  ddl!m"Z"m#Z# ej$        %                    ej$        &                    e'          d          Z(i Z)ddl!m*Z* e	j+        j,        Z-ej$        %                    ej$        &                    e'          d          Z.i Z/ G d de	j0                  Z1 G d de"          Z2 G d de"          Z3 G d de"          Z4 G d de"          Z5dS )z!Cyril Jaquier, Yaroslav Halchenkoz>Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav HalchenkoGPL    N   )ConfigReaderConfigReaderUnsharedDefinitionInitConfigReaderNoSectionError)configparserinc)
JailReaderextractOptionssplitWithOptions)FilterReader)JailsReader)ActionReaderCommandAction)Configurator)MyTime)version   )LogCaptureTestCasewith_tmpdirfiles)
CONFIG_DIRconfigc                   d     e Zd Z fdZd ZddZd ZddZd Zd	 Z	d
 Z
d Zd Zd Zd Z xZS )ConfigReaderTestc                     t          t          |                                            t          j        d          | _        t          | j                  | _        dS )zCall before every test case.zf2b-temp)prefixbasedirN)superr   setUptempfilemkdtempdr   c)self	__class__s    E/usr/lib/python3/dist-packages/fail2ban/tests/clientreadertestcase.pyr!   zConfigReaderTest.setUp7   sM    $%%''':...$&///$&&&    c                 8    t          j        | j                   dS )zCall after every test case.N)shutilrmtreer$   r&   s    r(   tearDownzConfigReaderTest.tearDown=   s    -r)   Nc                    t           j        j        |v rwt           j                            |          }t           j                            | j        |          }t           j                            |          st          j        |           t          | j        d|d          }||	                    d|z             ||	                    |           |
                                 d S )N/wz
[section]
option = %s
	)ospathsepdirnamejoinr$   existsmakedirsopenwriteclose)r&   fnamevaluecontentr$   d_fs          r(   _writezConfigReaderTest._writeA   s    W[E	wu1
TVQ2
'..

 KOOO
dfffee$c**!
77      777'')))))r)   c                     t          j        | j        d|           |                     | j                            d                     d S )Nr0   r%   )r2   unlinkr$   
assertTruer%   read)r&   r<   s     r(   _removezConfigReaderTest._removeR   sE    )tvvvuu%&&&//$&++c""#####r)   r%   c                     |                      | j                            |                     | j                            ddg          d         S )Nsection)intoptionrJ   )rD   r%   rE   
getOptions)r&   r@   s     r(   
_getoptionzConfigReaderTest._getoptionV   sA    //$&++a..!!!			9'8&9	:	:8	DDr)   c                 (   | j                             d           | j                             ddd           | j                             ddd           | j                             ddd           | j                             dd          }|                     |dd	d
d           | j                             dd          }|                     |dd	d d           | j                             ddddd          }|                     |dd	d
d           d S )N
Definitiona1br%   test))rI   rO   r   )boolrQ   r   )rI   r%   r   r   Tr   )rO   rQ   r%   ))rI   rO   )rS   rQ   )rI   r%   )rI   r   )rS   r   )r%   add_sectionsetrK   assertSortedEqual)r&   optss     r(   testConvertzConfigReaderTest.testConvertZ   s$   &\"""&**\3$$$&**\3$$$&**\3'''			<7
9 
9$QT::;;;			<.
0 
0$QT==>>>			<	+J77
9 
9$QT::;;;;;r)   c                    t           j                            | j        d          }|                     dd           |                     |                     d          d           t          j        |d           t          j        |t           j	                  s/| 
                    | j                            d                     d S dd l}t          j        d|                                z            )Nzd.confr   r$   z0Skipping on %s -- access rights are not enforced)r2   r3   r6   r$   rA   assertEqualrL   chmodaccessR_OKassertFalser%   rE   platformunittestSkipTest)r&   r@   r_   s      r(   testInaccessibleFilez%ConfigReaderTest.testInaccessibleFilei   s    gll468$$!++h4??3''+++(1a... 
1bg		 eDFKK$$%%%%%???		MPXPaPaPcPcc	d	ddr)   c                    |                      | j                            d                     |                     dd           |                     |                                 d           |                     dd           |                     |                                 d           |                     dd           |                     |                                 d	           |                     d
d           |                     |                                 d	           |                     dd           |                     |                                 d           |                     dd           |                     |                                 d           |                     dd           |                     |                                 d           |                     d           |                     d           |                     |                                 d           |                     d           |                     |                                 d	           |                     d           |                     |                                 d           |                     d
           |                     |                                 d           d S )Nr%   c.confrP   r   2r   zc.d/98.conf998i  zc.d/90.conf990zc.d/99.conf999i  zc.local3   zc.d/1.local4   i  )r^   r%   rE   rA   rZ   rL   rF   r-   s    r(   testOptionalDotDDirz$ConfigReaderTest.testOptionalDotDDirv   sp   46;;s##$$$++h4??$$a(((++h4??$$a(((++mU###4??$$c***++mU###4??$$c***++mU###4??$$c***++i4??$$a(((++mS!!!4??$$a(((,,},,y4??$$c***,,}4??$$c***,,}4??$$c***,,}4??$$a(((((r)   c                 6   |                      dd d           |                      dd d           |                      dd d           |                      dd d	           |                      d
d d            G d dt                    } |ddi           | _        | j                            | j                   |                     | j                                                   | j                            i d           | j                                        }| 	                    |
                    d          d           | 	                    |
                    d          d           | 	                    |
                    d          d           d S )Nrd   zS
[INCLUDES]
before = ib.conf
after  = ia.conf
[Definition]
test = %(default/test)s
r=   r>   zib.confz,
[DEFAULT]
test = A
[Definition]
option = 1
zib.localz,
[DEFAULT]
test = B
[Definition]
option = 2
zia.confz,
[DEFAULT]
test = C
[Definition]
oafter = 3
zia.localz,
[DEFAULT]
test = D
[Definition]
oafter = 4
c                   &    e Zd ZddgddgddgdZdS )?ConfigReaderTest.testLocalInIncludes.<locals>.TestDefConfReaderrI   Nstring)rJ   oafterrR   )__name__
__module____qualname___configOpts r)   r(   TestDefConfReaderrq      s0        t}t} ;;;r)   ry   r%   rJ   T)allr   rs   rl   rR   D)rA   r   r%   
setBaseDirr$   rD   rE   rK   getCombinedrZ   get)r&   ry   os      r(   testLocalInIncludesz$ConfigReaderTest.testLocalInIncludes   s   ++hd -+    ++it .+    ++j /+    ++it .+    ++j /+       4    S(B//$&&DF//$&++--   &BD!!!
f!155??A&&&155??A&&&155==#&&&&&r)   c                    |                      | j                            d                     |                     dd d           |                     | j                            d                     |                     | j                                        ddg           |                     | j                            dd          d           |                     | j                            dd	          d
           |                     | j                            dd          d           |                     | j                            dd          d           |                     | j                            dd          d           d S )Nizi.confzu
[DEFAULT]
b = a
zz = the%(__name__)s

[section]
y = 4%(b)s
e = 5${b}
z = %(__name__)s

[section2]
z = 3%(__name__)s
ro   rH   section2y4aez5${b}zzz
thesection	3section2)r^   r%   rE   rA   rD   rZ   sectionsr~   r-   s    r(   testInterpolationsz#ConfigReaderTest.testInterpolations   sR   46;;s##$$$++hd -+    //$&++c""###46??$$y*&=>>>46::i--t44446::i--w77746::i--y99946::i..===46::j#..<<<<<r)   c                    |                      | j                            d                     |                     dd d           |                     | j                            d                     |                     | j                            dd          d           |                     | j                            dd          d	           d S )
Ngg.confz4
[DEFAULT]
# A comment
b = a
c = d ;in line comment
ro   DEFAULTrQ   rO   r%   r$   )r^   r%   rE   rA   rD   rZ   r~   r-   s    r(   testCommentszConfigReaderTest.testComments   s    46;;s##$$$++hd -+    //$&++c""###46::i--s33346::i--s33333r)   c                 2   |                      | j                            d                     |                     dd d           |                     | j                            d                     |                     | j                            dd          d           |                     | j                            dd          d	           |                     | j                            d
d          d           |                     | j                            d
d          d           |                     | j                            d
d          d           |                     | j                            d
d          d           |                     | j                            dd          d           |                     | j                            dd          d           |                     | j                            dd          d           |                     | j                            dd          d           |                     t          | j        j        dd           |                     t          | j        j        d
d           d S )Nr   r   z
[DEFAULT]
a = def-a
b = def-b,a:`%(a)s`
c = def-c,b:"%(b)s"
d = def-d-b:"%(known/b)s"

[jail]
a = jail-a-%(test/a)s
b = jail-b-%(test/b)s
y = %(test/y)s

[test]
a = test-a-%(default/a)s
b = test-b-%(known/b)s
x = %(test/x)s
y = %(jail/y)s
ro   rR   rO   ztest-a-def-arQ   ztest-b-def-b,a:`test-a-def-a`jailzjail-a-test-a-def-az+jail-b-test-b-def-b,a:`jail-a-test-a-def-a`r%   z5def-c,b:"jail-b-test-b-def-b,a:`jail-a-test-a-def-a`"r$   z'def-d-b:"def-b,a:`jail-a-test-a-def-a`"z'def-c,b:"test-b-def-b,a:`test-a-def-a`"z def-d-b:"def-b,a:`test-a-def-a`"r   zdef-c,b:"def-b,a:`def-a`"zdef-d-b:"def-b,a:`def-a`"xr   )	r^   r%   rE   rA   rD   rZ   r~   assertRaises	Exceptionr-   s    r(   testTargetedSectionOptionsz+ConfigReaderTest.testTargetedSectionOptions   s.   46;;s##$$$++hd -+   $ //$&++c""###46::fc**N;;;46::fc**,KLLL46::fc**,ABBB46::fc**,YZZZ46::fc**,cddd46::fc**,UVVV46::fc**,UVVV46::fc**,NOOO46::i--/JKKK46::i--/JKKKItvz63777Itvz6377777r)   )NN)r%   )rt   ru   rv   r!   r.   rA   rF   rL   rX   rb   rm   r   r   r   r   __classcell__r'   s   @r(   r   r   5   s        0 0 0 0 0     "$ $ $E E E E< < <e e e) ) )4.' .' .'`= = =.
4 
4 
4 8  8  8  8  8  8  8r)   r   c                        e Zd Z fdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zed             Zd Z xZS )JailReaderTestc                 H     t          t          |           j        |i | d S N)r    r   __init__r&   argskwargsr'   s      r(   r   zJailReaderTest.__init__  s+    &%&777777r)   c                 R   dD ]"}|                      t          d|d          ddg           |                      t          d|d          ddg           |                      t          d|d          ddg           |                      t          d|d          ddg           |                      t          d|d          ddg           |                      t          d|d          ddg           |                      t          d	|d          d	dg           $d S )
N)
	 rO   rQ   za[x=y]za[x=y][z=z]za[x="y][z"]z
a[x="y z"]z
a[x="y	z"]z
a[x="y
z"])rZ   r   )r&   r4   s     r(   testSplitWithOptionsz#JailReaderTest.testSplitWithOptions  sj    W Wc$$sss_55#QTAUVVV$$CCC%9::(QTAUVVV$$%>??-QTAUVVV$$%>??-QTAUVVV$$%=>>,QTAUVVV$$%>??-QTAUVVV$$%>??-QTAUVVVVW Wr)   c                 ~    t          dt          t                    }|                     t          |j                   d S )NXXXABSENTXXXr   share_config)r
   r   CONFIG_DIR_SHARE_CFGr   
ValueErrorrE   r&   r   s     r(   testIncorrectJailz JailReaderTest.testIncorrectJail  s5    	NJEY	Z	Z	Z$J	*****r)   c                 |   t          dt          t                    }|                     |                                           |                     |                                           |                     |                                           |                     d           |                     d           d S )Nemptyactionr   z"No filter set for jail emptyactionz'No actions were defined for emptyaction)r
   IMPERFECT_CONFIGIMPERFECT_CONFIG_SHARE_CFGrD   rE   rK   	isEnabledassertLoggedr   s     r(   testJailActionEmptyz"JailReaderTest.testJailActionEmpty  s    	M+;Jd	e	e	e$//$))++//$//##$$$//$..""###8999=>>>>>r)   c                    t          dt          t                    }|                     |                                           |                     |                                           |                     |                                           |                     dt          z             |                     d           d S )Nmissingbitsjailr   zJFound no accessible config files for 'filter.d/catchallthebadies' under %szUnable to read the filter	r
   r   r   rD   rE   r^   rK   r   r   r   s     r(   testJailActionFilterMissingz*JailReaderTest.testJailActionFilterMissing"  s    	%/?Nh	i	i	i$//$))++4??$$%%%//$..""###`cssttt/00000r)   c                 R   t          dt          t                    }|                     |                                           |                     |                                           |                     |                                           |                     d           d S )Nbrokenactiondefr   z$Invalid action definition 'joho[foo'r   r   s     r(   testJailActionBrokenDefz&JailReaderTest.testJailActionBrokenDef*      	%/?*
, 
, 
,$//$))++4??$$%%%//$..""###:;;;;;r)   c                 j   t          dt          t                    }|                     |                                           |                     |                                           |                     |                                           |                     |j        d         d           d S )N
tz_correctr   logtimezoneUTC+0200)	r
   r   r   rD   rE   rK   r   rZ   optionsr   s     r(   testJailLogTimeZonez"JailReaderTest.testJailLogTimeZone2  s    	L*:*
, 
, 
,$//$))++//$//##$$$//$..""###4<.
;;;;;r)   c                 R   t          dt          t                    }|                     |                                           |                     |                                           |                     |                                           |                     d           d S )Nbrokenfilterdefr   z$Invalid filter definition 'flt[test'r   r   s     r(   testJailFilterBrokenDefz&JailReaderTest.testJailFilterBrokenDef:  r   r)   c                 2   t           j                            d           t          dt          t
                    }|                     |                                           |                     |                                           | 	                    |
                                           |                     |                                d           |                    d           |                     |                                d           d S )NTstocksshdr   zssh-funky-blocker)r`   F2BSkipIfCfgMissingr
   r   r   rD   rE   rK   r^   r   rZ   getNamesetNamer   s     r(   testStockSSHJailzJailReaderTest.testStockSSHJailB  s    
,d+++	FJ=Q	R	R	R$//$))++//$//##$$$4>>##$$$4<<>>6***,,"###4<<>>#677777r)   c                 >   t           j                            d           t          dt          t
          d          }|                     |                                           |                     |                                           |                     |	                                           |
                                }|                     g dgd |D                        |                     g dgd |D                        |                     g d	gd
 |D                        |                    g d          }d}|D ]Q}|                     t          |          dk    o|d                             d                     |dz  }||k    r d S Rd S )NTr   sshd-override-flt-optsr   r   force_enable)rU   r   	prefregexz^Testc                 P    g | ]#}t          |          d k    |d          dk    !|$S )r   r   len.0r   s     r(   
<listcomp>z>JailReaderTest.testOverrideFilterOptInJail.<locals>.<listcomp>W  s4    <<<!Q!!(;(;A(;(;(;r)   )rU   r   addjournalmatchz
_COMM=testc                 P    g | ]#}t          |          d k    |d          dk    !|$S )r   r   r   r   s     r(   r   z>JailReaderTest.testOverrideFilterOptInJail.<locals>.<listcomp>Z  s5    BBB!Q!!0A(A(AA(A(A(Ar)   )rU   r   maxlinesr   c                 P    g | ]#}t          |          d k    |d          dk    !|$S )r   r   r   r   s     r(   r   z>JailReaderTest.testOverrideFilterOptInJail.<locals>.<listcomp>]  s4    ;;;!Q!!
(:(:A(:(:(:r)   )rU   r   usednsnor   r   regexr   )r`   r   r   r
   r   r   rD   rE   rK   r   convertrZ   indexr^   r   endswith)r&   r   stream	usednsidxr   r   s         r(   testOverrideFilterOptInJailz*JailReaderTest.testOverrideFilterOptInJailL  s   
,d+++	,6F*
? 
? 
?$//$))++//$//##$$$//$..""###<<>>& KKKL<<v<<<> > > VVVWBBvBBBD D D DDDE;;v;;;= = = llLLLMM)!  aCFFQJ91Q4==#9#9:::61)mmUUUm r)   c           	         t           j                            d           dD ]}dD ]}t          d|                                z   t
          t          d          }|                     |                                           |                     |	                                           |
                                }|                     d|                                dd	|z  ggd
 |D                        ьd S )NTr   )r   r   )JRNLFILETESTINITchecklogtype_r   rU   addfailregexz^%s failure from <HOST>$c                 P    g | ]#}t          |          d k    |d          dk    !|$S )r   r   r   r   s     r(   r   z=JailReaderTest.testLogTypeOfBackendInJail.<locals>.<listcomp>s  s4    AAAA3q66A::!A$.*@*@a*@*@*@r)   )r`   r   r   r
   lowerr   r   rD   rE   rK   r   rZ   r   )r&   r   prefliner   r   s        r(   testLogTypeOfBackendInJailz)JailReaderTest.testLogTypeOfBackendInJailf  s   
,d+++ 
C 
Ca3 C Cxohnn&6&66@P,4A A ADOODIIKK   OODOO%%&&&\\^^Fudllnnn>X[c>cdeAAAAAC C C CC
C 
Cr)   c                    d}dddif}t          |          }|                     ||           |                     di ft          d                     |                     ddddft          d	                     |                     d
i ft          d
                     |                     dddift          d                     |                     dddift          d                     |                     t          t           d           |                     t          t           d           |                     t          t           d           |                     t          t           d           |                     t          t           d           d}di f}t          |          }|                     ||           d}ddddddddd d!d"d"d#f}t          |          }|                     ||           t          |                    dd$                    }|d%         t          d& |d'                                         D                       f}|                     ||           d S )(Nzmail-whois[name=SSH]z
mail-whoisnameSSHzmail.who_iscatdog)rO   rQ   zmail.who_is[a=cat,b=dog]zmail--ho_ismailrO   ,zmail[a=',']rQ   zmail[a=b, ]z	mail-how[z-mail[a="test with interim (wrong) "" quotes"]z-mail[a='test with interim (wrong) '' quotes']zmail[a='x, y, z', b=x, y, z]z	mail['s']zabc[]abczoption[opt01=abc,opt02="123",opt03="with=okay?",opt04="andwith,okay...",opt05="how about spaces",opt06="single'in'double",opt07='double"in"single',  opt08= leave some space, opt09=one for luck, opt10=, opt11=]rJ   123z
with=okay?zandwith,okay...zhow about spaceszsingle'in'doublezdouble"in"singlezleave some spacezone for luck )opt01opt02opt03opt04opt05opt06opt07opt08opt09opt10opt11][r   c              3   L   K   | ]\  }}||                     d d          fV   dS )r   r  N)replace)r   kvs      r(   	<genexpr>z1JailReaderTest.testSplitOption.<locals>.<genexpr>  s9      BBdaAIIc4  !BBBBBBr)   r   )r   rZ   r   r   r
  dictitems)r&   rJ   expectedresult	expected2s        r(   testSplitOptionzJailReaderTest.testSplitOptionu  s{   !&VUO,(&!!&8V$$$M2&}(E(EFFFM5#9#9:NKe<f<fgggM2&}(E(EFFFFS#J')F)FGGGFS#J')F)FGGGJ<<<J0cdddJ0cdddJ0RSSSJ@@@ &R[(&!!&8V$$$ c&   ( &!!&8V$$$ &..d3344&{BBhqk.?.?.A.ABBBBB) 9f%%%%%r)   c                 "   t          ddt          t                    }|                     |                                           |                     |                                           |                     |j        d         d           |                     |j        d         d           |                     d |j	        D             g d	d
dddddgddgddggggg dd
dddddgddgddgddggggg dd
dddddgddgddggggg           d S )N	multi-logT)r   r   r   logpathza.log
b.log
c.logactionzeaction[actname='ban']
action[actname='log', logpath="a.log
b.log
c.log
d.log"]
action[actname='test']c                 6    g | ]}|                                 S rx   )r   r   rO   s     r(   r   z6JailReaderTest.testMultiLineOption.<locals>.<listcomp>  s     III!!))++IIIr)   )rU   r  	addactionban	multi-setr  	actionbanz4echo "name: ban, ban: <ip>, logs: a.log
b.log
c.log"actnamer   )rU   r  r  logr  z:echo "name: log, ban: <ip>, logs: a.log
b.log
c.log
d.log"za.log
b.log
c.log
d.log)rU   r  r  rR   rR   z5echo "name: test, ban: <ip>, logs: a.log
b.log
c.log")
r
   r   r   rD   rE   rK   rZ   r   rV   _JailReader__actionsr   s     r(   testMultiLineOptionz"JailReaderTest.testMultiLineOption  s   	Kd<L[u	v	v	v$//$))++//$//##$$$4<	*,ABBB4<)  ,^  _  _  _IIt/HIII,,,{KSXJK[[ / 
 -,,{KSXQR,-/D[ / 
 .--[(TZKL[] 0 L     r)   c           	      F   t           j                            d           t          ddt                    }t          j        |d           |j                                        }t          d          |d<   | 
                    |                                           |                                }g }|D ]wt                    dk    rd         d	k    r"d         d
k    r|                               Dd         dk    r'|                    fdd         D                        xdt           z  }|                     t          |          d           |                     |d         d	dddd
|g           |                     |d         d	dddd
|g           d S )NTr   blocklisttest)r   r   r   ))rt   r#  )filterr   )	failregexz^test <HOST>$)senderzf2b-test@example.com)blocklist_de_apikeyztest-key)r  zX%(action_blocklist_de)s
mynetwatchman[port=1234,protocol=udp,agent="%(fail2ban_agent)s"]rl   r   rU   agentr  c                 J    g | ]}|d          dk    dgdd         z   |z    S )r   r(  rU   r   rl   rx   )r   r   cmds     r(   r   z3JailReaderTest.testVersionAgent.<locals>.<listcomp>  s6    JJJ1!A$'//#ac("Q&///r)   zFail2Ban/%sr   r  blocklist_der   mynetwatchman)r`   r   r   r
   r   r   rE   _cfgget_sectionsr  rD   rK   r   r   appendextendr   rZ   )r&   r   r   r   act	useragentr*  s         @r(   testVersionAgentzJailReaderTest.testVersionAgent  s   
,d+++	O$
	K	K	K$D&!!!Y##%%(" $  (? //$//##$$$<<>>&
# L Lc	#hh!mm	!foo#a&G++JJsOOOOA+JJJJJJAJJJKKKg%)3s88Q3q6E?HngW`abbb3q6E?HowXabcccccr)   c                    t           j                            |d          }t          |d                                           t           j                            |d          }t          j        d|           |                     t          j        t           j                            |d                    |g           |                     t          j        |          g            | 	                    d|z             |                     t          j        t           j                            |d                    g            d S )Nf1r1   f2nonexisting*z4File %s is a dangling link, thus cannot be monitored)
r2   r3   r6   r9   r;   symlinkrZ   r
   _globr   )r&   r$   r5  r6  s       r(   testGlobzJailReaderTest.testGlob  s    
w||At"r3--	w||At"*]2 :#BGLLC$8$899B4@@@:#B'',,,JROPPP:#BGLLM$B$BCCRHHHHHr)   c                    t          i           }|                     |                                g            |                     |                    d                     |                     t          |j        di            |                     t          |j        d           |                     t          |j	        dd           |                     t          |j
        di            d S )Nr   rR   any)r   rZ   r   r^   has_sectionr   r   merge_sectionr   r~   rK   )r&   r%   s     r(   testCommonFunctionz!JailReaderTest.testCommonFunction  s    ###!1::<<$$$1==(()))NAOVR@@@NAIv666NAE65999NAL&"=====r)   )rt   ru   rv   r   r   r   r   r   r   r   r   r   r   r   r  r!  r3  r   r;  rA  r   r   s   @r(   r   r     s3       8 8 8 8 8	W 	W 	W+ + +? ? ?1 1 1< < << < << < <8 8 8  4C C C3& 3& 3&j  0d d dB I I +I > > > > > > >r)   r   c                   D    e Zd Zd Zd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
S )FilterReaderTestc                 &   g ddddg dgg dg dg dg d	g}t          ddi           }|                    t                     |                                 |                    d            |                     |                                |           t          ddd
dit          t                    }|                                 |                    d            d|d         d<   |                     |                                |           d S )N)rU   
testcase01r   r   r  rE  r   )z^\s*(?:\S+ )?(?:kernel: \[\d+\.\d+\] )?(?:@vserver_\S+ )?(?:(?:\[\d+\])?:\s+[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?|[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?(?:\[\d+\])?:)?\s*(?:error: PAM: )?Authentication failure for .* from <HOST>\s*$z^\s*(?:\S+ )?(?:kernel: \[\d+\.\d+\] )?(?:@vserver_\S+ )?(?:(?:\[\d+\])?:\s+[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?|[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?(?:\[\d+\])?:)?\s*(?:error: PAM: )?User not known to the underlying authentication module for .* from <HOST>\s*$a  ^\s*(?:\S+ )?(?:kernel: \[\d+\.\d+\] )?(?:@vserver_\S+ )?(?:(?:\[\d+\])?:\s+[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?|[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?(?:\[\d+\])?:)?\s*(?:error: PAM: )?User not known to the\nunderlying authentication.+$<SKIPLINES>^.+ module for .* from <HOST>\s*$)rU   rE  addignoreregexz"^.+ john from host 192.168.1.1\s*$)rU   rE  r   z
_COMM=sshd+z_SYSTEMD_UNIT=sshd.servicez_UID=0)rU   rE  r   zFIELD= with spaces rG  zAFIELD= with + char and spaces)rU   rE  datepatternz%Y %m %d %H:%M:%Sr   5r   r      r   )r   r|   TEST_FILES_DIRrE   rK   rV   r   TEST_FILES_DIR_SHARE_CFG)r&   outputfilterReaders      r(   rX   zFilterReaderTest.testConvert  sY   '''~ 06 06 06 7* * *? ? ?B B B<<</&2 lL"==,.)))$ --//888lL:s:K)>C C C,$&)B---//88888r)   c                 $   t          dddddt          t                    }|                                 |                    d            |                                }|                     |d         d           |                     d           d S )NrE  z<test>X)r   rR   rJ  r   z6Wrong int value 'X' for 'maxlines'. Using default one:)r   rN  rM  rE   rK   r}   assertNotEqualr   r&   rP  rW   s      r(   testConvertOptionsz#FilterReaderTest.testConvertOptions-  s    lLxY\:]:])>C C C,$		!	!	#	#$d:&,,,LMMMMMr)   c                     g dg}t          ddi t          t                    }|                                 |                    d            |                                }|                     ||           d S )N)rU   jailnamer   z to=sweet@example.com fromip=<IP>
substitionrW  rJ  r   rN  rM  rE   rK   r   rV   r&   rO  rP  r%   s       r(   !testFilterReaderSubstitionDefaultz2FilterReaderTest.testFilterReaderSubstitionDefault6  s    SSST&lJ)>C C C,$!F#####r)   c                     t          ddi t          t                    }|                                 |                    d            |                                }|                     d|d         v            d S )N
testcase02rW  rJ  r   r%  )r   rN  rM  rE   rK   r}   rD   rT  s      r(   testFilterReaderSubstKnownz+FilterReaderTest.testFilterReaderSubstKnown?  s     lJ)>C C C,$		!	!	#	#$//&D--.....r)   c                     g dg}t          ddddit          t                    }|                                 |                    d            |                                }|                     ||           d S )N)rU   rW  r   zto=sour@example.com fromip=<IP>rX  rW  honeypotzsour@example.comrJ  rY  rZ  s       r(   testFilterReaderSubstitionSetz.FilterReaderTest.testFilterReaderSubstitionSetJ  s    RRRS&lJEW8X)>C C C,$!F#####r)   c                    g dg}t          d          \  }}t          dd|t          t                    }|                                 |                    d            |                                }|                     ||           d S )N)rU   rW  r   z?^to=test,sweet@example.com,test2,sweet@example.com fromip=<IP>$zusubstition[failregex="^<known/failregex>$", honeypot="<sweet>,<known/honeypot>", sweet="test,<known/honeypot>,test2"]rX  rW  rJ  r   r   rN  rM  rE   rK   r   rV   r&   rO  
filterName	filterOptrP  r%   s         r(   testFilterReaderSubstitionKnownz0FilterReaderTest.testFilterReaderSubstitionKnownS  s    rrrs&(z| |*ilJ	)>C C C,$!F#####r)   c                    g dg}t          d          \  }}t          dd|t          t                    }|                                 |                    d            |                                }|                     ||           d S )N)rU   rW  r   z)^\s*to=fail2ban@localhost fromip=<IP>\s*$zUsubstition[failregex="^\s*<Definition/failregex>\s*$", honeypot="<default/honeypot>"]rX  rW  rJ  rc  rd  s         r(   !testFilterReaderSubstitionSectionz2FilterReaderTest.testFilterReaderSubstitionSection^  s    ^^^_&(\^ ^*ilJ	)>C C C,$!F#####r)   c                    t          ddddit          t                    }|                                 |                    d            |                     t          t           j        |           t          dddddt          t                    }|                                 |                    d            |                     t          t           j        |           d S )NrX  rW  r`  z
<honeypot>rJ  z<sweet>)r`  sweet)r   rN  rM  rE   rK   r   r   r   )r&   rP  s     r(   testFilterReaderSubstitionFailz/FilterReaderTest.testFilterReaderSubstitionFaili  s    lJ\8R)>C C C,$J 4lCCClJYYe8f8f)>C C C,$J 4lCCCCCr)   c                    t           j                            t           j                            t          d                    }t          t           j                            |d          di           }|                     |                                t           j                            |d          t           j                            |d          g           	 |                    d            |	                    dd           |	                    dd           |	                    dd           d S # t          $ r#}|                     d	|z             Y d }~d S d }~ww xY w)
Nfilter.dztestcase01.confrE  ztestcase-common.confrN   __prefix_liner%  ignoreregexz)unexpected options after readexplicit: %s)r2   r3   abspathr6   rM  r   rZ   readexplicitrK   r~   r   fail)r&   path_rP  r   s       r(   testFilterReaderExplicitz)FilterReaderTest.testFilterReaderExplicitw  sG   
'//"',,~zBB
C
C%bgll52CDDlTVWW,<,,..GLL.//eEV1W1WX  @4   L/222L+...L-00000	 @ @ @998A>?????????@s   AD2 2
E<EEN)rt   ru   rv   rX   rU  r[  r^  ra  rg  ri  rl  ru  rx   r)   r(   rC  rC    s        *9 *9 *9XN N N$ $ $	/ 	/ 	/$ $ $	$ 	$ 	$	$ 	$ 	$D D D@ @ @ @ @r)   rC  c                   2    e Zd ZddZd Zed             ZdS )JailsReaderTestCacheFNc                    t          ||          }|                    |           |                                 |                                 |                                 |                     |                    d                      d S )Nr   r   )r   r|   	readEarlygetEarlyOptionsreadAllrD   rK   )r&   r   r   r   configurators        r(   _readWholeConfz#JailsReaderTestCache._readWholeConf  s    <lSSS,'"""   //,))$//00000r)   c                     d}|                                                      d          D ]}t          j        d|z   |          r|dz  } |S )Nr   r   z^\s*Reading files?: .*/r   )getLogrsplitrematch)r&   	filematchcntss       r(   _getLoggedReadCountz(JailsReaderTestCache._getLoggedReadCount  sU    	#;;==%%  ah))3Q77 1HC	*r)   c                    t           j                                         t          j        }t
          j        t          _        	 t          j        |           t          j	        t          |           t          j        t          dz   |dz              t          j        t          dz   |dz              t                      }|                     ||           |                     d          }|                     |dk    d|z             |                     |d	|
           |                     d          }|                     |dk    d|z             |                     d          }|                     |dk    d|z             |                     d          }|                     |dk    d|z             |t          _        d S # |t          _        w xY w)Nz
/jail.confz/jail.localz/fail2ban.confz/fail2ban.localr=  z
jail.localr   z3Unexpected count by reading of jail files, cnt = %sTry  zjail\.localz:Unexpected count by second reading of jail files, cnt = %szfilter\.d/common\.confz5Unexpected count by reading of filter files, cnt = %szaction\.d/iptables\.confz5Unexpected count by reading of action files, cnt = %s)r`   r   
SkipIfFastr	   logLevelloggingDEBUGr+   r,   copytreer   copyr  r~  r  rD   )r&   r   saved_ll	share_cfgr  s        r(   testTestJailConfCachez*JailsReaderTestCache.testTestJailConfCache  s   
,%($]/'	=	?:w'''	;zL('M*ABBB	;z,,g8I.IJJJ vv9 wY777		!	!,	/	/3 ??3!8RUXXYYY wT	JJJ		!	!.	1	13??3!8Y\__``` 
	!	!";	<	<3??3!8TWZZ[[[		!	!"=	>	>3??3!8TWZZ[[[&?h?&&&&s   E3G G)FN)rt   ru   rv   r~  r  r   r  rx   r)   r(   rw  rw    sR        1 1 1 1   #' #' +#' #' #'r)   rw  c                        e Zd Z fdZd Zd Zd Zd Zd Zd Z	d Z
ed	             Zd
 Zd Zed             Z xZS )JailsReaderTestc                 H     t          t          |           j        |i | d S r   )r    r  r   r   s      r(   r   zJailsReaderTest.__init__  s+    '%'888888r)   c                     t           j                            d          s2t          d          }|                     t
          |j                   d S d S )Nz/XXXr   )r2   r3   r7   r   r   r   rE   )r&   readers     r(   testProvidingBadBasedirz'JailsReaderTest.testProvidingBadBasedir  sP    			 .'''6Z-----. .r)   c                    t          t          t                    }|                     |                                           |                     |                    d                     |                     t          |j	                   |	                    d          }d | _
        |                     |g dg ddd	d
g dgdd	gg dg dg dg dg dddddddgddgddgggg dg dg dg dddgddgddgddgg ddd gd!d"gd!d#gd!d$gd!d%gg           |                     d&           |                     d'           |                     d(           d S ))Nr   F)ignoreWrongTallow_no_files)addr   auto)r  test-known-interpr  r  r  r   )z*failure test 1 (filter.d/test.conf) <HOST>z+failure test 2 (filter.d/test.local) <HOST>z"failure test 3 (jail.local) <HOST>start)r  missinglogfilesr  )rU   r  r   <IP>)r  brokenactionr  )rU   r  r   r  )rU   r  r  r  r  r  r  zhit with big stick <ip>r  r   )r  parse_to_end_of_jail.confr  )rU   r  r   r  )rU   r   r   r  )rU   r   r   r   r   r  r  )r  r   r  r   zconfig-errorz~Jail 'brokenactiondef' skipped, because of wrong configuration: Invalid action definition 'joho[foo': unexpected option syntaxz~Jail 'brokenfilterdef' skipped, because of wrong configuration: Invalid filter definition 'flt[test': unexpected option syntaxzoJail 'missingaction' skipped, because of wrong configuration: Unable to read action 'noactionfileforthisaction'zmJail 'missingbitsjail' skipped, because of wrong configuration: Unable to read the filter 'catchallthebadies'z!Errors in jail 'missingbitsjail'.zSkipping...z6No file(s) found for glob /weapons/of/mass/destruction)r   r   r   rD   rE   r^   rK   r   r   r   maxDiffrV   r   assertNotLogged)r&   jailscomm_commandss      r(   testReadTestJailConfz$JailsReaderTest.testReadTestJailConf  s   
.=W
X
X
X%//%**,,5###66777J...--t-44-$,"""(((%~ 8 8 8 
 !"&&&666###333888.(N,- n= 
 100@@@111444m n)*(((l EF EFuwsuE$% % %L 7888}%%%LMMMMMr)   c           
         t           j                            d           t          j        t          j                            t          dd                    D ]}t          j                            |          	                    dd          }t          |di t                    }|                     |                                           	 |                    i            nG# t          $ r:}|                     d	|d
t!          |          j        d|           Y d }~nd }~ww xY w|                    d          s|                     d|                                d|z             |                     |j                            dd                                          d|z             |                    t2          j        t7          d          z            }|                     |                    d          dd|z             |dv r/|                     d|                    dd          d|z             d S )NTr   action.d*.confz.confr   r   r   zaction r   z: z-commonrN   z.Action file %r is lacking [Definition] sectionmsgr  z#Action file %r is lacking actionban)timeoutbantime)ignorer   z5Action file %r does not contains jail-name 'f2b-TEST')pfziptables-allportsiptables-multiportzf2b-TESTactionstartzSAction file %r: interpolation of actionstart does not contains jail-name 'f2b-TEST')r`   r   r   globr2   r3   r6   r   basenamer
  r   rD   rE   rK   r   rs  typert   r   assertInr   _optsr~   stripr}   r   _escapedTagsrU   rZ   )r&   actionConfig
actionNameactionReaderr   rW   s         r(   testReadStockActionConfz'JailsReaderTest.testReadStockActionConf  sq   
,d+++iZX N NOO p pl  ..66wCC:z62zJJJ<??<$$&&'''GB
 G G GIIIZZZa1A1A1A11EFFFFFFFFG


i
(
( pMM, 5 5 7 7	9L	H  J J J 	OOL&**;;;AACC	.	=  ? ? ? ##&-C)D)DD $ F FDTXXf%%v	@<	O  Q Q Q FFF	]]:txxr::
_bn
n  p p p-p ps   C%%
D)/0D$$D)c           	         t           j                            d           t          t          t
                    }|                     |                                           |                     |                                           |	                                }| 
                    |g            t                      }|                                D ]}|dk    r
|                    |d          }t          |          \  }}|                    |           |                     t!          |                     t#          |||t
          t                    }|                     |                                d|z              |                    i            |                     |j                            dd	                                                     |                    |d
          }|                     t!          |                                                     t)          |          D ]K}	t          |	          \  }
}|                     t!          |
                     |                     t+          |t,                               |
dk    r|                     d|           t1          |
|i t
          t                    }|                     |                                           |                    i            |	                                }|                     t!          |                     |                     |j                            dd	                                                     Md S )NTr   r   INCLUDESr$  rJ  zFailed to read filter:r%  r   r  r  portr  )r`   r   r   r   r   r   rD   rE   rK   r   rZ   rU   r   r~   r   r  r   r   r  r  r   
isinstancer  r  r   )r&   r  r  
allFiltersr   re  rf  rP  actionsr1  actNameactOptr  cmdss                 r(   testReadStockJailConfz%JailsReaderTest.testReadStockJailConf  s   
,d+++
j7K
L
L
L%//%**,,//%""$$%%%--//- ="%%% uu* nn %E %Ed
j		$)):)*55:y>>*??3z??### z4%z; ; ;<??<$$&&'?*'LMMM2 ??<%))+r::@@BBCCCYYtX&&7??3w}}''((( w'' E Es$S))OGVOOCLL!!!OOJvt,,---&&&	]]66"""r&
< < <LOOL%%''(((B!!DOOCII 	OOL&**;;;AACCDDDDE-%E %Er)   c           
         t           j                            d           t          t          dt
                    }|                     |                                           |                     |                                           t          d t          j
        t          j                            ddd                    D                       }t          d |j        D                       }d | _        |                     |                    |          d	|                    |          z             |                     |                    |          d
|                    |          z             d S )NTr   r   r   r   c              3      K   | ]v}|                     d           |                     d          ,t          j                            t          j                            |          d                   d         V  wdS )zcommon.confz-aggressive.confr   r   N)r   r2   r3   splitextsplitr  s     r(   r  zBJailsReaderTest.testReadStockJailFilterComplete.<locals>.<genexpr>^  s       J JJJ}%%J)*4F)G)GJ  q!1!1!!455a8 J J J J J Jr)   r   rn  r  c              3   V   K   | ]$}t          |j        d                    d         V  %dS )r$  r   N)r   r   )r   r   s     r(   r  zBJailsReaderTest.testReadStockJailFilterComplete.<locals>.<genexpr>b  sG        15>$,x())!,     r)   z=More filters exists than are referenced in stock jail.conf %rz2Stock jail.conf references non-existent filters %r)r`   r   r   r   r   r   rD   rE   rK   rU   r  r2   r3   r6   r  r  issubset
difference)r&   r  filtersfilters_jails       r(   testReadStockJailFilterCompletez/JailsReaderTest.testReadStockJailFilterCompleteX  sz   
,d+++
jtJ^
_
_
_%//%**,,//%""$$%%% J JIbgll8ZBBCCJ J J J J'   9>    , $,//'""<00CgFXFXYeFfFffh h h//,''008<;R;RSZ;[;[[] ] ] ] ]r)   c                    t           j                            d           t          t          dt
                    }|                     |                                           |                     |                                           |	                    d          }|                     t          |                     |D ]\}t          |          dk    rG|d         |d         gdd	gk    r1|                     t          j        |d                   dk               ]d
D ]V}|                     d|gd |D                        |                     d|ddg|           |                     d|g|           W|                     |d         d         d           |j        D ]W}|j        }|                                }|                     t          |          d|z             |D ]}|	                                }|                                }	dt%          |          v r|                     d|j                   d}
|d|	g}|D ]}t          |          dk    r/|d         dk    r#|dd         |k    rdd |d         D             v }
n;t          |          dk    r(|d         dk    r|dd         |k    r|d         dk    rd}
|
r n|                     |
d|dt%          |                     Yd S )NTr   r  r  rj   r   r   rU   r  )r   recidiver  c              3   h   K   | ]-}t          |          d k    |d         dk    !|dd         V  .dS )rj   r   r  Nr   r   r   r*  s     r(   r  zDJailsReaderTest.testReadStockJailConfForceEnabled.<locals>.<genexpr>  s@      KKSQ3q6U??S!W????KKr)   r   warnr  rL  zNo actions found for jail %sr  z<blocktype>	blocktypeFr  rl   r  r   c                     g | ]
}|d          S )r   rx   r  s     r(   r   zEJailsReaderTest.testReadStockJailConfForceEnabled.<locals>.<listcomp>  s    ,J,J,JSV,J,J,Jr)   rK  z	Found no z command among )r`   r   r   r   r   r   rD   rE   rK   r   r   r   str2secondsr  rZ   _JailsReader__jailsr   r   str	_initOpts)r&   r  r  commandjr  	jail_namer  commandsaction_nameblocktype_presenttarget_commands               r(   !testReadStockJailConfForceEnabledz1JailsReaderTest.testReadStockJailConfForceEnabledk  s[   
,d+++ jtJ^
_
_
_%//%**,,//%""$$%%%--t-44- //#m$$%%%  8 8g	'llaWQZ4	8JJJOOF&wqz22Q6777   . .a ==%KKKKKM M M ==%Hf-}====='1}---- =$Q'111% + +a#7yy{{9 ??3w<<)I5  7 7 7  + +v~~H..""KH%%	]]; 0111 (K8^  
g,,

wqz[88qs|~%%(,J,Jwqz,J,J,JJLL1u!4!4qs|~%%'!**C*C 	 u	__
..#h---)  + + +%++ +r)   c                    t           j                            d           t                      }|                    t
                     |                     |                                t
                     |                                 |	                                }|                     |d         d           |                     |d         d           |
                                 |                                 |                                 |                                fd}|                      |d           |d	          cxk     o |d
          k     nc            |                      |d           |d          k               |                      |d           |d          k               |                     g dg dg dg dg dg dg dg           |j                            d           |                     |j                                        d           |                     |                                t
                     d S )NTr   socketz/var/run/fail2ban/fail2ban.sockpidfilez/var/run/fail2ban/fail2ban.pidc                     t                    D ]!\  }}|d         dk    r|d         | k    r|c S "t          d| d          )Nr   rU   r   zDid not find command 'set z' among commands )	enumerater   )rJ   r   r   r  s      r(   find_setz7JailsReaderTest.testStockConfigurator.<locals>.find_set  se    ""  tq!tu}}1XXX	6688 
 
 r)   syslogsocketloglevel	logtarget
dbpurgeagedbfiledbmaxmatches)rU   r  r  )rU   r  INFO)rU   r  z/var/log/fail2ban.log)rU   	allowipv6r  )rU   r  z"/var/lib/fail2ban/fail2ban.sqlite3)rU   r  
   )rU   r  1dz/tmp)r`   r   r   r   r|   r   rZ   
getBaseDirrz  r{  r|  rK   convertToProtocolgetConfigStreamrD   rV   _Configurator__jails)r&   r}  rW   r  r  s       @r(   testStockConfiguratorz%JailsReaderTest.testStockConfigurator  s   
,d+++,*%%%<**,,j999		%	%	'	'$4>#DEEE4	?$DEEE  """))++(     //8Nhhz22JJJJXXk5J5JJJJJ   //((<((88H+=+==>>>//((>**XXh-?-??@@@ ###111   ;;;#    #..v666<4??AA6JJJ<**,,j99999r)   c                 :   t          j        t           j                            |d                     t          j        t           j                            |d                     t	          t           j                            |dd          d                                           t	          t           j                            |dd          d                                           t	          t           j                            |d          d          }|                    d           |                                 t          |i           }|                     |	                                           |                     |
                                           |                    d	
          }d |D             }|                     t          t          d |D                                 d           |                     |d         d         d           d S )Nrn  r  ztestaction1.confr1   ztestfilter1.conf	jail.confz
[testjail1]
enabled = true
action = testaction1[actname=test1]
         testaction1[actname=test2]
         testaction.py
         testaction.py[actname=test3]
filter = testfilter1
r   Tr  c                 B    g | ]}|d d         g dk    |dd          S )Nrj   )rU   	testjail1r  rx   )r   comms     r(   r   z:JailsReaderTest.testMultipleSameAction.<locals>.<listcomp>  sC     5 5 5d
2A2h33333 abb333r)   c              3   &   K   | ]}|d          V  dS )r   Nrx   )r   r  s     r(   r  z9JailsReaderTest.testMultipleSameAction.<locals>.<genexpr>  s&      ??6!9??????r)   rl   rL  z{})r2   mkdirr3   r6   r9   r;   r:   r   rD   rE   rK   r   rZ   r   rU   )r&   r   jailfdr  r  add_actionss         r(   testMultipleSameActionz&JailsReaderTest.testMultipleSameAction  s   (27<<,,---(27<<,,---rw||GZ);<<cBBHHJJJrw||GZ);<<cBBHHJJJWk22C88&,,     	,,...
gB
7
7
7%//%**,,//%""$$%%%--t-44-5 5m 5 5 5+ 3s??;?????@@!DDD ;r?2&-----r)   c                 L    |                      t          d| j        d           d S )Nz'Have not found any log file for .* jailpollingbackend)assertRaisesRegexr   _testLogPathr-   s    r(   testLogPathFileFilterBackendz,JailsReaderTest.testLogPathFileFilterBackend  s6    %Oi  ) ) ) ) )r)   c                     	 ddl m} n&# t          $ r}t          j        d          d }~ww xY w|                     d           |                     d           d S )Nr   )FilterSystemdz&systemd python interface not availablesystemdr  zsystemd[journalflags=2])server.filtersystemdr  r   r`   ra   r  )r&   r  r   s      r(   testLogPathSystemdBackendz)JailsReaderTest.testLogPathSystemdBackend   s    E3333333	 E E E		C	D	DDEI&&&566666s   	 
,',c                    t          t          j                            |d          d          }|                    d|d|d           |                                 t          |          }|                     |                                           |                     |	                                           |
                                 d S )Nr  r1   z&
[testjail1]
enabled = true
backend = z
logpath = ze/not/exist.log
          /this/path/should/not/exist.log
action = 
filter = 
failregex = test <HOST>
r   )r9   r2   r3   r6   r:   r;   r   rD   rE   rK   r   )r&   r   r	  r  r  s        r(   r  zJailsReaderTest._testLogPath  s    Wk22C88&,,, ww	 	 	 	 	,,...
g
&
&
&%//%**,,//%""$$%%%--/////r)   )rt   ru   rv   r   r  r  r  r  r  r  r  r   r  r  r  r  r   r   s   @r(   r  r    s       9 9 9 9 9. . .
/N /N /Nbp p p6<E <E <E~] ] ]&=+ =+ =+~2: 2: 2:h . . +.:) ) )7 7 7   +    r)   r  )6
__author____copyright____license__r  r  r2   r  r+   r"   r`   client.configreaderr   r   r   r   clientr	   client.jailreaderr
   r   r   client.filterreaderr   client.jailsreaderr   client.actionreaderr   r   client.configuratorr   server.mytimer   r   utilsr   r   r3   r6   r5   __file__rM  rN  r   r   r   r   r   r   TestCaser   r   rC  rw  r  rx   r)   r(   <module>r!     s  ( 1
P   				 				   , , , , , , , , , , , , $ $ $ $ $ $ L L L L L L L L L L . . . . . . , , , , , , = = = = = = = = . . . . . . " " " " " "       2 2 2 2 2 2 2 2bgooh77AA       |0 7<< 9 98DD  N8 N8 N8 N8 N8x( N8 N8 N8bv> v> v> v> v>' v> v> v>rG@ G@ G@ G@ G@) G@ G@ G@T7' 7' 7' 7' 7'- 7' 7' 7'tV V V V V( V V V V Vr)   