
    `jV                        d dl Z d dlZd dlmZmZ d dlmZ d dlmZm	Z	m
Z
 d dlmZmZmZ d dlmZmZ d dlmZmZmZmZ d dlmZmZmZ d d	l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'm(Z( ddl)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0 ddl1m2Z2 ddl3m4Z4 dZ5 G d de4          Z6 G d de4          Z7 G d de4          Z8 G d de4          Z9dS )    N)InvalidSignature
InvalidTag)default_backend)hasheshmacserialization)ecpaddingrsa)decode_dss_signatureencode_dss_signature)Cipheraead
algorithmsmodes)InvalidUnwrapaes_key_unwrapaes_key_wrap)PKCS7)load_pem_private_keyload_pem_public_key)int_to_bytes)load_pem_x509_certificate   )
ALGORITHMS)JWEErrorJWKError)base64_to_longbase64url_decodebase64url_encodeensure_binaryis_pem_format
is_ssh_keylong_to_base64   )get_random_bytes)Keyc                   ~    e Zd Zej        Zej        Zej        ZefdZd Z	d Z
d Zd Zd Zd Zd Zd	 Zd
 Zd ZdS )CryptographyECKeyc                    |t           j        vrt          d|z            t           j        | j        t           j        | j        t           j        | j        i	                    |          | _
        || _        || _        t          |d          st          |d          r	|| _        d S t          |d          r'|                                                    d          }t#          |t$                    r|                     |          | _        d S t#          |t(                    r|                    d          }t#          |t,                    r	 	 t/          ||                                           }n4# t0          $ r' t3          |d |                                           }Y nw xY wn!# t4          $ r}t          |          d }~ww xY w|| _        d S t          d|z            )N*hash_alg: %s is not a valid hash algorithmpublic_bytesprivate_bytesto_pemutf-8passwordbackendz%Unable to parse an ECKey from key: %s)r   ECr   ES256SHA256ES384SHA384ES512SHA512gethash_alg
_algorithmcryptography_backendhasattrprepared_keyr.   decode
isinstancedict_process_jwkstrencodebytesr   
ValueErrorr   	Exceptionselfkey	algorithmr=   es        f/var/www/app.qaans.com/backend/venv/lib/python3.11/site-packages/jose/backends/cryptography_backend.py__init__zCryptographyECKey.__init__&   s   JM))G)STTT dkdkdk
 #i..	 	
 $$8!3'' 	73+H+H 	 #DF3!! 	/**,,%%g..Cc4   	 $ 1 1# 6 6DFc3 	&**W%%Cc5!! 	"h-c43L3L3N3NOOCC! h h h.sT4KdKdKfKfgggCCCh " " "qkk!" !$DF>DEEEs6   "E1 0F& 1.F"F& !F""F& &
G0F??Gc                 
                        d          dk    s%t          d                     d          z            t          fddD                       st          d          t                               d                    }t                               d                    }t          j        t          j        t          j        d	d
                  }t	          j        || |                      }dv r^t                               d                    }t	          j	        ||          }|
                    |                                           S |                    |                                           S )Nktyr3   z0Incorrect key type. Expected: 'EC', Received: %sc              3       K   | ]}|v V  	d S N .0kjwk_dicts     rN   	<genexpr>z1CryptographyECKey._process_jwk.<locals>.<genexpr>W   s'      <<Q1=<<<<<<    )xycrvz Mandatory parameters are missingr[   r\   )P-256P-384P-521r]   d)r:   r   allr   r	   	SECP256R1	SECP384R1	SECP521R1EllipticCurvePublicNumbersEllipticCurvePrivateNumbersprivate_keyr=   
public_key)rJ   rX   r[   r\   curvepublicra   privates    `      rN   rC   zCryptographyECKey._process_jwkS   s^   ||E""d**MPXP\P\]bPcPccddd<<<<*;<<<<< 	?=>>>8<<,,--8<<,,--\\\
 
 5/	 .q!UUWW==(??x||C0011A4Q??G&&t'@'@'B'BCCC$$T%>%>%@%@AAArZ   c                 ^    t          t          j        | j        j        dz                      S )zDetermine the correct serialization length for an encoded signature component.

        This is the number of bytes required to encode the maximum key value.
        g       @)intmathceilr?   key_sizerJ   s    rN   _sig_component_lengthz'CryptographyECKey._sig_component_lengthl   s'    
 49T.7#=>>???rZ   c                     t          |          \  }}|                                 }t          ||          t          ||          z   S )z4Convert signature from DER encoding to RAW encoding.)r   rs   r   )rJ   der_signaturerscomponent_lengths        rN   _der_to_rawzCryptographyECKey._der_to_raws   sF    #M2215577A/00<CS3T3TTTrZ   c                 B   |                                  }t          |          t          d|z            k    rt          d          |d|         }||d         }t                              |d          }t                              |d          }t          ||          S )z4Convert signature from RAW encoding to DER encoding.r   zInvalid signatureNbig)rs   lenrn   rG   
from_bytesr   )rJ   raw_signaturerx   r_bytess_bytesrv   rw   s          rN   _raw_to_derzCryptographyECKey._raw_to_dery   s    5577}Q)9%9!:!:::0111 1!1 12 0 1 12NN7E**NN7E**#Aq)))rZ   c                 N   | j         j        dz  | j        j        j        k    r0t          d| j        j        j        d| j         j        z  fz            | j                            |t          j	        |                                                      }| 
                    |          S )N   z1this curve (%s) is too short for your digest (%d))r;   digest_sizer?   rj   rq   	TypeErrornamesignr	   ECDSAry   )rJ   msg	signatures      rN   r   zCryptographyECKey.sign   s    =$q(4+<+B+KKK'*.*;*A*FDMLeHe)fg   %**30I0IJJ		***rZ   c                     	 |                      |          }| j                            ||t          j        |                                                      dS # t          $ r Y dS w xY w)NTF)r   r?   verifyr	   r   r;   rH   )rJ   r   sigr   s       rN   r   zCryptographyECKey.verify   sn    	((--I$$YRXdmmoo5N5NOOO4 	 	 	55	s   AA 
A'&A'c                 ,    t          | j        d          S Nr,   r>   r?   rr   s    rN   	is_publiczCryptographyECKey.is_public       t(.999rZ   c                     |                                  r| S |                     | j                                        | j                  S rS   r   	__class__r?   ri   r<   rr   s    rN   ri   zCryptographyECKey.public_key   >    >> 	K~~d/::<<doNNNrZ   c                 >   |                                  r<| j                            t          j        j        t          j        j                  }|S | j                            t          j        j        t          j	        j
        t          j                              }|S )Nencodingformatr   r   encryption_algorithm)r   r?   r,   r   EncodingPEMPublicFormatSubjectPublicKeyInfor-   PrivateFormatTraditionalOpenSSLNoEncryption)rJ   pems     rN   r.   zCryptographyECKey.to_pem   s    >> 	#00&/3M<V<k 1  C J--"+/ .A!.!;!=!= . 
 

 
rZ   c                    |                                  s| j                                        }n| j        }dddd| j        j        j                 }| j        j        j        dz   dz  }| j        d|t          |                                j	        |          
                    d	          t          |                                j        |          
                    d	          d
}|                                  sE| j                                        j        }t          ||          
                    d	          |d<   |S )Nr^   r_   r`   )	secp256r1	secp384r1	secp521r1   r   r3   )sizeASCII)algrQ   r]   r[   r\   ra   )r   r?   ri   rj   r   rq   r<   r$   public_numbersr[   r@   r\   private_numbersprivate_value)rJ   ri   r]   rq   datar   s         rN   to_dictzCryptographyECKey.to_dict   s@   ~~ 	+*5577JJ*J !  
 
 

!
&	( %+4q8Q> ?
 9 9 ; ; =HMMMTTU\]]
 9 9 ; ; =HMMMTTU\]]
 
 ~~ 	U -==??MM&}8DDDKKGTTDIrZ   N)__name__
__module____qualname__r   r5   r7   r9   r   rO   rC   rs   ry   r   r   r   r   ri   r.   r   rT   rZ   rN   r)   r)   !   s        ]F]F]F<K +F +F +F +FZB B B2@ @ @U U U
* 
* 
*+ + +  : : :O O O
      rZ   r)   c                      e Zd Zej        Zej        Zej        Z ej                    Z	 ej
         ej         ej                               ej                    d          Z ej
         ej         ej                               ej                    d          ZefdZd Zd Zd Zd Zd Zd Zdd
Zd Zd Zd ZdS )CryptographyRSAKeyNc                 n   |t           j        vrt          d|z            t           j        | j        t           j        | j        t           j        | j        i	                    |          | _
        || _        t           j        | j        t           j        | j        t           j        | j        i	                    |          | _        || _        t#          |d          rt#          |d          st#          |d          r	|| _        d S t'          |t(                    r|                     |          | _        d S t'          |t,                    r|                    d          }t'          |t0                    r	 |                    d          r|                     |           d S 	 t7          ||                                           | _        n9# t8          $ r, t;          |d |                                           | _        Y nw xY wn!# t<          $ r}t          |          d }~ww xY wd S t          d|z            )	Nr+   r,   r   r-   r/   s   -----BEGIN CERTIFICATE-----r0   z'Unable to parse an RSA_JWK from key: %s)r   RSAr   RS256r5   RS384r7   RS512r9   r:   r;   r<   RSA1_5RSA_OAEPRSA_OAEP_256r
   r=   r>   r?   rA   rB   rC   rD   rE   rF   
startswith_process_certr   rG   r   rH   rI   s        rN   rO   zCryptographyRSAKey.__init__   s:   JN**G)STTT dkdkdk
 #i..	 	
 $ t{#T%6
 #i..	 	 %9! C(( 	WS:J-K-K 	PWX[]lPmPm 	 #DFc4   	 $ 1 1# 6 6DFc3 	&**W%%Cc5!! 	
">>"@AA &&s+++Fv(;CAZAZA\A\(](]D%%! v v v(<S4Y]YrYrYtYt(u(u(uD%%%v " " "qkk!"F@3FGGGs<   3*H  'G H 3G>;H =G>>H 
H HH c           	      f                        d          dk    s%t          d                     d          z            t                               dd                    }t                               d                    }t          j        ||          }dvr'|                    |                                           S t                               d                    }g d}t          fd	|D                       rt          fd
|D                       st          d          t          d                   }t          d                   }t          d                   }	t          d                   }
t          d                   }nXt          j	        |||          \  }}t          j
        ||          }	t          j        ||          }
t          j        ||          }t          j        ||||	|
||          }|                    |                                           S )NrQ   r   z1Incorrect key type. Expected: 'RSA', Received: %srM      nra   )pqdpdqqic              3       K   | ]}|v V  	d S rS   rT   rU   s     rN   rY   z2CryptographyRSAKey._process_jwk.<locals>.<genexpr>  s'      77Q1=777777rZ   c              3       K   | ]}|v V  	d S rS   rT   rU   s     rN   rY   z2CryptographyRSAKey._process_jwk.<locals>.<genexpr>  s'      ??Q1=??????rZ   z2Precomputed private key parameters are incomplete.r   r   r   r   r   )r:   r   r   r   RSAPublicNumbersri   r=   anyrb   rsa_recover_prime_factorsrsa_crt_dmp1rsa_crt_dmq1rsa_crt_iqmpRSAPrivateNumbersrh   )rJ   rX   rM   r   rk   ra   extra_paramsr   r   r   r   r   rl   s    `           rN   rC   zCryptographyRSAKey._process_jwk  s   ||E""e++NQYQ]Q]^cQdQddeee8<<S11228<<,,--%a++h$$T%>%>%@%@AAA x||C0011A777L7777,77777 ,????,????? Y ##WXXX"8C=11"8C=11#HTN33#HTN33#HTN33 4Q1==1%a++%a++%a+++Aq!RRHHG&&t'@'@'B'BCCCrZ   c                 |    t          ||                                           }|                                | _        d S rS   )r   r=   ri   r?   )rJ   rK   s     rN   r   z CryptographyRSAKey._process_cert,  s5    'T-F-F-H-HIINN,,rZ   c                     	 | j                             |t          j                    |                                           }n!# t
          $ r}t          |          d }~ww xY w|S rS   )r?   r   r
   PKCS1v15r;   rH   r   )rJ   r   r   rM   s       rN   r   zCryptographyRSAKey.sign0  se    	)..sG4D4F4FXXII 	 	 	1++	s   ?A 
A AA c                    |                                  st          j        d           	 |                                 j                            ||t          j                    |                                            dS # t          $ r Y dS w xY w)NzKAttempting to verify a message with a private key. This is not recommended.TF)
r   warningswarnri   r?   r   r
   r   r;   r   )rJ   r   r   s      rN   r   zCryptographyRSAKey.verify7  s    ~~ 	lMjkkk	OO*11#sG<L<N<NPTP]P]P_P_```4 	 	 	55	s   AA> >
BBc                 ,    t          | j        d          S r   r   rr   s    rN   r   zCryptographyRSAKey.is_publicA  r   rZ   c                     |                                  r| S |                     | j                                        | j                  S rS   r   rr   s    rN   ri   zCryptographyRSAKey.public_keyD  r   rZ   PKCS8c                    |                                  ro|dk    rt          j        j        }n*|dk    rt          j        j        }nt          d|z            | j                            t          j        j	        |          }|S |dk    rt          j
        j        }n*|dk    rt          j
        j        }nt          d|z            | j                            t          j        j	        |t          j                              S )Nr   PKCS1zInvalid format specified: %rr   r   )r   r   r   r   r   rG   r?   r,   r   r   r   r   r   r-   r   )rJ   
pem_formatfmtr   s       rN   r.   zCryptographyRSAKey.to_pemI  s    >> 	W$$#0Ew&&#06 !?*!LMMM#00-:P:T]`0aaCJ  -3CC7""-@CC;jHIII .."+/R_RlRnRn / 
 
 	
rZ   c                    |                                  s| j                                        }n| j        }| j        dt	          |                                j                                      d          t	          |                                j                                      d          d}|                                  s|	                    t	          | j        
                                j                                      d          t	          | j        
                                j                                      d          t	          | j        
                                j                                      d          t	          | j        
                                j                                      d          t	          | j        
                                j                                      d          t	          | j        
                                j                                      d          d           |S )Nr   r   )r   rQ   r   rM   )ra   r   r   r   r   r   )r   r?   ri   r<   r$   r   r   r@   rM   updater   ra   r   r   dmp1dmq1iqmp)rJ   ri   r   s      rN   r   zCryptographyRSAKey.to_dict_  s   ~~ 	+*5577JJ*J ?
 9 9 ; ; =>>EEgNN
 9 9 ; ; =>>EEgNN	
 
 ~~ 
	KK'(9(I(I(K(K(MNNUUV]^^'(9(I(I(K(K(MNNUUV]^^'(9(I(I(K(K(MNNUUV]^^():)J)J)L)L)QRRYYZabb():)J)J)L)L)QRRYYZabb():)J)J)L)L)QRRYYZabb 	 	 	 rZ   c                     	 | j                             || j                  }n!# t          $ r}t	          |          d }~ww xY w|S rS   )r?   encryptr
   rH   r   )rJ   key_datawrapped_keyrM   s       rN   wrap_keyzCryptographyRSAKey.wrap_keyz  sV    	+33HdlKKKK 	 	 	1++	 s    # 
A<Ac                     	 | j                             || j                  }|S # t          $ r}t	          |          d }~ww xY wrS   )r?   decryptr
   rH   r   )rJ   r   unwrapped_keyrM   s       rN   
unwrap_keyzCryptographyRSAKey.unwrap_key  sR    	 -55k4<PPM   	 	 	1++	s   !$ 
A=A)r   )r   r   r   r   r5   r7   r9   r
   r   r   OAEPMGF1SHA1r   r   r   rO   rC   r   r   r   r   ri   r.   r   r   r   rT   rZ   rN   r   r      sZ       ]F]F]FWFw|LGL77MMH7<]V]__ = =}v}PTUUL<K -H -H -H -H^'D 'D 'DR- - -    : : :O O O

 
 
 
,  6      rZ   r   c                      e Zd Zej        ej        ej        ej        fZej	        ej
        ej        ej        fZej        ej        ej        ej        ej        fZej        fZej        fZej        ej        ej        fZej        ej        ej	        ej        ej        ej        ej        ej        ej        ej        ej        ej        ej        ej        ej        ej        ej        ej        ej        ej        ej
        ej        ej        ej        ej        dej        dej        diZej        j        dz  ddZ d Z!d Z"ddZ#ddZ$d	 Z%d
 Z&dS )CryptographyAESKeyNr      )CBCGCMc                    |t           j        vrt          d|z            |t           j                            t           j                  vrt          d|z            || _        | j                            | j                  | _	        || j
        v r%t          |          dk    rt          d|           || j        v r%t          |          dk    rt          d|           || j        v r%t          |          dk    rt          d|           || j        v r%t          |          d	k    rt          d
|           || j        v r%t          |          dk    rt          d|           || _        d S )Nz%s is not a valid AES algorithmz%s is not a supported algorithm   zKey must be 128 bit for alg    zKey must be 192 bit for alg     zKey must be 256 bit for alg 0   zKey must be 384 bit for alg @   zKey must be 512 bit for alg )r   AESr   	SUPPORTEDunion
AES_PSEUDOr<   MODESr:   _modeKEY_128r|   KEY_192KEY_256KEY_384KEY_512_keyrJ   rK   rL   s      rN   rO   zCryptographyAESKey.__init__  sy   JN**<yHIIIJ066z7LMMMM<yHIII#Z^^DO44
$$SRE)EEFFF$,&&3s88r>>E)EEFFF$,&&3s88r>>E)EEFFF$,&&3s88r>>E)EEFFF$,&&3s88r>>E)EEFFF			rZ   c                 @    | j         dt          | j                  d}|S )Noctr   rQ   rW   )r<   r    r  )rJ   r   s     rN   r   zCryptographyAESKey.to_dict  s#    u;KDI;V;VWWrZ   c                    t          |          }	 | j                            | j        j        t
          j        j                  }t          |          }|                     |          }|j        dk    rUt          j
        | j                  }|                    |||          }|d t          |          dz
           }|dd          }	nt          t          j        | j                  |t                                }|                                }
t#          t
          j        j                                                  }|                    |          }||                                z  }|
                    |          |
                                z   }d }	|||	fS # t*          $ r}t-          |          d }~ww xY w)Nr   r   ir2   )r!   IV_BYTE_LENGTH_MODE_MAPr:   r  r   r   r   
block_sizer&   r   AESGCMr  r   r|   r   r   	encryptorr   padderr   finalizerH   r   )rJ   
plain_textaadiv_byte_lengthivmodeciphercipher_text_and_tagcipher_textauth_tagr  r  padded_datarM   s                 rN   r   zCryptographyAESKey.encrypt  s   ":..
	!9==djoz~OhiiN!.11B::b>>DyE!!TY//&,nnRS&I&I#12QC8K4L4Lr4Q2QR.stt4
ty 9 94IZIZ[[[",,..	z~899@@BB$mmJ77v000'..{;;i>P>P>R>RR{H,, 	 	 	1++	s   FF 
F=)F88F=c                 2   t          |          }	 t          |          }|                     |          }|j        dk    re|t          d          t	          j        | j                  }||z   }	 |                    |||          }n# t          $ r t          d          w xY wt          t          j        | j                  |t                                }|                                }	|	                    |          }
|
|	                                z  }
t#          t          j        j                                                  }|                    |
          }||                                z  }|S # t(          $ r}t          |          d }~ww xY w)Nr   ztag cannot be NonezInvalid JWE Auth Tagr  )r!   r  r   rG   r   r  r  r   r   r   r   r   r   r   	decryptorr   r  r   r  unpadderrH   )rJ   r  r  r  tagr  r  r  r  r  padded_plain_textr   rM   s                rN   r   zCryptographyAESKey.decrypt  s   #K00	r""B::b>>DyE!!;$%9:::TY//&1C&7#;!'4G!M!MJJ! ; ; ;"#9:::;  
ty 9 94IZIZ[[[",,..	$-$4$4[$A$A!!Y%7%7%9%99! !:;;DDFF%__->??
h//111
 	 	 	1++	s1   AE8 0B E8 B""CE8 8
FFFc                 h    t          |          }t          | j        |t                                }|S rS   )r!   r   r  r   )rJ   r   r  s      rN   r   zCryptographyAESKey.wrap_key  s.     **"49h8I8IJJrZ   c                     t          |          }	 t          | j        |t                                }n!# t          $ r}t          |          d }~ww xY w|S rS   )r!   r   r  r   r   r   )rJ   r   r  causes       rN   r   zCryptographyAESKey.unwrap_key  s`    #K00	"'	;@Q@QRRJJ 	" 	" 	"5//!	"s   "4 
AAArS   )NNN)'r   r   r   r   A128GCM	A128GCMKWA128KWA128CBCr  A192GCM	A192GCMKWA192KWA192CBCr  A256GCM	A256GCMKWA256KWA128CBC_HS256A256CBCr  A192CBC_HS384r  A256CBC_HS512r  AES_KW_ALGSr   r   r   r   r   r   r  r  rO   r   r   r   r   r   rT   rZ   rN   r   r     s       !:#79JJL^_G!:#79JJL^_G G ')G')G$j&79JKK 	EIEIEI %) %) %)EIEIEIeieiei444E$ '1n&?1&DWUU  ,     .   6  
    rZ   r   c                       e Zd ZdZej         ej                    ej         ej	                    ej
         ej                    iZd Zd Zd Zd Zd ZdS )CryptographyHMACKeyzf
    Performs signing and verification operations using HMAC
    and the specified hash function.
    c                 "   |t           j        vrt          d|z            || _        | j                            |          | _        t          |t                    r| 	                    |          | _
        d S t          |t                    s$t          |t                    st          d          t          |t                    r|                    d          }t          |          st          |          rt          d          || _
        d S )Nr+   z+Expecting a string- or bytes-formatted key.r/   zdThe specified key is an asymmetric key or x509 certificate and should not be used as an HMAC secret.)r   HMACr   r<   ALG_MAPr:   	_hash_algrA   rB   rC   r?   rD   rF   rE   r"   r#   r  s      rN   rO   zCryptographyHMACKey.__init__  s	   JO++G)STTT#)))44c4   	 $ 1 1# 6 6DF#s## 	JJsE,B,B 	JHIIIc3 	&**W%%C 	C 	9  
  rZ   c                    |                     d          dk    s%t          d|                     d          z            |                     d          }|                    d          }t          |          }t	          |          }|S )NrQ   r
  z1Incorrect key type. Expected: 'oct', Received: %srW   r/   )r:   r   rE   rF   r   )rJ   rX   rW   s      rN   rC   z CryptographyHMACKey._process_jwk'  s|    ||E""e++NQYQ]Q]^cQdQddeeeLLHHW!HHQrZ   c                 b    | j         dt          | j                                      d          dS )Nr
  r   r  )r<   r    r?   r@   rr   s    rN   r   zCryptographyHMACKey.to_dict2  s5    ?!$"344;;GDD
 
 	
rZ   c                     t          |          }t          j        | j        | j        t                                }|                    |           |                                }|S )Nr  )r!   r   r9  r?   r;  r   r   r  )rJ   r   hr   s       rN   r   zCryptographyHMACKey.sign9  sR    C  Id'ARARSSS	JJLL	rZ   c                    t          |          }t          |          }t          j        | j        | j        t                                }|                    |           	 |                    |           d}n# t          $ r d}Y nw xY w|S )Nr  TF)	r!   r   r9  r?   r;  r   r   r   r   )rJ   r   r   r?  verifieds        rN   r   zCryptographyHMACKey.verify@  s    C  C  Id'ARARSSS		HHSMMMHH 	 	 	HHH	s   "A: :B	B	N)r   r   r   __doc__r   HS256r   r5   HS384r7   HS512r9   r:  rO   rC   r   r   r   rT   rZ   rN   r7  r7    s         
 *2BMFMOOU_UegtgmgtgvgvwG     0	 	 	
 
 
  
 
 
 
 
rZ   r7  ):ro   r   cryptography.exceptionsr   r   cryptography.hazmat.backendsr   cryptography.hazmat.primitivesr   r   r   )cryptography.hazmat.primitives.asymmetricr	   r
   r   /cryptography.hazmat.primitives.asymmetric.utilsr   r   &cryptography.hazmat.primitives.ciphersr   r   r   r   &cryptography.hazmat.primitives.keywrapr   r   r   &cryptography.hazmat.primitives.paddingr   ,cryptography.hazmat.primitives.serializationr   r   cryptography.utilsr   cryptography.x509r   	constantsr   
exceptionsr   r   utilsr   r   r    r!   r"   r#   r$    r&   baser'   _bindingr)   r   r   r7  rT   rZ   rN   <module>rW     s     @ @ @ @ @ @ @ @ 8 8 8 8 8 8 F F F F F F F F F F F F F F F F F F F F f f f f f f f f R R R R R R R R R R R R ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 8 8 8 8 8 8 b b b b b b b b + + + + + + 7 7 7 7 7 7 " " " " " " + + + + + + + +                             g g g g g g g gT| | | | | | | |~z z z z z z z zzC C C C C# C C C C CrZ   