
    dg                        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 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 d dlmZmZ d d	lmZ d d
lmZmZmZmZmZ d dlmZmZmZm Z m!Z!m"Z"m#Z# d dl$m%Z%m&Z&m'Z' d dl(m)Z)m*Z*m+Z+m,Z, d dl-m.Z. d dl/m0Z0m1Z1m2Z2m3Z3 d dl4m5Z5 d dlm6Z6m7Z7 d dl8m9Z9 d dl:m;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZAmBZB d dlCmDZDmEZE dZFdZGdZHdZIdZJdZKdZLdZM e	d      ZN G d d e"      ZO G d! d"e0      ZPd# ZQd$ ZRd% ZSd9d&ZTd:d'ZUd( ZVd) ZWd* ZXd+ ZYd, ZZd- Z[d. Z\ G d/ d0e]      Z^d1 Z_d;d2Z` G d3 d4e]      Za G d5 d6e]      Zb G d7 d8e]      Zcy)<    N)defaultdict)datetime	timedelta)saxutils)conf)logger)textutil))get_agent_supported_features_list_for_crpSupportedFeatureNames)validate_param)	add_eventWALAEventOperationreport_eventCollectOrReportEventDebugInfoadd_periodic)ProtocolNotFoundErrorResourceGoneErrorExtensionDownloadErrorInvalidContainerErrorProtocolError	HttpErrorExtensionErrorCodes)
httpclient
bytebufferustr)	GoalStateTRANSPORT_CERT_FILE_NAMETRANSPORT_PRV_FILE_NAMEGoalStateProperties)HostPluginProtocol)DataContractProvisionStatusVMInfoVMStatus)GuestAgentExtensionEventsSchema)fileutilrestutil)	CryptUtil)	parse_docfindallfindfindtextgettext
remove_bomget_bytes_from_pem
parse_json)
AGENT_NAMECURRENT_VERSIONzhttp://{0}/?comp=versionszhttp://{0}/machine?comp=healthz&http://{0}/machine?comp=rolePropertiesz%http://{0}/machine?comp=telemetrydataz
2012-11-30
WireServer   i      )minutesc                       e Zd Zy)UploadErrorN)__name__
__module____qualname__     F/usr/lib/python3/dist-packages/azurelinuxagent/common/protocol/wire.pyr8   r8   B   s    r=   r8   c                   V    e Zd Zd ZddZd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zy)WireProtocolc                 >    |t        d      t        |      | _        y )NzWireProtocol endpoint is None)r   
WireClientclientselfendpoints     r>   __init__zWireProtocol.__init__G   s      ?@@ *r=   c                    | j                   j                          t        j                  j	                  t        j                         t              }t        j                  j	                  t        j                         t              }t        t        j                               }|j                  ||       |r0t        j                  d       | j                   j                          y y )Nz1Initializing goal state during protocol detection)rC   check_wire_protocol_versionospathjoinr   get_lib_dirr   r   r(   get_openssl_cmdgen_transport_certr   inforeset_goal_state)rE   init_goal_statetrans_prv_filetrans_cert_file	cryptutils        r>   detectzWireProtocol.detectL   s    //1d&6&6&8&=?'',,t'7'7'9'?Ad2245	$$^_E KKKLKK((* r=   c                 8    | j                   j                          y N)rC   "update_host_plugin_from_goal_staterE   s    r>   rY   z/WireProtocol.update_host_plugin_from_goal_state[   s    668r=   c                 6    | j                   j                         S rX   )rC   get_endpointrZ   s    r>   r\   zWireProtocol.get_endpoint^   s    {{''))r=   c                    | j                   j                         }| j                   j                         }t               }d |_        |j
                  |_        |j                  |_        |j                  |_
        |j                  |_        |S rX   )rC   get_goal_stateget_hosting_envr#   subscriptionIdvm_namevmNamedeployment_name
tenantName	role_nameroleNamerole_instance_idroleInstanceName)rE   
goal_statehosting_envvminfos       r>   
get_vminfozWireProtocol.get_vminfoa   sp    [[//1
kk113 $#++'77%//","="=r=   c                 N    | j                   j                         }|j                  S rX   )rC   	get_certs	cert_list)rE   certificatess     r>   rn   zWireProtocol.get_certsm   s     {{,,.%%%r=   c                 6    | j                   j                         S rX   )rC   r^   rZ   s    r>   r^   zWireProtocol.get_goal_stateq   s    {{))++r=   c                 D   t        d|t               |j                  ;| j                  j	                  |j                  |j
                  |j                         |j                  j                  2|j                  j                  }| j                  j                  |       y y )Nprovision_status)
r   r"   statusrC   report_health	subStatusdescription
propertiescertificateThumbprintreport_role_prop)rE   rs   
thumbprints      r>   report_provision_statusz$WireProtocol.report_provision_statust   s    )+;_M"".KK%%&6&=&=&6&@&@&6&B&BD &&<<H)44JJJKK((4 Ir=   c                     t        d|t               | j                  j                  j	                  |       | j                  j                          y )N	vm_status)r   r$   rC   status_blobset_vm_statusupload_status_blobrE   r~   s     r>   report_vm_statuszWireProtocol.report_vm_status   s6    {Ix8--i8&&(r=   c                 :    | j                   j                  |       y rX   )rC   r   )rE   events_iterators     r>   r   zWireProtocol.report_event   s      1r=   c                 :    | j                   j                  |       y rX   )rC   upload_logs)rE   logss     r>   r   zWireProtocol.upload_logs   s    %r=   c                 B    | j                   j                  j                  S rX   )rC   r   datarZ   s    r>   get_status_blob_dataz!WireProtocol.get_status_blob_data   s    {{&&+++r=   N)T)r9   r:   r;   rG   rV   rY   r\   rl   rn   r^   r|   r   r   r   r   r<   r=   r>   r@   r@   F   s>    +
+9*
&,	5)
2&,r=   r@   c                 ,    dj                  | ||      }|S )Na  <?xml version="1.0" encoding="utf-8"?><RoleProperties><Container><ContainerId>{0}</ContainerId><RoleInstances><RoleInstance><Id>{1}</Id><Properties><Property name="CertificateThumbprint" value="{2}" /></Properties></RoleInstance></RoleInstances></Container></RoleProperties>)format)container_idrg   r{   xmls       r>   _build_role_propertiesr      s$     |%5zB  Jr=   c                 j   |rgd}t        |      }|d | }|t        |      z
  }|dkD  r$t        j                  dj                  |             t	        j
                  t        |            }d}	|0t	        j
                  t        |            }dj                  ||      }	dj                  | ||||	      }
|
S )Nif  r   z3Trimmed health report description by {0} characters zK<Details><SubStatus>{0}</SubStatus><Description>{1}</Description></Details>as  <?xml version="1.0" encoding="utf-8"?><Health xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GoalStateIncarnation>{0}</GoalStateIncarnation><Container><ContainerId>{1}</ContainerId><RoleInstanceList><Role><InstanceId>{2}</InstanceId><Health><State>{3}</State>{4}</Health></Role></RoleInstanceList></Container></Health>)lenr   rP   r   r   escaper   )incarnationr   rg   rt   	substatusrw   max_chars_before_encodinglen_before_trimtrimmed_char_countdetailr   s              r>   _build_health_reportr      s     $(!k*!"<#<=,s;/??!KKELL& ood;&78FOODO4	  "(	;!? 	$ {#'	% . Jr=   c                 d    | j                   | j                  | j                  | j                  d}|S )z7
    Convert VMStatus object to status blob format
    )computerNameosName	osVersionversion)hostnameosname	osversionr   )	ga_statusv1_ga_guest_infos     r>   ga_status_to_guest_infor      s8    
 "**""(($$	 r=   c                     || dS )N)langmessager<   )msgr   s     r>   (__get_formatted_msg_for_status_reportingr      s     r=   c                 ^    |t        j                         n|}t        j                  | |      S rX   )timegmtimestrftime)time_format	timestamps     r>   '_get_utc_timestamp_for_status_reportingr      s%    !*!2	I==i00r=   c                     | j                   | j                  t        | j                        d}| j                  t        | j                        |d<   |S )N)r   rt   formattedMessageupdateStatus)r   rt   r   r   update_statusget_ga_update_status_to_v1)r   v1_ga_statuss     r>   ga_status_to_v1r      sR    $$""DYEVEVWL *'A)BYBY'Z^$r=   c                 v    | j                   | j                  | j                  t        | j                        d}|S )N)expectedVersionrt   coder   )expected_versionrt   r   r   r   )r   v1_ga_update_statuss     r>   r   r      s;    (99&&""D]EZEZ[	 r=   c                     g }| D ]K  }|j                   |j                  |j                  t        |j                        d}|j                  |       M |S )N)namert   r   r   )r   rt   r   r   r   append)sub_status_liststatus_listr   rt   s       r>   ext_substatus_to_v1r     sZ    K$ #	NN&&NN HIZIZ [	
 	6"# r=   c                    | y t               }t        | j                        }| j                  | j                  | j
                  | j                  | j                  t        | j                        dd|d}t        |      dk7  r||d   d<   |S )N)r   configurationAppliedTime	operationrt   r   r   g      ?)rt   r   timestampUTCr   rt   r   )r   r   substatusListr   r   r   rt   r   r   r   r   )
ext_statusr   v1_sub_statusv1_ext_statuss       r>   ext_status_to_v1r     s    79I'
(@(@AM OO(2(K(K#-- ''OO HI[I[ \
 !M =Q/<h,r=   c                 |   | j                   | j                  | j                  | j                  dd}| j                  t        | j                        |d<   t        | j                        }| j                  F|D|| j                  j                  d|d<   | j                  r| j                  j                  |d   d<   |S )NT)handlerVersionhandlerNamert   r   useExactVersionr   )settingsStatussequenceNumberruntimeSettingsStatusextensionName)
r   r   rt   r   r   r   r   extension_statusr   supports_multi_config)ext_handler_statusv1_handler_statusr   s      r>   ext_handler_status_to_v1r   *  s    ,44)..$++"'' !!-0XYkYsYs0t,-$%7%H%HIM**6=;T+0AAPP6
12 33J\JmJmJrJr56Gr=   c                     | j                   }|y t        |j                        t        |j                        |j
                  |j                  |j                  d}d|i}|S )N)r   )r   r   
inSvdSeqNort   r   goalStateAggregateStatus)goal_state_aggregate_statusr   r   r   processed_timein_svd_seq_nort   r   )vm_artifacts_aggregate_statusgs_aggregate_statusv1_goal_state_aggregate_statusv1_artifact_aggregate_statuss       r>   #vm_artifacts_aggregate_status_to_v1r   C  ss    7SS" EEXE`E`a?J]JlJlm)77%,,#((&" 	#$B$  ('r=   c                 R   t               }t        | j                        }t        | j                        }t	        | j                  j
                        }g }| j                  j                  D ]  }|j                  t        |              ||d}|||d<   d|||d}g }	t               j                         D ]-  \  }
}|	j                  |j                  |j                  d       / | j                  j                  r"|	j                  t        j                  dd       |	r|	|d<   |S )N)guestAgentStatushandlerAggregateStatusvmArtifactsAggregateStatusz1.1)r   r   aggregateStatusguestOSInfo)KeyValuez1.0supportedFeatures)r   r   vmAgentr   r   r   extensionHandlersr   r   r
   itemsr   r   supports_fast_trackr   	FastTrack)r~   r   r   r   v1_vm_artifact_aggregate_statusv1_handler_status_listhandler_statusv1_agg_statusv1_vm_statussupported_features_features               r>   vm_status_to_v1r   V  sA   79I.y/@/@A"9#4#45L&I77'9##++== P%%&>~&NOP )"8M
 '26U23 !('	L ?AGGI 

7!!|| 	

 ,,!!,66	
 ,>()r=   c                   L    e 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y)
StatusBlobc                 <    d | _         || _        d | _        d | _        y rX   )r~   rC   typer   )rE   rC   s     r>   rG   zStatusBlob.__init__  s    		r=   c                 4    t        d|t               || _        y )Nr   )r   r$   r~   r   s     r>   r   zStatusBlob.set_vm_status  s    y)X6"r=   c                 V    t        | j                        }t        j                  |      S rX   )r   r~   jsondumps)rE   reports     r>   to_jsonzStatusBlob.to_json  s     0zz&!!r=   z
2014-02-14c                 f    t        j                  d       | j                         | _        || _        y )NzPrepare status blob)r   verboser  r   r   )rE   	blob_types     r>   preparezStatusBlob.prepare  s#    ,-LLN		r=   c                 R   	 | j                   dvr$t        dj                  | j                               | j                   dk(  r| j                  || j                         y| j                  || j                         y# t        $ r }t        j                  d|       Y d }~yd }~ww xY w)N)	BlockBlobPageBlobzIllegal blob type: {0}r  Tz!Initial status upload failed: {0}F)	r   r   r   put_block_blobr   put_page_blob	Exceptionr   r  )rE   urles      r>   uploadzStatusBlob.upload  s    	C99 99#$<$C$CDII$NOOyyK'##C3  ""3		2 	CNN>BB	Cs   AA=  A= =	B&B!!B&c                 Z    t        |      dt               | j                  j                  dS )Nr  )Content-Lengthx-ms-blob-type	x-ms-datex-ms-versionr   r   	__class____storage_version__rE   	blob_sizes     r>   get_block_blob_headersz!StatusBlob.get_block_blob_headers  s)    "9o)@B NN>>	
 	
r=   c                 <   t        j                  d       | j                  t        |            }| j                  j                  t        j                  |||      }|j                  t        j                  k7  r$t        dj                  |j                              y )NzPut block blobz Failed to upload block blob: {0})r   r  r  r   rC   call_storage_servicer'   http_putrt   r   CREATEDr8   r   )rE   r  r   headersresps        r>   r  zStatusBlob.put_block_blob  s{    '(--c$i8{{//0A0A3gV;;*,,,299$++FH H -r=   c                 \    dt        |      dt               | j                  j                  dS )N0r  )r  zx-ms-blob-content-lengthr  r  r  r  r  s     r>   get_page_blob_create_headersz'StatusBlob.get_page_blob_create_headers  s,    !(,Y(@B NN>>
 	
r=   c                     t        ||z
        t               dj                  ||dz
        d| j                  j                  dS )Nzbytes={0}-{1}r4   update)r  r  z
x-ms-rangezx-ms-page-writer  )r   r   r   r  r  )rE   startends      r>   get_page_blob_page_headersz%StatusBlob.get_page_blob_page_headers  sB    "3;/@B)00a@' NN>>
 	
r=   c                    t        j                  d       t        |d      }t        t	        |      dz   dz        dz  }| j                  |      }| j                  j                  t        j                  |d|      }|j                  t        j                  k7  r$t        dj                  |j                              |j                  d      d	k  rd
j                  |      }ndj                  |      }t        j                  d       d}d	}d	}|t	        |      k  rt!        t	        |      ||z         }||z
  }	t        |dz   dz        dz  }
|
|z
  }t        |      }||| |d	|	 | j#                  ||
      }| j                  j                  t        j                  |t%        |      |      }||j                  t        j                  k7  r$t        dj                  |j                              |}|t	        |      k  ry y )NzPut page blobutf-8encodingi  i   r   z!Failed to clean up page blob: {0}?r   z{0}?comp=pagez{0}&comp=pagezUpload page blobi  @ zFailed to upload page blob: {0})r   r  	bytearrayintr   r'  rC   r   r'   r!  rt   r   r"  r8   r   countminr,  r   )rE   r  r   page_blob_sizer#  r$  page_maxr*  r+  content_sizepage_endbuf_sizebufs                r>   r  zStatusBlob.put_page_blob  s   ' 0c$i#o45;33NC{{//0A0A3GT;;*,,,3::4;;GI I 99S>Q!((-C!((-C)*"CIoc$i!12C;LC#I,-3H%'HH%C#'s#3C< 55eXFG;;33!!3	D
 |t{{j.@.@@!5<<T[[IK KE# CIor=   N)r9   r:   r;   rG   r   r  r  r
  r  r  r  r'  r,  r  r<   r=   r>   r   r     s=    #" '
 
H

'r=   r   c                 b   t        d      }t        | j                        }d}|t        u rd}n@|t        u rd}n5t        |      j                  d      dkD  rd}n|t        u rd}n
|t        u rd}|j                  | j                  t        j                  t        | j                              |      S )	Nz&<Param Name="{0}" Value={1} T="{2}" />r   z	mt:uint64zmt:wstrz	'unicode'r   zmt:boolz
mt:float64)r   r   valuer3  strr4  boolfloatr   r   r   	quoteattr)paramparam_format
param_type	attr_types       r>   event_param_to_v1rF    s    @ALekk"JIS		s			j				,q	0		t			u	 	uzz'11$u{{2CD(* *r=   c                     d}| j                   D ]  }|t        |      z  } t        d      j                  | j                  |      }|j                  |      S )Nr   z'<Event id="{0}"><![CDATA[{1}]]></Event>)
parametersrF  r   r   eventIdencode)eventr0  paramsrB  	event_strs        r>   event_to_v1_encodedrN  
  sZ    F!! +#E**+>?FFu}}V\]IH%%r=   c                   0   e Zd Zd Zd Zd Zd Zd Zed        Z	d Z
d Zd	 Zd
 Zd*dZed        Zd+dZd,dZd-dZd Zd Zd.dZej.                  d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/d!Z$d" Z%d# Z&d$ Z'd% Z(d& Z)d' Z*d( Z+d) Z,y)0rB   c                 z    t        j                  d|       || _        d | _        d | _        t        |       | _        y )NzWire server endpoint:{0})r   rP   	_endpoint_goal_state_host_pluginr   r   rD   s     r>   rG   zWireClient.__init__  s5    .9! %d+r=   c                     | j                   S rX   )rQ  rZ   s    r>   r\   zWireClient.get_endpoint      ~~r=   c                 F   	 d|d<    ||i |}t        j                  |      r?dj                  |d         }||dj                  |j                        z  }t	        |      	 |S # t
        $ r  t        $ r(}t	        dj                  t        |                  d }~ww xY w)NF	use_proxyz[Wireserver Failed] URI {0} r   z [HTTP Failed] Status Code {0}z[Wireserver Exception] {0})r'   request_failedr   rt   r   r   r  r   )rE   http_reqargskwargsr$  r   r  s          r>   call_wireserverzWireClient.call_wireserver  s    	N"'F;T,V,D&&t,4;;DGD#;BB4;;OOC#C((	 -  ! 	 	N < C CDG LMM	Ns   A!A& &B 8#BB c                 <    |y t        |      }t        |d      }|S )Nr.  r/  )r.   r   )rE   r   xml_texts      r>   decode_configzWireClient.decode_config3  s%    <$w/r=   c                     | j                  t        j                  ||      }| j                  |j	                               S )Nr#  )r\  r'   http_getr_  read)rE   urir#  r$  s       r>   fetch_configzWireClient.fetch_config:  s6    ##H$5$5sG#L!!$))+..r=   c                 .    d|vs|d   d|d<    | |i |S )NrW  Tr<   )rY  rZ  r[  s      r>   r   zWireClient.call_storage_service>  s0     f${(;(C"&F;(((r=   c                 2    | j                  d|gd      d   S )Nzartifacts profile blobFuse_verify_headerr4   )_fetch_content)rE   rd  s     r>   fetch_artifacts_profile_blobz'WireClient.fetch_artifacts_profile_blobF  s$    ""#;cUV["\]^__r=   c                 r    | j                  d||      \  }}| j                         j                  |       |S )Nmanifestrh  )rj  get_host_pluginupdate_manifest_uri)rE   urisri  rd  contents        r>   fetch_manifestzWireClient.fetch_manifestI  s:    **:tO`*aW2237r=   c                 j      j                          fd} fd} j                  ||||      S )aZ  
        Walks the given list of 'uris' issuing HTTP GET requests; returns a tuple with the URI and the content of the first successful request.

        The 'download_type' is added to any log messages produced by this method; it should describe the type of content of the given URIs
        (e.g. "manifest", "extension package", etc).
        c                 ,    j                  |       d   S )Nr   )fetch)rd  rE   s    r>   <lambda>z+WireClient._fetch_content.<locals>.<lambda>W  s    djjoa&8 r=   c                     j                  |       \  }}j                  ||dt        j                        \  }}|S )Nrh  F)rW  retry_codes)get_artifact_requestru  r'   'HGAP_GET_EXTENSION_ARTIFACT_RETRY_CODES)rd  request_urirequest_headersresponser   host_ga_pluginrE   ri  s        r>   hgap_downloadz0WireClient._fetch_content.<locals>.hgap_downloadY  sO    +9+N+Nsfw+N+x(K**[/U`h  aQ  aQ*  RKHaOr=   )direct_downloadr  rn  _download_with_fallback_channel)rE   download_typerp  ri  r  r  r~  s   `  `  @r>   rj  zWireClient._fetch_contentN  sE     --/8	
 33M4Yh  yF3  G  	Gr=   c                     	  j                         	 fd}	 fd}fd} j                  ||||       y)aP  
        Downloads the ZIP package specified in 'uris' (which is a list of alternate locations for the ZIP), saving it to 'target_file' and then expanding
        its contents to 'target_directory'. Deletes the target file after it has been expanded.

        The 'package_type' is only used in log messages and has no other semantics. It should specify the contents of the ZIP, e.g. "extension package"
        or "agent package"

        The 'use_verify_header' parameter indicates whether the verify header should be added when using the extensionArtifact API of the HostGAPlugin.
        c                 .    j                  | d d      S )NTr#  rW  )stream)rd  rE   target_files    r>   rv  z1WireClient.download_zip_package.<locals>.<lambda>l  s    dkk#{D\`k&a r=   c                 p    j                  | j                        \  }}j                  ||d      S )N)ri  artifact_manifest_urlFr  )ry  manifest_urir  )rd  r{  r|  r~  rE   r  ri  s      r>   r  z6WireClient.download_zip_package.<locals>.hgap_downloadn  sN    +9+N+Nsfw  P^  Pk  Pk+N  ,l(K;;{K\a;bbr=   c                  2    t         j                         S rX   )rB   _try_expand_zip_package)package_typetarget_directoryr  s   r>   rv  z1WireClient.download_zip_package.<locals>.<lambda>r  s    
 B B<Q\^n o r=   )r  r  on_downloadedNr  )
rE   r  rp  r  r  ri  r  r  r  r~  s
   `` ```   @r>   download_zip_packagezWireClient.download_zip_package`  sI     --/a	c p,,\4Q`p}  N[,  	\r=   Nc           
      b   t        j                  d|       t        j                         }|}t	        j
                  |       d}t        |      D ]  \  }	t        j                         |z
  }
|
t        kD  rBdj                  ||
|	t        |      t        |            }t        |t        j                        	 | j                  fdfd      }| |        |fc S  t        dj                  |t        |            t        j                        # t        $ r}|}Y d}~d}~ww xY w)	a]  
        Walks the given list of 'uris' issuing HTTP GET requests, attempting to download the content of each URI. The download is done using both the default and
        the fallback channels, until one of them succeeds. The 'direct_download' and 'hgap_download' functions define the logic to do direct calls to the URI or
        to use the HostGAPlugin as a proxy for the download. Initially the default channel is the direct download and the fallback channel is the HostGAPlugin,
        but the default can be depending on the success/failure of each channel (see _download_using_appropriate_channel() for the logic to do this).

        The 'download_type' is added to any log messages produced by this method; it should describe the type of content of the given URIs
        (e.g. "manifest", "extension package, "agent package", etc).

        When the download is successful, _download_with_fallback_channel invokes the 'on_downloaded' function, which can be used to process the results of the download. This
        function should return True on success, and False on failure (it should not raise any exceptions). If the return value is False, the download is considered
        a failure and the next URI is tried.

        When the download succeeds, this method returns a (uri, response) tuple where the first item is the URI of the successful download and the second item is
        the response returned by the successful channel (i.e. one of direct_download and hgap_download).

        This method enforces a timeout (_DOWNLOAD_TIMEOUT) on the download and raises an exception if the limit is exceeded.
        zDownloading {0}NonezJTimeout downloading {0}. Elapsed: {1} URIs tried: {2}/{3}. Last error: {4})r   c                              S rX   r<   )r  rd  s   r>   rv  z<WireClient._download_with_fallback_channel.<locals>.<lambda>  s    O\_L` r=   c                              S rX   r<   )r  rd  s   r>   rv  z<WireClient._download_with_fallback_channel.<locals>.<lambda>  s    jwx{j| r=   Nz5Failed to download {0} from all URIs. Last error: {1})r   rP   r   nowrandomshuffle	enumerate_DOWNLOAD_TIMEOUTr   r   r   r   r   PluginManifestDownloadError#_download_using_appropriate_channelr  )rE   r  rp  r  r  r  
start_timeuris_shuffledmost_recent_errorindexelapsedr   r}  	exceptionrd  s      ``         @r>   r  z*WireClient._download_with_fallback_channelv  sV   & 	%}5\\^
}%"#M2 	.JE3llnz1G**fmmn{  ~E  GL  NQ  RV  NW  Y]  ^o  Yp  q,W;N;j;jkk	.CCD`b|} ,!OH}$	." %%\%c%cdqsw  yJ  tK  &L  Sf  SB  SB  C  	C  .$-!.s   ;&D	D."D))D.c           
         t        j                  d| |       	 t        j                  |      j	                  |       	 	 t        j                  |       y # t
        $ r}t        j                  d| t        |             t        j                  j                  |      rM	 t        j                  |        # t
        $ r*}t        j                  d|t        |             Y d }~ d }~ww xY w d }~ww xY w# t
        $ r*}t        j                  d|t        |             Y d }~y d }~ww xY w# 	 t        j                  |       w # t
        $ r*}t        j                  d|t        |             Y d }~w d }~ww xY wxY w)NzUnzipping {0}: {1}zError while unzipping {0}: {1}zCannot delete {0}: {1})r   rP   zipfileZipFile
extractallr  errorr   rJ   rK   existsshutilrmtreewarnremove)r  r  r  r  s       r>   r  z"WireClient._try_expand_zip_package  s.   (,D	TOOK(334DET		+&  	LL9<iYww~~./]MM"23  ! ]KK 8:JDQZO\\]	  T4k4	?SSTT		+& T4k4	?SSTs   $A C3 	C0?C+B43C+4	C'= C"C+"C''C++C00D) 3	D&< D!!D&)E7+E E7	E4
 E/*E7/E44E7c           	      &   	 t        j                  d|||       | j                  |||      }|et        j                  |      sPd}t        |d|      5 }d}|s3|j                  |      }	|j                  |	       t        |	      |k  }|s3ddd       yy# 1 sw Y   yxY w#  t        j                  j                  |      rM	 t        j                  |        # t        $ r*}
t        j                  d|t        |
             Y d}
~
 d}
~
ww xY w xY w)zb
        Downloads the content of the given 'uri' and saves it to the 'destination' file.
        z,Fetch [{0}] with headers [{1}] to file [{2}]Ni   wbFr   zCan't delete {0}: {1})r   r  _fetch_responser'   rX  openrc  writer   rJ   rK   r  r  r  r  r   )rE   rd  destinationr#  rW  r}  
chunk_sizedestination_fhcompletechunkr  s              r>   r  zWireClient.stream  s   	NNI3PWYde++C)DH#H,C,CH,M(
+tZ8 ;N$H& (j 9&,,U3#&u:
#: '; ; 	ww~~k*WIIk*  ! WKK 7d9oVVWsT   AB! 7BB! BB! B! !!DCD	D" DDDDc                    t        j                  d||       d}d}| j                  |||||      }	|	Lt        j                  |	|      s5|	j                         }
|r| j                  |
      n|
}|	j                         }||fS )z
        Returns a tuple with the content and headers of the response. The headers are a list of (name, value) tuples.
        zFetch [{0}] with headers [{1}]N)rx  ok_codesr  )r   r  r  r'   rX  rc  r_  
getheaders)rE   rd  r#  rW  decoderx  r  rq  response_headersr}  response_contents              r>   ru  zWireClient.fetch  s     	7gF''Wi[ck'l(?(?S[(\'}}>Dd(()9:JZG'224(((r=   c                 p   d }	 | j                  t        j                  ||||      }| j                         }t        j                  ||      rrt        j
                  |      }dj                  ||      }	t        j                  |	       |)|j                  |t        j                  |       d|       t        |	      ||j                  |d       |S # t        t        t        f$ rI}
dj                  |
      }	t        j                  |	       t        t        j                   d|	d	        d }
~
ww xY w)
N)r#  rW  rx  r  zFetch failed from [{0}]: {1}rB   )
is_healthysourcer}  )r  zFetch failed: {0}Fop
is_successr   	log_event)r   r'   rb  rn  rX  read_response_errorr   r   r  report_fetch_healthrequest_failed_at_hostpluginr   r   IOErrorr   r   HttpGet)rE   rd  r#  rW  rx  r  r$  host_pluginerror_responser   r  s              r>   r  zWireClient._fetch_response  s4   	,,!!#' - )D ..0K&&th?!)!=!=d!C4;;CPC *33CCKChChimCn?n;G=K 4 M $C((*33C3M  ='2 	%,,U3CKK.665RUafg		s   CC D5,AD00D5c                 H    | j                   t        j                  |        yy)zv
        Fetches a new goal state and updates the Container ID and Role Config Name of the host plugin client
        N)rS  r   update_host_plugin_headersrZ   s    r>   rY   z-WireClient.update_host_plugin_from_goal_state   s#     (006 )r=   c                     | j                   7| j                   j                  |       | j                   j                  |       y y rX   )rS  update_container_idupdate_role_config_name)rE   r   role_config_names      r>   update_host_pluginzWireClient.update_host_plugin  s<    (11,?556FG )r=   Fc                     	 | j                   t        | |      | _         y| j                   j                  |       y# t        $ r  t        $ r(}t        dj                  t        |                  d}~ww xY w)zK
        Updates the goal state if the incarnation or etag changed
        NsilentError fetching goal state: {0})rR  r   r)  r   r  r   r   )rE   r  r  s      r>   update_goal_statezWireClient.update_goal_state  sr    		Z'#,T&#A   ''v'6 	 	Z @ G GY XYY	Zs   > > A8#A33A8c                     	 |st        j                  d       t        | ||      | _        y# t        $ r  t
        $ r(}t	        dj                  t        |                  d}~ww xY w)z'
        Resets the goal state
        z$Forcing an update of the goal state.)goal_state_propertiesr  r  N)r   rP   r   rR  r   r  r   r   )rE   r  r  r  s       r>   rQ   zWireClient.reset_goal_state  sc    		ZBC(EZcijD 	 	Z @ G GY XYY	Zs   *- A'#A""A'c                 H    | j                   t        d      | j                   S )Nz1Trying to fetch goal state before initialization!)rR  r   rZ   s    r>   r^   zWireClient.get_goal_state*  s&    # STTr=   c                 \    | j                   t        d      | j                   j                  S )Nz:Trying to fetch Hosting Environment before initialization!)rR  r   rj   rZ   s    r>   r_   zWireClient.get_hosting_env/  s,    # \]]+++r=   c                 \    | j                   t        d      | j                   j                  S )Nz2Trying to fetch Shared Conf before initialization!)rR  r   shared_confrZ   s    r>   get_shared_confzWireClient.get_shared_conf4  s,    # TUU+++r=   c                 \    | j                   t        d      | j                   j                  S )Nz3Trying to fetch Certificates before initialization!)rR  r   certsrZ   s    r>   rn   zWireClient.get_certs9  s,    # UVV%%%r=   c                 \    | j                   t        d      | j                   j                  S )Nz4Trying to fetch Remote Access before initialization!)rR  r   remote_accessrZ   s    r>   get_remote_accesszWireClient.get_remote_access>  s,    # VWW---r=   c                    t         j                  | j                               }| j                  |d       }t	        |      }|j                         }t        |k(  rt        j                  dt               y t        |j                         v r1t        j                  dt               t        j                  d|       y dj                  t              }t        |      )NzWire protocol version:{0}zServer preferred version:{0}zEAgent supported wire protocol version: {0} was not advised by Fabric.)VERSION_INFO_URIr   r\   re  VersionInfoget_preferredPROTOCOL_VERSIONr   rP   get_supportedr   )rE   rd  version_info_xmlversion_info	preferredr  s         r>   rI   z&WireClient.check_wire_protocol_versionC  s    %%d&7&7&9:,,S$7"#34 ..0	y(KK35EF!;!;!==KK35EFKK6	B*+162B+C '..r=   c                 l   	  |       S # t         t        f$ r}| j                         }|j                  |j                  }}dj                  ||t        |            }t        j                  t        j                  |       | j                          |j                  |j                  }}dj                  ||      }t        j                  t        j                  |       	  |       }	dj                  ||||      }t        t        j                  t        t        t        j                  d|d       |	cY d}~S # t         t        f$ rd}dj                  ||||t!        |      j"                        }t        t        j                  t        t        t        j                  d|d        d}~ww xY wd}~ww xY w)	z
        Calls host_func on host channel and accounts for stale resource (ResourceGoneError or InvalidContainerError).
        If stale, it refreshes the goal state and retries host_func.
        z[PERIODIC] Request failed with the current host plugin configuration. ContainerId: {0}, role config file: {1}. Fetching new goal state and retrying the call.Error: {2}za[PERIODIC] Host plugin reconfigured with new parameters. ContainerId: {0}, role config file: {1}.z[PERIODIC] Request succeeded using the host plugin channel after goal state refresh. ContainerId changed from {0} to {1}, role config file changed from {2} to {3}.T)deltar   r   r  r  r   r  Nz[PERIODIC] Request failed using the host plugin channel after goal state refresh. ContainerId changed from {0} to {1}, role config file changed from {2} to {3}. Exception type: {4}.F)r   r   rn  r   r  r   r   r   periodic_infoEVERY_SIX_HOURSrY   r   r1   r2   r   
HostPluginr   r9   )
rE   	host_funcr  r  old_container_idold_role_config_namer   new_container_idnew_role_config_namerets
             r>   %_call_hostplugin_with_container_checkz0WireClient._call_hostplugin_with_container_checkS  s   
-	;!#89 +	..0K5@5M5M{OkOk2%v&68LdSXkZ    !7!7=3355@5M5M{OkOk2==CVDTVj=k   !7!7=kBBH&IY[kI]_sCu  6#9#9",%4 2 = =(,%('+- 
%'<= --3V4DFVXl4H$u+J^J^.`  6#9#9",%4 2 = =(-%('+- ?+	s;   	 F3CF. AD82F38F+AF&&F++F..F3c           	           fd}t         j                  r||}}n||}}	  |       S # t        $ r}|}Y d}~nd}~ww xY w	  |       }t         j                   t         _        dj                  t         j                  rdnd      }	t	        j
                  |	       t        t        t        j                  t        d|	d       |S # t        $ r2}t        d	j                  t        |      t        |                  d}~ww xY w)
a  
        Does a download using both the default and fallback channels. By default, the primary channel is direct, host channel is the fallback.
        We call the primary channel first and return on success. If primary fails, we try the fallback. If fallback fails,
        we return and *don't* switch the default channel. If fallback succeeds, we change the default channel.
        c                  &    j                         S rX   )r  )r  rE   s   r>   rv  z@WireClient._download_using_appropriate_channel.<locals>.<lambda>  s    D4^4^_l4m r=   Nz'Default channel changed to {0} channel.HostGAPluginDirectTF)r  r   r  r   r  zYDownload failed both on the primary and fallback channels. Primary: [{0}] Fallback: [{1}])r    is_default_channelr  r   r   rP   r   r1   r   DefaultChannelChanger2   r   r   )
rE   r  r  !hgap_download_function_with_retryprimary_channelsecondary_channelr  primary_channel_errorreturn_valuer   s
   ` `       r>   r  z.WireClient._download_using_appropriate_channel  s)    -n)001RTc.O1@Bc.O	."$$ 	.$-!	.	n,.L 9K8]8]4]1?FFYkY~Y~~  EM  NGKK j%7%L%LVerv  AH  TY  Z 	nw~~  @D  EZ  @[  ]a  bk  ]l  m  n  n	ns)   * 	?:?BC 	D -C;;D c                    | j                         j                  }|j                  c| j                  d       | j                         j                  }|j                  t	        d      t        j                  d|j                         |j                  }	 | j                  j                  |       	 | j                         }|j!                  | j                  |j                  |j                         y # t        $ r(}t        dj                  t        |                  d }~ww xY w# t"        $ r | j%                          Y y t        $ r7}dj                  t        |            }| j'                  |d       Y d }~nd }~ww xY w	 | j                  j)                  |j                        ry 	 t        d
      # t        $ rA}dj                  t        |            }| j'                  |d	       Y d }~t        d
      d }~ww xY w)NTr  zStatus upload uri is missingzNRefreshed the goal state to get the status upload blob. New Goal State ID: {0}z#Exception creating status blob: {0}z"Falling back to direct upload: {0})r  z$Exception uploading status blob: {0}Fz/Failed to upload status blob via either channel)r^   extensions_goal_statestatus_upload_blobrQ   r   r   rP   idstatus_upload_blob_typer   r
  r  r   r   r   rn  put_vm_statusr   rY   report_status_eventr  )rE   r  r	  r  hostr   s         r>   r   zWireClient.upload_status_blob  s    $ 3 3 5 K K 33;!!!.$($7$7$9$O$O!$77?+,JKKKKhj  kC  kC  D)AA		W$$Y/	;'')Dt//1F1Y1Y[p  \I  \I  J  	W E L LTRSW UVV	W  ! 	335 	;6==d1gFC$$ST$::	;
	<&&'<'O'OP Q MNN	  	<8??QHC$$SU$;;MNN		<sO   C5 3AD) 5	D&>#D!!D&)FF-E>>F%F9 9	H-G>>Hc                 ,   | j                         }t        |j                  |j                  |      }|j	                  d      }t
        j                  | j                               }| j                         }	 | j                  t        j                  |||      }|j                  t        j                   k7  r3t        dj                  |j                  |j#                                     y # t        $ r}t        dj                  |            d }~ww xY w)Nr.  ra  z#Failed to send role properties: {0}z)Failed to send role properties: ,{0}: {1})r^   r   r   rg   rJ  ROLE_PROP_URIr   r\   get_header_for_xml_contentr\  r'   	http_postr   r   rt   r   ACCEPTEDrc  )rE   r{   ri   	role_proprole_prop_urir#  r$  r  s           r>   rz   zWireClient.report_role_prop  s   ((*
*:+B+B+5+F+F+57	 $$W-	%,,T->->-@A113	4''(:(:(5(107 ( 9D ;;*--- "./5vdkk6:iik0CD D .  	4 "()/4 4	4s   7#C+ +	D4DDc                 :   | j                         }t        |j                  |j                  |j                  |||      }|j                  d      }t        j                  | j                               }| j                         }	 | j                  t        j                  |||dd      }t        j                  |      r3t        dj                  |j                   |j#                                     y # t        $ r}	t        dj                  |	            d }	~	ww xY w)Nr.        )r#  	max_retryretry_delayz$Failed to send provision status: {0}z*Failed to send provision status: ,{0}: {1})r^   r   r   r   rg   rJ  HEALTH_REPORT_URIr   r\   r  r\  r'   r  r   r   rX  rt   rc  )
rE   rt   r   rw   ri   health_reporthealth_report_urir#  r$  r  s
             r>   ru   zWireClient.report_health  s   ((*
,Z-C-C-7-D-D-7-H-H-3-6-8: &,,W5-44T5F5F5HI113	4 ''(:(:(9(5072446 ( 8D ""4( "./5vdkk6:iik0CD D )  	4 "()/4 4	4s   %C2 2	D;DDc                 T   t         j                  | j                               }t        d      j                  |      j	                  |      }t        d      j	                  |      }||z   |z   }	 | j                         }| j                  t        j                  |||      }	t        j                  |	      rGt        j                  |	j                                t        dj                  |	j                              y # t        $ r}
t        dj                  |
            d }
~
ww xY w)NzE<?xml version="1.0"?><TelemetryData version="1.0"><Provider id="{0}">z</Provider></TelemetryData>zFailed to send events:{0})TELEMETRY_URIr   r\   r   rJ  r  r\  r'   r  r   r   rX  r   r  rc  rt   )rE   provider_idrM  r0  rd  data_format_headerdata_format_footerr   headerr$  r  s              r>   send_encoded_eventzWireClient.send_encoded_event  s   ""4#4#4#67!"ijqq) 	!"?@GGQ "I-0BB	G446F ''(:(:CvND ""4(NN499;'+224;;?A A )  	G ; B B1 EFF	Gs   02C? ?	D'D""D'c           
      r    i t        t         j                        }t        t              } fd}|D ]  }	 |j                  vrd|j                  <   t        |      }t        |      t        k\  r|j                  D cg c]{  }|j                  t        j                  t        j                  t        j                  t        j                  fv sNt        |j                        dz   t        |j                         z   } }}t#        j$                  t"        j&                  dj)                  t+        |      t        |      t                     t        |j                     |z         t        k\  rbt#        j,                  dj)                  ||j                                   ||j                  |       d|j                  <   d||j                  <   |j                     |z   |j                  <   ||j                  xx   dz  cc<    t7        j9                               D ]8  }
|
   s	t#        j,                  dj)                  ||
                 ||
|       : |j;                          y c c}w # t.        $ r4}	t#        j0                  d	t3        j4                  |	             Y d }	~	{d }	~	ww xY w)
N)r   c                     	 j                  | |           y # t        $ r}|j                  |       Y d }~y d }~wt        $ r}|j	                  |       Y d }~y d }~ww xY wrX   )r!  UnicodeErrorupdate_unicode_errorr  update_op_error)r  
debug_info	uni_errorr  r;  rE   s       r>   _send_eventz,WireClient.report_event.<locals>._send_event%  sX    2''S5EF ;//	:: 2**5112s    	A8AAAr=   :zJSingle event too large: {0}, with the length: {1} more than the limit({2})zNo of events this request = {0}r   r4   z+Unexpected error when generating Events:{0})r   	OP_REPORTr   r3  
providerIdrN  r   MAX_EVENT_BUFFER_SIZErH  r   r%   NameVersion	OperationOperationSuccessr   r=  r   periodic_warnEVERY_HALF_HOURr   r>  r  r  r  r	   format_exceptionlistkeysreport_debug_info)rE   r   r'  events_per_providerr)  rK  rM  xdetails_of_eventr  r  r;  s   `          @r>   r   zWireClient.report_event   sj   2=Z=d=de
)#.	2 % 	mEm##3.,/C(()/6	y>%::TYTdTd (\qhihnhn)H)M)MOnOvOv)H)R)R)H)Y)Y)[i[QVVs(:T!''](J (\$ (\ (()?)?)u*0&5E1FIXm*np  s5++,y89=RRNN#D#K#KL_`e`p`pLq#rs 0 0*=,/C(()<='(8(89 ),E,<,<(=	(IE$$%#E$4$45:55	m@  
+ 	5K;@GGH[\gHhijK4	5
 	$$&;(\(  mI8KdKdejKkllms9   AI9AI40I4AI9B:I94I99	J6)J11J6c                 @    t        t        j                  |||        y )Nr  )r   r   ReportStatus)rE   r   r  s      r>   r
  zWireClient.report_status_eventU  s    *77 *$#-~	/r=   c                     dt         dS )NWALinuxAgent)x-ms-agent-namer  r  rZ   s    r>   
get_headerzWireClient.get_header[  s    -,
 	
r=   c                     dt         ddS )Nr>  ztext/xml;charset=utf-8)r?  r  zContent-Typer@  rZ   s    r>   r  z%WireClient.get_header_for_xml_contenta  s    -,4
 	
r=   c                    t         j                  j                  t        j                         t
              }	 t        j                  |      }t        |      }dt        d|dS # t        $ r }t        dj                  ||            d }~ww xY w)NzFailed to read {0}: {1}r>  DES_EDE3_CBC)r?  r  zx-ms-cipher-namez!x-ms-guest-agent-public-x509-cert)rJ   rK   rL   r   rM   r   r&   	read_filer  r   r   r/   r  )rE   rT   rq  r  certs        r>   get_header_for_certzWireClient.get_header_for_certh  s    '',,t'7'7'9;ST	V((9G "'*-, .15	
 	
	  	V 9 @ @RS TUU	Vs   A# #	B,BBc                     | j                   3t        | j                               | _         t        j                  |        | j                   S rX   )rS  r    r\   r   r  rZ   s    r>   rn  zWireClient.get_host_pluginw  s>    $ 243D3D3F GD006   r=   c                 J    | j                         j                  j                  S rX   )r^   r  on_holdrZ   s    r>   get_on_holdzWireClient.get_on_hold}  s    ""$::BBBr=   c                 D    | j                         }|j                  |      S rX   )rn  
put_vm_log)rE   rq  r  s      r>   r   zWireClient.upload_logs  s    ##%w''r=   rX   )NN)NNTNN)NNNN)F)utf8)-r9   r:   r;   rG   r\   r\  r_  re  staticmethodr   rk  rr  rj  r  r  r  r  ru  r  rY   r  r  r   AllrQ   r^   r_   r  rn   r  rI   r  r  r   rz   ru   r!  r   r
  rA  r  rG  rn  rK  r   r<   r=   r>   rB   rB     s   ,*/ ) )`
G$\,+CZ T T$2)!F7H
Z 6I5L5LUZ Z 
,
,
&
.
/ 2hn>1OfD*D:A*3'j/


!C(r=   rB   c                   $    e Zd Zd Zd Zd Zd Zy)r  c                 P    t        j                  d       | j                  |       y)z|
        Query endpoint server for wire protocol version.
        Fail if our desired protocol version is not seen.
        zLoad Version.xmlN)r   r  parse)rE   r^  s     r>   rG   zVersionInfo.__init__  s    
 	)*

8r=   c                 X   t        |      }t        |d      }t        |d      | _        t	        j
                  d| j                         g | _        t        |d      }t        |d      }|D ]>  }t        |      }t	        j                  d|       | j                  j                  |       @ y )N	Preferredr/  z*Fabric preferred wire protocol version:{0}	Supportedz*Fabric supported wire protocol version:{0})r)   r+   r,   r  r   rP   	supportedr*   r-   r  r   )rE   r^  xml_docr  rW  supported_versionnoder   s           r>   rS  zVersionInfo.parse  s    H%+.	!)Y7@NN	$ +.	#Iy9% 	+DdmGNNG"$NN!!'*		+r=   c                     | j                   S rX   )r  rZ   s    r>   r  zVersionInfo.get_preferred  rU  r=   c                     | j                   S rX   )rW  rZ   s    r>   r  zVersionInfo.get_supported  rU  r=   N)r9   r:   r;   rG   rS  r  r  r<   r=   r>   r  r    s    + r=   r  c                       e Zd ZdZd Zd Zy)InVMArtifactsProfileaA  
    deserialized json string of InVMArtifactsProfile.
    It is expected to contain the following fields:
    * inVMArtifactsProfileBlobSeqNo
    * profileId (optional)
    * onHold (optional)
    * certificateThumbprint (optional)
    * encryptedHealthChecks (optional)
    * encryptedApplicationProfile (optional)
    c                 x    t        j                  |      s%| j                  j                  t	        |             y y rX   )r	   is_str_empty__dict__r)  r0   )rE   artifacts_profiles     r>   rG   zInVMArtifactsProfile.__init__  s.    $$%67MM  ,=!>? 8r=   c                 l    d| j                   v r&t        | j                        j                         dk(  S y)NonHoldtrueF)ra  r>  rd  lowerrZ   s    r>   
is_on_holdzInVMArtifactsProfile.is_on_hold  s.    t}}$t{{#))+v55r=   N)r9   r:   r;   __doc__rG   rg  r<   r=   r>   r^  r^    s    	@r=   r^  )zen-US)z%Y-%m-%dT%H:%M:%SZN)r.  )dr  rJ   r  r  r   r  collectionsr   r   r   xml.saxr   azurelinuxagent.commonr   r   azurelinuxagent.common.utilsr	   .azurelinuxagent.common.agent_supported_featurer
   r   #azurelinuxagent.common.datacontractr   azurelinuxagent.common.eventr   r   r   r   r    azurelinuxagent.common.exceptionr   r   r   r   r   r   r   azurelinuxagent.common.futurer   r   r   *azurelinuxagent.common.protocol.goal_stater   r   r   r   *azurelinuxagent.common.protocol.hostpluginr    'azurelinuxagent.common.protocol.restapir!   r"   r#   r$   %azurelinuxagent.common.telemetryeventr%   r&   r'   &azurelinuxagent.common.utils.cryptutilr(   %azurelinuxagent.common.utils.textutilr)   r*   r+   r,   r-   r.   r/   r0   azurelinuxagent.common.versionr1   r2   r  r  r  r  r  ENDPOINT_FINE_NAMESHORT_WAITING_INTERVALr-  r  r8   r@   r   r   r   r   r   r   r   r   r   r   r   r   objectr   rF  rN  rB   r  r^  r<   r=   r>   <module>r|     sW  &  	     # (  ' ) 1 { >0 0t t t F F  I c c Q ; <B B B F. 4 87 !  ) a( 	) 	E,< E,P&3l
1


,2(&,^o od*&&p	( p	(f& B6 r=   