U
    {hc                     @   s  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
 d dlmZ d dl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mZmZmZmZ G dd dZG dd deZG dd deZe   G dd deZ!e!   G dd deZ"e"   G dd deZ#e#   G dd deZ$G dd deZ%dd Z&G dd deZ'G d d! d!eZ(G d"d# d#eZ)G d$d% d%eZ*G d&d' d'eZ+G d(d) d)eZ,G d*d+ d+eZ-G d,d- d-eZ.G d.d/ d/eZ/d0S )1    )BytesIO)Path)patch)TestCaseoverride_settings)hooks)image_operations)InvalidFilterSpecErrorUnknownOutputImageFormatError)TransformOperation)FilterImage)get_rendition_or_not_found)get_test_image_fileget_test_image_file_avifget_test_image_file_jpegget_test_image_file_tiffget_test_image_file_webpc                   @   s<   e Zd ZdZdd Zdd Zdd Zdd	 Zed
d Z	dS )DummyImageTransformz~
    This class pretends to be a ImageTransform but instead, it records
    the operations that have been performed on it
    c                 C   s   |  | || _g | _d S N)_check_sizesize
operations)selfr    r   r/var/www/dating/data/www/fatepal.com/env/lib/python3.8/site-packages/wagtail/images/tests/test_image_operations.py__init__   s    
zDummyImageTransform.__init__c                 C   s   t | j}| j |_|S r   )r   r   r   copy)r   cloner   r   r   r   $   s    
zDummyImageTransform.clonec                 C   s,   |  | |  }|jd|f ||_|S )z^
        Change the image size, stretching the transform to make it fit the new size.
        resize)r   r   r   appendr   )r   r   r   r   r   r   r   )   s
    
zDummyImageTransform.resizec                 C   s<   |  t|j |  }|jdt|f t|j|_|S )z7
        Crop the image to the specified rect.
        crop)r   tupler   r   r   r    )r   rectr   r   r   r   r!   3   s
    zDummyImageTransform.cropc                 C   sj   t | tr>t| dks>t| d | d ks>t| d | d krFtd| d dk s^| d dk rftdd S )N   r      z(Image size must be a 2-tuple of integersz0Image width and height must both be 1 or greater)
isinstancer"   lenint	TypeError
ValueErrorr   r   r   r   r   =   s    
zDummyImageTransform._check_sizeN)
__name__
__module____qualname____doc__r   r   r   r!   staticmethodr   r   r   r   r   r      s   

r   c                   @   s\   e Zd ZdZg Zg Zg Zg Zedd Z	edd Z
edd Zedd	 Zed
d ZdS )ImageTransformOperationTestCaseNc                    s     fdd}t d |_|S )Nc                    s8   | j d }  D ]\}}| t||| qd S N-)operation_classsplititemsassertEqualgetattr)r   	operationattrvalueexpected_outputfilter_specr   r   test_filter_specT   s    zOImageTransformOperationTestCase.make_filter_spec_test.<locals>.test_filter_specztest_filter_%sstrr,   )clsr>   r=   r?   r   r<   r   make_filter_spec_testR   s    z5ImageTransformOperationTestCase.make_filter_spec_testc                    s$    fdd}t d tj|_|S )Nc                    s   | j t| jf d  d S r2   )assertRaisesr	   r4   r5   r   r>   r   r   test_filter_spec_error`   s     z[ImageTransformOperationTestCase.make_filter_spec_error_test.<locals>.test_filter_spec_errorztest_filter_{}_raises_{})rA   formatr	   r,   )rB   r>   rG   r   rF   r   make_filter_spec_error_test^   s     z;ImageTransformOperationTestCase.make_filter_spec_error_testc                    s"    fdd}t d |_|S )Nc                    sH   t f }| jd }t|j|jf}|||}| |j  d S r2   )	r   r4   r5   r   widthheightrunr7   r   r   imager9   contextr=   r>   image_kwargsr   r   test_runn   s
    
z?ImageTransformOperationTestCase.make_run_test.<locals>.test_runztest_run_%sr@   )rB   r>   rQ   r=   rR   r   rP   r   make_run_testl   s    z-ImageTransformOperationTestCase.make_run_testc                    s     fdd}t d  |_|S )Nc              	      sP   t f }| j d }t|j|jf}| t ||| W 5 Q R X d S r2   )	r   r4   r5   r   rJ   rK   rD   r*   rL   rM   r>   rQ   r   r   
test_norun   s
    
zCImageTransformOperationTestCase.make_norun_test.<locals>.test_norunztest_norun_%sr@   )rB   r>   rQ   rU   r   rT   r   make_norun_test   s    z/ImageTransformOperationTestCase.make_norun_testc                 C   s   | j d krd S | jD ]}| j| }t| |j| q| jD ]}| |}t| |j| q8| jD ]}| j| }t| |j| q\| j	D ]}| j
| }t| |j| qd S r   )r4   filter_spec_testsrC   setattrr,   filter_spec_error_testsrI   	run_testsrS   norun_testsrV   )rB   argsZfilter_spec_testr>   Zfilter_spec_error_testZrun_testZ
norun_testr   r   r   setup_test_methods   s    








z2ImageTransformOperationTestCase.setup_test_methods)r,   r-   r.   r4   rW   rY   rZ   r[   classmethodrC   rI   rS   rV   r]   r   r   r   r   r1   K   s   



r1   c                   @   s  e Zd ZejZdddddfdddddfdddddfdddd	dfd
ddddfdddd	dfdddddfgZdddddddgZddddddgfddddddgfddddddgfd dddd!ddd"dd#gfd$dddd!ddd"d%gfd&d'dd'd!ddd"d(gfd)d'ddd!dd*d"d+d,gfd-dddd.gfd/d0dd1d!ddd"d2gfd3d0d0d1d1d0d0d"d4gfd5d	d	dd6gfd7d	d	dd6gfd8d	d	dd6gfgZd9S ):TestFillOperationzfill-800x600   X  r   )rJ   rK   Zcrop_closenesszhello-800x600zfill-800x600-c0zfill-800x600-c100r%   zfill-800x600-c50g      ?zfill-800x600-c1000zfill-800000x100i 5 d   fillzfill-800zfill-abczfill-800xabczfill-800x600-zfill-800x600x10zfill-800x600-d100  rJ   rK   )r!   )r   }   rd   ik  )r   )r`   ra   zfill-200x200  i  )r!   )r   Z   rg   iv  )r   )   ri   z
fill-80x60  )rJ   rK   focal_point_xfocal_point_yfocal_point_widthfocal_point_height)r   )P   <   zfill-80x60-c100)r!   )i    rd     zfill-100x60-c100  )r!   )il  rq   rs   rr   zfill-50x50-c100   )r!   )i  i  i  i&  )r   )2   ru   zfill-1000x800)r!   )r   
   rb   rh   zfill-1000x800-c100  i  )r!   )   rb   i  i  zfill-1500x1500-c100)r!   )r   r   rw   rw   fill-100x100)r!   )r   r   r%   r%   zfill-100x150zfill-150x100N)	r,   r-   r.   r   ZFillOperationr4   rW   rY   rZ   r   r   r   r   r_      s  





	
 r_   c                   @   s   e Zd ZejZdddddfdddddfgZddd	d
dddgZdddddgfdddddgfdddddgfdddddgfgZdS )TestMinMaxOperationzmin-800x600minr`   ra   )methodrJ   rK   zmax-800x600maxzmin-800zmin-abczmin-800xabczmin-800x600-zmin-800x600-c100zmin-800x600x10rd   re   )r   )r`   r`   )r   )ra   ra   zmax-400x400r%   r   )  r%   r   )r%   r   N)	r,   r-   r.   r   ZMinMaxOperationr4   rW   rY   rZ   r   r   r   r   rz   x  sB   			rz   c                   @   s~   e Zd ZejZddddfddddfgZddd	d
gZdddddgfdddddgfdddddgfdddddgfgZdS )TestWidthHeightOperationz	width-800rJ   r`   )r|   r   z
height-600rK   ra   zwidth-800x600z	width-abczwidth-800-c100	width-400rd   rj   re   )r   )r   ri   z
height-400)r   )r`   r   r%   r~   r   N)	r,   r-   r.   r   ZWidthHeightOperationr4   rW   rY   rZ   r   r   r   r   r     s<   
			r   c                   @   s   e Zd ZejZddddfddddfgZdddd	gZdd
dddgfdd
dddgfdd
dddededffgfdd
dddgfdddddgfgZ	dS )TestScaleOperationz	scale-100scalerb   )r|   percentzscale-50ru   zscale-800x600z	scale-abczscale-800-c100rd   rj   re   )r   )rd   rj   )r   )rj   rx   zscale-83.0322r   gjt@gjty@r%   )r   )rj   r%   )r   )r%   rx   N)
r,   r-   r.   r   ZScaleOperationr4   rW   rY   r(   rZ   r   r   r   r   r     sF   
				r   c                   @   s$   e Zd Zdd Zdd Zdd ZdS )TestCacheKeyc                 C   s0   t ddd}tdd}||}| |d d S )Nrd   re   zmax-100x100spec r   r   Zget_cache_keyr7   r   rN   fil	cache_keyr   r   r   test_cache_key&  s    

zTestCacheKey.test_cache_keyc                 C   s0   t ddd}tdd}||}| |d d S )Nrd   re   ry   r   Z2e16d0bar   r   r   r   r   test_cache_key_fill_filter-  s    

z'TestCacheKey.test_cache_key_fill_filterc                 C   s8   t ddddddd}tdd}||}| |d d S )Nrd   rb   rj   )rJ   rK   rm   rn   rk   rl   ry   r   Z0bbe3b2fr   r   r   r   r   +test_cache_key_fill_filter_with_focal_point4  s    

z8TestCacheKey.test_cache_key_fill_filter_with_focal_pointN)r,   r-   r.   r   r   r   r   r   r   r   r   %  s   r   c                   @   s$   e Zd Zdd Zdd Zdd ZdS )DummyOperationc                 C   s   d S r   r   rE   r   r   r   	constructD  s    zDummyOperation.constructc                 C   s   d S r   r   r   rO   rN   r   r   r   run_mockG  s    zDummyOperation.run_mockc                 C   s   |  || |S r   )r   r   r   r   r   rL   J  s    zDummyOperation.runN)r,   r-   r.   r   r   rL   r   r   r   r   r   C  s   r   c                   C   s   dt fdt fgS )NZ
operation1Z
operation2)r   r   r   r   r   register_image_operations_hookO  s    r   c                   @   s,   e Zd Zeedededd Z	dS )
TestFilterr   register_image_operationsc                 C   s<   t dd}tjjdt d}||t  | |jd d S )Noperation1|operation2r   
Test imagetitlefiler$   )	r   r   objectscreater   rL   r   r7   Z
call_count)r   r   r   rN   r   r   r   test_runs_operationsT  s    
zTestFilter.test_runs_operationsN)
r,   r-   r.   r   objectr   r   register_temporarilyr   r   r   r   r   r   r   S  s   
 r   c                   @   s    e Zd Zededd ZdS )TestUnknownOutputImageFormatr   c                 C   s4   t dd}tjjdt d}| t|j|t  d S )Nr   r   r   r   )	r   r   r   r   r   rD   r
   rL   r   r   r   rN   r   r   r   test_run_raises_errord  s    
 z2TestUnknownOutputImageFormat.test_run_raises_errorN)r,   r-   r.   r   r   r   r   r   r   r   r   r   c  s
    r   c                   @   s\   e 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d ZdS )TestFormatFilterc                 C   s<   t dd}tjjdt d}||t }| |jd d S )Nwidth-400|format-avifr   r   r   Zavif	r   r   r   r   r   rL   r   r7   format_namer   r   rN   outr   r   r   	test_avifp  s    
zTestFormatFilter.test_avifc              	   C   sX   t dd}tjjdt d}t }td}||| W 5 Q R X |j|dddd	 d S )
Nzwidth-400|format-avif-losslessr   r   r   PIL.Image.Image.saveAVIFi  )qualityZchroma	r   r   r   r   r   r   r   rL   assert_called_withr   r   rN   fsaver   r   r   test_avif_losslessz  s    

z#TestFormatFilter.test_avif_losslessc                 C   s<   t dd}tjjdt d}||t }| |jd d S )Nzwidth-400|format-jpegr   r   r   Zjpegr   r   r   r   r   	test_jpeg  s    
zTestFormatFilter.test_jpegc                 C   s<   t dd}tjjdt d}||t }| |jd d S )Nzwidth-400|format-pngr   r   r   pngr   r   r   r   r   test_png  s    
zTestFormatFilter.test_pngc                 C   s<   t dd}tjjdt d}||t }| |jd d S )Nzwidth-400|format-gifr   r   r   Zgifr   r   r   r   r   test_gif  s    
zTestFormatFilter.test_gifc                 C   s<   t dd}tjjdt d}||t }| |jd d S )Nwidth-400|format-webpr   r   r   webpr   r   r   r   r   	test_webp  s    
zTestFormatFilter.test_webpc                 C   s<   t dd}tjjdt d}||t }| |jd d S )Nwidth-400|format-icor   r   r   Zicor   r   r   r   r   test_ico  s    
zTestFormatFilter.test_icoc                 C   s@   t dd}tjjdt d}t||}| t|jj	j
d d S )Nr   r   r   r   z.ico)r   r   r   r   r   r   r7   r   r   namesuffix)r   r   Z
good_imageZ	renditionr   r   r   test_ico_rendition  s    

z#TestFormatFilter.test_ico_renditionc              	   C   sX   t dd}tjjdt d}t }td}||| W 5 Q R X |j|dddd	 d S )
Nzwidth-400|format-webp-losslessr   r   r   r   WEBPro   Tr   Zlosslessr   r   r   r   r   test_webp_lossless  s    

z#TestFormatFilter.test_webp_losslessc                 C   s4   t dd}tjjdt d}| t|j|t  d S )Nzwidth-400|format-foor   r   r   )	r   r   r   r   r   rD   r	   rL   r   r   r   r   r   test_invalid  s    
zTestFormatFilter.test_invalidN)r,   r-   r.   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   o  s   






r   c                   @   sX   e Zd Zdd Zdd Zdd Zdd Zd	d
 Zedddd Z	edddd Z
dS )TestAvifQualityFilterc              	   C   sV   t dd}tjjdt d}t }td}||| W 5 Q R X |j|ddd d S )	Nr   r   r   r   r   r   ro   r   )	r   r   r   r   r   r   r   rL   r   r   r   r   r   test_default_quality  s    

z*TestAvifQualityFilter.test_default_qualityc              	   C   sV   t dd}tjjdt d}t }td}||| W 5 Q R X |j|ddd d S 	Nz$width-400|avifquality-40|format-avifr   r   r   r   r   (   r   	r   r   r   r   r   r   r   rL   r   r   r   r   r   test_avif_quality_filter  s    

z.TestAvifQualityFilter.test_avif_quality_filterc                 C   s4   t dd}tjjdt d}| t|j|t  d S )Nz%width-400|avifquality-abc|format-avifr   r   r   	r   r   r   r   r   rD   r	   rL   r   r   r   r   r    test_avif_quality_filter_invalid  s    
z6TestAvifQualityFilter.test_avif_quality_filter_invalidc                 C   s4   t dd}tjjdt d}| t|j|t  d S )Nzwidth-400|avifqualityr   r   r   r   r   r   r   r   !test_avif_quality_filter_no_value  s    
z7TestAvifQualityFilter.test_avif_quality_filter_no_valuec                 C   s4   t dd}tjjdt d}| t|j|t  d S )Nz%width-400|avifquality-101|format-avifr   r   r   r   r   r   r   r    test_avif_quality_filter_too_big  s    
z6TestAvifQualityFilter.test_avif_quality_filter_too_bigru   )ZWAGTAILIMAGES_AVIF_QUALITYc              	   C   sV   t dd}tjjdt d}t }td}||| W 5 Q R X |j|ddd d S )	Nr   r   r   r   r   r   ru   r   r   r   r   r   r   test_avif_quality_setting  s    

z/TestAvifQualityFilter.test_avif_quality_settingc              	   C   sV   t dd}tjjdt d}t }td}||| W 5 Q R X |j|ddd d S r   r   r   r   r   r   *test_avif_quality_filter_overrides_setting  s    

z@TestAvifQualityFilter.test_avif_quality_filter_overrides_settingN)r,   r-   r.   r   r   r   r   r   r   r   r   r   r   r   r   r     s   
r   c                   @   sX   e Zd Zdd Zdd Zdd Zdd Zd	d
 Zedddd Z	edddd Z
dS )TestJPEGQualityFilterc              	   C   sZ   t dd}tjjdt d}t }td}||| W 5 Q R X |j|ddddd	 d S )
Nr   r   r   r   r   JPEGU   Tr   optimizeZprogressiver   r   r   r   r   r   ,  s    

z*TestJPEGQualityFilter.test_default_qualityc              	   C   sZ   t dd}tjjdt d}t }td}||| W 5 Q R X |j|ddddd	 d S 
Nzwidth-400|jpegquality-40r   r   r   r   r   r   Tr   r   r   r   r   r   test_jpeg_quality_filter9  s    

z.TestJPEGQualityFilter.test_jpeg_quality_filterc                 C   s4   t dd}tjjdt d}| t|j|t  d S )Nzwidth-400|jpegquality-abcr   r   r   r   r   r   r   r    test_jpeg_quality_filter_invalidF  s    
z6TestJPEGQualityFilter.test_jpeg_quality_filter_invalidc                 C   s4   t dd}tjjdt d}| t|j|t  d S )Nzwidth-400|jpegqualityr   r   r   r   r   r   r   r   !test_jpeg_quality_filter_no_valueN  s    
z7TestJPEGQualityFilter.test_jpeg_quality_filter_no_valuec                 C   s4   t dd}tjjdt d}| t|j|t  d S )Nzwidth-400|jpegquality-101r   r   r   r   r   r   r   r    test_jpeg_quality_filter_too_bigV  s    
z6TestJPEGQualityFilter.test_jpeg_quality_filter_too_bigru   )ZWAGTAILIMAGES_JPEG_QUALITYc              	   C   sZ   t dd}tjjdt d}t }td}||| W 5 Q R X |j|ddddd	 d S )
Nr   r   r   r   r   r   ru   Tr   r   r   r   r   r   test_jpeg_quality_setting^  s    

z/TestJPEGQualityFilter.test_jpeg_quality_settingc              	   C   sZ   t dd}tjjdt d}t }td}||| W 5 Q R X |j|ddddd	 d S r   r   r   r   r   r   *test_jpeg_quality_filter_overrides_settingl  s    

z@TestJPEGQualityFilter.test_jpeg_quality_filter_overrides_settingN)r,   r-   r.   r   r   r   r   r   r   r   r   r   r   r   r   r   +  s   
r   c                   @   sX   e Zd Zdd Zdd Zdd Zdd Zd	d
 Zedddd Z	edddd Z
dS )TestWebPQualityFilterc              	   C   sX   t dd}tjjdt d}t }td}||| W 5 Q R X |j|dddd	 d S )
Nr   r   r   r   r   r   ro   Fr   r   r   r   r   r   r   |  s    

z*TestWebPQualityFilter.test_default_qualityc              	   C   sX   t dd}tjjdt d}t }td}||| W 5 Q R X |j|dddd	 d S 
Nz$width-400|webpquality-40|format-webpr   r   r   r   r   r   Fr   r   r   r   r   r   test_webp_quality_filter  s    

z.TestWebPQualityFilter.test_webp_quality_filterc                 C   s4   t dd}tjjdt d}| t|j|t  d S )Nz%width-400|webpquality-abc|format-webpr   r   r   r   r   r   r   r    test_webp_quality_filter_invalid  s    
z6TestWebPQualityFilter.test_webp_quality_filter_invalidc                 C   s4   t dd}tjjdt d}| t|j|t  d S )Nzwidth-400|webpqualityr   r   r   r   r   r   r   r   !test_webp_quality_filter_no_value  s    
z7TestWebPQualityFilter.test_webp_quality_filter_no_valuec                 C   s4   t dd}tjjdt d}| t|j|t  d S )Nz%width-400|webpquality-101|format-webpr   r   r   r   r   r   r   r    test_webp_quality_filter_too_big  s    
z6TestWebPQualityFilter.test_webp_quality_filter_too_bigru   )ZWAGTAILIMAGES_WEBP_QUALITYc              	   C   sX   t dd}tjjdt d}t }td}||| W 5 Q R X |j|dddd	 d S )
Nr   r   r   r   r   r   ru   Fr   r   r   r   r   r   test_webp_quality_setting  s    

z/TestWebPQualityFilter.test_webp_quality_settingc              	   C   sX   t dd}tjjdt d}t }td}||| W 5 Q R X |j|dddd	 d S r   r   r   r   r   r   *test_webp_quality_filter_overrides_setting  s    

z@TestWebPQualityFilter.test_webp_quality_filter_overrides_settingN)r,   r-   r.   r   r   r   r   r   r   r   r   r   r   r   r   r   {  s   
r   c                   @   s4   e Zd Zdd Zdd Zdd Zdd Zd	d
 ZdS )TestBackgroundColorFilterc                 C   s<   t dd}tjjdt d}||t }| |  d S )Nr   r   r   r   )	r   r   r   r   r   rL   r   Z
assertTrue	has_alphar   r   r   r   test_original_has_alpha  s    
z1TestBackgroundColorFilter.test_original_has_alphac                 C   s<   t dd}tjjdt d}||t }| |  d S )Nzwidth-400|bgcolor-fffr   r   r   	r   r   r   r   r   rL   r   ZassertFalser   r   r   r   r   test_3_digit_hex  s    
z*TestBackgroundColorFilter.test_3_digit_hexc                 C   s<   t dd}tjjdt d}||t }| |  d S )Nzwidth-400|bgcolor-ffffffr   r   r   r   r   r   r   r   test_6_digit_hex  s    
z*TestBackgroundColorFilter.test_6_digit_hexc                 C   s4   t dd}tjjdt d}| t|j|t  d S )Nzwidth-400|bgcolor-foor   r   r   	r   r   r   r   r   rD   r*   rL   r   r   r   r   r   r     s    
z&TestBackgroundColorFilter.test_invalidc                 C   s4   t dd}tjjdt d}| t|j|t  d S )Nzwidth-400|bgcolor-1234r   r   r   r   r   r   r   r   test_invalid_length  s    
z-TestBackgroundColorFilter.test_invalid_lengthN)r,   r-   r.   r   r   r   r   r   r   r   r   r   r     s
   

r   c                   @   s*   e Zd Zdd Zeddiddd ZdS )TestWebpFormatConversionc                 C   s<   t dd}tjjdt d}||t }| |jd dS )z0by default, webp images will be converted to pngr   r   r   r   r   N	r   r   r   r   r   rL   r   r7   r   r   r   r   r   test_webp_convert_to_png  s    
z1TestWebpFormatConversion.test_webp_convert_to_pngr   )Z WAGTAILIMAGES_FORMAT_CONVERSIONSc                 C   s<   t dd}tjjdt d}||t }| |jd dS )zMWAGTAILIMAGES_FORMAT_CONVERSIONS can be overridden to disable webp conversionr   r   r   r   r   Nr   r   r   r   r   !test_override_webp_convert_to_png	  s    
z:TestWebpFormatConversion.test_override_webp_convert_to_pngN)r,   r-   r.   r   r   r   r   r   r   r   r     s   r   c                   @   s   e Zd Zdd Zdd ZdS )TestCheckSizec              
   C   sH   ddddg}|D ]2}| j |d | tjj|dd W 5 Q R X qd S )N      ?r   r   r%   r%   r   r%   r%   r+   TZallow_floating_point)subTestassertIsNoner   ImageTransformr   )r   sizesr   r   r   r   #test_check_size_when_floats_allowed  s     z1TestCheckSize.test_check_size_when_floats_allowedc                 C   sl   dddg}|D ]B}| j |d, | t tjj|dd W 5 Q R X W 5 Q R X q| tjjddd d S )Nr   r   r   r+   Fr   r   )r   rD   r)   r   r   r   r   )r   Z
fail_sizesr   r   r   r   %test_check_size_when_floats_forbidden'  s"      z3TestCheckSize.test_check_size_when_floats_forbiddenN)r,   r-   r.   r   r   r   r   r   r   r     s   r   N)0ior   pathlibr   Zunittest.mockr   Zdjango.testr   r   Zwagtailr   Zwagtail.imagesr   Zwagtail.images.exceptionsr	   r
   Zwagtail.images.image_operationsr   Zwagtail.images.modelsr   r   Zwagtail.images.shortcutsr   Zwagtail.images.tests.utilsr   r   r   r   r   r   r1   r_   r]   rz   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   sB   	2a J63;lPPP1