
    =[j;S                       d Z ddlmZ ddlZddlZddlZddlZddlmZ ddl	m
Z
 ddlmZ ddlmZ dd	d
ddZdZdZdZdZdZdZ edd          Zedz
  ez  Z edd          Z edd          Z edd          Z edd          ZdZdZddiZ ed           G d d                       Z  e dd          Z! e ee          Z"dSdTd'Z#dUd)Z$dVd*Z%dWd,Z&dXd-Z'dYd/Z(dZd0Z)d[d3Z*d\d5Z+d]d7Z,d^d;Z-d_d=Z.d`dad>Z/dbdAZ0 ed           G dB dC                      Z1 ed           G dD dE                      Z2 G dF dG          Z3 G dH dI          Z4dcdMZ5dddNZ6 G dO dP          Z7 G dQ dR          Z8dS )ez?Pure-Python bridge prover for Apple's trusted-device HSA2 flow.    )annotationsN)	dataclass)Optional)
InvalidTag)AESGCMi @        @   )nrpdklens   com.apple.security.webprovers   com.apple.security.webverifiers	   SPAKE2Web    s   webVerifiers	   webProver@FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF      @5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B@FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551@6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296@4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5B02886e2f97ace46e55ba9dd7242579f2993b64e16ef3dcab95afd497333d8fa12fB03d8bbd6c639c62937b04d997f38c3770719c629d7014d49a24b4f98baa1292b49)   r   T)frozenc                  @    e Zd ZU dZded<   ded<   ed	d            ZdS )
_Pointz:Affine P-256 point used by the bridge SPAKE2 math helpers.Optional[int]xyreturnboolc                &    | j         du p| j        du S )z3Return whether this point is the point at infinity.N)r   r   selfs    c/home/thesage/.hermes/hermes-agent/venv/lib/python3.11/site-packages/pyicloud/hsa2_bridge_prover.pyis_infinityz_Point.is_infinity0   s     v~/4/    Nr    r!   )__name__
__module____qualname____doc____annotations__propertyr&    r'   r%   r   r   )   sR         DD0 0 0 X0 0 0r'   r   valueintlengthr   r    bytesc                    |(t          d|                                 dz   dz            }|                     |d          S )z)Encode an integer using big-endian bytes.Nr	      r   big)max
bit_lengthto_bytes)r0   r2   s     r%   _int_to_bytesr:   :   s@    ~Q))++a/A566>>&%(((r'   strc                P    t          j        |                     d                    S )z&Decode a base64 string into raw bytes.ascii)base64	b64decodeencoder0   s    r%   _b64_to_bytesrB   A   s    ELL11222r'   c                P    t          j        |                               d          S )z+Encode raw bytes as an ASCII base64 string.r=   )r>   	b64encodedecoderA   s    r%   _bytes_to_b64rF   F   s!    E""))'222r'   pointc                    | j         rt          d          dt          | j        d                                          z   t          | j        d                                          z   S )z:Encode a P-256 point using SEC1 uncompressed point format.z$Cannot encode the point at infinity.04r   )r&   
ValueErrorr:   r   hexr   rG   s    r%   _encode_pointrM   K   s]     A?@@@-,,00222]57B5O5O5S5S5U5UUUr'   c                   t                               |           }t          |          dk    r_|d         dk    rSt          t                              |dd         d          t                              |dd         d                    }nt          |          dk    r|d         dv rt                              |dd         d          }t          |d	t                    t          |z  z   t          z   t          z  }t          |t          dz   dz  t                    }|dz  |d         dz  k    r| t          z  }t          ||          }nt          d
          t          |          st          d          |S )zGDecode a compressed or uncompressed SEC1 point into affine coordinates.A   r      r	   !   r6   )   r   Nr   z!Unsupported P-256 point encoding.zInvalid P-256 point.)r3   fromhexlenr   r1   
from_bytespow_P256_P_P256_A_P256_BrJ   _is_on_curve)r0   rawrG   x_coordrhsy_coords         r%   _decode_pointr_   R   sQ   
--

C
3xx2~~#a&D..NN3qt9e,,NN3r"u:u--
 
 
SRCFl22..QRR%007Aw'''G*;;gEPcGaKA-w77Q;#a&1*$$x7*Gw((<=== 1/000Lr'   r!   c                    | j         rdS | j        | j        J t          | j        dt                    t          | j        dt                    t
          | j        z  z   t          z   z
  t          z  dk    S )z:Return whether a point lies on the configured P-256 curve.FNrR   r   r   )r&   r   r   rV   rW   rX   rY   rL   s    r%   rZ   rZ   i   sw     u757#6#66EGQ  uw7##g&77'A	C  r'   c                z    | j         r| S | j        | j        J t          | j        | j         t          z            S )z-Return the additive inverse of a P-256 point.)r&   r   r   r   rW   rL   s    r%   _negaterb   t   sB     757#6#66%'UWH/000r'   leftrightc                   | j         r|S |j         r| S | j        | j        J |j        |j        J | j        |j        k    r"| j        |j        z   t          z  dk    rt          S | j        |j        k    rd| j        |j        k    rT| j        dk    rt          S d| j        z  | j        z  t
          z   t          d| j        z  dt                    z  t          z  }n;|j        | j        z
  t          |j        | j        z
  dt                    z  t          z  }||z  | j        z
  |j        z
  t          z  }|| j        |z
  z  | j        z
  t          z  }t          ||          S )zAdd two affine P-256 points.Nr   r   rR   )r&   r   r   rW   	_INFINITYrX   rV   r   )rc   rd   sloper\   r^   s        r%   _add_pointsri   |   sW     6$&"4"44757#6#66vdfuw.'9Q>>vTVuw..6Q;;Z$& 7*c!df*b'.J.JJ 'DF"c%'DF*:B&H&HHGSu}tv%/7:G()DF2g=G'7###r'   scalarc                    |t           z  }t          }| }|r,|dz  rt          ||          }t          ||          }|dz  }|,|S )z8Multiply a P-256 point by a scalar using double-and-add.r	   )_P256_ORDERrg   ri   )rG   rj   resultaddends       r%   _multiply_pointro      sb    
kFFF
 A: 	1 00FVV,,1	  
 Mr'   partsc                     t                      }| D ]M}|                    t          |                              dd                     |                    |           Nt	          |          S )zGConcatenate transcript parts using the bridge's length-prefixed format.r   little)	bytearrayextendrT   r9   r3   )rp   outputparts      r%   _concat_length_prefixedrw      sc    [[F  c$ii((H55666d==r'   ikmsaltinfoc                   t          j                    j        }|sd|z  }t          j        || t           j                                                  }t                      }d}d}t          |          |k     rst          j        |||z   t          |g          z   t           j                                                  }|	                    |           |dz  }t          |          |k     st          |d|                   S )zBDerive key material using the bridge worker's HKDF-like expansion.    r'   r	   N)
hashlibsha256digest_sizehmacnewdigestrs   rT   r3   rt   )	rx   ry   rz   r2   hash_lenprkblockspreviouscounters	            r%   
_hkdf_liker      s    ~+H "!
(4gn
-
-
4
4
6
6C[[FHG
f++

8tOeWI...N
 
 &((	 	
 	h1 f++

 !!!r'   requested_lengthc                    d| v rdS |S )zEReturn the bridge-specific output length for a given HKDF info label.   ConfirmationKeysr
   r/   )rz   r   s     r%   _confirmation_key_lengthr      s    d""rr'   c           	     D    t          | d|t          ||                    S )z:Derive one bridge sub-key from raw shared-secret material.r'   )rx   ry   rz   r2   )r   r   )rx   rz   r2   s      r%   _derive_keyr      s/    'f55	   r'   raw_key_hextuple[str, str]c                    t                               |           }t          |t          t                    }t          |t
          t                    }|                                |                                fS )z@Split the raw bridge key into prover and verifier AES/HMAC keys.)r3   rS   r   _VERIFIER_KEY_INFO_KEY_LENGTH_PROVER_KEY_INFOrK   )r   raw_keyverifier_key
prover_keys       r%    _derive_prover_and_verifier_keysr      sX    mmK((Gw(:KHHLW&6DDJz~~////r'   c                  J    e Zd ZU dZded<   ded<   ded<   dd	Zdd
ZddZdS )_ClientSharedSecretzCClient-side shared-secret transcript and derived confirmation keys.r3   
transcriptr;   share_pshare_vr    Nonec                   t          j        | j                                                  }t                              | d|           t          |dd          }t                              | d|dd                    t                              | d|dd                    t          |dt                    }t                              | d	|           dS )
FDerive confirmation keys and the final shared key from the transcript._hash_transcriptr   r
   _confirm_clientNr   _confirm_server	   SharedKey_shared_key)r}   r~   r   r   object__setattr__r   r   )r$   r   confirmations
shared_keys       r%   __post_init__z!_ClientSharedSecret.__post_init__   s    0077994!3V<<<#F,?DD4!2M#2#4FGGG4!2M"##4FGGG {CC
4
;;;;;r'   c                    t          j        | j        t                              | j                  t          j                                                  S )z.Return the prover's HMAC confirmation message.)	r   r   r   r3   rS   r   r}   r~   	hexdigestr#   s    r%   get_confirmationz$_ClientSharedSecret.get_confirmation   =    x MM$,''N
 
 )++		r'   message_hexc                    t          j        | j        t                              | j                  t          j                                                  }||k    rt          d          | j
        S )z?Verify the server confirmation and return the shared key bytes.z invalid confirmation from server)r   r   r   r3   rS   r   r}   r~   r   rJ   r   r$   r   expecteds      r%   verifyz_ClientSharedSecret.verify   b    8 MM$,''N
 
 )++	 	
 {""?@@@r'   Nr    r   r    r;   r   r;   r    r3   r)   r*   r+   r,   r-   r   r   r   r/   r'   r%   r   r      sv         MMLLLLLL< < < <   	  	  	  	  	  	 r'   r   c                  J    e Zd ZU dZded<   ded<   ded<   dd	Zdd
ZddZdS )_ServerSharedSecretzCServer-side shared-secret transcript and derived confirmation keys.r3   r   r;   r   r   r    r   c           	     n   t          j        | j                                                  }t	          |dd          }t
                              | d|dd                    t
                              | d|dd                    t
                              | dt	          |dt                               dS )	r   r   r
   r   Nr   r   r   r   )r}   r~   r   r   r   r   r   r   )r$   r   r   s      r%   r   z!_ServerSharedSecret.__post_init__  s    007799#F,?DD4!2M#2#4FGGG4!2M"##4FGGGk::	
 	
 	
 	
 	
r'   c                    t          j        | j        t                              | j                  t          j                                                  S )z0Return the verifier's HMAC confirmation message.)	r   r   r   r3   rS   r   r}   r~   r   r#   s    r%   r   z$_ServerSharedSecret.get_confirmation  r   r'   r   c                    t          j        | j        t                              | j                  t          j                                                  }||k    rt          d          | j
        S )z?Verify the prover confirmation and return the shared key bytes.z invalid confirmation from client)r   r   r   r3   rS   r   r}   r~   r   rJ   r   r   s      r%   r   z_ServerSharedSecret.verify  r   r'   Nr   r   r   r   r/   r'   r%   r   r      sv         MMLLLLLL

 

 

 

   	  	  	  	  	  	 r'   r   c                  *    e Zd ZdZddZdd
ZddZdS )_ClientHandshakez=Client-side SPAKE2 handshake state for Apple's bridge prover.x_scalarr1   w0w1r    r   c               L    || _         || _        || _        d| _        d| _        dS )z@Initialize the prover handshake with the derived SPAKE2 scalars.N)_x_w0_w1_message1_pointr   )r$   r   r   r   s       r%   __init__z_ClientHandshake.__init__+  s,     15&*r'   r;   c                    t          t          t          | j                  t          t	          t
                    | j                            }|| _        t          |          | _	        | j	        S )z)Return the prover's first SPAKE2 message.)
ri   ro   
_GENERATORr   r_   	_SPAKE2_Mr   r   rM   r   r$   rG   s     r%   get_messagez_ClientHandshake.get_message9  X    J00M)44dh??
 
  %$U++|r'   server_message_hexr   c                   | j         | j        t          d          t          |          }|j        rt          d          t          |t          t          t          t                    | j	                                      }t          || j
                  }t          || j                  }t          t          t          t          t                               t%          t          t&                                        t                               t%          t          t                                        t                               t%          | j                             t                               t%          |                    t                               t%          |                    t                               t%          |                    t)          | j	                  
  
        }t+          || j        |          S )z8Finish the handshake using the verifier's first message.N(get_message must be called before finishinvalid curve pointr   r   r   )r   r   rJ   r_   r&   ri   rb   ro   	_SPAKE2_Nr   r   r   rw   _SPAKE2_CONTEXT_CLIENT_IDENTITY_SERVER_IDENTITYr3   rS   rM   r   r:   r   )r$   r   server_pointadjustedy_pointv_pointr   s          r%   finishz_ClientHandshake.finishC  s   '4<+?GHHH$%788# 	42333OM)$<$<dhGGHH
 
 "(DG44!(DH55,MM-i(@(@AABBMM-i(@(@AABBMM-(<==>>MM-5566MM-0011MM-0011$(##
 

 #!L&
 
 
 	
r'   N)r   r1   r   r1   r   r1   r    r   r   )r   r;   r    r   r)   r*   r+   r,   r   r   r   r/   r'   r%   r   r   (  sV        GG+ + + +   
 
 
 
 
 
r'   r   c                  *    e Zd ZdZdd	ZddZddZdS )_ServerHandshakezAServer-side SPAKE2 handshake state used by the local test helper.y_scalarr1   r   verifier_pointr   r    r   c               L    || _         || _        || _        d| _        d| _        dS )zEInitialize the verifier handshake with its scalar and verifier point.N)_yr   _verifier_pointr   r   )r$   r   r   r   s       r%   r   z_ServerHandshake.__init__h  s-     -15&*r'   r;   c                    t          t          t          | j                  t          t	          t
                    | j                            }|| _        t          |          | _	        | j	        S )z+Return the verifier's first SPAKE2 message.)
ri   ro   r   r   r_   r   r   r   rM   r   r   s     r%   r   z_ServerHandshake.get_messagev  r   r'   client_message_hexr   c                   | j         | j        t          d          t          |          }|j        rt          d          t          |t          t          t          t                    | j	                                      }t          || j
                  }t          | j        | j
                  }t          t          t          t          t                               t%          t          t                                        t                               t%          t          t&                                        t                               t%          |                    t                               t%          | j                             t                               t%          |                    t                               t%          |                    t)          | j	                  
  
        }t+          ||| j                  S )z?Finish the verifier handshake using the prover's first message.Nr   r   r   )r   r   rJ   r_   r&   ri   rb   ro   r   r   r   r   rw   r   r   r   r3   rS   rM   r   r:   r   )r$   r   client_pointr   r   verifier_sharer   s          r%   r   z_ServerHandshake.finish  s   '4<+?GHHH$%788# 	42333OM)$<$<dhGGHH
 
 "(DG44()=twGG,MM-i(@(@AABBMM-i(@(@AABBMM-5566MM-(<==>>MM-0011MM-7788$(##
 

 #!&L
 
 
 	
r'   N)r   r1   r   r1   r   r   r    r   r   )r   r;   r    r   r   r/   r'   r%   r   r   e  sV        KK+ + + +   
 
 
 
 
 
r'   r   passwordsalt_b64tuple[int, int]c                $   t          j        |                     d          fdt          |          it          }t          |          dz  }t                              |d|         d          t                              ||d         d          fS )z=Derive the SPAKE2 scalars from the user code and bridge salt.utf-8ry   rR   Nr6   )r}   scryptr@   rB   _SCRYPT_PARAMSrT   r1   rU   )r   r   derivedmidpoints       r%   _compute_w0_w1r     s    n   8$$  G
 7||q Hwyy)511wxyy)511 r'   c                 T    d} | dk    rt          j        t                    } | dk    | S )z<Return a random scalar in the non-zero P-256 subgroup range.r   )secrets	randbelowrl   )rj   s    r%   _random_nonzero_scalarr     s0    F
A++";// A++Mr'   c                  Z    e Zd ZdZddZddZdd	ZddZddZddZ	ddZ
ddZddZdS )TrustedDeviceBridgeProverz3Client-side prover mirroring Apple's prover worker.r    r   c                Z    d| _         d| _        d| _        d| _        d| _        d| _        dS )zBInitialize empty prover state for one bridge verification attempt.NF)_client_shared_secret_raw_key	_verified_verifier_key_prover_keyr#   s    r%   r   z"TrustedDeviceBridgeProver.__init__  s5    37=A'+,0*.r'   r   r;   codec                    t          ||          \  }}t          t                      ||          | _        d| _        d| _        d| _        d| _        d| _        dS )zBInitialize the prover with Apple's salt and the user-entered code.)r   r   r   NF)	r   r   r   r   r   r   r   r   r   )r$   r   r  r   r   s        r%   init_with_saltz(TrustedDeviceBridgeProver.init_with_salt  sh    h//B'+--
 
 

 #!r'   c                `    | j         t          d          | j                                         S )z)Return the prover's first bridge message.Nz1init_with_salt must be called before get_message1)r   rJ   r   r#   s    r%   get_message1z&TrustedDeviceBridgeProver.get_message1  s-    <PQQQ|'')))r'   r   c                    | j         t          d          | j                             |          | _        |                                 S )zHProcess Apple's first bridge message and return the prover confirmation.Nz5init_with_salt must be called before process_message1)r   rJ   r   r   get_message2)r$   r   s     r%   process_message1z*TrustedDeviceBridgeProver.process_message1  sC    <TUUU"l11+>>  """r'   c                `    | j         t          d          | j                                         S )zDReturn the prover confirmation generated from the shared transcript.N3process_message1 must be called before get_message2r   rJ   r   r#   s    r%   r  z&TrustedDeviceBridgeProver.get_message2  /    &RSSS"33555r'   dict[str, object]c                    | j         t          d          | j                             |                                          }|| _        t          |          \  | _        | _        d| _        d|dS )z@Verify Apple's confirmation and persist the derived bridge keys.Nz7process_message1 must be called before process_message2T)
isVerifiedkey)	r   rJ   r   rK   r   r   r   r   r   r$   r   r   s      r%   process_message2z*TrustedDeviceBridgeProver.process_message2  sq    &VWWW%,,[99==??/OPW/X/X,D,"7333r'   r!   c                    | j         S )z>Return whether the bridge confirmation exchange has completed.)r   r#   s    r%   is_verifiedz%TrustedDeviceBridgeProver.is_verified  s
    ~r'   c                <    | j         t          d          | j         S )z0Return the raw shared bridge key as hexadecimal.NzNo bridge key is available yet.)r   rJ   r#   s    r%   get_keyz!TrustedDeviceBridgeProver.get_key  s!    = >???}r'   ciphertext_b64c                   | j         t          d          	 t          |          }|d         }t          |         \  }}|dd|z            }|d|z   d|z   |z            }|d|z   |z   d         }t	          t
                              | j                                                 |||z   t          |g                    }	|	                    d          S # t          t          t          t          f$ r}
t          d          |
d}
~
ww xY w)z0Decrypt Apple's final encrypted validation code.N%Bridge verifier key is not available.r   r	   r   zMalformed bridge payload)r   rJ   rB   _AES_GCM_LAYOUTSr   r3   rS   decryptrE   
IndexErrorKeyErrorr   UnicodeDecodeError)r$   r  payloadversion	iv_length
tag_lengthivtag
ciphertext	plaintextexcs              r%   decrypt_messagez)TrustedDeviceBridgeProver.decrypt_message  s%   %DEEE	B#N33GajG$4W$=!IzQ]*+B!i-!i-**DDEC Y!;!=!=>Ju}}T-?@@AAIIS wi   I
 ##G,,,Hj2DE 	B 	B 	B788cA	Bs   B=C D3DD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  r  r  r  r(  r/   r'   r%   r   r     s        ==/ / / /       * * * *# # # #6 6 6 64 4 4 4      B B B B B Br'   r   c                  B    e Zd ZdZddZddZdd
ZddZddZddZ	dS ) _TrustedDeviceBridgeServerProverz?Internal test helper mirroring Apple's server-side bridge flow.r   r;   r   r    r   c                   t          ||          \  }}t          t          |          }t          t	                      ||          | _        d| _        d| _        d| _        d| _	        dS )zEInitialize the local verifier helper with the same password and salt.)r   r   r   N)
r   ro   r   r   r   _serverr   r   r   r   )r$   r   r   r   r   r   s         r%   r   z)_TrustedDeviceBridgeServerProver.__init__  sq    (33B(R88'+--)
 
 

 >B'+,0*.r'   c                4    | j                                         S )z+Return the verifier's first bridge message.)r-  r   r#   s    r%   r  z-_TrustedDeviceBridgeServerProver.get_message1  s    |'')))r'   r   c                h    | j                             |          | _        |                                 S )z@Process the prover message and return the verifier confirmation.)r-  r   r   r  )r$   r   s     r%   r  z1_TrustedDeviceBridgeServerProver.process_message1#  s-    "l112DEE  """r'   c                `    | j         t          d          | j                                         S )zFReturn the verifier confirmation generated from the shared transcript.Nr
  r  r#   s    r%   r  z-_TrustedDeviceBridgeServerProver.get_message2(  r  r'   r   c                    | j         t          d          | j                             |                                          }|| _        t          |          \  | _        | _        |S )zCVerify the prover confirmation and persist the derived bridge keys.Nz6process_message1 must be called before verify_message2)r   rJ   r   rK   r   r   r   r   r  s      r%   verify_message2z0_TrustedDeviceBridgeServerProver.verify_message2.  sa    &UVVV%,,[99==??/OPW/X/X,D,r'   r&  c                   | j         t          d          d}t          |         \  }}t          j        |          }t          t                              | j                                                 ||	                    d          t          |g                    }|d|          }|| d         }t          |g          |z   |z   |z   }	t          |	          S )zIEncrypt a plaintext validation code using Apple's AES-GCM payload layout.Nr  r   r   )r   rJ   r  r   token_bytesr   r3   rS   encryptr@   rF   )
r$   r&  r   r!  r"  r#  	encryptedr%  r$  r  s
             r%   encrypt_messagez0_TrustedDeviceBridgeServerProver.encrypt_message7  s    %DEEE 0 9	: ++5==);<<==EEW%%7)
 
	
 ||,
%	""R'#-
:W%%%r'   N)r   r;   r   r;   r    r   r   )r   r;   r    r;   r)  )r&  r;   r    r;   )
r)   r*   r+   r,   r   r  r  r  r2  r7  r/   r'   r%   r+  r+    s        II/ / / /* * * *# # # #
6 6 6 6   & & & & & &r'   r+  )N)r0   r1   r2   r   r    r3   )r0   r;   r    r3   )r0   r3   r    r;   )rG   r   r    r;   )r0   r;   r    r   )rG   r   r    r!   )rG   r   r    r   )rc   r   rd   r   r    r   )rG   r   rj   r1   r    r   )rp   r3   r    r3   )
rx   r3   ry   r3   rz   r3   r2   r1   r    r3   )rz   r3   r   r1   r    r1   )r
   )rx   r3   rz   r3   r2   r1   r    r3   )r   r;   r    r   )r   r;   r   r;   r    r   )r    r1   )9r,   
__future__r   r>   r}   r   r   dataclassesr   typingr   cryptography.exceptionsr   +cryptography.hazmat.primitives.ciphers.aeadr   r   r   r   r   r   r   r   r1   rW   rX   rY   rl   _P256_GX_P256_GYr   r   r  r   rg   r   r:   rB   rF   rM   r_   rZ   rb   ri   ro   rw   r   r   r   r   r   r   r   r   r   r   r   r+  r/   r'   r%   <module>r?     sD   E E " " " " " "     ! ! ! ! ! !       . . . . . . > > > > > > 
	
	
	  3 4 #  
#PRT
U
UQ;'
!
#PRT
U
UcF  3QSUVV3QSUVVP	P	x=  $	0 	0 	0 	0 	0 	0 	0 	0 F4	VHh''
) ) ) ) )3 3 3 3
3 3 3 3
V V V V   .   1 1 1 1$ $ $ $6
 
 
 
   " " " "(       0 0 0 0 $"  "  "  "  "  "  "  " J $$  $  $  $  $  $  $  $ N:
 :
 :
 :
 :
 :
 :
 :
z:
 :
 :
 :
 :
 :
 :
 :
z      SB SB SB SB SB SB SB SBl8& 8& 8& 8& 8& 8& 8& 8& 8& 8&r'   