
    R                        S r SSKJr  SSKJr  SSKJr  SSKJr  SSKrSSKrSSKrSSK	r	SSK
Jr  SSKrSSKrSSKrSSKJr  SS	KJr  SS
KJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSK J!s  J"r"  SSK#J!s  J$r$  SSK#J%r%  SSK#J&r&  SSK#J'r'  SSK(J)r)  SSK*J+r+  SSK,J-r-  SSK.J/r/  SSK	J0r0J1r1  \0" \1" SSS5      5        SSK
J2r2  Sr3 " S  S!\45      r5 " S" S#\45      r6 " S$ S%\45      r7 " S& S'\5      r8 " S( S)\45      r9 " S* S+\5      r: " S, S-\"Rv                  Rx                  5      r= " S. S/\"R|                  5      r?g)0z<Unit and integration tests for gsutil command_runner module.    )absolute_import)print_function)division)unicode_literalsN)input)command_runner)Command)CommandArgument)CommandRunner)HandleArgCoding)HandleHeaderCoding)CommandException)CloudObjectCompleter)CloudOrLocalObjectCompleter)LocalObjectCompleter)LocalObjectOrCannedACLCompleter)NoOpCompleter)ARGCOMPLETE_AVAILABLE)SetBotoConfigForTest)unittest)system_util)GSUTIL_PUB_TARBALL)InsistAscii)SECONDS_PER_DAY)add_moveMovedModulemockzunittest.mock)r   zgs_host is set to non-default value; trying to fetch gsutil version metadata from the wrong host would fail repeatedly, taking a long time for retry backoffs before finally failing the test.c                       \ rS rSrSrSrg)FakeArgparseArgumentA   z"Fake for argparse parser argument. N)__name__
__module____qualname____firstlineno____doc____static_attributes__r!       2platform/gsutil/gslib/tests/test_command_runner.pyr   r   A   s    *r(   r   c                   .    \ rS rSrSrSS jrS rS rSrg)	FakeArgparseParserF   zFake for argparse parser.c                 ,    / U l         S U l        Xl        g N)	arguments
subparsersname)selfr1   s     r)   __init__FakeArgparseParser.__init__I   s    DNDOIr(   c                 P    [        5       nU R                  R                  U5        U$ r.   )r   r/   append)r2   unused_argsunused_kwargsarguments       r)   add_argumentFakeArgparseParser.add_argumentN   s!    #%HNN(#Or(   c                 8    [        5       U l        U R                  $ r.   )FakeArgparseSubparsersr0   r2   s    r)   add_subparsers!FakeArgparseParser.add_subparsersS   s    ,.DO??r(   )r/   r1   r0   NDefault)	r"   r#   r$   r%   r&   r3   r:   r?   r'   r!   r(   r)   r+   r+   F   s    !

r(   r+   c                   (    \ rS rSrSrS rSS jrSrg)r=   X   zContainer for nested parsers.c                     / U l         g r.   parsersr>   s    r)   r3   FakeArgparseSubparsers.__init__[   s	    DLr(   c                 N    [        US9nU R                  R                  U5        U$ )N)r1   )r+   rG   r6   )r2   r1   r8   parsers       r)   
add_parser!FakeArgparseSubparsers.add_parser^   s#    T*FLLMr(   rF   NrA   )r"   r#   r$   r%   r&   r3   rK   r'   r!   r(   r)   r=   r=   X   s    %r(   r=   c            	       v    \ rS rSrSr\R                  " S\" SSS9/S9r\R                  " S/ SS	S	0 S
9r
S rSrg)FakeCommandWithInvalidCompleterd   z1Command with an invalid completer on an argument.fake1argBAD)	completerargparse_argumentscommand_helpfake command for tests	help_namehelp_name_aliases	help_typehelp_one_line_summary	help_textsubcommand_help_textc                     g r.   r!   r>   s    r)   r3   (FakeCommandWithInvalidCompleter.__init__q       r(   r!   N)r"   r#   r$   r%   r&   r	   CreateCommandSpecr
   command_specHelpSpec	help_specr3   r'   r!   r(   r)   rN   rN   d   sM    9**?5E#J"KM, 13)75M)A468)	r(   rN   c            	       f    \ rS rSrSrSrSr\R                  " S \\\	" S5      \	" S5      /00S9r
Srg	)
FakeCommandWithNestedArgumentsu   eventset   arg1arg2rT   r!   N)r"   r#   r$   r%   subcommand_namesubcommand_subnamenum_argsr	   rb   r
   rc   r'   r!   r(   r)   rg   rg   u   sL    /(**+K/>3E7Fv7N7Fv7NH5A1?-.,r(   rg   c            
       *   \ rS rSrSr\R                  " S\R                  " 5       \R                  " 5       \R                  " 5       \R                  " 5       \R                  " 5       \R                  " 5       /S9r\R                  " S/ SSS0 S9rS rS	rg
)FakeCommandWithCompleters   z%Command with various completer types.fake2rT   rV   rW   rX   c                     g r.   r!   r>   s    r)   r3   "FakeCommandWithCompleters.__init__   ra   r(   r!   N)r"   r#   r$   r%   r&   r	   rb   r
   MakeZeroOrMoreCloudURLsArgumentMakeZeroOrMoreFileURLsArgument%MakeZeroOrMoreCloudOrFileURLsArgumentMakeFreeTextArgument%MakeZeroOrMoreCloudBucketURLsArgumentMakeFileURLOrCannedACLArgumentrc   rd   re   r3   r'   r!   r(   r)   rr   rr      s    -**

9
9
;

8
8
:

?
?
A

.
.
0

?
?
A

8
8
:		, 13)75M)A468)	r(   rr   c                   N  ^  \ rS rSrSrU 4S jrU 4S jrS r\R                  " \
R                  \5      S 5       r\R                  " \
R                  \5      S 5       r\R                  " \
R                  \5      S 5       r\R                  " \
R                  \5      S	 5       r\R                  " \
R                  \5      S
 5       r\R                  " \
R                  \5      S 5       r\R                  " \
R                  \5      S 5       r\R                  " \
R                  \5      S 5       r\R                  " \
R                  \5      S 5       r\R                  " \
R                  \5      S 5       r\R                  " \
R                  \5      S 5       r\R                  " \
R                  \5      S 5       rS r\R                  " \
R                  \5      S 5       rS r\R8                  " \S5      S 5       r\R8                  " \S5      S 5       rS r S r!S r"Sr#U =r$$ )TestCommandRunnerUnitTests   z<Unit tests for gsutil update check in command_runner module.c                 n  >^ ^ [         [        T ]  5         T R                  5       T l        [
        R                  R                  [        R                  ST R                  S9nT R                  UR                  5        UR                  5         [        R                  " [        R                   5      mTR#                  5       (       d?  T(       d  [%        S[        R                   -  5      eTSS mTR#                  5       (       d  M?  [        R&                  T l        U4S j[        l        S [        l        ST l        U 4S	 j[        R.                  l        S
T l        [        R4                  T l        U 4S j[        l        T R9                  S5      T l        T R=                  T R:                  SSS9T l        g)(Sets up the command runner mock objects.*GetLastCheckedForGsutilUpdateTimestampFilereturn_valuez#Version number (%s) is not numeric.Nc                     > [        T5      S-   $ )N   )float)uvbase_versions     r)   <lambda>2TestCommandRunnerUnitTests.setUp.<locals>.<lambda>   s    eL6IA6Mr(   c                     gNyr!   ps    r)   r   r          Sr(   Tc                     > T R                   $ r.   )running_interactivelyr>   s   r)   r   r      s    **r(   r   c                     > T R                   $ r.   )version_mod_timer>   s   r)   r   r      s    1F1Fr(   pubzgsutil.tar.gzfoo)
bucket_uriobject_namecontents) superr~   setUpCreateTempFiletimestamp_file_pathr   patchobjectr   	boto_util
addCleanupstopstartsix	text_typegslibVERSION	isnumericr   LookUpGsutilVersionold_look_up_gsutil_versionr   r   r   IsRunningInteractivelyr   GetGsutilVersionModifiedTimeprevious_version_mod_timeCreateBucketpub_bucket_uriCreateObjectgsutil_tarball_uri)r2   get_timestamp_file_patcherr   	__class__s   ` @r)   r    TestCommandRunnerUnitTests.setUp   sl   	
$d13  $224D!%!2!2  4-- "3 "/ 	OO.334$$& ==/L$$&&D$}} - . 	.!#2&l	 $$&&
 '5&H&HD#)MN& )N "&D* 5 D%*%G%GD")FE& ++E2D"//4;N;N<K9> 0 @Dr(   c                 ^  > [         [        U ]  5         U R                  [        l        [        [        l        U R                  [        l	        [        R                  R                  R                  [        l        U R                  R                  5         U R                  R!                  5         gz+Tears down the command runner mock objects.N)r   r~   tearDownr   r   r   r   r   r   r   utilsr   r   r   
delete_keyr   delete_bucketr2   r   s    r)   r   #TestCommandRunnerUnitTests.tearDown   sx    	
$d46)-)H)HN& N)-)G)GE& 	66 ) 	&&(%%'r(   c                 Z    [         R                  =(       d    [        R                  " 5       $ r.   )r   IS_PACKAGE_INSTALLr   InvokedViaCloudSdkr>   s    r)   _IsPackageOrCloudSDKInstall6TestCommandRunnerUnitTests._IsPackageOrCloudSDKInstall   s    ##G{'E'E'GGr(   c                     [         R                  R                  [        S5       nSUl        SU l        U R                  U R                  R                  S5      5        SSS5        g! , (       d  f       g= f)zDTests that py3 prompt is not triggered if not running interactively.version_infork   FverN)	r   r   r   sysmajorr   assertFalser   MaybePromptForPythonUpdater2   r   s     r)   test_py3_not_interactive3TestCommandRunnerUnitTests.test_py3_not_interactive   sU     
		3	/<l#(d 
t**EEeLM 
0	/	/s   9A''
A5c                 .   [        S/5         [        R                  R                  [        S5       nSUl        U R                  U R                  R                  S5      5        SSS5        SSS5        g! , (       d  f       N= f! , (       d  f       g= f)zATests that py3 prompt is not triggered if skipped in boto config.)GSUtilskip_python_update_promptTruer   rk   r   N)	r   r   r   r   r   r   r   r   r   r   s     r)   test_py3_skipped_in_boto3TestCommandRunnerUnitTests.test_py3_skipped_in_boto   sr     
N   
!::S.1\,,GGNO 2
! 
!11
! 
!s"   %B2A5$B5
B	?B
Bc                     [         R                  R                  [        S5       nSUl        U R                  SU R                  R                  S5      5        SSS5        g! , (       d  f       g= f)z/Tests that py3 prompt is triggered on Python 2.r   rk   Tr   Nr   r   r   r   r   assertEqualr   r   r   s     r)   test_py3_prompt_on_py21TestCommandRunnerUnitTests.test_py3_prompt_on_py2   sS     
		3	/<l
t**EEeLN 
0	/	/   3A!!
A/c                     [         R                  R                  [        S5       nSUl        U R                  SU R                  R                  S5      5        SSS5        g! , (       d  f       g= f)z3Tests that py3 prompt is not triggered on Python 3.r      Fr   Nr   r   s     r)   test_py3_prompt_on_py31TestCommandRunnerUnitTests.test_py3_prompt_on_py3   sS     
		3	/<l
u**EEeLN 
0	/	/r   c                    [        S/5         [        U R                  S5       nUR                  [	        [        [        R                  " 5       S[        -  -
  5      5      5        SSS5        SU l        U R                  SU R                  R                  SS5      5        SSS5        g! , (       d  f       NJ= f! , (       d  f       g= f)z@Tests that update is not triggered if not running interactively.r   software_update_check_period1wrk   NFlsr   )r   openr   writestrinttimer   r   r   r   #MaybeCheckForAndOfferSoftwareUpdater2   fs     r)   test_not_interactive/TestCommandRunnerUnitTests.test_not_interactive   s     
N   
!((#.!	C		a/&99:;< /#(d 





A
A$
JL
! 
!..
! 
!s#   B:AB)%;B:)
B7	3B::
Cc                    [         R                  R                  U R                  5      (       a   [         R                  " U R                  5        U R                  [         R                  R                  U R                  5      5        [        R                  " 5       U l        U R                  SU R                  R                  SS5      5        g)z?Tests when no timestamp file exists and VERSION file is recent.Fr   r   N)ospathexistsr   remover   r   r   r   r   r   r>   s    r)   #test_no_tracker_file_version_recent>TestCommandRunnerUnitTests.test_no_tracker_file_version_recent  s     
ww~~d..//ii(()RWW^^D$<$<=> IIKDt""FFtQOQr(   c                    [         R                  R                  U R                  5      (       a   [         R                  " U R                  5        U R                  [         R                  R                  U R                  5      5        SU l        U R                  5       (       + nU R                  UU R                  R                  SS5      5        g)z<Tests when no timestamp file exists and VERSION file is old.r   r   N)r   r   r   r   r   r   r   r   r   r   r   )r2   expecteds     r)    test_no_tracker_file_version_old;TestCommandRunnerUnitTests.test_no_tracker_file_version_old  s     
ww~~d..//ii(()RWW^^D$<$<=>D3355H??aHJr(   c                 \    U R                  SU R                  R                  SS5      5        gz8Tests that update is not triggered for certain commands.Fupdater   N)r   r   r   r>   s    r)   test_invalid_commands0TestCommandRunnerUnitTests.test_invalid_commands"  s,     	??!LNr(   c                     U R                   [        l        U R                  SU R                  R	                  SS5      5        gr   )r   r   r   r   r   r>   s    r)   ,test_fails_silently_when_version_check_failsGTestCommandRunnerUnitTests.test_fails_silently_when_version_check_fails)  s:     *.)H)HN&??!LNr(   c                     [        U R                  S5       nUR                  S5        SSS5        U R                  SU R                  R                  SS5      5        g! , (       d  f       N;= f)z4Tests no update if timestamp file has invalid value.r   NaNNFr   r   )r   r   r   r   r   r   r   s     r)   test_invalid_file_contents5TestCommandRunnerUnitTests.test_invalid_file_contents2  sV     
d&&	,ggen 
-t""FFtQOQ 
-	,s   A
A,c                    [        S/5         [        U R                  S5       nUR                  [	        [        [        R                  " 5       S[        -  -
  5      5      5        SSS5        U R                  5       (       + nU R                  UU R                  R                  SS5      5        SSS5        g! , (       d  f       NX= f! , (       d  f       g= f)z/Tests update should be triggered if time is up.r   r   rk   Nr   r   )r   r   r   r   r   r   r   r   r   r   r   r   )r2   r   r   s      r)   test_update_should_trigger5TestCommandRunnerUnitTests.test_update_should_trigger:  s     
N   
!((#.!	C		a/&99:;< /5577h





A
A$
JL
! 
!..
! 
!s$   CAB7%A	C7
C	C
Cc                    [        S/5         [        U R                  S5       nUR                  [	        [        [        R                  " 5       S[        -  -
  5      5      5        SSS5        U R                  SU R                  R                  SS5      5        SSS5        g! , (       d  f       NC= f! , (       d  f       g= f)z+Tests update not triggered if not time yet.)r   r   3r   rk   NFr   r   )r   r   r   r   r   r   r   r   r   r   r   r   s     r)   test_not_time_for_update_yet7TestCommandRunnerUnitTests.test_not_time_for_update_yetF  s     
N   
!((#.!	C		a/&99:;< /





A
A$
JL	
! 
!..
! 
!s#   B3AB"%4B3"
B0	,B33
Cc                    [        S/5         [        U R                  S5       nUR                  [	        [        [        R                  " 5       S[        -  -
  5      5      5        SSS5        S [        l	        U R                  SU R                  R                  SS5      5        SSS5        g! , (       d  f       NO= f! , (       d  f       g= f)	z8Tests no update triggered if user says no at the prompt.r   r   rk   Nc                     g)Nnr!   r   s    r)   r   HTestCommandRunnerUnitTests.test_user_says_no_to_update.<locals>.<lambda>W  s    sr(   Fr   r   )r   r   r   r   r   r   r   r   r   r   r   r   r   s     r)   test_user_says_no_to_update6TestCommandRunnerUnitTests.test_user_says_no_to_updateQ  s    	N   
!((#.!	C		a/&99:;< /*n





A
A$
JL
! 
!..
! 
!s$   B?AB.%A B?.
B<	8B??
Cc                 R   [        S/5         [        U R                  S5       nUR                  [	        [        [        R                  " 5       S[        -  -
  5      5      5        SSS5        U R                  5       (       + nU R                  UU R                  R                  SS5      5        [        R                  " 5       R                  5       n [        R                  " 5       R                  [        R                   5        U R                  SU R                  R                  SS5      5        [        R                  " 5       R                  U5         SSS5        g! , (       d  f       N= f! [        R                  " 5       R                  U5        f = f! , (       d  f       g= f)zATests that update isn't triggered when loglevel is in quiet mode.r   r   rk   Nr   r   F)r   r   r   r   r   r   r   r   r   r   r   r   logging	getLoggergetEffectiveLevelsetLevelERROR)r2   r   r   prev_loglevels       r)   )test_update_check_skipped_with_quiet_modeDTestCommandRunnerUnitTests.test_update_check_skipped_with_quiet_mode\  s<    
N   
!((#.!	C		a/&99:;< / 5577h





A
A$
JL '');;=m4$$W]]3CCD!L	N 	$$]3%
! 
!..  	$$]3%
! 
!s=   FAE%A,FAE/0$F
E,	(F/&FF
F&c                 &   [         R                  R                  [        5       0n[        U R                  U R
                  US9n[        5       n UR                  U5        g ! [         a%  nU R                  S[        U5      5         S nAg S nAff = f)Nbucket_storage_uri_classgsutil_api_class_map_factorycommand_mapzUnknown completer)rN   rc   command_namer   mock_bucket_storage_uri!mock_gsutil_api_class_map_factoryr+   ConfigureCommandArgumentParsersRuntimeErrorassertInr   )r2   r   runnerrJ   es        r)   4test_command_argument_parser_setup_invalid_completerOTestCommandRunnerUnitTests.test_command_argument_parser_setup_invalid_completers  s     	(44AA+-K
 !%!=!=%)%K%K!F
  !F1,,V4 1
mm'Q001s   A! !
B+BBz#Tab completion requires argcompletec                    [         R                  R                  [        5       0n[        U R                  U R
                  US9n[        5       nUR                  U5        UR                  R                  S   nU R                  UR                  [         R                  R                  5        UR                  R                  S   nU R                  UR                  [         R                  5        UR                  R                  S   nU R                  UR                  [         R                  5        U R                  [        UR                  5      [         R                   5        g )Nr  r   )rg   rc   r!  r   r"  r#  r+   r$  r0   rG   r   r1   rn   ro   lenr/   rp   )r2   r   r'  rJ   cur_subparsers        r)   <test_command_argument_parser_setup_nested_argparse_argumentsWTestCommandRunnerUnitTests.test_command_argument_parser_setup_nested_argparse_arguments  s-    	'33@@*,K !%!=!=%)%K%K!F  !F
**62 %%--a0M]''3@@MMO ",,44Q7M]''3CCE ",,44Q7M]''3FFH 	S0013<<>r(   c                 "   [         R                  R                  [        5       0n[        U R                  U R
                  US9n[        5       nUR                  U5        U R                  S[        UR                  R                  5      5        UR                  R                  S   nU R                  S[        UR                  5      5        U R                  [        [        UR                  S   R                  5      5        U R                  [         [        UR                  S   R                  5      5        U R                  ["        [        UR                  S   R                  5      5        U R                  [$        [        UR                  S   R                  5      5        U R                  [        [        UR                  S   R                  5      5        U R                  [&        [        UR                  S   R                  5      5        g )	Nr  r   r      rk   r         )rr   rc   r!  r   r"  r#  r+   r$  r   r,  r0   rG   r/   r   typerS   r   r   r   r   )r2   r   r'  main_parser	subparsers        r)   -test_command_argument_parser_setup_completersHTestCommandRunnerUnitTests.test_command_argument_parser_setup_completers  s   
 	"..;;%'K
 !%!=!=%)%K%K!F
 %&K
**;7QK22::;<&&..q1IQI//01))--a0::;=))--a0::;=0)--a0::;=]D)<)<Q)?)I)I$JK))--a0::;=4)--a0::;=r(   c                     / SQn[        U5        U H,  nU R                  [        U[        R                  5      5        M.     g)z/Tests that gsutil encodes valid args correctly.)r   z-pzabc:defzgs://bucketN)r   
assertTrue
isinstancer   r   )r2   argsas      r)   test_valid_arg_coding0TestCommandRunnerUnitTests.test_valid_arg_coding  s2     2DD
oojCMM23 r(   c                     SSS.n[        U5        U R                  [        US   [        R                  5      5        [        US   S5        g )Nz
text/plain   bãr)content-typex-goog-meta-foorC  rB  zBValue of non-custom-metadata header contained non-ASCII characters)r   r:  r;  r   r   r   r2   headerss     r)   test_valid_header_coding3TestCommandRunnerUnitTests.test_valid_header_coding  sL    $!G w 	OOJw'893==IJLNr(   c                     SS0nU R                  [        S5         [        U5        S S S 5        g ! , (       d  f       g = f)NrB  rA  zInvalid non-ASCII)assertRaisesRegexr   r   rD  s     r)    test_invalid_header_coding_fails;TestCommandRunnerUnitTests.test_invalid_header_coding_fails  s3    v&G			 02F	G! 
H	G	Gs   0
>)r   r   r   r   r   r   r   )%r"   r#   r$   r%   r&   r   r   r   r   skipIfutilHAS_NON_DEFAULT_GS_HOSTSKIP_BECAUSE_RETRIES_ARE_SLOWr   r   r   r   r   r   r   r   r   r  r  r  r  r  r)  
skipUnlessr   r.  r7  r>  rF  rJ  r'   __classcell__r   s   @r)   r~   r~      s   D(@T(H ??4//1NON PN ??4//1NOP PP ??4//1NON PN ??4//1NON PN ??4//1NO	L P	L ??4//1NOQ PQ ??4//1NO	J P	J ??4//1NON PN ??4//1NON PN ??4//1NOQ PQ ??4//1NO	L P	L ??4//1NOL PL	L ??4//1NO4 P4,1$ ,<>>>>@ ,<>=>=@4N" "r(   r~   c                   ~   ^  \ rS rSrSrU 4S jrU 4S jr\R                  " \	R                  \5      S 5       rSrU =r$ )!TestCommandRunnerIntegrationTestsi  zCIntegration tests for gsutil update check in command_runner module.c                 .  > [         [        U ]  5         U R                  SS9U l        [
        R                  R                  [        R                  SU R                  S9nU R                  UR                  5        UR                  5         S [        l        g)r   0)r   r   r   c                     gr   r!   r   s    r)   r   9TestCommandRunnerIntegrationTests.setUp.<locals>.<lambda>  r   r(   N)r   rT  r   r   r   r   r   r   r   r   r   r   r   r   )r2   r   r   s     r)   r   'TestCommandRunnerIntegrationTests.setUp  s    	
+T8:  $22C2@D!%!2!2  4-- "3 "/ 	OO.334$$& )Nr(   c                 H   > [         [        U ]  5         [        [        l        gr   )r   rT  r   r   r   r   s    r)   r   *TestCommandRunnerIntegrationTests.tearDown  s    	
+T;= Nr(   c                     [        S/SS9   [        R                  " 5       U l        U R                  R                  S[        /5        SSS5        g! , (       d  f       g= f)zCTests that gsutil tarball version lookup works without credentials.r   F)use_existing_configr   N)r   r   r   RunNamedCommandr   r>   s    r)   'test_lookup_version_without_credentialsITestCommandRunnerIntegrationTests.test_lookup_version_without_credentials  sP     
NO27
9*88:d
))$1C0DE	
9 
9 
9s   <A
A)r   r   )r"   r#   r$   r%   r&   r   r   r   rL  rM  rN  rO  r_  r'   rQ  rR  s   @r)   rT  rT    s9    K) !
 ??4//1NOF PFr(   rT  )@r&   
__future__r   r   r   r   r  r   r   r   	six.movesr   botor   r   r   gslib.commandr	   gslib.command_argumentr
   gslib.command_runnerr   r   r   gslib.exceptionr   gslib.tab_completer   r   r   r   r   gslib.tests.testcaseteststestcasegslib.tests.utilrM  r   r   r   gslib.utilsr   gslib.utils.constantsr   gslib.utils.text_utilr   gslib.utils.unit_utilr   r   r   r   rO  r   r   r+   r=   rN   rg   rr   unit_testcaseGsUtilUnitTestCaser~   GsUtilIntegrationTestCaserT  r!   r(   r)   <module>rt     s   C & %  '  	  
   
    ! 2 . 0 3 , 3 : 3 > , ' '   2 1 % # 4 - 1 % VV_	5 6 : 6 
 $	V 		g 	".V ."	 	2C"!7!7!J!J C"L
F(J(J Fr(   