
    $gb                         d Z ddlmZmZmZ ddlmZmZ	 ddl
mZ ddlmZ ddlmZ ddlmZ  G d d	e          Z G d
 de          Z G d de          Z G d de          ZdS )z]
Classes and functions for dealing with MAC addresses, EUI-48, EUI-64, OUI, IAB
identifiers.
    )NotRegisteredErrorAddrFormatErrorDictDotLookup)eui48eui64)	mac_eui48)
eui64_base)	IPAddress)_open_binaryc                   (    e Zd ZdZdZd Zd Zd ZdS )BaseIdentifierz$Base class for all IEEE identifiers.)_value__weakref__c                     d | _         d S Nr   selfs    T/var/www/html/netbox-4.1.3/venv/lib/python3.11/site-packages/netaddr/eui/__init__.py__init__zBaseIdentifier.__init__   s        c                     | j         S )z):return: integer value of this identifierr   r   s    r   __int__zBaseIdentifier.__int__   s
    {r   c                     | j         S )zG
        :return: return the integer value of this identifier.
        r   r   s    r   	__index__zBaseIdentifier.__index__   s     {r   N)__name__
__module____qualname____doc__	__slots__r   r   r    r   r   r   r      sL        ..)I        r   r   c                   t     e Zd ZdZdZ fdZd Zd Zd Zd Z	d Z
d	 Zed
             ZddZd Zd Z xZS )OUIz
    An individual IEEE OUI (Organisationally Unique Identifier).

    For online details see - http://standards.ieee.org/regauth/oui/

    )recordsc                    t          t          |                                            ddlm} g | _        t          |t                    r*t          |	                    dd          d          | _
        nQt          |t                    r*d|cxk    rdk    rn n|| _
        n$t          d|          t          d|          | j
        |j        v rt          t          d	          }|j        | j
                 D ]Y\  }}|                    |           |                    |                              d
          }|                     |||           Z|                                 dS t+          d|d          )z
        Constructor

        :param oui: an OUI string ``XX-XX-XX`` or an unsigned integer.             Also accepts and parses full MAC/EUI-48 address strings (but not             MAC/EUI-48 integers)!
        r   ieee-     z OUI int outside expected range: zunexpected OUI format: zoui.txtUTF-8zOUI z not registered!N)superr#   r   netaddr.euir'   r$   
isinstancestrintreplacer   
ValueError	TypeError	OUI_INDEXr   __package__seekreaddecode_parse_datacloser   )r   ouir'   fhoffsetsizedata	__class__s          r   r   zOUI.__init__0   s    	c4!!### 	%$$$$$c3 	B ckk#r22B77DKKS!! 	BC####8#####! j!NOOO)33@AAA ;$.((k955B $t{ ; 5 5wwt}}++G44  vt4444HHJJJJJ$$%FGGGr   c                 *    t          | j                  S r   )hashr   r   s    r   __hash__zOUI.__hash__W   s    DK   r   c                     t          |t                    s.	 |                     |          }n# t          $ r
 t          cY S w xY w| j        |j        k    S r   r/   r#   rA   	ExceptionNotImplementedr   r   others     r   __eq__z
OUI.__eq__Z   b    %%% 	&&u-- & & &%%%%&{el**   - A Ac                     t          |t                    s.	 |                     |          }n# t          $ r
 t          cY S w xY w| j        |j        k    S r   rF   rI   s     r   __ne__z
OUI.__ne__b   rL   rM   c                     | j         | j        fS )z+:returns: Pickled state of an `OUI` object.r   r$   r   s    r   __getstate__zOUI.__getstate__j   s    {DL((r   c                 $    |\  | _         | _        dS )z;:param state: data used to unpickle a pickled `OUI` object.NrQ   r   states     r   __setstate__zOUI.__setstate__n   s    $)!T\\\r   c                 j   dddg ||d}|                     d          D ]y}|                                }|sd|v r<| j        |d<   |                     dd          d         |d	<   t          |           |d
<   Yd|v r^|d                             |           z| j                            |           dS )z.Returns a dict record from raw OUI record datar   r)   )idxr<   orgaddressr>   r?   
(hex)rX   N   rY   r<   	(base 16)rZ   )splitstripr   r0   appendr$   )r   r@   r>   r?   recordlines         r   r:   zOUI._parse_datar   s     
 
 JJt$$ 	/ 	/D::<<D $ $u $

4 3 3A 6u #D		u$$y!((....F#####r   c                 *    t          | j                  S )z0Number of registered organisations with this OUI)lenr$   r   s    r   	reg_countzOUI.reg_count   s     4<   r   r   c                 6    t          | j        |                   S )a  
        The IEEE registration details for this OUI.

        :param index: the index of record (may contain multiple registrations)
            (Default: 0 - first registration)

        :return: Objectified Python data structure containing registration
            details.
        )r   r$   )r   indexs     r   registrationzOUI.registration   s     T\%0111r   c                 >    | j         }d|dz	  dz  |dz	  dz  |dz  fz  S )z*:return: string representation of this OUI%02X-%02X-%02Xr*         r   r   int_vals     r   __str__zOUI.__str__   s4    +GrMT#9GqLD;PRY\`R`"aaar   c                     d| z  S )@:return: executable Python string to recreate equivalent object.z	OUI('%s')r!   r   s    r   __repr__zOUI.__repr__       T!!r   )r   )r   r   r   r   r    r   rD   rK   rO   rR   rV   r:   propertyrf   ri   rp   rs   __classcell__rA   s   @r   r#   r#   &   s          I%H %H %H %H %HN! ! !+ + ++ + +) ) )* * *$ $ $6 ! ! X!
2 
2 
2 
2b b b
" " " " " " "r   r#   c                   r     e Zd ZdZ	 dZedd            Zd fd	Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Z xZS )IAB)iP  iU@ )rb   Fc                     |dz	  | j         v r|dfS d}d|z  }|dz	  }||z  |z
  }|dz	  | j         v r(|r%|dk    rt          dt          |          z            nt          dt          |          z            ||fS )z
        :param eui_int: a MAC IAB as an unsigned integer.

        :param strict: If True, raises a ValueError if the last 12 bits of
            IAB MAC/EUI-48 address are non-zero, ignores them otherwise.
            (Default: False)
           r   i      z%r is not a strict IAB!z%r is not an IAB address!)IAB_EUI_VALUESr3   hex)clseui_intstrict	user_maskiab_maskiab_bits	user_bitss          r   split_iab_maczIAB.split_iab_mac   s     rMc000A:	*b=x'83	Ns111 M)q.. !:S^^!KLLL83w<<GHHH""r   c                 b   t          t          |                                            ddlm} dddg ddd| _        t          |t                    rFt          |	                    dd          d          }| 
                    ||          \  }}|| _        nJt          |t                    r"| 
                    ||          \  }}|| _        nt          d|d	          | j        |j        v rt          t          d
          }|j        | j                 d         \  }}	|| j        d<   |	| j        d<   |                    |           |                    |	                              d          }
|                     |
||	           |                                 dS t+          d|d          )a  
        Constructor

        :param iab: an IAB string ``00-50-C2-XX-X0-00`` or an unsigned             integer. This address looks like an EUI-48 but it should not             have any non-zero bits in the last 3 bytes.

        :param strict: If True, raises a ValueError if the last 12 bits             of IAB MAC/EUI-48 address are non-zero, ignores them otherwise.             (Default: False)
        r   r&   r)   )rX   iabrY   rZ   r>   r?   r(   r*   )r   zunexpected IAB format: !ziab.txtr>   r?   r,   zIAB z not unregistered!N)r-   ry   r   r.   r'   rb   r/   r0   r1   r2   r   r   r4   	IAB_INDEXr   r6   r7   r8   r9   r:   r;   r   )r   r   r   r'   ro   iab_intuser_intr=   r>   r?   r@   rA   s              r   r   zIAB.__init__   s    	c4!!### 	%$$$$$ 
 
 c3 	C #++c2..33G $ 2 276 2 J JGX!DKKS!! 	C $ 2 23v 2 F FGX!DKK)CCCABBB ;$.((k955B!^DK8;NVT$*DK!"&DKGGFOOO774==''00DT64000HHJJJJJ$$333%HIIIr   c                     t          |t                    s.	 |                     |          }n# t          $ r
 t          cY S w xY w| j        |j        k    S r   r/   ry   rA   rG   rH   r   rI   s     r   rK   z
IAB.__eq__   rL   rM   c                     t          |t                    s.	 |                     |          }n# t          $ r
 t          cY S w xY w| j        |j        k    S r   r   rI   s     r   rO   z
IAB.__ne__  rL   rM   c                     | j         | j        fS )z+:returns: Pickled state of an `IAB` object.r   rb   r   s    r   rR   zIAB.__getstate__  s    {DK''r   c                 $    |\  | _         | _        dS )z;:param state: data used to unpickle a pickled `IAB` object.Nr   rT   s     r   rV   zIAB.__setstate__  s    #( T[[[r   c                 L   |                     d          D ]}|                                }|sd|v rK| j        | j        d<   |                     dd          d         | j        d<   t	          |           | j        d<   hd|v rm| j        d	                             |           dS )
z.Returns a dict record from raw IAB record datar[   r\   rX   Nr]   rY   r   r^   rZ   )r_   r`   r   rb   r0   ra   )r   r@   r>   r?   rc   s        r   r:   zIAB._parse_data  s    JJt$$ 	4 	4D::<<D $%)[E"%)ZZa%8%8%;E"%(YYE""$$I&--d3333	4 	4r   c                 *    t          | j                  S )z*The IEEE registration details for this IAB)r   rb   r   s    r   ri   zIAB.registration(  s    T[)))r   c                 `    | j         dz  }d|dz	  dz  |dz	  dz  |dz	  dz  |dz	  dz  |dz  fz  S )z*:return: string representation of this IAB   z%02X-%02X-%02X-%02X-%02X-00    rl      r*   rm   r   rn   s     r   rp   zIAB.__str__,  sW    +",]d"]d"]d"\T!dN0
 
 	
r   c                     d| z  S )rr   z	IAB('%s')r!   r   s    r   rs   zIAB.__repr__8  rt   r   )F)r   r   r   r}   r    classmethodr   r   rK   rO   rR   rV   r:   ri   rp   rs   rv   rw   s   @r   ry   ry      s        )N I# # # [#02J 2J 2J 2J 2J 2Jh+ + ++ + +( ( () ) )4 4 4 * * *

 

 

" " " " " " "r   ry   c                       e Zd ZdZdZd( fd	Zd Zd Zd Zd Z	 e
ee	dd	          Zd
 Zd Zd Z e
eedd          Ze
d             Ze
d             Zd Ze
d             Ze
d             Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd)dZe
d             Ze
d             Z e
d             Z!d  Z"d! Z#d" Z$d# Z%e
d$             Z&d)d%Z'd& Z(d' Z) xZ*S )*EUIz
    An IEEE EUI (Extended Unique Identifier).

    Both EUI-48 (used for layer 2 MAC addresses) and EUI-64 are supported.

    Input parsing for EUI-48 addresses is flexible, supporting many MAC
    variants.

    )_module_dialectNc                 L   t          t          |                                            d| _        t	          |t                    rI|||j        j        k    rt          d          |j        | _        |j        | _        |p|j        | _        dS |8|dk    rt          | _        ns|dk    rt          | _        n`t          d|z            t	          |t                    r9d|cxk    rdk    rn nt          | _        nd|cxk     rdk    rn nt          | _        || _        || _        dS )	aJ  
        Constructor.

        :param addr: an EUI-48 (MAC) or EUI-64 address in string format or             an unsigned integer. May also be another EUI object (copy             construction).

        :param version: (optional) the explicit EUI address version, either             48 or 64. Mainly used to distinguish EUI-48 and EUI-64 identifiers             specified as integers which may be numerically equivalent.

        :param dialect: (optional) one of the :ref:`mac_formatting_dialects` to
            be used to configure the formatting of EUI-48 (MAC) addresses.
        Nz2cannot switch EUI versions using copy constructor!0   @   zunsupported EUI version %rr   r|   l    )r-   r   r   r   r/   versionr3   r   dialect_eui48_eui64r1   value)r   addrr   r   rA   s       r   r   zEUI.__init__J  s>    	c4!!###dC   	"w$,2F'F'F !XYYY<DL+DK"2dlDLF"}}%B% !=!GHHH $$$ *.........#)DLL#d@@@@.@@@@@@#)DL
 r   c                 4    | j         | j        j        | j        fS )z+:returns: Pickled state of an `EUI` object.)r   r   r   r   r   s    r   rR   zEUI.__getstate__{  s    {DL0$,>>r   c                     |\  }}}|| _         |dk    rt          | _        n%|dk    rt          | _        nt	          d|          || _        dS )zN
        :param state: data used to unpickle a pickled `EUI` object.

        r   r   z$unpickling failed for object state: N)r   r   r   r   r3   r   )r   rU   r   r   r   s        r   rV   zEUI.__setstate__  s[    
 #(wb==!DLL]]!DLL*PQQQr   c                     | j         S r   r   r   s    r   
_get_valuezEUI._get_value  s
    {r   c                    | j         t          t          fD ]}	 |                    |          | _        || _          nb# t
          $ rU 	 dt          |          cxk    r|j        k    r!n nt          |          | _        || _         Y  nn# t          $ r Y nw xY wY w xY w| j         t          d|          d S t          |t                    rN	 | j                             |          | _        d S # t
          $ r t          d|| j         j        fz            w xY wdt          |          cxk    r| j         j        k    rn nt          |          | _        d S t          d|          )Nr   zfailed to detect EUI version: zaddress %r is not an EUIv%dzbad address format: )r   r   r   
str_to_intr   r   r1   max_intr3   r/   r0   r   )r   r   modules      r   
_set_valuezEUI._set_value  s   <!6*  "("3"3E":":DK#)DLE&   E

<<<<fn<<<<<*-e**DK+1DL!EE%    |#%oEE&STTT $# %%% O"&,"9"9%"@"@DKKK&   )5@T8UU  
 E

::::dl&::::::"%e**DKKK)/ee*MNNNs?   !<
B=BB
BBBBBC0 0)DzAa positive integer representing the value of this EUI identifier.c                     | j         S r   )r   r   s    r   _get_dialectzEUI._get_dialect  s
    }r   c                     || j         t          u rt          S t          S t	          |d          rt	          |d          r|S t          d          )N	word_sizeword_fmtz*custom dialects should subclass mac_eui48!)r   r   r	   r   hasattrr4   r   r   s     r   _validate_dialectzEUI._validate_dialect  sY    =|v%%!!  uk** Nwuj/I/I N LMMMr   c                 :    |                      |          | _        d S r   )r   r   r   s     r   _set_dialectzEUI._set_dialect  s    ..u55r   zXa Python class providing support for the interpretation of various MAC
 address formats.c                     | j         t          k    rt          | j        dz	            S | j         t          k    rt          | j        dz	            S dS )z:The OUI (Organisationally Unique Identifier) for this EUI.r   (   N)r   r   r#   r   r   r   s    r   r<   zEUI.oui  sP     <6!!tzR'(((\V##tzR'((( $#r   c                     | j         t          k    rdt          | dd                   z  S | j         t          k    rdt          | dd                   z  S dS )z*The EI (Extension Identifier) for this EUIrk         z%02X-%02X-%02X-%02X-%02Xrm   N)r   r   tupler   r   s    r   eizEUI.ei  s\     <6!!#eD1I&6&666\V##-d1Q3i0@0@@@ $#r   c                 .    | j         dz	  t          j        v S )z<:return: True if this EUI is an IAB address, False otherwiser   )r   ry   r}   r   s    r   is_iabz
EUI.is_iab  s    r!c&888r   c                 \    |                                  rt          | j        dz	            S dS )zr
        If is_iab() is True, the IAB (Individual Address Block) is returned,
        ``None`` otherwise.
        r{   N)r   ry   r   r   s    r   r   zEUI.iab  s3     ;;== 	*t{b()))	* 	*r   c                     | j         j        S )z/The EUI version represented by this EUI object.)r   r   r   s    r   r   zEUI.version  s     |##r   c                    t          |t                    rY| j        j        }| |cxk    r	|dz
  k    sn t	          d          | j                            | j        | j                  |         S t          |t                    rZ| j                            | j        | j                  fdt          |
                    t                               D             S t          d|d          )z
        :return: The integer value of the word referenced by index (both             positive and negative). Raises ``IndexError`` if index is out             of bounds. Also supports Python list slices for accessing             word groups.
           z!index out range for address type!c                      g | ]
}|         S r!   r!   ).0iwordss     r   
<listcomp>z#EUI.__getitem__.<locals>.<listcomp>  s    FFFE!HFFFr   zunsupported type r   )r/   r1   r   	num_words
IndexErrorr   int_to_wordsr   slicerangeindicesre   r4   )r   rX   r   r   s      @r   __getitem__zEUI.__getitem__  s     c3 
	=/IJ399999q=9999 !DEEE<,,T[$-HHMMU## 	=L--dk4=IIEFFFFeS[[U-D-D&EFFFF)ccc;<<<r   c                 V   t          |t                    rt          d          t          |t                    st	          d          d|cxk    r| j        j        dz
  k    sn t          d|fz            t          |t                    st	          d          d|cxk    r| j        j        k    s n t          d|| j        j	        fz            t          | j                            | j        | j                            }|||<   | j                            |          | _        dS )	z=Set the value of the word referenced by index in this addressz"settable slices are not supported!zindex not an integer!r   r   z'index %d outside address type boundary!zvalue not an integer!z.value %d outside word size maximum of %d bits!N)r/   r   NotImplementedErrorr1   r4   r   r   r   max_wordr   listr   r   r   words_to_int)r   rX   r   r   s       r   __setitem__zEUI.__setitem__  s6   c5!! 	L%&JKKK#s## 	53444C8888DM3a78888F#OPPP%%% 	53444E3333T]33333@E4=KbCcc   T\..t{DMJJKKc
l//66r   c                 8    t          | j        | j        f          S )zA:return: hash of this EUI object suitable for dict keys, sets etc)rC   r   r   r   s    r   rD   zEUI.__hash__$  s    T\4;/000r   c                     t          |t                    s.	 |                     |          }n# t          $ r
 t          cY S w xY w| j        | j        f|j        |j        fk    S zy
        :return: ``True`` if this EUI object is numerically the same as other,             ``False`` otherwise.
        r/   r   rA   rG   rH   r   r   rI   s     r   rK   z
EUI.__eq__(  r    
 %%% 	&&u-- & & &%%%%&dk*u}el.KKKrM   c                     t          |t                    s.	 |                     |          }n# t          $ r
 t          cY S w xY w| j        | j        f|j        |j        fk    S r   r   rI   s     r   rO   z
EUI.__ne__4  r   rM   c                     t          |t                    s.	 |                     |          }n# t          $ r
 t          cY S w xY w| j        | j        f|j        |j        fk     S )z
        :return: ``True`` if this EUI object is numerically lower in value than             other, ``False`` otherwise.
        r   rI   s     r   __lt__z
EUI.__lt__@  r    
 %%% 	&&u-- & & &%%%%&dk*emU\-JJJrM   c                     t          |t                    s.	 |                     |          }n# t          $ r
 t          cY S w xY w| j        | j        f|j        |j        fk    S )z
        :return: ``True`` if this EUI object is numerically lower or equal in             value to other, ``False`` otherwise.
        r   rI   s     r   __le__z
EUI.__le__L  r   rM   c                     t          |t                    s.	 |                     |          }n# t          $ r
 t          cY S w xY w| j        | j        f|j        |j        fk    S )z
        :return: ``True`` if this EUI object is numerically greater in value             than other, ``False`` otherwise.
        r   rI   s     r   __gt__z
EUI.__gt__X  r   rM   c                     t          |t                    s.	 |                     |          }n# t          $ r
 t          cY S w xY w| j        | j        f|j        |j        fk    S )z
        :return: ``True`` if this EUI object is numerically greater or equal             in value to other, ``False`` otherwise.
        r   rI   s     r   __ge__z
EUI.__ge__d  r   rM   c                 B    | j                             | j        |          S )z
        :param word_sep: (optional) the separator to insert between words.             Default: None - use default separator for address type.

        :return: human-readable binary digit string of this address.
        )r   int_to_bitsr   )r   word_seps     r   bitszEUI.bitsp  s     |''X>>>r   c                 @    | j                             | j                  S )z8The value of this EUI address as a packed binary string.)r   int_to_packedr   r   s    r   packedz
EUI.packedy  s     |))$+666r   c                 @    | j                             | j                  S )z<A list of unsigned integer octets found in this EUI address.)r   r   r   r   s    r   r   z	EUI.words~  s     |((555r   c                 @    | j                             | j                  S )z
        The value of this EUI address in standard Python binary
        representational form (0bxxx). A back port of the format provided by
        the builtin bin() function found in Python 2.6.x and higher.
        )r   
int_to_binr   r   s    r   binzEUI.bin  s     |&&t{333r   c                     | j         dk    r | j        dz	  }| j        dz  }|dz  dz  |z  }n| j        }|                     |d          S )a2  
        - If this object represents an EUI-48 it is converted to EUI-64             as per the standard.
        - If this object is already an EUI-64, a new, numerically             equivalent object is returned instead.

        :return: The value of this EUI object as a new 64-bit EUI object.
        r   r   r+   r   l      |r   r   )r   r   rA   )r   first_three
last_three	new_values       r   r   z	EUI.eui64  s^     <2++Kx/J$*l:ZGII I~~i~444r   c                 N    |                                  }|xj        dz  c_        |S )z
        - create a new EUI object with a modified EUI-64 as described in RFC 4291 section 2.5.1

        :return: a new and modified 64-bit EUI object.
        l          )r   r   )r   r   s     r   modified_eui64zEUI.modified_eui64  s'     

::r   c                     t          |          t          |                                           z   }t          |d          S )a5  
        .. note:: This poses security risks in certain scenarios.             Please read RFC 4941 for details. Reference: RFCs 4291 and 4941.

        :param prefix: ipv6 prefix

        :return: new IPv6 `IPAddress` object based on this `EUI`             using the technique described in RFC 4291.
        r   r   )r1   r   r
   )r   prefixro   s      r   ipv6zEUI.ipv6  s;     f++D$7$7$9$9 : ::!,,,,r   c                 ,    |                      d          S )a  
        .. note:: This poses security risks in certain scenarios.             Please read RFC 4941 for details. Reference: RFCs 4291 and 4941.

        :return: new link local IPv6 `IPAddress` object based on this `EUI`             using the technique described in RFC 4291.
        l	                  @ )r   r   s    r   ipv6_link_localzEUI.ipv6_link_local  s     yy;<<<r   c                     d| j                                         i}|                                 r| j                                        |d<   t	          |          S )z
        A record dict containing IEEE registration details for this EUI
        (MAC-48) if available, None otherwise.
        r#   ry   )r<   ri   r   r   r   )r   r@   s     r   infozEUI.info  sQ     tx,,../;;== 	2(//11DKT"""r   c                 l    |                      |          }| j                            | j        |          S )a:  
        Format the EUI into the representational format according to the given
        dialect

        :param dialect: one of the :ref:`mac_formatting_dialects` defining the
            formatting of EUI-48 (MAC) addresses.

        :return: EUI in representational format according to the given dialect
        )r   r   
int_to_strr   )r   r   validated_dialects      r   formatz
EUI.format  s3     !227;;|&&t{4EFFFr   c                 L    | j                             | j        | j                  S )z':return: EUI in representational format)r   r  r   r   r   s    r   rp   zEUI.__str__  s    |&&t{DMBBBr   c                     d| z  S )rr   z	EUI('%s')r!   r   s    r   rs   zEUI.__repr__  rt   r   )NNr   )+r   r   r   r   r    r   rR   rV   r   r   ru   r   r   r   r   r   r<   r   r   r   r   r   r   rD   rK   rO   r   r   r   r   r   r   r   r   r   r   r   r   r  r  rp   rs   rv   rw   s   @r   r   r   =  s         (I/ / / / / /b? ? ?  $   O  O  OD HK	 E  
N 
N 
N6 6 6 h	)	 G ) ) X) A A XA9 9 9 * * X* $ $ X$= = =&7 7 701 1 1
L 
L 
L
L 
L 
L
K 
K 
K
L 
L 
L
K 
K 
K
L 
L 
L? ? ? ? 7 7 X7 6 6 X6 4 4 X45 5 5&   - - -= = = 	# 	# X	#G G G GC C C" " " " " " "r   r   N)r   netaddr.corer   r   r   netaddr.strategyr   r   r   r   netaddr.strategy.eui48r   netaddr.strategy.eui64r	   
netaddr.ipr
   netaddr.compatr   objectr   r#   ry   r   r!   r   r   <module>r     s^   
 L K K K K K K K K K = = = = = = = = , , , , , , - - - - - -             ' ' ' ' ' '    V   &" " " " ". " " "DR" R" R" R" R". R" R" R"jh" h" h" h" h". h" h" h" h" h"r   