
    Vh@j                         d dl mZmZmZ eZdZdZdZd dl	Z	d dl
Z
	 d dlmZmZ d dlmZmZ d dlmZmZ d d	lmZ d d
lmZ  G d de      Z G d de      Zd Zd Zedk(  r e        yy# e$ r Y Mw xY w)    )absolute_importdivisionprint_functiona  
module: docker_swarm
short_description: Manage Swarm cluster
description:
  - Create a new Swarm cluster.
  - Add/Remove nodes or managers to an existing cluster.
extends_documentation_fragment:
  - community.docker.docker
  - community.docker.docker.docker_py_1_documentation
  - community.docker.attributes
  - community.docker.attributes.actiongroup_docker

attributes:
  check_mode:
    support: full
  diff_mode:
    support: full
  idempotent:
    support: full

options:
  advertise_addr:
    description:
      - Externally reachable address advertised to other nodes.
      - This can either be an address/port combination in the form V(192.168.1.1:4567), or an interface followed by a port
        number, like V(eth0:4567).
      - If the port number is omitted, the port number from the listen address is used.
      - If O(advertise_addr) is not specified, it will be automatically detected when possible.
      - Only used when swarm is initialised or joined. Because of this it is not considered for idempotency checking.
    type: str
  default_addr_pool:
    description:
      - Default address pool in CIDR format.
      - Only used when swarm is initialised. Because of this it is not considered for idempotency checking.
      - Requires API version >= 1.39.
    type: list
    elements: str
  subnet_size:
    description:
      - Default address pool subnet mask length.
      - Only used when swarm is initialised. Because of this it is not considered for idempotency checking.
      - Requires API version >= 1.39.
    type: int
  listen_addr:
    description:
      - Listen address used for inter-manager communication.
      - This can either be an address/port combination in the form V(192.168.1.1:4567), or an interface followed by a port
        number, like V(eth0:4567).
      - If the port number is omitted, the default swarm listening port is used.
      - Only used when swarm is initialised or joined. Because of this it is not considered for idempotency checking.
    type: str
    default: 0.0.0.0:2377
  force:
    description:
      - Use with state V(present) to force creating a new Swarm, even if already part of one.
      - Use with state V(absent) to Leave the swarm even if this node is a manager.
    type: bool
    default: false
  state:
    description:
      - Set to V(present), to create/update a new cluster.
      - Set to V(join), to join an existing cluster.
      - Set to V(absent), to leave an existing cluster.
      - Set to V(remove), to remove an absent node from the cluster. Note that removing requires Docker SDK for Python >=
        2.4.0.
      - M(community.docker.docker_node) can be used to demote a manager before removal.
    type: str
    default: present
    choices:
      - present
      - join
      - absent
      - remove
  node_id:
    description:
      - Swarm id of the node to remove.
      - Used with O(state=remove).
    type: str
  join_token:
    description:
      - Swarm token used to join a swarm cluster.
      - Used with O(state=join).
      - If this value is specified, the corresponding value in the return values will be censored by Ansible. This is a side-effect
        of this value not being logged.
    type: str
  remote_addrs:
    description:
      - Remote address of one or more manager nodes of an existing Swarm to connect to.
      - Used with O(state=join).
    type: list
    elements: str
  task_history_retention_limit:
    description:
      - Maximum number of tasks history stored.
      - Docker default value is V(5).
    type: int
  snapshot_interval:
    description:
      - Number of logs entries between snapshot.
      - Docker default value is V(10000).
    type: int
  keep_old_snapshots:
    description:
      - Number of snapshots to keep beyond the current snapshot.
      - Docker default value is V(0).
    type: int
  log_entries_for_slow_followers:
    description:
      - Number of log entries to keep around to sync up slow followers after a snapshot is created.
    type: int
  heartbeat_tick:
    description:
      - Amount of ticks (in seconds) between each heartbeat.
      - Docker default value is V(1) seconds.
    type: int
  election_tick:
    description:
      - Amount of ticks (in seconds) needed without a leader to trigger a new election.
      - Docker default value is V(10) seconds.
    type: int
  dispatcher_heartbeat_period:
    description:
      - The delay (in nanoseconds) for an agent to send a heartbeat to the dispatcher.
      - Docker default value is 5 seconds, which corresponds to a value of V(5000000000).
    type: int
  node_cert_expiry:
    description:
      - Automatic expiry for nodes certificates, given in nanoseconds.
      - Docker default value is 90 days, which corresponds to a value of V(7776000000000000).
    type: int
  name:
    description:
      - The name of the swarm.
    type: str
  labels:
    description:
      - User-defined key/value metadata.
      - Label operations in this module apply to the docker swarm cluster. Use M(community.docker.docker_node) module to add/modify/remove
        swarm node labels.
      - Requires API version >= 1.32.
    type: dict
  signing_ca_cert:
    description:
      - The desired signing CA certificate for all swarm node TLS leaf certificates, in PEM format.
      - This must not be a path to a certificate, but the contents of the certificate.
      - Requires API version >= 1.30.
    type: str
  signing_ca_key:
    description:
      - The desired signing CA key for all swarm node TLS leaf certificates, in PEM format.
      - This must not be a path to a key, but the contents of the key.
      - Requires API version >= 1.30.
    type: str
  ca_force_rotate:
    description:
      - An integer whose purpose is to force swarm to generate a new signing CA certificate and key, if none have been specified.
      - Docker default value is V(0).
      - Requires API version >= 1.30.
    type: int
  autolock_managers:
    description:
      - If set, generate a key and use it to lock data stored on the managers.
      - Docker default value is V(false).
      - M(community.docker.docker_swarm_info) can be used to retrieve the unlock key.
    type: bool
  rotate_worker_token:
    description: Rotate the worker join token.
    type: bool
    default: false
  rotate_manager_token:
    description: Rotate the manager join token.
    type: bool
    default: false
  data_path_addr:
    description:
      - Address or interface to use for data path traffic.
      - This can either be an address in the form V(192.168.1.1), or an interface, like V(eth0).
      - Only used when swarm is initialised or joined. Because of this it is not considered for idempotency checking.
      - Requires API version >= 1.30.
    type: str
    version_added: 2.5.0
  data_path_port:
    description:
      - Port to use for data path traffic.
      - This needs to be a port number like V(9789).
      - Only used when swarm is initialised. Because of this it is not considered for idempotency checking.
      - Requires API version >= 1.40.
    type: int
    version_added: 3.1.0

requirements:
  - "L(Docker SDK for Python,https://docker-py.readthedocs.io/en/stable/) >= 1.10.0"
  - Docker API >= 1.25
author:
  - Thierry Bouvet (@tbouvet)
  - Piotr Wojciechowski (@WojciechowskiPiotr)
a  
---
- name: Init a new swarm with default parameters
  community.docker.docker_swarm:
    state: present

- name: Update swarm configuration
  community.docker.docker_swarm:
    state: present
    election_tick: 5

- name: Add nodes
  community.docker.docker_swarm:
    state: join
    advertise_addr: 192.168.1.2
    join_token: SWMTKN-1--xxxxx
    remote_addrs: ['192.168.1.1:2377']

- name: Leave swarm for a node
  community.docker.docker_swarm:
    state: absent

- name: Remove a swarm manager
  community.docker.docker_swarm:
    state: absent
    force: true

- name: Remove node from swarm
  community.docker.docker_swarm:
    state: remove
    node_id: mynode

- name: Init a new swarm with different data path interface
  community.docker.docker_swarm:
    state: present
    advertise_addr: eth0
    data_path_addr: ens10

- name: Init a new swarm with a different data path port
  community.docker.docker_swarm:
    state: present
    data_path_port: 9789
a  
swarm_facts:
  description: Information about swarm.
  returned: success
  type: dict
  contains:
    JoinTokens:
      description: Tokens to connect to the Swarm.
      returned: success
      type: dict
      contains:
        Worker:
          description:
            - Token to join the cluster as a new *worker* node.
            - B(Note:) if this value has been specified as O(join_token), the value here will not be the token, but C(VALUE_SPECIFIED_IN_NO_LOG_PARAMETER).
              If you pass O(join_token), make sure your playbook/role does not depend on this return value!
          returned: success
          type: str
          example: SWMTKN-1--xxxxx
        Manager:
          description:
            - Token to join the cluster as a new *manager* node.
            - B(Note:) if this value has been specified as O(join_token), the value here will not be the token, but C(VALUE_SPECIFIED_IN_NO_LOG_PARAMETER).
              If you pass O(join_token), make sure your playbook/role does not depend on this return value!
          returned: success
          type: str
          example: SWMTKN-1--xxxxx
    UnlockKey:
      description: The swarm unlock-key if O(autolock_managers=true).
      returned: on success if O(autolock_managers=true) and swarm is initialised, or if O(autolock_managers) has changed.
      type: str
      example: SWMKEY-1-xxx

actions:
  description: Provides the actions done on the swarm.
  returned: when action failed.
  type: list
  elements: str
  example: ['This cluster is already a swarm cluster']
N)DockerExceptionAPIError)DockerBaseClassRequestException)DifferenceTrackersanitize_labels)AnsibleDockerSwarmClient)	to_nativec                   @     e Zd Z fdZed        Zd Zd Zd Z xZ	S )TaskParametersc                    t         t        |           d | _        d | _        d | _        d | _        d | _        d | _        d | _	        d | _
        d | _        d | _        d | _        d | _        d | _        d | _        d | _        d | _        d | _        d | _        d | _        d | _        d | _        d | _        d | _        d | _        d | _        y N)superr   __init__advertise_addrlisten_addrremote_addrs
join_tokendata_path_addrdata_path_portsnapshot_intervaltask_history_retention_limitkeep_old_snapshotslog_entries_for_slow_followersheartbeat_tickelection_tickdispatcher_heartbeat_periodnode_cert_expirynamelabels
log_driversigning_ca_certsigning_ca_keyca_force_rotateautolock_managersrotate_worker_tokenrotate_manager_tokendefault_addr_poolsubnet_size)self	__class__s    q/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/community/docker/plugins/modules/docker_swarm.pyr   zTaskParameters.__init__=  s    nd,." "" "&,0)"&.2+"!+/( $	#"#!%#' $(!!%    c                     t               }| j                  j                  j                         D ]!  \  }}||j                  v st        |||       # |j                  |        |S r   )r   moduleparamsitems__dict__setattrupdate_parameters)clientresultkeyvalues       r/   from_ansible_paramsz"TaskParameters.from_ansible_params\  s]    ! --..446 	,JCfoo%U+	, 	  (r0   c                 z   |d   }|j                  d      xs
 t               }| j                  |j                  d      | _        | j                  |j                  d      | _        |j                  d      xs
 t               }| j                  |j                  d      | _        |j                  d      xs
 t               }| j
                  |j                  d      | _        | j                  |j                  d	      | _        | j                  |j                  d
      | _        | j                  |j                  d      | _        | j                  |j                  d      | _	        |j                  d      xs
 t               }| j                  |j                  d      | _
        |j                  d      xs
 t               }| j                  |j                  d      | _        | j                  
|d   | _        | j                  |j                  d      xs i | _        d|d   v r|d   d   | _        y y )NSpecCAConfigNodeCertExpiryForceRotate
DispatcherHeartbeatPeriodRaftSnapshotIntervalKeepOldSnapshotsHeartbeatTickLogEntriesForSlowFollowersElectionTickOrchestrationTaskHistoryRetentionLimitEncryptionConfigAutoLockManagersNameLabels	LogDriverTaskDefaults)getdictr!   r'   r    r   r   r   r   r   r   r(   r"   r#   r$   )r-   
swarm_infospec	ca_config
dispatcherraftorchestrationencryption_configs           r/   update_from_swarm_infoz%TaskParameters.update_from_swarm_infof  s   &!HHZ(2DF	  ($-MM2B$CD!'#,==#?D XXl+5tv
++3/9~~>O/PD,xx)46!!)%)XX.@%AD"""*&*hh/A&BD#&"&((?";D..626((;W2XD/%!%.!9D1;TV,,40=0A0AB]0^D- HH%78BDF!!)%6%:%:;M%ND"99VDI;;((8,2DK$~..">2;?DO /r0   c                     t        ddddddddd	d
ddddd      }t               }|j                         D ],  \  }}|j                  |   d   st        | |      }|(|||<   .  |j                  di || _        y )Nr   r   r   r   r   r   r    r!   r"   r#   r%   r&   r'   r(   r$   )r   r   r   r   r   r   r    r!   r"   r#   r%   r&   r'   r(   r$   	supported )rS   r4   option_minimal_versionsgetattrcreate_swarm_specrU   )r-   r8   assignr3   destsourcer;   s          r/   r7   z TaskParameters.update_parameters  s    1)G3+K+)(E/-+-1#
" "LLN 	%LD&11&9+FD&)E $t	% -F,,6v6	r0   c                 B   | j                   D ]O  }|dv r|j                  |   d   st        | |      }|*t        ||      }||k7  s<|j                  |||       Q | j                  r|j                  ddd       | j
                  r|j                  ddd       |S )N)r   r   r   r   r)   r*   rU   r+   r,   r   r   r]   	parameteractiver)   TFr*   )r5   r_   r`   addr)   r*   )r-   otherr8   differenceskr;   other_values          r/   compare_to_activez TaskParameters.compare_to_active  s     	HA ' ' 11!4[AD!$E}!%+K#U;G	H ##OO1T%OP$$OO2d5OQr0   )
__name__
__module____qualname__r   staticmethodr<   r[   r7   rn   __classcell__r.   s   @r/   r   r   <  s-     >  (@T76r0   r   c                   T     e Zd Z fdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Z xZS )SwarmManagerc                    t         t        |           || _        || _        | j                  j
                  | _        i | _        |j                  j                  d   | _	        |j                  j                  d   | _
        |j                  j                  d   | _        t               | _        t        j                  |      | _        d| _        y )Nstateforcenode_idF)r   rv   r   r8   results
check_moderT   r2   r3   rx   ry   rz   r
   rk   r   r<   
parameterscreated)r-   r8   r{   r.   s      r/   r   zSwarmManager.__init__  s    lD*,++00]]))'2
]]))'2
}}++I6,.(<<VDr0   c                    | j                   | j                  | j                  | j                  d} |j	                  | j
                                | j                  j                  j                  s| j                  j                  r=t               }| j                  j                         \  |d<   |d<   || j                  d<   y y )Npresentjoinabsentremovebeforeafterdiff)
init_swarmr   leaver   rR   rx   r8   r2   _diffr}   debugrS   rk   get_before_afterr{   )r-   
choice_mapr   s      r/   __call__zSwarmManager.__call__  s    IIjjkk	

 	#
tzz"$;;##t'<'<6D,0,<,<,M,M,O)DNDM#'DLL  (=r0   c                 `   	 | j                   j                         }t        j                  |d      }t        j                  |      | _        d| j                  d<   | j
                  | j                  d<   | j                         }| j
                  j                  |       y # t        $ r Y y w xY w)NF)ensure_asciichangedswarm_facts)
r8   inspect_swarmjsondumpsloadsrT   r{   get_unlock_keyupdater   )r-   datajson_str
unlock_keys       r/   r   zSwarmManager.inspect_swarm  s    	;;,,.Dzz$U;H"jj2DO&+DLL#*.//DLL',,.JOO"":. 		s   BB! !	B-,B-c                     dd i}| j                         s|S 	 | j                  j                         xs |S # t        $ r |cY S w xY w)N	UnlockKey)has_swarm_lock_changedr8   r   r   )r-   defaults     r/   r   zSwarmManager.get_unlock_key  sN    %**,N	;;--/:7: 	N	s   6 AAc                     | j                   j                  xr) | j                  xs | j                  j	                  d      S )Nr(   )r}   r(   r~   rk   has_difference_for)r-   s    r/   r   z#SwarmManager.has_swarm_lock_changed  s7    00 
LLTD,,??@ST	
r0   c                 Z   | j                   s+| j                  j                         r| j                          y | j                  s&| j
                  j                  | j
                  j                  | j                   | j
                  j                  d}| j
                  j                  | j
                  j                  |d<   | j
                  j                  | j
                  j                  |d<   | j
                  j                  | j
                  j                  |d<   | j
                  j                  | j
                  j                  |d<   	  | j                  j                  di | | j                  j                         s'| j                  s| j                  j                  d       d| _        | j%                          | j&                  d	   j)                  d
| j*                  j-                  d      z         | j.                  j1                  ddd       d| j&                  d<   | j*                  j-                  d      | j*                  j-                  d      d| j&                  d<   y # t        $ r2}| j                  j                  dt!        |      z         Y d }~:d }~ww xY w)N)r   r   force_new_cluster
swarm_specr+   r,   r   r   z&Can not create a new Swarm Cluster: %sz!Swarm not created or other error!TactionszNew Swarm cluster created: %sIDrx   r   r   rf   r   
JoinTokensr   )r   r   r   r^   )ry   r8   check_if_swarm_manager_SwarmManager__update_swarmr|   r}   r   r   rU   r+   r,   r   r   r   r   failr   r~   r   r{   appendrT   rR   rk   ri   )r-   init_argumentsexcs      r/   r   zSwarmManager.init_swarm   s   zzdkk@@B!"&//"@"@#::%)ZZ"oo22	N 00<6:oo6W6W23**6040K0K}---937??3Q3Q/0--937??3Q3Q/0\&&&88 {{113??  !DEY&&'F$//J]J]^bJc'deW	(K"&Y//--l;,,[9'
]#  \  !IIVYN!Z[[\s   I/ /	J*8'J%%J*c                    	 | j                          | j                  d   d   }| j                  j                  | j                         t	               }|j                  | j                         | j                  j                  || j                  | j                         | j                  j                  r.| j                  d   j                  d       d| j                  d<   y t        j                  | j                        }|j                  | j                         | j                  sQ| j                  j                  ||j                  | j                  j                   | j                  j"                         | j                          | j                  d   j                  d	       d
| j                  d<   y # t$        $ r1}| j                  j'                  dt)        |      z         Y d }~y d }~ww xY w)NVersionIndexr   zNo modificationFr   )versionr   r)   r*   z"Can not update a Swarm Cluster: %szSwarm cluster updatedT)r   rT   r}   r[   r   rn   r8   rk   emptyr{   r   r<   r7   r|   update_swarmrU   r)   r*   r   r   r   )r-   r   old_parametersr7   r   s        r/   __update_swarmzSwarmManager.__update_swarm'  s   	 ooi09GOO224??C+-N11$//BOO--ndkk4K[K[\%%Y'../@A*/Y' . B B4;; O//<??((#0A0F0F(,(K(K)-)M)M ) O 	Y&&'>?"&Y  	KKAIcNRS	s   C F8 #BF8 8	G2'G--G2c                    | j                   j                         r| j                  d   j                  d       y | j                  s| j
                  j                  | j
                  j                  | j
                  j                  | j
                  j                  d}| j
                  j                  | j
                  j                  |d<   	  | j                   j                  di | | j                  d   j                  d       | j                  j!                  ddd	
       d| j                  d<   y # t        $ r1}| j                   j                  dt        |      z         Y d }~d }~ww xY w)Nr   z%This node is already part of a swarm.)r   r   r   r   r   z"Can not join the Swarm Cluster: %sz"New node is added to swarm clusterjoinedTFrf   r   r^   )r8   check_if_swarm_noder{   r   r|   r}   r   r   r   r   r   
join_swarmr   r   r   rk   ri   )r-   join_argumentsr   s      r/   r   zSwarmManager.joinB  s*   ;;**,LL#**+RS $ < <"oo88#::"&//"@"@	N --937??3Q3Q/0X&&&88 	Y&&'KLXeD"&Y	  X  !E	RU!VWWXs   D5 5	E/>'E**E/c                    | j                   j                         s| j                  d   j                  d       y | j                  s'	 | j                   j                  | j                         | j                  d   j                  d       | j                  j                  ddd	       d
| j                  d<   y # t        $ r1}| j                   j                  dt        |      z         Y d }~d }~ww xY w)Nr   z!This node is not part of a swarm.)ry   z-This node can not leave the Swarm Cluster: %szNode has left the swarm clusterr   r   r   rf   Tr   )r8   r   r{   r   r|   leave_swarmry   r   r   r   rk   ri   )r-   r   s     r/   r   zSwarmManager.leaveW  s    {{..0LL#**+NOc''djj'9 	Y&&'HIX)L"&Y	  c  !PS\]`Sa!abbcs   &B9 9	C3'C..C3c                    | j                   j                         s| j                   j                  d       	 | j                   j                  | j                  d      }|s| j                   j                  d       | j                  s2	 | j                   j                  | j                  | j                         | j                  d   j                  d       | j                  j                  d	d
d       d| j                  d<   y # t
        $ r Y y w xY w# t
        $ r1}| j                   j                  dt        |      z         Y d }~d }~ww xY w)NzThis node is not a manager.   )rz   repeat_checkz?Can not remove the node. The status node is ready and not down.)rz   ry   z2Can not remove the node from the Swarm Cluster: %sr   z#Node is removed from swarm cluster.r   FTrf   r   )r8   r   r   check_if_swarm_node_is_downrz   r   r|   remove_nodery   r   r{   r   rk   ri   )r-   status_downr   s      r/   r   zSwarmManager.removed  s   {{113KK:;	++AA$,,efAgK KK^_h''DJJ'O 	Y&&'LMXtD"&Y  		  h  !UXabeXf!fgghs)   'D 1D 	DD	E'E		E)ro   rp   rq   r   r   r   r   r   r   r   r   r   r   rs   rt   s   @r/   rv   rv     s6    $(

%
N'6'*''r0   rv   c                 :    | j                   j                  d   dk(  S )Nrx   r   )r2   r3   )r8   s    r/   _detect_remove_operationr   z  s    ==(H44r0   c                  L   t        dAi dt        d      dt        d      dt        d      dt        ddg d	
      dt        dd      dt        dd      dt        dd      dt        dd      dt        d      dt        d      dt        d      dt        d      dt        d      dt        d      dt        d      dt        d      dt        d      d t        d!      d"t        d      d#t        dd      d$t        d      d%t        d      d&t        d      d't        dd      d(t        dd      d)t        dd      d*t        d      } dd+ddgfdd,d&gfg}t        t        d-d./      t        d-d0/      t        d-d0/      t        d-d0/      t        d-1      t        d-1      t        d2t        d34      t        d5d6/      t        d5d6/      t        d5d0/      t        d7d8/      9      }t        | d|d:|;      }t        |j                  j
                  d    d |       	 t        dd<g =      } t        ||               |j                  j                  dAi | y # t        $ rG}|j                  d>j                  t        |            t        j                         ?       Y d }~y d }~wt        $ rG}|j                  d@j                  t        |            t        j                         ?       Y d }~y d }~ww xY w)BNr   str)typer   r   intrx   r   r   )r   r   choicesry   boolF)r   r   r   z0.0.0.0:2377r   list)r   elementsr   T)r   no_logr   r   r   r   r   r   r    r!   r"   r#   rS   r%   r&   r'   r(   rz   r)   r*   r+   r,   r   r   z2.6.0z1.32)docker_py_versiondocker_api_versionz1.30)r   z2.4.0zremove swarm nodes)r   detect_usage	usage_msgz4.0.0z1.39z6.0.0z1.40)r#   r%   r&   r'   r(   r$   remove_operationr+   r,   r   r   z1.10.0)argument_specsupports_check_moderequired_ifmin_docker_versionr_    )r   r9   r   z(An unexpected docker error occurred: {0})	exceptionzhAn unexpected requests error occurred when Docker SDK for Python tried to talk to the docker daemon: {0}r^   )rS   r   r   r   r2   r3   rv   	exit_jsonr   r   formatr   	traceback
format_excr	   )r   r   r_   r8   r{   es         r/   mainr   ~  s\    '' ' y:ab	
 . e^< v6 U40 E* &*u%5  U+ (,'7 ' & %)e$4  5)!" u#$  %& %('( t4)* %(+, F+-. % /0 !fe<12 "vu=34 FU;56 e$7M> 
&><89	(YK(K
 #g&Iw6Rg&Qw6R9'2%1*

 VT7vNg&Qg&Q$ &# # 7F FMM((2HfE.
 	&VW%'*'* w>EEiPQlS_h_s_s_uvv .v}}  H  IJ  K  L**, 	 	. 	..s$   	;J 	L#=KL#=LL#__main__)
__future__r   r   r   r   __metaclass__DOCUMENTATIONEXAMPLESRETURNr   r   docker.errorsr   r   ImportError@ansible_collections.community.docker.plugins.module_utils.commonr   r	   >ansible_collections.community.docker.plugins.module_utils.utilr
   r   ?ansible_collections.community.docker.plugins.module_utils.swarmr   +ansible.module_utils.common.text.convertersr   r   rv   r   r   ro   r^   r0   r/   <module>r      s    A @DL*X'
R  	7

 e AB_ BJv'? v'r5M.` zF I  		s   A* *A21A2