
    )k                        d Z ddlmZ ddlmZ ddlm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 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 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 ddlm Z  ddl!m"Z" ddl#m$Z$ ddl#m%Z% ddl&Z&dZ'dZ( e
jR                  d      Z*dZ+dZ,dZ-dZ.i Z/ G d d ej`                  dd            Z1i d e1dd       d! e1dd       d" e1dd#       d$ e1d%d& e1d%d&        e1d'd&       d()      d* e1dd       d+ e1d,d#       d- e1d.d       d/ e1dd#       d0 e1d1d#       d2 e1d3d       d4 e1dd       d5 e1dd&       d6 e1dd       d7 e1d3d       d8 e1dd       d9 e1dd       d: e1d,d#        e1dd        e1dd#        e1dd        e1d,d#        e1d3d        e1dd        e1dd        e1d,d#        e1dd        e1dd        e1dd        e1d;d        e1d,d#        e1dd#        e1dd#       d<Z2e2jg                  e/       d=Z4d>Z5d?Z6d@Z7 ej`                  dAdB      Z8 G dC dDejr                        Z9 G dE dFe9      Z: G dG dHe9      Z; G dI dJe9      Z< G dK dLe9      Z= G dM dNe9      Z> G dO dPe9      Z?dQ Z@ej                  dadR       ZBdS ZCdbdTZDdU ZEdcdVZFdW ZGdX ZHdY ZIdZ ZJd[ ZKd\ ZLd] ZMd^ ZNej                  j                  fd_ZQd` ZRy)dz'Common utilities for Composer commands.    )absolute_import)division)unicode_literalsN)util)api_adapter)storage_api)storage_util)base)parsers)config)
exceptions)execution_utils)log)
console_io)resource_printer)encoding)filesv1
KUBECONFIGz#^[a-z](?:[-0-9a-z]{0,62}[0-9a-z])?$gcloudkubectlz!Unable to find [gcloud] on path!
zAccessing a Cloud Composer environment requires the kubernetes commandline
client [kubectl]. To install, run
  $ gcloud components install kubectl
c                   (     e Zd ZdZ	 	 d fd	Z xZS )SupportedAirflowVersion c                 0    t         t        |   | |||      S N)superr   __new__)clsfrom_version
to_versionallowed_nested_subcommands	__class__s       /lib/googlecloudsdk/command_lib/composer/util.pyr   zSupportedAirflowVersion.__new__R   s$    (#6\:'AC C    )N3.0.0N)__name__
__module____qualname__	__slots__r   __classcell__r#   s   @r$   r   r   L   s     )18)-C Cr%   r   z2from_version to_version allowed_nested_subcommandsbackfillz2.0.0)r    r!   clearconnectionsz3.1.0dbz2.3.0r&   z2.6.3)checktrim)r    r!   r"   	dag_statedagsz1.10.14
delete_dagz1.10.1kerberos
kubernetesz2.1.4list_dag_runsz1.10.2	list_dagszlist-import-errors
list_tasksnext_executionpausepoolpoolsz1.10.15)renderrolesrunz	sync-perm	sync_permtask_failed_deps
task_statetaskstesttrigger_dagunpauseupgrade_checkusers	variablesversiondefaultz--namespacez-nactiveGkePodStatuszname phase isReadyc                       e Zd ZdZy)Errorz-Class for errors raised by Composer commands.Nr'   r(   r)   __doc__r   r%   r$   rQ   rQ      s    5r%   rQ   c                       e Zd ZdZy)KubectlErrorz5Class for errors raised when shelling out to kubectl.NrR   r   r%   r$   rU   rU          =r%   rU   c                       e Zd ZdZy)GsutilErrorz4Class for errors raised when shelling out to gsutil.NrR   r   r%   r$   rX   rX      s    <r%   rX   c                   "     e Zd ZdZ fdZ xZS )OperationErrorzHClass for errors raised when a polled operation completes with an error.c                 L    t         t        |   dj                  ||             y )NzOperation [{}] failed: {})r   rZ   __init__format)selfoperation_namedescriptionr#   s      r$   r\   zOperationError.__init__   s%    	.$()D)K)K*% &r%   )r'   r(   r)   rS   r\   r+   r,   s   @r$   rZ   rZ      s    P& &r%   rZ   c                       e Zd ZdZy)EnvironmentCreateErrorz5Class for errors raised when creating an environment.NrR   r   r%   r$   rb   rb      rV   r%   rb   c                       e Zd ZdZy)EnvironmentDeleteErrorz5Class for errors raised when deleting an environment.NrR   r   r%   r$   rd   rd      rV   r%   rd   c                       e Zd ZdZy)InvalidUserInputErrorzGClass for errors raised when a user input fails client-side validation.NrR   r   r%   r$   rf   rf      s    Or%   rf   c                     t        j                         }t        j                  |dj	                  |       |       |j                         S )zConstructs text output listing the elements of items and a title.

  Args:
    title: string, the listing title
    items: iterable, the iterable whose elements to list

  Returns:
    string, text representing list title and elements.
  zlist[title="{0}"])out)ioStringIOr   Printr]   getvalue)titleitemsbufs      r$   ConstructListrp      s9     	# 3 : :5 AsK	r%   c              #     K   t        j                          t        j                         5 }t        j
                  j                  |d      }t        j                  t        j                  t              }	 t        j                  t        j                  t        |       t        j                  t              }|j                  ||       }|j!                  |      }|j"                  }	|	xr |	j$                  xr |	j&                   }
|
rBt         j(                  j+                         s$t-        dj/                  |j0                              t         j(                  j3                  ||j0                  |       | t        j                  t        j                  t        |       	 ddd       y# t        j                  t        j                  t        |       w xY w# 1 sw Y   yxY ww)au  Context manager that manages a temporary kubeconfig file for a GKE cluster.

  The kubeconfig file will be automatically created and destroyed and will
  contain only the credentials for the specified GKE cluster. The 'KUBECONFIG'
  value in `os.environ` will be temporarily updated with the temporary
  kubeconfig's path. Consequently, subprocesses started with
  googlecloudsdk.core.execution_utils.Exec while in this context manager will
  see the temporary KUBECONFIG environment variable.

  Args:
    location_id: string, the id of the location to which the cluster belongs
    cluster_id: string, the id of the cluster
    kubecontext_override: string, the kubecontext override

  Raises:
    Error: If unable to get credentials for kubernetes cluster.

  Returns:
    the path to the temporary kubeconfig file

  Yields:
    Due to b/73533917, linter crashes without yields.
  
kubeconfigzGUnable to get cluster credentials. User must have edit permission on {})kubecontext_overrideN)gke_utilCheckKubectlInstalledr   TemporaryDirectoryospathjoinr   GetEncodedValueenvironKUBECONFIG_ENV_VAR_NAMESetEncodedValuegke_api_adapterNewAPIAdapterGKE_API_VERSIONParseCluster
GetCluster
masterAuthclientCertificate	clientKeyClusterConfigUseGCPAuthProviderrQ   r]   	projectIdPersist)location_id
cluster_idrs   tempdirrr   old_kubeconfiggke_apicluster_refclusterauthmissing_credss              r$   TemporaryKubeconfigr      su    2   "!Wg|4J--bjj.EGN/rzz+BJO--o>g(([Ak"";/gdMD$:$:Mt~~Nm	x55HHJ ''-vk.C.C'DF 	F$$



3 % 
 rzz+B-/+ "!* rzz+B-/+ "!s6   )G&A	G5DF,9)G#	G&,+GGG#G&c           	      \   | j                   j                  j                  rS| j                   j                  j                  | j                   j                  j                  j                  d      dz   d S | j                   j                  | j                   j                  j                  d      dz   d }t        j                  t              }|j                  t        j                               j                  D cg c]J  }|j                  |k(  r9|j                  |j                  j                  d      dz   d xs |j                  L }}|st        d      t        |      dk(  r|d   S |t!        j"                  |D cg c]  }dj%                  |       c}dd         S c c}w c c}w )	a|  Finds the location ID of the GKE cluster running the provided environment.

  Args:
    env_object: Environment, the environment, likely returned by an API call,
      whose cluster location to extract

  Raises:
    Error: if Kubernetes cluster is not found.

  Returns:
    str, the location ID (a short name like us-central1-b) of the GKE cluster
    running the environment
  /   Nz$Kubernetes Engine cluster not found.r   z[{}]zLCluster found in more than one location. Please select the desired location:)rM   message)r   
nodeConfiglocationrfind
gkeClusterr~   r   r   ListClustersr   
GetProjectclustersnamezonerQ   lenr   PromptChoicer]   )
env_objectgke_clusterr   ccluster_zoneszs         r$   ExtractGkeClusterLocationIdr     s    !!**''001B1B1M1M2:(55:2J 2K L L !!,,Z->->-I-I.3eCj1.= .> ?+ ))/:'
 ##G$6$6$89BBB!	
;	 jj!!#&*+,66B  
 
 6
77
=Q	z..!./Av}}Q/ 
  0s   ;AF$ F)
c                     t        j                         }g d}	 t        ||j                  t        j
                  j                  |       |j                         j                  d      D cg c]  }|rt        |j                  d        }}|j                  d        |D cg c]+  }|j                  j                         d	k(  r|j                  - }}|st        d
       |d   S 	 t         fd|D              S # t        $ r}t        d|z        d}~ww xY wc c}w c c}w # t         $ r t        d      w xY w)a  Returns the name of a running pod in a GKE cluster.

  Retrieves pods in the GKE cluster pointed to by the current kubeconfig
  context. To target a specific cluster, this command should be called within
  the context of a TemporaryKubeconfig context manager.

  If pod_substr is not None, the name of an arbitrary running pod
  whose name contains pod_substr is returned; if no pod's name contains
  pod_substr, an Error is raised. If pod_substr is None, an arbitrary running
  pod is returned.

  Pods with 'Ready: true' condition state are preferred. If there are no such
  pods, any running pod will be returned.

  Args:
    pod_substr: string, a filter to apply to pods. The returned pod name must
      contain pod_substr (if it is not None).
    kubectl_namespace: string or None, namespace to query for gke pods

  Raises:
    Error: if GKE pods cannot be retrieved or desired pod is not found.
  )getpods--outputzyjsonpath={range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\t"}{.status.conditions[?(.type=="Ready")].status}{"\n"})out_funcerr_func	namespacezError retrieving GKE pods: %sN
	c                 <    | j                   j                         dk7  S )Ntrue)isReadylower)xs    r$   <lambda>zGetGkePod.<locals>.<lambda>o  s    !))//"3v"=r%   )keyrunningzZNo running GKE pods found. If the environment was recently started, please wait and retry.r   c              3   ,   K   | ]  }|v s|  y wr   r   ).0pod
pod_substrs     r$   	<genexpr>zGetGkePod.<locals>.<genexpr>  s     A|zS/@|s   	zZDesired GKE pod not found. If the environment was recently started, please wait and retry.)ri   rj   RunKubectlCommandwriter   errrU   rQ   rl   splitrO   sortphaser   r   nextStopIteration)r   kubectl_namespacepod_outargse
pod_statuscluster_podsrunning_podss   `       r$   	GetGkePodr   ?  sk   . KKM'
$5#	%  ((*0066*	 J$$T*+6   => %$*						!Y	. oo$   

 ? @ @ ?@A|AAA9 
 5
/!3
445 
 @
 ? @ @@s/   1D - D &0D%-D* 	D
DD*D?c                 0    t         j                  |       duS )z>Returns True if the provided name is a valid environment name.N)ENVIRONMENT_NAME_PATTERNmatch)r   s    r$   IsValidEnvironmentNamer     s    	!	'	'	-T	99r%   c                    t        j                  t        t        j                         j
                        }|t        j                  t              }|t        t              t        |t        j                  |g|        }	 t        j                  |d|fdd      }|rt        d      y# t        j                  t        j                  f$ r#}t        t        j                   |            d}~ww xY w)a  Shells out a command to kubectl.

  This command should be called within the context of a TemporaryKubeconfig
  context manager in order for kubectl to be configured to access the correct
  cluster.

  Args:
    args: list of strings, command line arguments to pass to the kubectl
      command. Should omit the kubectl command itself. For example, to execute
      'kubectl get pods', provide ['get', 'pods'].
    out_func: str->None, a function to call with the stdout of the kubectl
      command
    err_func: str->None, a function to call with the stderr of the kubectl
      command
    namespace: str or None, the kubectl namespace to apply to the command

  Raises:
    Error: if kubectl could not be called
    KubectlError: if the invocation of kubectl was unsuccessful
  NTc                     t        |       S r   )HandleKubectlErrorStream)r   r   s    r$   r   z#RunKubectlCommand.<locals>.<lambda>  s    5hDr%   )no_exitr   r   universal_newlinesz&kubectl returned non-zero status code.)r   FindExecutableOnPath_KUBECTL_COMPONENT_NAMEr   Pathssdk_bin_pathrQ   MISSING_KUBECTL_MSGAddKubectlNamespacer   ArgsForExecutableToolExecPermissionErrorInvalidCommandErrorrU   six	text_type)r   r   r   r   kubectl_path	exec_argsretvalr   s     `     r$   r   r     s    . ++,C,2LLN,G,GI,--.EFL
#
$$!66|KdKM)) !!D!F 
?
@@  
)
)

-
-
/ )
s}}Q'
(()s   B0 0#C6C11C6c                 z    | xs t         j                  j                  }d|v r ||        |d       y  ||       y )NzUnable to connect to the serverz>
Please, check if you have connectivity to GKE control plane.
)r   statusrk   )r   r   err_handler_funcs      r$   r   r     s=    1!1!1&#-SJL Sr%   c                 &    | j                  dd      S )zBConverts an image version string to a kubernetes namespace string..-)replace)image_versions    r$   $ConvertImageVersionToNamespacePrefixr     s    			sC	((r%   c                    t        |       }g d}t        j                         }t        ||j                  t
        j                  j                         t        |j                         j                  d            }|D ]^  }|j                         r|j                  d      nd}|s)|d   j                         t        k(  sD|d   j                  |      sY|d   c S  t        S )al  Checks environment for valid namespace options.

  First checks for the existence of a kubectl namespace based on the env image
  version. If namespace does not exist, then return the 'default' namespace.

  Args:
    env_image_version: str, the environment image version string.

  Returns:
    The namespace string to apply to any `environments run` commands.
  )r   r   z--all-namespacesz%--sort-by=.metadata.creationTimestampr   zEjsonpath={range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\n"}z--ignore-not-found=truer   r   Nr   r   )r   ri   rj   r   r   r   r   reversedrl   r   stripr   NAMESPACE_STATUS_ACTIVE
startswithDEFAULT_NAMESPACE)env_image_versionimage_version_ns_prefixr   	ns_output
namespacesns_entryns_partss          r$   FetchKubectlNamespacer     s     A
$ kkm)D)//377==9 	**,22489*h'/~~'7x~~d#THXa[&&(,CC67a[  
r%   c                     | |S t         t        hj                  t        |            r0d}|rt        |d   v rd}| t         fD ]  }|j                  ||        |S )ar  Adds namespace arguments to the provided list of kubectl args.

  If a namespace arg is not already present, insert `--namespace <namespace>`
  after the `kubectl` command and before all other arg elements.

  Resulting in this general format:
    ['kubectl', '--namespace', 'namespace_foo', ... <remaining args> ... ]

  Args:
    namespace: name of the namespace scope
    kubectl_args: list of kubectl command arguments. Expects that the first
      element will be the `kubectl` command, followed by all additional
      arguments.

  Returns:
    list of kubectl args with the additional namespace args (if necessary).
  r   r   )NAMESPACE_ARG_NAMENAMESPACE_ARG_ALIAS
isdisjointsetr   insert)r   kubectl_argsidxnew_args       r$   r   r     sn    $  -.99#l:KL
C/<?Bc 12#w' 3 
r%   c                    	 | j                  d      }|rEt        j                         }t        j                  j                  |       }|j                  |      }nt        j                  |       }i }|5 }|D ]W  }|j                         }|r|j                  d      r't        |      \  }}	||v rt        dj                  |            |	||<   Y |cddd       S # 1 sw Y   yxY w# t        j                  t        j                  t        j                  f$ r0 t        j                  t        dj                  |                    Y yw xY w)a  Parses the given requirements file into a requirements dictionary.

  If the file path is GCS file path, use GCS file parser to parse requirements
  file. Otherwise, use local file parser.

  Args:
    requirements_file_path: Filepath to the requirements file.

  Returns:
    {string: string}, dict mapping from PyPI package name to extras and version
    specifier, if provided.

  Raises:
    Error: if requirements file cannot be read.
  zgs://#z+Duplicate package in requirements file: {0}Nz$Unable to read requirements file {0})r   r   StorageClientr	   ObjectReferenceFromUrl
ReadObjectr   
FileReaderr   SplitRequirementSpecifierrQ   r]   core_exceptionsreraise)
requirements_file_pathis_gcs_file_pathstorage_client
object_reffile_contentrequirementsrequirements_filerequirement_specifierpackagerL   s
             r$   ParseRequirementsFiler    s6    &-88A"002n//778NOj#..z:l%%&<=lL	*#4
 5 ; ; =$(=(H(H(M
45JKl";BB7KM M 'W $5  
 ++{((,*<*<	= &4;;"$ 	%&&s2   A1C' 3AC	C' C$ C' $C' 'AE	E	c                    | j                         }d}t        j                  ||       }d}|rB| d|j                          j                         }| |j                         d j                         }|st	        dj                  |             ||fS )aI  Splits the package name from the other components of a requirement spec.

  Only supports PEP 508 `name_req` requirement specifiers. Does not support
  requirement specifiers containing environment markers.

  Args:
    requirement_specifier: str, a PEP 508 requirement specifier that does not
      contain an environment marker.

  Returns:
    (string, string), a 2-tuple of the extracted package name and the tail of
    the requirement specifier which could contain extras and/or a version
    specifier.

  Raises:
    Error: No package name was found in the requirement spec.
  z(\[|\(|==|>=|!=|<=|<|>|~=|===) Nz5Missing package name in requirement specifier: \'{}\')r   researchstartrQ   r]   )r  r  tail_start_regex
tail_matchtails        r$   r  r  @  s    $ "'')'6yy)+@A*	$#$7Z%5%5%78>>@G !1!1!3!45;;=D	
HOO    	$r%   c           	         t        d |xs g D              }t        j                  d t        t	        j
                  |xs i             D              }| r9t	        j
                  |      D cg c]  \  }} |||       }}}| ||      fS g }	t               }
|D ]4  }|	j                  dj                  ||             |
j                  |       6 g }t	        j
                  |      D ]D  \  }}|j                   |||             ||
vs$|	j                  dj                  ||             F |	j                          dj                  |	       ||      fS c c}}w )a  Builds the field mask and patch environment for an environment update.

  Follows the environments update semantic which applies operations
  in an effective order of clear -> remove -> set.

  Leading and trailing whitespace is stripped from elements in remove_keys
  and the keys of set_entries.

  Args:
    clear: bool, If true, the patch removes existing keys.
    remove_keys: iterable(string), Iterable of keys to remove.
    set_entries: {string: string}, Dict containing entries to set.
    field_mask_prefix: string, The prefix defining the path to the base of the
      proto map to be patched.
    entry_cls: AdditionalProperty, The AdditionalProperty class for the type of
      entry being updated.
    env_builder: [AdditionalProperty] -> Environment, A function which produces
      a patch Environment with the given list of entry_cls properties.

  Returns:
    (string, Environment), a 2-tuple of the field mask defined by the arguments
    and a patch environment produced by env_builder.
  c              3   <   K   | ]  }|j                           y wr   r   r   ks     r$   r   z%BuildPartialUpdate.<locals>.<genexpr>x       9'8!AGGI'8   c              3   F   K   | ]  \  }}|j                         |f  y wr   r$  r   r&  vs      r$   r   z%BuildPartialUpdate.<locals>.<genexpr>{  $      (K!IAqwwy!n!I   !r   valuez{}.{},)r  collectionsOrderedDictsortedr   	iteritemsappendr]   addr   ry   )r.   remove_keysset_entriesfield_mask_prefix	entry_clsenv_builderr   r/  entriesfield_mask_entries	seen_keyss              r$   BuildPartialUpdater?  _  sY   2 9{'8b'899+ '' (K!'k6GR(H!I(K K+
 --44JC 	c'4   k'222e)cgnn->DEMM#  'MM+.jc5NN9E23
)/@# FG / 	$	%{7';	;;'s   -Ec           
         t        j                  d |D              }| rt        j                         }t        d |xs g D              }|D ]
  }||v s||=  t        j                  d t        t	        j
                  |xs i             D              }|j                  |        |t	        j
                  |      D cg c]  \  }} |||       c}}      S c c}}w )a:  Builds the patch environment for an environment update.

  To be used when BuildPartialUpdate cannot be used due to lack of support for
  field masks containing map keys.

  Follows the environments update semantic which applies operations
  in an effective order of clear -> remove -> set.

  Leading and trailing whitespace is stripped from elements in remove_keys
  and the keys of set_entries.

  Args:
    clear: bool, If true, the patch removes existing keys.
    remove_keys: iterable(string), Iterable of keys to remove.
    set_entries: {string: string}, Dict containing entries to set.
    initial_entries: [AdditionalProperty], list of AdditionalProperty class with
      key and value fields, representing starting dict to update from.
    entry_cls: AdditionalProperty, The AdditionalProperty class for the type of
      entry being updated.
    env_builder: [AdditionalProperty] -> Environment, A function which produces
      a patch Environment with the given list of entry_cls properties.

  Returns:
    Environment, a patch environment produced by env_builder.
  c              3   L   K   | ]  }|j                   |j                  f  y wr   r.  )r   entrys     r$   r   z%BuildFullMapUpdate.<locals>.<genexpr>  s!      )=,;5uyy%++Os   "$c              3   <   K   | ]  }|j                           y wr   r$  r%  s     r$   r   z%BuildFullMapUpdate.<locals>.<genexpr>  r'  r(  c              3   F   K   | ]  \  }}|j                         |f  y wr   r$  r*  s      r$   r   z%BuildFullMapUpdate.<locals>.<genexpr>  r,  r-  r.  )r1  r2  r  r3  r   r4  update)	r.   r7  r8  initial_entriesr:  r;  entries_dictr   r/  s	            r$   BuildFullMapUpdaterH    s    8 (( )=,;)= =, **,L9{'8b'899+c
l
s
  '' (K!'k6GR(H!I(K K+k"	l33*#u Cu%3 
  s   ?C
c                     t        j                  |      j                  j                  j                  }| j
                  |k(  S )a=  Returns whether an environment currently is in the RUNNING state.

  Args:
    environment: Environment, an object returned by an API call representing the
      environment to check.
    release_track: base.ReleaseTrack, the release track of command. Will dictate
      which Composer client library will be used.
  )release_track)api_utilGetMessagesModuleEnvironmentStateValueValuesEnumRUNNINGstate)environmentrJ  running_states      r$   IsInRunningStaterS    s<       %''2{3G3G  
		m	++r%   c                     | y| D ]  }	 t        j                  |        y# t        $ r}t        dj	                  |            d}~ww xY w)zValidates given master authorized networks.

  Args:
    networks: Iterable(string) or None. List of networks in CIDR notation.
  Nz%Invalid master authorized network: {})	ipaddressIPv4Network	Exceptionrf   r]   )networksnetworkr   s      r$    ValidateMasterAuthorizedNetworksrZ    sW     
g=G$   =!
1
8
8
;= ==s   "	A
AA
r   )NN)NNN)SrS   
__future__r   r   r   r1  
contextlibri   rU  rw   r  googlecloudsdk.api_lib.composerr   rK   googlecloudsdk.api_lib.containerr   r~   rt   googlecloudsdk.api_lib.storager   r	   googlecloudsdk.callioper
   #googlecloudsdk.command_lib.composerr   googlecloudsdk.corer   r   r  r   r   googlecloudsdk.core.consoler   googlecloudsdk.core.resourcer   googlecloudsdk.core.utilr   r   r   r   r|   compiler   _GCLOUD_COMPONENT_NAMEr   MISSING_GCLOUD_MSGr   SUBCOMMAND_DEPRECATION
namedtupler   SUBCOMMAND_ALLOWLISTrE  r   r   r   r   rO   rQ   rU   rX   rZ   rb   rd   rf   rp   contextmanagerr   r   r   r   r   r   r   r   r   r  r  r?  rH  ReleaseTrackGArS  rZ  r   r%   r$   <module>ro     s   . &  '   	  	 	 < K = 6 7 ( 7 & = / # 2 9 - * 
& %2::&KL ! #    	C4k448: 	CKTgFK TgF	K
 TgFK 	  ,%,B ,%,B(
	K& TgF)K* Y7K-K. X'J1K2 TgF5K6 WI9K: X'J=K> TgFAKB TgFEKF TgFIKJ X'JMKN TgFQKR TgFUKV Y7KYK\ 	 TgFWITgFY7KX'JTgFTgFY7KTgFTgFTgFY7KY7KTgFTgFUK ^   2 3 "  " %{%%n6JK6O!! 6>5 >=% =&U &>U >>U >PE P  // //d(VC@L:
/Ad)
"J F*&Z>2<j/d 150A0A0D0D , =r%   