
     i_f                        d Z ddlZddlZddlmZ ddlmZmZ ddl	m
Z
mZ ddlmZ dd	lmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZ ddlZddl Z  e j!        d
          Z" G d de          Z# G d de
          Z$dS )a"
  
AMBER PRMTOP topology parser
============================

Reads an AMBER top file to build the system.

Amber keywords are turned into the following attributes:

+----------------------------+----------------------+
| AMBER flag                 | MDAnalysis attribute |
+============================+======================+
| ATOM_NAME                  | names                |
+----------------------------+----------------------+
| CHARGE                     | charges              |
+----------------------------+----------------------+
| ATOMIC_NUMBER              | elements             |
+----------------------------+----------------------+
| MASS                       | masses               |
+----------------------------+----------------------+
| BONDS_INC_HYDROGEN         | bonds                |
| BONDS_WITHOUT_HYDROGEN     |                      |
+----------------------------+----------------------+
| ANGLES_INC_HYDROGEN        | angles               |
| ANGLES_WITHOUT_HYDROGEN    |                      |
+----------------------------+----------------------+
| DIHEDRALS_INC_HYDROGEN     | dihedrals / improper |
| DIHEDRALS_WITHOUT_HYDROGEN |                      |
+----------------------------+----------------------+
| ATOM_TYPE_INDEX            | type_indices         |
+----------------------------+----------------------+
| AMBER_ATOM_TYPE            | types                |
+----------------------------+----------------------+
| RESIDUE_LABEL              | resnames             |
+----------------------------+----------------------+
| RESIDUE_POINTER            | residues             |
+----------------------------+----------------------+

TODO:
  Add support for Chamber-style topologies
  More stringent tests

.. Note::

   The Amber charge is converted to electron charges as used in
   MDAnalysis and other packages. To get back Amber charges, multiply
   by 18.2223.

   Chamber-style Amber topologies (i.e. topologies generated via parmed
   conversion of a CHARMM topology to an AMBER one) are not currently
   supported. Support will likely be added in future MDAnalysis releases.

   As of version 2.0.0, elements are no longer guessed if ATOMIC_NUMBER records
   are missing. In those scenarios, if elements are necessary, users will have
   to invoke the element guessers after parsing the topology file. Please see
   :mod:`MDAnalysis.guessers` for more details.

.. _`PARM parameter/topology file specification`:
   https://ambermd.org/FileFormats.php#topo.cntrl

Classes
-------

.. autoclass:: TOPParser
   :members:
   :inherited-members:

    N   )Z2SYMB)openanyFORTRANReader   )TopologyReaderBasechange_squash)Topology)	Atomnames	AtomtypesAtomidsChargesElementsMassesResnamesResidsResnumsSegidsChainIDsAtomAttrBondsAngles	Dihedrals	ImproperszMDAnalysis.topology.TOPParserc                       e Zd ZdZdZdZdZdS )TypeIndiceszNumerical type of each Atomtype_indices
type_indexatomN)__name__
__module____qualname____doc__attrnamesingularlevel     g/srv/www/vhosts/g4struct/public_html/venv/lib/python3.11/site-packages/MDAnalysis/topology/TOPParser.pyr   r   {   s#        %%HHEEEr(   r   c                   ~    e Zd ZdZg dZd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zd Zd ZdedefdZdS )	TOPParsera  Reads topology information from an AMBER top file.

    Reads the following Attributes if in topology:
    - Atomnames
    - Charges
    - Masses
    - Elements
    - Atomtypes
    - Resnames
    - Type_indices
    - Bonds
    - Angles
    - Dihedrals (inc. impropers)
    - ChainIDs (from %RESIDUE_CHAINID)
    - Segids (from %RESIDUE_CHAINID)

    The format is defined in `PARM parameter/topology file
    specification`_.  The reader tries to detect if it is a newer
    (AMBER 12?) file format by looking for the flag "ATOMIC_NUMBER".

    .. _`PARM parameter/topology file specification`:
       https://ambermd.org/FileFormats.php#topo.cntrl

    Additionally, the RESIDUE_CHAINID non-standard flag is supported. This
    can be added with the `addPDB`_ command from parmed:

    .. _`addPDB`: https://parmed.github.io/ParmEd/html/parmed.html#addpdb

    Notes
    -----
    Elements are obtained from the atomic numbers (if present). If a given
    input atomic number does not belong to an element (usually either -1 or 0),
    the element will be assigned an empty record.

    .. versionchanged:: 0.7.6
      parses both amber10 and amber12 formats
    .. versionchanged:: 0.19.0
      parses bonds, angles, dihedrals, and impropers
    .. versionchanged:: 1.0.0
      warns users that chamber-style topologies are not currently supported
    .. versionchanged:: 2.0.0
      no longer guesses elements if missing
    .. versionchanged:: 2.7.0
      gets Segments and chainIDs from flag RESIDUE_CHAINID, when present
    )TOPPRMTOPPARM7c                 b     dd j         ddfdd j        ddfdd j        ddfdd j        d	dfdd j        d
dfdd j        ddfdd j        ddfdd j        ddfdd j        ddfdd j        ddfdd j        ddfdd j        ddfdd j        ddfdd j        ddfdd j	        ddfd}i  t           j                  5  _        t           j                  }|                    d          s't          d                     j                            t           j                                                  }|d         dk    sP|d         dk    rd                      j                  }nd!                     j                  }t          |          |                    d"          s)t           j                  }|                    d"          )t           j                    fd#t%          d          D             }d$ |D             }t           j                  }|                    d%          d                                         }|	 ||         \  }	}
}}}||         |	z  }||
z  }||
z  dk    r|dz  } ||	|           |<    fd'}n# t(          $ r  fd(}Y nw xY w	  |            }|dk    r|                                s
 |            }	 |                    d%          d                                         }n;# t*          $ r d) j         d*}t+          |          d&w xY w# t,          $ r d&}Y nw xY w|d&d&d&           n# 1 swxY w Y   t/           d                   }                     d          }|                    |           t5          j        |t4          j        +          }t;          t=          |d&d,         |dd&                             D ]\  }\  }}||||<   t/           d                   }t?          d- tA          j!                             d                               d                    D                        d.<   tE          d/ tA          j!                             d                               d                    D                        d0<    #                                         d                               d                    \   d1<    d2<   d vr1d3}tH          %                    |           tM          j'        |           nSt5          j(         d         j)        d4k              r0d5}tH          %                    |           tM          j'        |           tU          t5          j+        |          dz              d6<   tY          t5          j+        |          dz              d7<   t[          t5          j+        |          dz              d8<   d v r~t/           d                   |k    ret]           d         f d         f          \  }\  } fd9|D             }t_          |           d<   ta          |           d:<   t/          |          }n~d v rJd;| d<t/           d                    d=}tH          %                    |           tM          j'        |           t_          t5          j1        d>gtd          +                     d<   d&}d}tg          |||ti           )                                          ||?          }|S )@z{Parse Amber PRMTOP topology file *filename*.

        Returns
        -------
        A MDAnalysis Topology object
        r      namer      charge
   elementsmassr   typesresname   respoint   bondhr   bonda   anghangadihh   diha   segids)	ATOM_NAMECHARGEATOMIC_NUMBERMASSATOM_TYPE_INDEXAMBER_ATOM_TYPERESIDUE_LABELRESIDUE_POINTERBONDS_INC_HYDROGENBONDS_WITHOUT_HYDROGENANGLES_INC_HYDROGENANGLES_WITHOUT_HYDROGENDIHEDRALS_INC_HYDROGENDIHEDRALS_WITHOUT_HYDROGENRESIDUE_CHAINIDz%VEz2{0} is not a valid TOP file. %VE Missing in headerTITLECTITLEze{0} is detected as a Chamber-style TOP file. At this time MDAnalysis does not support such topologiesz6{0} is not a valid TOP file. 'TITLE' missing in headerz%FLAG POINTERSc                 \    g | ](}t          j                                                  )S r'   )nexttopfilestrip).0iselfs     r)   
<listcomp>z#TOPParser.parse.<locals>.<listcomp>   s/    GGG$t|,,2244GGGr(   c                 Z    g | ](}|                                 D ]}t          |          )S r'   )splitint)r[   r\   ks      r)   r^   z#TOPParser.parse.<locals>.<listcomp>   s3    FFF1AGGIIFFqAFFFFr(   %FLAGNc                  ,    t           j                  S N)rX   rY   r]   s   r)   next_getterz$TOPParser.parse.<locals>.next_getter  s    #DL111r(   c                  ,                                      S re   )skipperrf   s   r)   rg   z$TOPParser.parse.<locals>.next_getter  s    #||~~-r(   z9%FLAG section not found, formatting error for PARM7 file  dtypec                     g | ]}|S r'   r'   r[   r\   s     r)   r^   z#TOPParser.parse.<locals>.<listcomp>4  s(          r(   bondsc                     g | ]}|S r'   r'   ro   s     r)   r^   z#TOPParser.parse.<locals>.<listcomp>=  s    NNN1QNNNr(   angles	dihedrals	improperszATOMIC_NUMBER record not found, elements attribute will not be populated. If needed these can be guessed using universe.guess_TopologyAttrs(to_guess=['elements']). zUnknown ATOMIC_NUMBER value found for some atoms, these have been given an empty element record. If needed these can be guessed using universe.guess_TopologyAttrs(to_guess=['elements']).atomidsresidsresnumsc                 ,    g | ]}d          |         S )rE   r'   )r[   rattrss     r)   r^   z#TOPParser.parse.<locals>.<listcomp>c  s"    ;;;qh*;;;r(   r   zNumber of residues (z-) does not match number of %RESIDUE_CHAINID (z). Skipping section.SYSTEM)r{   atom_resindexresidue_segindex)5parse_namesparse_chargesparse_elementsparse_massesparse_type_indicesparse_typesparse_resnamesparse_residxparse_bondedparse_chainidsr   filenamerY   rX   
startswith
ValueErrorformatr`   rangerZ   KeyError
IndexErrorStopIterationlenpopappendnpzerosint32	enumeratezipr   	itertoolschainr   parse_dihedralsloggerwarningwarningswarnanyvaluesr   aranger   r   r	   r   r   arrayobjectr
   list)!r]   kwargssectionsheadertitleemsg
topremarkssys_infonext_sectionnum_per_recordper_linefuncr1   sect_numnumnumlinesrg   lineerrmsgn_atomsresptrsresidxr\   xyn_resmsgsegidxrE   chainidsn_segstopr{   s!   `                               @r)   parsezTOPParser.parse   s    R!161=!T/1=T%8*aH4,fa8'  !"2t'7!DT%8)RH !2t'8*bI#$b$*;Wa"H'("d.?!&L$%r4+<fa#H()2t/@&!'L'("d.?&K!+ !"2t':HbI7
 
<  T]## G	;t|$,''F$$U++  vdm,,   &&,,..E!H''8x''%%+VDM%:%: D44:F4=4I4I  !&&&''(899 ,dl++ ''(899 ,GGGGeAhhGGGJFF
FFFH$,''F!<<00399;;L*2 . E^XtT8 #8,~=C"hHX~** A"&$~x"@"@E$K2 2 2 2 2 2   . . .. . . . . . .. ;&;==D1}}TZZ\\}*{}};'+zz'':':1'='C'C'E'E% ; ; ;?.2m? ? ?  )00d:; % ( ( (#'LLL(5 *GG	; G	; G	; G	; G	; G	; G	; G	; G	; G	; G	; G	; G	; G	; G	;T eFm$$))J''w'222"3wss|WQRR[#A#ABB 	 	IAv1F1Q3KKE)$%%  "IIg&&		'(:(:   
 
g !NN			&(9(9599V;L;LMMNNN
 
h 261E1EIIfuyy002
 2
.kE+.
 U""G 
 NN3M#VE*%,233 		G  NN3M# #29W#5#5#9::i 5!1!1A!566h"29U#3#3a#788i uU8_!5!5!>!> -x"U8_$6! !FIV <;;;F;;;H$VnnE(O ( 2 2E*[[FF5  T5 T T),U8_)=)=T T T  s###c"""$RXxj%G%G%GHHE(OFFu||~~&& #
 
 
 
sm   FMJ$3MJ)&M(J))M-.L3-L
	M
&L00M3M?MMMMMc                     t          | j                  }|                    d          s)t          | j                  }|                    d          )|S )zTOPParser :class: helper function, skips lines of input parm7 file
        until we find the next %FLAG entry and return that

        Returns
        -------
        line : string
            String containing the current line of the parm7 file
        rc   )rX   rY   r   )r]   r   s     r)   ri   zTOPParser.skipper  sQ     DL!!//'** 	&%%D //'** 	&r(   c                     |                      |d           }t          t          j        |t                              }|S )a  Extracts atoms names from parm7 file

        Parameters
        ----------
        num_per_record : int
            The number of entries for each record in the section (unused input)
        numlines : int
            The number of lines to be parsed in current section

        Returns
        -------
        attr : :class:`Atomnames`
            A :class:`Atomnames` instance containing the names of each atom as
            defined in the parm7 file
        c                     | S re   r'   r   s    r)   <lambda>z'TOPParser.parse_names.<locals>.<lambda>      A r(   rk   )parsesection_mapperr   r   r   r   r]   r   r   valsattrs        r)   r   zTOPParser.parse_names  <      ''++>>$f55566r(   c                     |                      |d           }t          t          j        |t                              }|S )a  Extracts the names of each residue

        Parameters
        ----------
        num_per_record : int
            The number of entries for each recrod in section (unused input)
        numlines : int
            The number of lines to be parsed in current section

        Returns
        -------
        attr : :class:`Resnames`
            A :class:`Resnames` instance containing the names of each residue
            as defined in the parm7 file
        c                     | S re   r'   r   s    r)   r   z*TOPParser.parse_resnames.<locals>.<lambda>  r   r(   rk   )r   r   r   r   r   r   s        r)   r   zTOPParser.parse_resnames  s<      ''++>>V44455r(   c                     |                      |d           }t          j        |t          j                  }|dz  }t	          |          }|S )a  Extracts the partial charges for each atom

        Parameters
        ----------
        num_per_record : int
            The number of entries for each record in section (unused input)
        numlines : int
            The number of lines to be parsed in current section

        Returns
        -------
        attr : :class:`Charges`
            A :class:`Charges` instance containing the partial charges of each
            atom as defined in the parm7 file
        c                      t          |           S re   floatr   s    r)   r   z)TOPParser.parse_charges.<locals>.<lambda>      E!HH r(   rk   g82@)r   r   r   float32r   )r]   r   r   r   chargesr   s         r)   r   zTOPParser.parse_charges  sO      ''2D2DEE(4rz2227wr(   c                 R    |                      |d           }t          |          }|S )a  Extracts the mass of each atom

        Parameters
        ----------
        num_per_record : int
            The number of entries for each record in section (unused input)
        numlines : int
            The number of lines to be parsed in current section

        Returns
        -------
        attr : :class:`Masses`
            A :class:`Masses` instance containing the mass of each atom as
            defined in the parm7 file
        c                      t          |           S re   r   r   s    r)   r   z(TOPParser.parse_masses.<locals>.<lambda>  r   r(   )r   r   r   s        r)   r   zTOPParser.parse_masses  s-      ''2D2DEEd||r(   c                     |                      |d           }t          t          j        |t                              }|S )a  Extracts the atomic numbers of each atom and converts to element type

        Parameters
        ----------
        num_per_record : int
            The number of entries for each record in section(unused input)
        numlines : int
            The number of lines to be pasred in current section

        Returns
        -------
        attr : :class:`Elements`
            A :class:`Elements` instance containing the element of each atom
            as defined in the parm7 file

        Note
        ----
        If the record contains unknown atomic numbers (e.g. <= 0), these will
        be treated as unknown elements and assigned an empty string value. See
        issues #2306 and #2651 for more details.

        .. versionchanged:: 2.0.0
           Unrecognised elements will now return a empty string. The parser
           will no longer attempt to guess the element by default.
        c                 `    t          |           dk    rt          t          |                    ndS )Nr   ru   )ra   r   r   s    r)   r   z*TOPParser.parse_elements.<locals>.<lambda>  s"    #a&&1**s1vv" r(   rk   )r   r   r   r   r   r   s        r)   r   zTOPParser.parse_elements  sE    6 ''DD
 
 V44455r(   c                     |                      |d           }t          t          j        |t                              }|S )a  Extracts the force field atom types of each atom

        Parameters
        ----------
        num_per_record : int
            The number of entries for each record in section (unused input)
        numlines : int
            The number of lines to be parsed in current section

        Returns
        -------
        attr : :class:`Atomtypes`
            A :class:`Atomtypes` instance containing the atom types for each
            atom as defined in the parm7 file
        c                     | S re   r'   r   s    r)   r   z'TOPParser.parse_types.<locals>.<lambda>  r   r(   rk   )r   r   r   r   r   r   s        r)   r   zTOPParser.parse_types   r   r(   c                     |                      |d           }t          t          j        |t          j                            }|S )a  Extracts the index of atom types of the each atom involved in Lennard
        Jones (6-12) interactions.

        Parameters
        ----------
        num_per_record : int
            The number of entries for each record in section (unused input)
        numlines : int
            The number of lines to be parsed in current section

        Returns
        -------
        attr :class:`TypeIndices`
            A :class:`TypeIndices` instance containing the LJ 6-12 atom type
            index for each atom
        c                      t          |           S re   ra   r   s    r)   r   z.TOPParser.parse_type_indices.<locals>.<lambda>%  s    CFF r(   rk   )r   r   r   r   r   r   s        r)   r   zTOPParser.parse_type_indices  s@    " ''2B2BCC28D999::r(   c                 4    |                      |d           }|S )a  Extracts the residue pointers for each atom

        Parameters
        ----------
        num_per_record : int
            The number of entries for each record in section (unused input)
        numlines : int
            The number of lines to be parsed in current section

        Returns
        -------
        vals : list of int
            A list of zero-formatted residue pointers for each atom
        c                 &    t          |           dz
  S )Nr   r   r   s    r)   r   z(TOPParser.parse_residx.<locals>.<lambda>8  s    CFFQJ r(   )r   )r]   r   r   r   s       r)   r   zTOPParser.parse_residx)  s"     ''2F2FGGr(   c                 `    fdt          dt                              D             }|S )a  Helper function to parse AMBER PRMTOP bonds/angles.

        Parameters
        ----------
        data : list of int
            Input list of the parm7 bond/angle section, zero-indexed
        num_per_record : int
            The number of entries for each record in the input list

        Returns
        -------
        vals : list of int tuples
            A list of tuples containing the atoms involved in a given bonded
            interaction

        Note
        ----
        In the parm7 format this information is structured in the following
        format: [ atoms 1:n, internal index ]
        Where 1:n represent the ids of the n atoms involved in the bond/angle
        and the internal index links to a given set of FF parameters.
        Therefore, to extract the required information, we split out the list
        into chunks of size num_per_record, and only extract the atom ids.
        c                 J    g | ]}t          ||z   d z
                      S )r   )tuple)r[   r   	chunksizedatas     r)   r^   z*TOPParser.parse_chunks.<locals>.<listcomp>T  sD     
 
 
 $q1y=1,,-..
 
 
r(   r   )r   r   )r]   r   r   r   s    `` r)   parse_chunkszTOPParser.parse_chunks;  sJ    2
 
 
 
 
1c$ii33
 
 
 r(   c                 `    |                      |d           }|                     ||          }|S )a  Extracts bond information from PARM7 format files

        Parameters
        ----------
        num_per_record : int
            The number of entries for each record in section
        numlines : int
            The number of lines to be parsed for this section

        Note
        ----
        For the bond/angle sections of parm7 files, the atom numbers are set to
        coordinate array index values. As detailed in `the specification`_,
        to recover the actual atom number, one
        should divide the values by 3 and add 1. Here, since we want to satisfy
        zero-indexing, we only divide by 3.

        .. _`the specification`: https://ambermd.org/FileFormats.php#topo.cntrl
        c                 &    t          |           dz  S )Nr;   r   r   s    r)   r   z(TOPParser.parse_bonded.<locals>.<lambda>n  s    c!ffk r(   )r   r   )r]   r   r   fieldssections        r)   r   zTOPParser.parse_bondedZ  s7    ( ))(4I4IJJ##FN;;r(   c                   
 g }
fd
 
| j                   }t          |          }t          |          D ]}t          | j                   }t          t	          |j                            D ]^}||j        |         j        |j        |         j                                                 }	|	r|	                     ||	                     _|S )a  Parses FORTRAN formatted section, and returns a list of all entries
        in each line

        Parameters
        ----------
        numlines : int
            The number of lines to be parsed in this section
        mapper : lambda operator
            Operator to format entries in current section

        Returns
        -------
        section : list
            A list of all entries in a given parm7 section
        c                     t          |           }|dd         dk    r#|dd                             d          d         S |dd         dk    r |           S t          d|           )	zZSkips '%COMMENT' lines until it gets the FORMAT specification
            for the section.NrD   z%FORMAT   )r   z%COMMENTzMInvalid header line. Does not begin with either %FLAG, %FORMAT nor %COMMENT:
)rX   r`   r   )filer   get_fmts     r)   r   z.TOPParser.parsesection_mapper.<locals>.get_fmt  s     ::DBQBx9$$ABBx~~c**1--bqbZ''wt}}$ -&*- -  r(   )
rY   r   r   rX   r   entriesstartstoprZ   r   )r]   r   mapperr   fmtr   r\   ljvalr   s             @r)   r   zTOPParser.parsesection_mapperr  s      	 	 	 	 	 gdl###x 	0 	0AT\""A3qy>>** 0 0	!*QYq\->>?EEGG 0NN66#;;///0 r(   c                 ,   g }g }t          j        ||          D ]}|d         dk     rL|                    |dd         t          |d                   fz   t          |d                   fz              Z|d         dk     rB|dd         t          |d                   fz   |dd         z   }|                    |           |                    |           t	          t          |                    }t          |          }t          |          }||fS )a  Combines hydrogen and non-hydrogen containing AMBER dihedral lists
        and extracts sublists for conventional dihedrals and improper angles

        Parameters
        ----------
        diha : list of tuples
            The atom ids of dihedrals not involving hydrogens
        dihh : list of tuples
            The atom ids of dihedrals involving hydrogens

        Returns
        -------
        dihedrals : :class:`Dihedrals`
            A :class:`Dihedrals` instance containing a list of all unique
            dihedrals as defined by the parm7 file
        impropers : :class:`Impropers`
            A :class:`Impropers` instance containing a list of all unique
            improper dihedrals as defined by the parm7 file

        Note
        ----
        As detailed in `the specification`_, the dihedral sections
        of parm7 files contain information about both conventional dihedrals
        and impropers. The following must be accounted for:
        1) If the fourth atom in a dihedral entry is given a negative value,
        this indicates that it is an improper.
        2) If the third atom in a dihedral entry is given a negative value,
        this indicates that it 1-4 NB interactions are ignored for this
        dihedrals. This could be due to the dihedral within a ring, or if it is
        part of a multi-term dihedral definition or if it is an improper.

        .. _`the specification`: https://ambermd.org/FileFormats.php#topo.cntrl
        r;   r   Nr   )r   r   r   abssortedsetr   r   )	r]   rC   rA   impropdihedr\   r   rs   rt   s	            r)   r   zTOPParser.parse_dihedrals  s   D t,, 	  	 Ataxxaes1Q4yyl2c!A$ii\ABBBB1!uAaD		|+ae3T""""Qs5zz""e$$	f%%	)##r(   r   r   c                 \    |                      |d           }t          j        |          }|S )a  Extracts the chainID of each residue

        Parameters
        ----------
        num_per_record : int
            The number of entries for each record in section (unused input)
        numlines : int
            The number of lines to be parsed in current section

        Returns
        -------
        attr : numpy array
            A numpy array containing the chainID of each residue as defined in
            the parm7 file
        c                     | S re   r'   r   s    r)   r   z*TOPParser.parse_chainids.<locals>.<lambda>  r   r(   )r   r   r   r   s        r)   r   zTOPParser.parse_chainids  s-      ''++>>x~~r(   N)r    r!   r"   r#   r   r   ri   r   r   r   r   r   r   r   r   r   r   r   r   ra   r   r'   r(   r)   r+   r+      s'       , ,\ (''FI I IV    (  (  ,  (  B  (  *  $  >  0) ) )V/$ /$ /$bS C      r(   r+   )%r#   numpyr   r   guesser.tablesr   lib.utilr   r   baser   r	   core.topologyr
   core.topologyattrsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   logging	getLoggerr   r   r+   r'   r(   r)   <module>r	     s  0B BF         # # # # # # - - - - - - - - 3 3 3 3 3 3 3 3 $ $ $ $ $ $                                   &  		:	;	;    (   ]	 ]	 ]	 ]	 ]	" ]	 ]	 ]	 ]	 ]	r(   