
    S`                     D   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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#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m0Z0 dd lm1Z1 dd!lm2Z2 dd"lm3Z3 dd#lm4Z4 dd$lm5Z5 dd%lm6Z6 dd&l7m8Z8 dd'l7m9Z9 dd(l7m:Z: dd)l7m;Z; dd*l7m<Z< dd+l7m=Z= dd,l7m>Z> dd-l7m?Z? dd.l7m@Z@ dd/l7mAZA dd0l7mBZB dd1l7mCZC dd2l7mDZD dd3l7mEZE dd4l7mFZF g d5ZGeGg d6z   ZHd7ZIg d8ZJd9ZK ej                  eM      ZN G d: d; ed<d=            ZO G d> d? ed@dA            ZP G dB dC edDdE            ZQ G dF dG edHdI            ZRddJZSdK ZTdL ZUdM ZVdN ZWdO ZXddPZYddQZZdR Z[dS Z\ddTZ]dU Z^dV Z_ddWZ` G dX dY      ZaddZZbd[ Zcd\ Zdd] Zed^ Zfd_ Zgd` Zhda Zidb Zjdc Zkdd Zl	 ddeZmdf Zndg Zo G dh diep      Zqdj Zrdk Zsdl Ztdm Zudn Zvdo Zwdp Zxdq Zydr Zzds Z{dt Z|du Z}dv Z~dw Zdx Zdy Z e j                  ee"dz      Z e j                  ee"d{      Z e j                  eed|      Z e j                  ed} d~      Z e j                  eed      Z e j                  ed d      Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd ZddZy# e$ r
 d dlmZ Y w xY w)    N)
namedtuple)chain)
attrgetter)
itemgetter)cached_property   )types   )COMPOSE_SPEC)COMPOSEFILE_V1)build_string_dict)	json_hash)parse_bytes)parse_nanoseconds_int)
splitdrive)ComposeVersion)env_vars_from_file)Environment)	split_env)CircularReference)ComposeFileNotFound)ConfigurationError)DuplicateOverrideFileFound)VERSION_EXPLANATION)!interpolate_environment_variables)$get_container_name_from_network_mode)"get_service_name_from_network_mode)sort_service_dicts)	MountSpec)parse_extra_hosts)parse_restart_spec)SecurityOpt)ServiceLink)ServicePort)VolumeFromSpec)
VolumeSpec)match_named_volumes)validate_against_config_schema)validate_config_section)validate_cpu)validate_credential_spec)validate_depends_on)validate_extends_file_path)validate_healthcheck)validate_ipc_mode)validate_links)validate_network_mode)validate_pid_mode)validate_service_constraints)validate_top_level_object)validate_ulimits)<cap_addcap_dropcgroup_parentcommand	cpu_countcpu_percent
cpu_period	cpu_quotacpu_rt_periodcpu_rt_runtime
cpu_sharescpuscpusetdetachdevice_cgroup_rulesdevicesdns
dns_searchdns_opt
domainname
entrypointenv_fileenvironmentextra_hosts	group_addhostnamehealthcheckimageipc	isolationlabelslinksmac_address	mem_limitmem_reservationmemswap_limitmem_swappinessnetoom_score_adjoom_kill_disablepidports
privileged	read_onlyrestartruntimesecretssecurity_optshm_size
pids_limit
stdin_openstop_signalsysctlsttyuseruserns_modevolume_drivervolumesvolumes_fromworking_dir)blkio_configbuildcontainer_namecredential_spec
dockerfileinit
log_driverlog_optloggingnetwork_modeplatformprofilesscalestop_grace_period)zhttp://zhttps://zgit://zgithub.com/zgit@)zdocker-compose.ymlzdocker-compose.yamlzcompose.ymlzcompose.yaml)zdocker-compose.override.ymlzdocker-compose.override.yamlzcompose.override.ymlzcompose.override.yamlc                   $     e Zd ZdZd fd	Z xZS )ConfigDetailsac  
    :param working_dir: the directory to use for relative paths in the config
    :type  working_dir: string
    :param config_files: list of configuration files to load
    :type  config_files: list of :class:`ConfigFile`
    :param environment: computed environment values for this project
    :type  environment: :class:`environment.Environment`
     c                 V    |t        j                  |      }t        |   | |||      S N)r   from_env_filesuper__new__)clsrq   config_filesrL   	__class__s       7/usr/lib/python3/dist-packages/compose/config/config.pyr   zConfigDetails.__new__   s3    %33K@KwlK
 	
    r   )__name__
__module____qualname____doc__r   __classcell__)r   s   @r   r   r      s    	
 
r   r   _ConfigDetailsz$working_dir config_files environmentc                   d    e Zd ZdZed        Zed        Zed        Zd Z	d Z
d Zd Zd	 Zd
 Zy)
ConfigFilez
    :param filename: filename of the config file
    :type  filename: string
    :param config: contents of the config file
    :type  config: :class:`dict`
    c                 &     | |t        |            S r   )	load_yaml)r   filenames     r   from_filenamezConfigFile.from_filename   s    8Yx011r   c                     | j                   j                  dd       }t        |t              rt        S |rt        |      S | j                  S )Nversion)configget
isinstancedictV1r   r   )selfr   s     r   config_versionzConfigFile.config_version   s;    ++//)T2gt$I*1~g&Ct||Cr   c                    | j                   j                  dd       }|s| j                   j                  dd       }| j                   j                  dd       }| j                   j                  dd       }|s|s|r>dD ]3  }t        | j                  | j                   j                  |i       |       5 t        S t        | j                  | j                   d       t
        S t        |t              r9t        j                  dj                  | j                  t
                     t
        S t        |t              s$t        dj                  | j                              t        |t              rKt        j                  d      }|j                  |      s%t        d	j                  || j                              |j!                  d
      r)t        dj                  | j                  t"                    t        S )Nr   servicesnetworksro   )r   r   ro   zUnexpected type for "version" key in "{}". Assuming "version" is the name of a service, and defaulting to Compose file version {}.z3Version in "{}" is invalid - it should be a string.z^[1-3]+(\.\d+)?$z Version "{}" in "{}" is invalid.1zVersion in "{}" is invalid. {})r   r   r)   r   VERSIONr   r   r   logwarningformatstrr   recompilematch
startswithr   )r   r   r   r   ro   sectionversion_patterns          r   r   zConfigFile.version   s   ++//)T2{{z48H{{z48Hkkooi6G8wB NG+t{{w'CWNN  $t{{J8Igt$KK 3396$--3LN I'3'$E&( ( gs# jj)<=O"((1(6VGT]]35 5 c"$0':; 
 r   c                 (    | j                         |   S r   )get_service_dicts)r   names     r   get_servicezConfigFile.get_service   s    %%'--r   c                 x    | j                   t        k(  r| j                  S | j                  j                  di       S )Nr   r   r   r   r   r   s    r   r   zConfigFile.get_service_dicts   s-    <<2;;{{z2..r   c                 d    | j                   t        k(  ri S | j                  j                  di       S Nro   r   r   s    r   get_volumeszConfigFile.get_volumes  '    \\R'rKT[[__Y-KKr   c                 d    | j                   t        k(  ri S | j                  j                  di       S )Nr   r   r   s    r   get_networkszConfigFile.get_networks  s'    \\R'rLT[[__Z-LLr   c                 d    | j                   t        k(  ri S | j                  j                  di       S )Nrd   r   r   s    r   get_secretszConfigFile.get_secrets	  r   r   c                 d    | j                   t        k(  ri S | j                  j                  di       S )Nconfigsr   r   s    r   get_configszConfigFile.get_configs  r   r   N)r   r   r   r   classmethodr   r   r   r   r   r   r   r   r   r    r   r   r   r      sh     2 2 D D + +Z./
LMLLr   r   _ConfigFilezfilename configc                       e Zd ZdZy)Configa  
    :param config_version: configuration file version
    :type  config_version: int
    :param version: configuration version
    :type  version: int
    :param services: List of service description dictionaries
    :type  services: :class:`list`
    :param volumes: Dictionary mapping volume names to description dictionaries
    :type  volumes: :class:`dict`
    :param networks: Dictionary mapping network names to description dictionaries
    :type  networks: :class:`dict`
    :param secrets: Dictionary mapping secret names to description dictionaries
    :type secrets: :class:`dict`
    :param configs: Dictionary mapping config names to description dictionaries
    :type configs: :class:`dict`
    N)r   r   r   r   r   r   r   r   r     s    r   r   _Configz@config_version version services volumes networks secrets configsc                       e Zd Zed        Zy)ServiceConfigc                     |st        d       | t        j                  j                  |      |r%t        j                  j                  |      ||      S |||      S )Nz!No working_dir for ServiceConfig.)
ValueErrorospathabspath)r   rq   r   r   r   s        r   with_abs_pathszServiceConfig.with_abs_paths%  sY    @AAGGOOK()1BGGOOH%	 	7?	 	r   N)r   r   r   r   r   r   r   r   r   r   #  s     r   r   _ServiceConfigz working_dir filename name configc           	         |dgk(  rlt        |rt        j                  j                  |      nt        j                         t        d t        j                  t        j                              g|      S |r.|D cg c]"  }t        j                  j                  | |      $ }}n<t        |       }|s|st        t              |st        |      }|st        t              t        j                  dj!                  dj                  |                   t        |r|n!t        j                  j#                  |d         |D cg c]  }t
        j%                  |       c}|      S c c}w c c}w )N-zUsing configuration files: {},r   )r   r   r   r   getcwdr   yaml	safe_loadsysstdinjoinget_default_config_filesr   SUPPORTED_FILENAMESr   debugr   dirnamer   )base_dir	filenamesrL   override_dirfs        r   findr   1  s   SE-9BGGOOL)ryy{dnnSYY789
 	
 8AB1RWW\\(A.B	B -X6	%&9::0>I)*=>>II-44SXXi5HIJ$"''//)A,*G.78	!	!!	$8  C  	9s   9'E$ E)
c           	      
   | d   }t        |       | dd  D ]k  }t        |       |j                  |j                  k7  s(t        dj                  |j                  |j                  |j                  |j                               y )Nr   r   zTVersion mismatch: file {} specifies version {} but extension file {} uses version {})r4   r   r   r   r   )r   	main_file	next_files      r   validate_config_versionr   O  s    QIi(!!"% 
(	!),	 1 11$44:F&&%%&&%%	5'( (	
(r   c                 $   t        t        |       \  }}|sy |d   }t        |      dkD  r;t        j	                  ddj                  |             t        j	                  d|       t        j                  j                  ||      gt        |      z   S )Nr   r   z4Found multiple config files with supported names: %s, z	Using %s
)	find_candidates_in_parent_dirsr   lenr   r   r   r   r   get_default_override_file)r   
candidatesr   winners       r   r   r   `  sy    78KXVZ]F
:JDIIV`LabL&)GGLLv&'*CD*IIIr   c           	         t         D cg c]_  }t        j                  j                  t        j                  j	                  | |            r t        j                  j	                  | |      a }}t        |      dkD  rt        |      |S c c}w )Nr   )DEFAULT_OVERRIDE_FILENAMESr   r   existsr   r   r   )r   override_filenameoverride_files_in_paths      r   r   r   o  s{    !;XHY!#TCT0U!V !ggll41BC X X !"Q&()?@@!!Xs   A$B
c           	         | D cg c]A  }t         j                  j                  t         j                  j                  ||            r|C }}|skt         j                  j                  |d      }t         j                  j	                  |      t         j                  j	                  |      k7  rt        | |      S ||fS c c}w )z
    Given a directory path to start, looks for filenames in the
    directory, and then each parent directory successively,
    until found.

    Returns tuple (candidates, path).
    z..)r   r   r   r   r   r   )r   r   r   r   
parent_dirs        r   r   r   x  s     ,5 CxWW^^BGGLLx$@A  CJ C WW\\$-
77??:&"''//$*??1)ZHHCs   AB>c           
          d}d}| D cg c]  }|j                  |      s| }}|rFt        j                  |j                  dj	                  t        d |D                    |             y y c c}w )NzSome services ({services}) use the '{key}' key, which will be ignored. Compose does not support '{key}' configuration - use `docker stack deploy` to deploy to a swarm.r   r   c              3   &   K   | ]	  }|d      yw)r   Nr   ).0ss     r   	<genexpr>z*check_swarm_only_config.<locals>.<genexpr>  s     )F!F))Fs   )r   key)r   r   r   r   r   sorted)service_dictswarning_templater   r   r   s        r   check_swarm_only_configr     sv    	6 
 C(7aAEE#J7H7##6)FX)F#FG $ 	
  8s
   A/A/c           	         t        | j                         | j                  D cg c]  }t        || j                  |       }}| j	                  |      } | j                  d   }t        | j                  dd      }t        | j                  dd      }t        | j                  dd	| j                        }t        | j                  d
d| j                        }t        | ||      }	|j                  t        k7  r|	D ]  }
t        |
|        t        |	       t        |j                  |j                  |	||||      S c c}w )a  Load the configuration from a working directory and a list of
    configuration files.  Files are loaded in order, and merged on top
    of each other to create the final configuration.

    Return a fully interpolated, extended and validated configuration.
    )interpolate)r   r   r   Volumer   Networkr   Secretr   r   )r   r   process_config_filerL   _replaceload_mappingrq   load_servicesr   r   r'   r   r   r   )config_detailsr   config_fileprocessed_filesr   ro   r   rd   r   r   service_dicts              r   loadr    sN    N778 *66 	K)C)CQ\]O  $,,/,JN++A.I##]HG ##^YH ##]Hn>X>XG ##]Hn>X>XG ".)UMB) 	7Lg6	7 M*)**I,=,=(GWF F7s   D<c                    i }| D ]  } t        ||             j                         D ]  \  }}|xs i ||<   |s|j                  d      }|rSt        ||||j                         t        |t              r|j                  d      |d<   n|j                  d      s||d<   d|v rt        |d         |d<   d|v rt        ||d         |d<   d|v st        |d         |d<   t        ||      }	|	s|	|d   d<     |S )Nexternalr   rT   filedriver_optsdevice)getattritemsr   validate_externalr   r   r   parse_labelsexpand_pathr   format_device_option)
r   get_funcentity_typerq   mappingr	  r   r   r  r  s
             r   r  r    s%   G# =:GK:<BBD 	=LD&"LbGDMzz*-H!+tV[=P=PQh-%-\\&%9F6NF+%)F6N6!#/x0@#Ax !,[&.!Iv&(9=))}% .k6B6<F=)(33	==6 Nr   c                 "   | dk7  ry |j                  dd      }|dk7  ry |d   j                  d      }|d   j                  d      }|rG|dk(  rA|r>t        j                  j                  t        j                  j	                  |            }|S y y y )Nr  driverlocalr  or  bind)r   r   r   r   
expanduser)r  r   r  r  r  fullpaths         r   r  r    s    hZZ'*F}!!#&AM"&&x0FQ&[V77??277#5#5f#=> $[qr   c                     |j                         D ]C  }| dk(  r|dk(  r|dvst        dj                  | |dj                  d |D                           y )Nr  r  )r  r   zD{} {} declared as external but specifies additional attributes ({}).r   c              3   ,   K   | ]  }|d k7  s	|  yw)r  Nr   )r   ks     r   r   z$validate_external.<locals>.<genexpr>  s     0Vqa:o0Vs   
)keysr   r   r   )r  r   r   r   r$  s        r   r  r    sh    [[] Y)#X(($tyy0VF0V'VXY Y	Yr   c                       fdfd}fd} j                   D cg c]  }|j                          }}t        j                  ||      } ||      S c c}w )Nc                 F   t         j                  j                  j                  | |      }t	        |j
                        }t        |j                               }|j                  |      }t        ||       t        ||j                  j
                        }|S )N)rL   r   )r   r   rq   r   ServiceExtendsResolverrL   process_servicerunr  validate_servicefinalize_servicer   )service_namer  service_namesservice_configresolverr  r	  r   s        r   build_servicez$load_services.<locals>.build_service  s    &55&&  	
 *K^5O5O
 'x||~6'000ED'&&
 r   c                     | j                         }t        | j                         D cg c]  \  }} |||       c}}      S c c}}w r   )r%  r   r  )r0  r/  r   r  r2  s       r   build_servicesz%load_services.<locals>.build_services  sO    &++-!&4&:&:&<#
"l $m<#
  	 #
s   A
c                     t        |       t        |      z  }|D ci c]:  }|t        | j                  |i       |j                  |i       j                        < c}S c c}w r   )setmerge_service_dicts_from_filesr   r   )baseoverrideall_service_namesr   r	  s       r   merge_servicesz%load_services.<locals>.merge_services  sl    IH5 *

 	 0r"T2&##% %
 	
 
s   ?A)r   r   	functoolsreduce)	r  r	  r   r4  r;  r  service_configsr0  r2  s	   ```     @r   r  r     sa    ,
 .<-H-H%) O  %%noFN.))s   Ac                 2    t        | j                  |||      S r   )r   r   )r	  r   r   rL   s       r   interpolate_config_sectionr@  1  s!    ,	 r   c                 h    t        | j                  ||       |rt        | j                  |||      S |S r   )r)   r   r   r   )r	  r   r   rL   r   s        r   process_config_sectionrB  :  s=    K00&'B0	 	 r   c                 F   t        | | j                         d||      }| j                  t        kD  rt	        | j
                        }||d<   t        | | j                         d||      |d<   t        | | j                         d||      |d<   t        | | j                         d||      |d<   t        | | j                         d	||      |d
<   n|}| j                  |      } t        | | j                         |r)||vr%t        dj                  || j                              | S )Nservicer   volumero   networkr   secretrd   r   r   r(  3Cannot extend service '{}' in {}: Service not found)rB  r   r   r   r   r   r   r   r   r   r  r(   r   r   r   )r	  rL   r.  r   r   processed_configs         r   r  r  F  sZ   %%%'H R 2 23'/$&<##%'
# (>$$&(
$ '=##%'
# '=##%'
# $&&.>&?K";0C0CDH4 AHHk2245 	5 r   c                   B    e Zd Zd	dZed        Zd Zd Zd Zd Z	d Z
y)
r)  Nc                 f    || _         |j                  | _        |xs g | _        || _        || _        y r   )r0  rq   already_seenr	  rL   )r   r0  r	  rL   rL  s        r   __init__zServiceExtendsResolver.__init__}  s5    ,)55(.B&&r   c                 Z    | j                   j                  | j                   j                  fS r   )r0  r   r   r   s    r   	signaturez ServiceExtendsResolver.signature  s%    ""++T-@-@-E-EEEr   c                 z    | j                   | j                  v r#t        | j                  | j                   gz         y r   )rO  rL  r   r   s    r   detect_cyclez#ServiceExtendsResolver.detect_cycle  s6    >>T...#D$5$58H$HII /r   c                     | j                          d| j                  j                  v r9 | j                  | j	                          }| j                  j                  |      S | j                  S )Nextendsr(  )rQ  r0  r   resolve_extendsvalidate_and_construct_extendsr  )r   r  s     r   r+  zServiceExtendsResolver.run  sc    ++222/4//1T1T1VWL&&//|/DD"""r   c                 2   | j                   j                  d   }t        |t              sd|i}| j	                  |      }|d   }|t
        j                  j                  | j                  j                        k(  r	 | j                  j                  |      }nUt        j                  |      }t!        | j                  |g       t#        || j$                  |      }|j                  |      }|||fS # t        $ r t        dj                  ||            w xY w)NrS  rD  rH  )r.  )r0  r   r   r   get_extended_config_pathr   r   r   r	  r   r   KeyErrorr   r   r   r   r   r  rL   )r   rS  config_pathr.  r0  extends_fileextended_files          r   rU  z5ServiceExtendsResolver.validate_and_construct_extends  s   %%,,Y7'4( '*G33G<y)"''//$*:*:*C*CDD!%!1!1!=!=l!K &33K@L#T%5%5|$DE/d..\M +66|DNNL88  (IPP$k3 s   ;C1 1%Dc                    t        t        j                  t        j                  j                  |      |||      | j                  | j                  | j                  gz   | j                        }|j                         }t        |      }t        |||       t        || j                  j                  | j                  j                         S )N)rL  rL   )r)  r   r   r   r   r   r	  rL  rO  rL   r+  r*  validate_extended_service_dictmerge_service_dictsr0  r   r   )r   extended_config_pathr  r.  r1  r0  other_service_dicts          r   rT  z&ServiceExtendsResolver.resolve_extends  s    )(( 45$	
 **dnn-==((	
 ",^<& 	
 #&&$$& 	&r   c                     | j                   j                  }t        | j                   j                  ||       d|v rt	        | j
                  |d         S |S )zService we are extending either has a value for 'file' set, which we
        need to obtain a full path too or we are extending from a service
        defined in our own file.
        r  )r0  r   r-   r   r  rq   )r   extends_optionsr   s      r   rW  z/ServiceExtendsResolver.get_extended_config_path  sY    
 &&//"$$	 _$t//1HIIr   r   )r   r   r   rM  propertyrO  rQ  r+  rU  rT  rW  r   r   r   r)  r)  |  s7    ' F FJ#94&0r   r)  c                    i }| j                  dg       D ]  }|j                  t        ||              |j                  t        | j                  d                   t	        fd|j                         D              S )zjUnpack any environment variables from an env_file, if set.
    Interpolate environment values if set.
    rK   rL   c              3   >   K   | ]  \  }}t        ||        y wr   resolve_env_varr   r$  vrL   s      r   r   z&resolve_environment.<locals>.<genexpr>  s     Ktq!1k2K   )r   updater   parse_environmentr   r  )r  rL   r   envrK   s    `   r   resolve_environmentrn    sp     C $$Z4 >

%h<=> JJ !1!1-!@ABKsyy{KKKr   c                 ^    t        |       }t        fd|j                         D              S )Nc              3   >   K   | ]  \  }}t        ||        y wr   rf  rh  s      r   r   z%resolve_build_args.<locals>.<genexpr>  s     Ltq!1k2Lrj  )parse_build_argumentsr   r  )	buildargsrL   argss    ` r   resolve_build_argsrt    s$     +DLtzz|LLLr   c                    dj                  ||      }d| v rt        d|z        d| v rt        d|z        d| v rt        | d         rt        d|z        d| v rt        | d         rt        d	|z        d
| v rt        d|z        y )Nz!Cannot extend service '{}' in {}:rU   z+%s services with 'links' cannot be extendedrp   z2%s services with 'volumes_from' cannot be extendedr[   z4%s services with 'net: container' cannot be extendedr{   z;%s services with 'network_mode: service' cannot be extended
depends_onz0%s services with 'depends_on' cannot be extended)r   r   r   r   )r  r   rD  error_prefixs       r   r]  r]    s    6==gxPL, 9LHJ 	J % @<OQ 	Q /U0CD$FUW W %-l>.JK$MP\\^ ^ |# >MO 	O $r   c                    d }| j                   | j                  }}t        |||        |       rt        |       t	        |        t        |        t        | |       t        | |       t        | |       t        | |       t        | |       t        |        t        |        |j                  d      s't        |      rt        dj!                  |            y y )Nc                  >    t         j                  dd  } d| v ryd| v ryy)Nr   pullFz
--no-buildT)r   argv)rs  s    r   build_imagez%validate_service.<locals>.build_image  s)    xx|T>4r   rQ   zService '{name}' contains uppercase characters which are not valid as part of an image name. Either use a lowercase service name or use the `image` field to set a custom name for the service image.r   )r   r   r3   validate_pathsr*   r5   r/   r1   r2   r,   r0   r.   r+   r   has_uppercaser   r   )r0  r/  r	  r|  r  r.  s         r   r,  r,    s     "0!6!68K8K,L |[I}|$ ^$nm4.-8nm46>=1(^,G$|)D P VV&	( 	( *E$r   c           	         | j                   }t        | j                        }d|v r)t        |d         D cg c]  }t	        ||       c}|d<   d|v rt        ||       d|v r |j                  d      t        ||      |d<   d|v rt        t        |d               |d<   d|v rt        |d         |d<   t        |      }dD ]  }||v st        ||         ||<    t        t        t        t        |                        }|S c c}w )NrK   rs   ro   rn   rj   rT   )rF   rG   tmpfs)rq   r   r   to_listr  process_build_sectionr   resolve_volume_pathsr   parse_sysctlsr  process_depends_onprocess_security_optprocess_blkio_configprocess_portsprocess_healthcheck)r0  rq   r  r   fields        r   r*  r*  %  s4    ,,K--.L\!  Z 89$
 T*$
Z 
 ,lK8L \%5%5o%F%N"6{L"QYL "3M,yBY4Z"[Y<!-l8.D!EX%l3L/ ?L "),u*=">L? ((<]L)> ) L 7$
s   Dc                     t        | d   t              rt        || d         | d<   y t        | d   t              rAd| d   v r| d   d   }t        ||      | d   d<   d| d   v rt	        | d   d         | d   d<   y y y )Nrs   contextrT   )r   r   resolve_build_pathr   r  )r  rq   r   s      r   r  r  H  s    ,w'- 2;W@U VW	L)4	0W--(3D/A+t/TL!),|G,,.:<;PQY;Z.[L!(+ -	 
1r   c                     d| vr| S g }| d   D ]H  }t        |t              r|j                  |       %|j                  t        j                  |             J || d<   | S )Nr_   )r   r$   appendextendparse)r  r_   port_definitions      r   r  r  S  sh    l"E'0 =o{3LL)LL**?;<	=
 "Lr   c                 p    d| v r,t        | d   t              s| d   D ci c]  }|ddi	 c}| d<   | S c c}w )Nrv  	conditionservice_started)r   r   )r  svcs     r   r  r  a  sP    |#J|L7QSW,X=I,=W&
69C+011&
\" &
s   3c           
         | j                  d      s| S dD ]c  }|| d   v s| d   j                  |g       D ]A  }|j                  dd      }t        |      |d<   |d   )t        dj                  |             e dD ]C  }|| d   v s| d   j                  |g       D ]!  }	 t	        |j                  dd            |d<   # E | S # t
        $ r* t        dj                  |j                  d                  w xY w)Nrr   )device_read_bpsdevice_write_bpsrater   z$Invalid format for bytes value: "{}")device_read_iopsdevice_write_iopsz5Invalid IOPS value: "{}". Must be a positive integer.)r   r   r   r   intr   )r  r  ri  r  s       r   r  r  i  s5   N+8 bL00!.155eR@ buuVQ''-&	V9$,-S-Z-Z[_-`aa	bb ; L00!.155eR@  #AEE&!$4 5AfI  " ,OVVWXW\W\]cWde s   "C3C9c                     d| vr| S | d   }d|v r	|d= dg|d<   dD ]+  }||vst        ||   t              rt        ||         ||<   - | S )NrP   disableNONEtest)intervaltimeoutstart_period)r   r  r   )r  hcr  s      r   r  r    ss    L(	m	$BByMX6
8 5?jEC8)"U)45	5
 r   c                    d| v rAg }|j                  d      }|j                  d      }| d   D ]_  }t        |t              r'|j                  t	        j
                  |||             :|j                  t        j
                  |||             a g }|D cg c]$  }t        |t              r|j                         n|& }}|D ]\  }t        t        t        d      |            j                  |j                        dkD  s>|j                  |j                                ^ |rt        ddj                  |      z        || d<   | S c c}w )Nro   COMPOSE_CONVERT_WINDOWS_PATHSCOMPOSE_FORCE_WINDOWS_HOSTinternalr   zDuplicate mount points: [%s]r   )get_booleanr   r   r  r   r  r&   as_volume_speclistmapr   countr  reprr   r   )	r  rL   finalized_volumes	normalizewin_hostri  duplicate_mountsmountsmounts	            r   finalize_service_volumesr    sG   L ++,KL	**+GHi( 	SA!T"!((Ix)PQ!(()9)9!Y)QR		S QbcA
1i(@!""$aGcc 	6EC
:.78>>u~~NQRR ''

5	6 $%C		*+&- . . #4Y ds   )E	c                 &   t        | j                        }d|v sd|v r"t        |||      |d<   |j                  dd        d|v r+|d   D cg c]  }t	        j
                  |||       c}|d<   t        ||      }d|v r<|j                  d      }t        |      }|r||v rdj                  |      |d<   n||d<   d|v rt        |d         |d<   d|v rt        |d         |d<   d	|v r3|d	   D 	cg c]!  }	t        j                  j                  |	      # c}	|d	<   d
|v r3|d
   D 
cg c]!  }
t        j                  j                  |
      # c}
|d
<   t        || j                  |       | j                   |d<   t#        |      S c c}w c c}	w c c}
w )NrL   rK   rp   r[   z
service:{}r{   r   rb   rd   r   r   )r   r   rn  popr%   r  r  r   r   parse_networksr!   r	   ServiceSecretr   normalize_buildrq   r   normalize_v1_service_format)r0  r/  r   rL   r   r  vfr{   rt   r   cs              r   r-  r-    s   --.L$
l(B&9,U`&a]#T*% #>2(
   ]G<(
^$
 ,L+FL#''.=lKn=+7+>+>~+NL(+7L(\!#1,z2J#KZ L "4\)5L"MYL 2>y2I#
-.E%%a(#
Y L 2>y2I#
-.E%%a(#
Y L."<"<kJ)..L&|44E(
,#

#
s   F0&F	'&Fc                     d| v sd| v r-d| vri | d<   d| v r| d   | d   d<   | d= d| v r| d   | d   d<   | d= d| v r:| j                  di       | d<   | d   j                  d| j                  d      i       | S )Nrx   ry   rz   r  optionsrv   rs   )r   rk  r  )r  s    r   r  r    s    |#yL'@L(&(L#<'0<\0JL#H-\*$1=i1HL#I.Y'|# , 0 0" =WW$$,**<8&
 	 r   c                 T    t        | ||      }d|v r
|d   |d<   |S d| v r| d   |d<   |S )zWhen merging services from multiple files we need to merge the `extends`
    field. This is not handled by `merge_service_dicts()` which is used to
    perform the `extends`.
    rS  )r^  )r8  r9  r   new_services       r   r7  r7    sO    
 &dHg>KH!))!4I  
d	!%iIr   c                   8    e Zd ZdZd Zd Zd	dZd	dZd Zd Z	y)
	MergeDictz>A dict-like object responsible for merging two dicts into one.c                      || _         || _        y r   r8  r9  )r   r8  r9  s      r   rM  zMergeDict.__init__   s    	 r   c                 >    || j                   v xs || j                  v S r   r  r   r  s     r   needs_mergezMergeDict.needs_merge  s    		!;Udmm%;;r   Nc                     | j                  |      sy  || j                  j                  ||      | j                  j                  ||            | |<   y r   )r  r8  r   r9  )r   r  
merge_funcdefaults       r   merge_fieldzMergeDict.merge_field  sG    & IIMM%)MMeW-/Ur   c                     | j                  |      sy |d } || j                  j                  |            | |<   | |   j                   || j                  j                  |                   y )Nc                     | xs i S r   r   ms    r   
parse_funcz+MergeDict.merge_mapping.<locals>.parse_func  s    wBr   )r  r8  r   rk  r9  )r   r  r  s      r   merge_mappingzMergeDict.merge_mapping  sa    & !u!56UU:dmm&7&7&>?@r   c                 T   fd}| j                  |      sy  || j                  j                  |g             }|j                   || j                  j                  |g                    t        |j                               D cg c]  }|j                          c}| |<   y c c}w )Nc                 .    t        fd| D        d      S )Nc              3   .   K   | ]  } |        y wr   r   )r   itemr  s     r   r   zHMergeDict.merge_sequence.<locals>.parse_sequence_func.<locals>.<genexpr>  s     @Dz$/@   r  )
to_mapping)seqr  s    r   parse_sequence_funcz5MergeDict.merge_sequence.<locals>.parse_sequence_func  s    @C@-PPr   )r  r8  r   rk  r9  r   valuesr  )r   r  r  r  mergedr  s     `   r   merge_sequencezMergeDict.merge_sequence  s    	Q &$TYY]]5"%=>)$--*;*;E2*FGH/5fmmo/FGttyy{GUGs   B%c                     | j                  |      r9| j                  j                  || j                  j                  |            | |<   y y r   )r  r9  r   r8  r  s     r   merge_scalarzMergeDict.merge_scalar%  s<    E"--++E499==3GHDK #r   r   )
r   r   r   r   rM  r  r  r  r  r  r   r   r   r  r    s&    H!</	A	HIr   r  c                 B   t        | |      }|j                  dt               |j                  dt               |j                  dt               |j                  dt
               |j                  dt               |j                  dt               |j                  dt        j                         |j                  dt        j                  j                         |j                  d	t        j                  j                         |j                  d
t        j                  j                         |j                  dt               |j                  dt         i        dD ]  }|j                  |t"                dD ]  }|j                  |t$        g         dD ]  }|j                  |t&                |j                  dt(        i        t+        || |       |j                  dt,        i        |j                  dt.        i        |j                  dt0        i        t3        t4              t3        |      z
  D ]  }|j7                  |        |t8        k(  rt;        || |       tA        |      S |j=                  d      rt?        || |      |d<   tA        |      S )NrL   rT   ulimitsrj   rv  storage_optrU   rd   r   re   rM   r   r  )ro   rE   )r6   r7   exposeexternal_linksrp   rD   r}   )rF   rG   rK   r  rz   rr   rP   deployrs   )!r  r  rl  r  parse_flat_dictr  parse_depends_onr  r#   r  r	   r  r   r"   r    r  merge_networksmerge_path_mappingsmerge_unique_items_listsmerge_list_or_stringmerge_loggingmerge_portsmerge_blkio_configmerge_healthchecksmerge_deployr6  ALLOWED_KEYSr  r   legacy_v1_merge_image_or_buildr  merge_buildr   )r8  r9  r   mdr  s        r   r^  r^  *  s-   	4	"B]$56X|,Y0Y.\#34]O4g{001i!4!4!:!:;i!4!4!:!:;ne&7&7&=&=>]$56NN:~rN:' 3
u123 D 	u6C	D < 4
u234 NN9mRN8D(#NN>#5rNBNN="4bNANN8\2N6\"SW, 
 "}&r4: 8O 
	 !"dH578Or   c                 b    d |D        }d | D        } t        t        t        | |                  S )Nc              3   2   K   | ]  }t        |        y wr   r   )r   r  s     r   r   z+merge_unique_items_lists.<locals>.<genexpr>X  s     )1A)   c              3   2   K   | ]  }t        |        y wr   r  )r   bs     r   r   z+merge_unique_items_lists.<locals>.<genexpr>Y  s     !qCF!r  )r   r6  r   r  s     r   r  r  W  s-    ))H!D!D#eD(+,--r   c                 r    |j                  d      du r|S | j                         }|j                  |       |S )NdisabledT)r   copyrk  )r8  r9  results      r   r  r  ]  s4    ||J4'YY[F
MM(Mr   c                 L   d }d}| j                  |      sy  || j                  j                  |g             }|j                   || j                  j                  |g                    t        |j                         t        d            D cg c]  }| c}| |<   y c c}w )Nc                 |    | D cg c]  }t        j                  |      D ]  }|   }}}t        |d      S c c}}w )Nr  )r$   r  r  )r  r  r   accs       r   r  z(merge_ports.<locals>.parse_sequence_funcf  s?     BT+*;*;D*ABQqBqBB#}-- Cs   #8r_   targetr   )r  r8  r   rk  r9  r   r  r   )r  r8  r9  r  r  r  r  s          r   r  r  e  s    . E>>%  UB!78F
MM%bkkooeR&@AB"(j>R"ST$TBuITs   	B!c                    d }t         ||       ||            }|j                  d       |j                  d       |j                  d       |j                  d       |j                  d       |j                  d       |j                  dt               |j	                  d	t
        g 
       |j                  dt               |j                  dt               t        |      S )Nc                 R    | j                  di       }t        |t              rd|iS |S )Nrs   r  )r   r   r   )rD  build_configs     r   to_dictzmerge_build.<locals>.to_dictu  s-    {{7B/lC(|,,r   r  rv   rF  r  rf   rS   rs  
cache_fromr  rT   rM   )	r  r  r  rq  r  r  r  r    r   )outputr8  r9  r
  r  s        r   r  r  t  s     
74='("3	4BOOIOOL!OOIOOHOOJOOK V23NN<!92NFX|,]$568Or   c                    t        | xs i |xs i       }|j                  d       |j                  d       |j                  d       |j                  dt               |j                  d       |j                  d       |j                  d       |j	                  d      r}t        |j
                  j                  d      xs i |j                  j                  d      xs i       }|j                  d	       |j                  d
t        i        t        |      |d<   |j	                  d      rt        |j
                  j                  d      xs i |j                  j                  d      xs i       }|j                  d       |j                  dt        g        |j                  dt        g        t        |      |d<   t        |      S )Nmodeendpoint_modereplicasrT   update_configrollback_configrestart_policy	resourceslimitsreservationsr  	placementmax_replicas_per_nodeconstraintspreferences)r  r  r  r  r  r8  r   r9  r  merge_reservationsr   r  merge_unique_objects_lists)r8  r9  r  resources_mdplacement_mds        r   r  r    sx   	4:2x~2	.BOOFOOO$OOJX|,_%&'%&	~~k" [!9!?RQ\A]Acacd""8,  1CR P|,;	~~k" [!9!?RQ\A]Acacd!!"9:  0HRT U  0JTV W|,;8Or   c                 (   i }t        |       t        |      z  }t        | t              r| D ci c]  }|i  c}n| } t        |t              r|D ci c]  }|i  c}n|}|D ]  }t        | j	                  |      xs i |j	                  |      xs i       }|j                  dt        g        |j                  dt        g        |j                  d       |j                  d       |j                  d       t        |      ||<    |S c c}w c c}w )Naliaseslink_local_ipspriorityipv4_addressipv6_address)	r6  r   r  r  r   r  r  r  r   )r8  r9  merged_networksall_network_namesr$  network_namer  s          r   r  r    s    OD	CM1$.tT$:4 aArE D,6x,Fx(!2(HH) 1txx-3X\\,5O5USUV
y":B?
')A2F

#
'
'(,R%1  !(s   
D

Dc                     t        | |      }|j                  d       |j                  d       |j                  dt        j                  j
                         |j                  dt        g        t        |      S )NrA   memorygeneric_resourcesrE   r  )	r  r  r  r	   GenericResourcer  r  r  r   r8  r9  r  s      r   r  r    s_    	4	"BOOFOOH)5+@+@+F+FGNN98"NE8Or   c                     | |z   D ci c]  }t        |      | }}t        d |j                         D        t        d            D cg c]  }|d   	 c}S c c}w c c}w )Nc              3   *   K   | ]  \  }}||f  y wr   r   )r   r$  ri  s      r   r   z-merge_unique_objects_lists.<locals>.<genexpr>  s     !DTQ1a&!Ds   r   r  r   )r   r   r  r   )r8  r9  ir  s       r   r  r    sV    '+h7!ilAo7F7 !DV\\^!D*UV-XYQAaDYY 8Ys   A
Ac                     t        | |      }|j                  d       d }dD ]  }|j                  ||g         t        |      S )Nweightc                     t        d      | D ci c]  } |      | }}|j                  fd|D               t        |j                               S c c}w )Nr   c              3   2   K   | ]  } |      |f  y wr   r   )r   r  get_paths     r   r   zAmerge_blkio_config.<locals>.merge_blkio_limits.<locals>.<genexpr>  s     8!hqk1%8s   r  )r   rk  r   r  )r8  r9  r  indexr4  s       @r   merge_blkio_limitsz.merge_blkio_config.<locals>.merge_blkio_limits  sR    f%)-.A!a..8x88elln(33 /s   A)r  r  r  r  weight_devicer  )r  r  r  r   )r8  r9  r  r6  r  s        r   r  r    sP    	4	"BOOH4 > 	u0"=	> 8Or   c                 B   t        | |      }|j                  d       |j                  d      | j                  d      k(  s| j                  d      |j                  dd        t	        |      S |j                  d      r|j                  di       |d<   t	        |      S )Nr  r  c                     | xs i S r   r   r  s    r   <lambda>zmerge_logging.<locals>.<lambda>  s
    ag2 r   )r  r  r   r  r   r,  s      r   r  r    s    	4	"BOOH	vvh488H--(1C1K
$56 8O 
i	  Y398Or   c                     | j                  dd        | j                  dd        d|v r	|d   | d<   y d|v r	|d   | d<   y d|v r	|d   | d<   y d|v r	|d   | d<   y y )NrQ   rs   )r  )r  r8  r9  s      r   r  r    sw    
JJw
JJw("7+w	H	"7+w	Dw-w	Dw-w 
r   c                 P    t        |       }|j                  t        |             |S r   )rl  rk  )r8  r9  rm  s      r   merge_environmentr=    s#    
D
!CJJ *+Jr   c                 P    t        |       }|j                  t        |             |S r   )r  rk  )r8  r9  rT   s      r   merge_labelsr?    s"    $F
MM,x()Mr   c                 6    d| v r| j                  dd      S | dfS )N=r    )split)kvpairs    r   split_kvrE    s$    
f}||C##rzr   c                      |si S t        |t              rt         fd|D              S t        |t              rt        |      S t        |d|d      )Nc              3   .   K   | ]  } |        y wr   r   )r   e
split_funcs     r   r   z%parse_dict_or_list.<locals>.<genexpr>  s     5aJqM5r  z "z" must be a list or mapping,)r   r  r   r   )rI  	type_name	argumentss   `  r   parse_dict_or_listrL    sQ    	)T"59555)T"I
	I	 r   zbuild argumentsrL   rT   c                 
    | d fS r   r   r$  s    r   r:  r:    s
    !T r   r   rj   c                     | ddifS )Nr  r  r   rN  s    r   r:  r:    s    1{4E&F"G r   rv  c                 V    | si S t        | t              rt        |       S t        d      )NzInvalid type: expected mapping)r   r   r   )ds    r   r  r    s)    	!TAw
=
>>r   c                 0    || |fS |r| |v r| ||    fS | d fS r   r   )r   valrL   s      r   rg  rg  !  s4    
Cx	+K$$$Dyr   c                 F    |d   D cg c]  }t        | |       c}S c c}w r   )resolve_volume_path)rq   r  rE  s      r   r  r  *  s0     #9- 	K0  s   c                    t        |t              r=|j                  dd      j                  d      r|d   dk(  rt	        | |d         |d<   |S d }t        |      \  }}|c|\  }}||S |j                  d      rt	        | |      }t        j                  j                  |      }dj                  |||r	d|z         S d      S |S )	NsourcerB  ).~typer  rX  z{}:{}{}:)
r   r   r   r   r  split_path_mappingr   r   r   r   )rq   rE  mount_paramscontainer_path	host_pathr  s         r   rU  rU  1  s    &$::h#..z:vf~QW?W*;x8HIF8L#5f#= NL&	4!!$#K;IGG&&y1		>$C$JXXTVXXr   c                     d| v roi }t        | d   t              r| j                  d      |d<   n?|j                  | d          d|v r't	        t        |j                  d      |            |d<   || d<   y y )Nrs   r  rs  )r   r   r  rk  r   rt  r   )r  rq   rL   rs   s       r   r  r  F  s}    ,l7+S1+//8E)LLg./ 1&uyy'8+F!f !&W r   c                 4    t        |      r|S t        | |      S r   )is_urlr  )rq   
build_paths     r   r  r  W  s    j{J//r   c                 ,    | j                  t              S r   )r   DOCKER_VALID_URL_PREFIXES)rc  s    r   rb  rb  ]  s      !:;;r   c                 H   d| v r| j                  di       }t        |t              r|}nt        |t              r
d|v r|d   }ny t	        |      sRt
        j                  j                  |      r$t        j                  |t
        j                        st        d|z        y y y )Nrs   r  zNbuild path %s either does not exist, is not accessible, or is not a valid URL.)r   r   r   r   rb  r   r   r   accessR_OKr   )r  rs   rc  s      r   r~  r~  a  s    ,  "-eS!Jt$e);y)J  z"
+299Z3Q$)+567 7 4R # r   c                 b    t        |       }|j                  t        |             t        |      S r   )dict_from_path_mappingsrk  path_mappings_from_dict)r8  r9  rQ  s      r   r  r  v  s)    %AHH$X./"1%%r   c                 .    | rt        d | D              S i S )Nc              3   2   K   | ]  }t        |        y wr   )r\  )r   ri  s     r   r   z*dict_from_path_mappings.<locals>.<genexpr>~  s     Aa&q)Ar  )r   )path_mappingss    r   rj  rj  |  s    A=AAA	r   c                 l    t        | j                               D cg c]  }t        |       c}S c c}w r   )r   r  join_path_mapping)rQ  ri  s     r   rk  rk    s'    *0*;<Qa <<<s   1c                    t        | t              r| j                  d      | fS t        |       \  }}d|v rJ|j	                  dd      \  }}t        |      \  }}d}d|v r|j                  dd      \  }}||z   ||z   |ffS | dfS )z
    Ascertain if the volume_path contains a host path as well as a container
    path. Using splitdrive so windows absolute paths won't cause issues with
    splitting on ':'.
    r  r[  r   N)r   r   r   r   rC  rsplit)volume_pathdrivevolume_confighost	containercontainer_driver^  r  s           r   r\  r\    s     +t$);77%k2E=
m)//Q7y*4Y*?'. #1#8#8a#@ ND.054<2FGGT""r   c                     | j                  dg       }g }|D ]&  }|j                  t        j                  |             ( |r|| d<   | S )Nre   )r   r  r"   r  )r  security_optsr  values       r   r  r    sR     $$^R8MF 0k''./0'-^$r   c                     | \  }}t        |t              r|S ||S |\  }}dj                  ||f      }|r|d|z   z  }|S )Nr[  )r   r   r   )pairrw  rv  r  r  s        r   rp  rp    sX    Y$	
d4+,cDj Fr   c                     t         j                  j                  t         j                  j                  | t         j                  j	                  |                  S r   )r   r   r   r   r   )rq   r   s     r   r  r    s3    77??277<<RWW5G5G5MNOOr   c                 0    t        |       t        |      z   S r   )r  r  s     r   r  r    s    4=78,,,r   c                 4    | g S t        | t              r| gS | S r   )r   r   )r{  s    r   r  r    s"    }		E3	wr   c                 B    | D ci c]  }t        ||      | c}S c c}w r   )r  )sequence	key_fieldr  s      r   r  r    s"    7?@tGD)$d*@@@s   c                 &    t        d | D              S )Nc              3   @   K   | ]  }|t         j                  v   y wr   )stringascii_uppercase)r   chars     r   r   z has_uppercase.<locals>.<genexpr>  s     ?$tv---?s   )anyr}  s    r   r  r    s    ?$???r   c                 x   	 t        | |rdnd|      5 }t        j                  |      cd d d        S # 1 sw Y   y xY w# t        t        j                  t
        f$ r\}|t        | dd      cY d }~S t        |dd      d	z   |j                  j                  z   }t        d
j                  ||            d }~ww xY w)Nrbr)encodingz	utf-8-sigF)r  binaryr   rB  rX  z{}: {})openr   r   OSError	YAMLErrorUnicodeDecodeErrorr   r  r   r   r   r   )r   r  r  fhrH  
error_names         r   r   r     s    
A(FDhG 	&2>>"%	& 	& 	&T^^%78 A XEJJQb1C7!++:N:NN
 Q!?@@As6   ? 3	? <? ? B9B4,B92AB44B9r   )T)NT)r<  rz   r   r   r  r   collectionsr   	itertoolsr   operatorr   r   r   r   ImportErrorrB  r	   constr   r   r   r   utilsr   r   r   r   r   r   r   rL   r   r   r   errorsr   r   r   r   r   interpolationr   sort_servicesr   r   r   r   r    r!   r"   r#   r$   r%   r&   
validationr'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   DOCKER_CONFIG_KEYSr  re  r   r   	getLoggerr   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r@  rB  r  r)  rn  rt  r]  r,  r*  r  r  r  r  r  r  r-  r  r7  r   r  r^  r  r  r  r  r  r  r  r  r  r  r  r=  r?  rE  rL  partialrq  rl  r  r  r  r  r  rg  r  rU  r  r  rb  r~  r  rj  rk  r\  r  rp  r  r  r  r  r  r   r   r   r   <module>r     ss     	 	  
 "    0)  + ( %   )  $ + $ " % ' & . ' < ? = -  $ %    !  + 6 / $ 0 + 2 , ) & - ) 4 1 (= ~ " % "  7  g!
J/1WX 
"SLM+<= SLlZ	#ef &J/1ST <("J"&
"'FTBY.*b	3lW Wt	LM
O4!(H F\2$6 "&+5\(
*I *IZ*Z.U*0 Z
(
(  *	))*<iIZ[ %I%%&8)]S  y  !3XxH"""#57JJW!	!!"4h	J$9$$G 
?*&"0<7*&=#,P-A@A}-  0//0s   L LL