U
    gz                     @   s  d dl 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lmZmZmZmZmZmZmZmZmZmZmZmZmZmZ 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#dS )    N   )InfoExtractor)PhantomJSwrapper   )Request)	HTTPError)
NO_DEFAULTExtractorError
clean_htmldetermine_extformat_fieldint_or_nonemerge_dicts
orderedSetremove_quotesremove_start
str_to_intupdate_url_queryurl_or_noneurlencode_postdatac                       s<   e Zd ZdZdZ fddZdd Zdd Zd	d
 Z  Z	S )PornHubBaseIEZpornhubzr(?:(?P<host>pornhub(?:premium)?\.(?:com|net|org))|pornhubvybmsymdol4iibwgwtkpwmeyd6luq2gxajgjzfjvotyt5zhyd\.onion)c           	         s    fdd}|||}|s |S |\}t fdddD r|d }t|trV|jn|}t dd}|j|d	 |||\}|fS )
Nc                     s   t tj| |S N)superr   _download_webpage_handle)argskwargs)	__class__self </tmp/pip-unpacked-wheel-q5ljy6pj/yt_dlp/extractor/pornhub.pydl"   s    z2PornHubBaseIE._download_webpage_handle.<locals>.dlc                 3   s   | ]}t | V  qd S r   research.0pwebpager   r   	<genexpr>,   s     z9PornHubBaseIE._download_webpage_handle.<locals>.<genexpr>)z <body\b[^>]+\bonload=["\']go\(\)z"document\.cookie\s*=\s*["\']RNKEY=z"document\.location\.reload\(true\)r   z2.0)Zrequired_version)html)any
isinstancer   urlr   get)	r   r   r   r    retZurlhZurl_or_requestr-   Zphantomr   r   r(   r   r   !   s    
z&PornHubBaseIE._download_webpage_handlec                 C   s
   d| _ d S NF)
_logged_inr   r   r   r   _real_initialize:   s    zPornHubBaseIE._real_initializec                 C   s<   |  |dd |  |dd |  |dd |  |dd d S )NZage_verified1ZaccessAgeDisclaimerPHZaccessAgeDisclaimerUKZaccessPH)_set_cookie)r   hostr   r   r   _set_age_cookies=   s    zPornHubBaseIE._set_age_cookiesc              	   C   s  | j r
d S |dd }| j|d\}}|d kr4d S d|d|krFdnd}| |d d| d	}d
d }||r|d| _ d S | |}|||d | jd| dd d| t|d|ddd}	|		ddkrd| _ d S |		d}
|
d k	rt
d|
 ddt
dd S )N.r   )Znetrc_machinezhttps://www.{}/{}loginZpremiumzpremium/ Downloading z login pagec                    s   t  fdddD S )Nc                 3   s   | ]}t | V  qd S r   r!   r$   r'   r   r   r)   X   s     z:PornHubBaseIE._login.<locals>.is_logged.<locals>.<genexpr>)zid="profileMenuDropdown"zclass="ph-icon-logout")r+   r'   r   r'   r   	is_loggedW   s    z'PornHubBaseIE._login.<locals>.is_loggedT)emailpasswordhttps://www.z/front/authenticatezLogging in to z0application/x-www-form-urlencoded; charset=UTF-8ZXMLHttpRequest)zContent-TypeZRefererzX-Requested-With)dataheaderssuccessr6   messagezUnable to login: expectedzUnable to log in)r3   splitZ_get_login_infoformat_download_webpageZ_hidden_inputsupdate_download_jsonr   r.   r	   )r   r8   siteusernamer?   Z	login_urlZ
login_pager=   Z
login_formresponserD   r   r   r   _loginC   sR      


 


 zPornHubBaseIE._login)
__name__
__module____qualname__Z_NETRC_MACHINE_PORNHUB_HOST_REr   r5   r9   rO   __classcell__r   r   r0   r   r      s   r   c                   @   sJ  e Zd ZdZdej dZdgZddddd	d
dddeeeede	e	e	dddddddddeeeede	e	dddidddddddd eeeede	e	d!d"d#igid$ddid%dd&d'd(d)d*d+d,d-d.d/dd0d1dd0d2dd0d3dd0d4dd0d5dd0d6dd0d7dd0d8dd0d9dd0d:dd0d;dd0d<dd0d=dd0gZ
d>d? Zd@dA ZdBS )C	PornHubIEzPornHub and Thumbzillaz(?x)
                    https?://
                        (?:
                            (?:[^/]+\.)?
                            z
                            /(?:(?:view_video\.php|video/show)\?viewkey=|embed/)|
                            (?:www\.)?thumbzilla\.com/video/
                        )
                        (?P<id>[\da-z]+)
                    zj<iframe[^>]+?src=["\'](?P<url>(?:https?:)?//(?:www\.)?pornhub(?:premium)?\.(?:com|net|org)/embed/[\da-z]+)z7http://www.pornhub.com/view_video.php?viewkey=648719015Z a6391306d050e4547f62b3f485dd9ba9Z	648719015mp4z>Seductive Indian beauty strips down and fingers her pink pussyZBabesZ20130628iQii     )idexttitleuploaderupload_date	timestampduration
view_count
like_countdislike_countcomment_count	age_limittags
categoriescast)r-   md5	info_dictz8http://www.pornhub.com/view_video.php?viewkey=1331683002Z
1331683002u   重庆婷婷女王足交Z20150213iTi  )rX   rY   rZ   r\   r]   r^   r_   r`   ra   rb   rc   rd   re   Zskip_downloadTzVVideo has been flagged for verification in accordance with our trust and safety policy)r-   rh   paramsskipz>https://www.pornhub.com/view_video.php?viewkey=ph5af5fef7c2aa7Zph5af5fef7c2aa7z.BFFS - Cute Teen Girls Share Cock On the FloorZBFFsin  enrY   srt)rX   rY   rZ   r[   r^   r_   r`   ra   rb   rc   rd   re   	subtitleszThis video has been disabledz=http://www.pornhub.com/view_video.php?viewkey=ph601dc30bae19aZph601dc30bae19azProjekt Melodyzprojekt-melodyZ20210205z4"Welcome to My Pussy Mansion" - CB Stream (02/03/21)zre:https?://.+)rX   r[   uploader_idr\   rZ   	thumbnail)r-   rh   z=http://www.pornhub.com/view_video.php?viewkey=ph557bbb6676d2dr-   Zonly_matchingz<http://fr.pornhub.com/view_video.php?viewkey=ph55ca2f9760862z7http://www.pornhub.com/view_video.php?viewkey=788152859z=http://www.pornhub.com/view_video.php?viewkey=ph572716d15a111z=http://www.pornhub.com/view_video.php?viewkey=ph56fd731fce6b7zEhttps://www.thumbzilla.com/video/ph56c6114abd99a/horny-girlfriend-sexz3http://www.pornhub.com/video/show?viewkey=648719015z8https://www.pornhub.net/view_video.php?viewkey=203640933z8https://www.pornhub.org/view_video.php?viewkey=203640933zEhttps://www.pornhubpremium.com/view_video.php?viewkey=ph5e4acdae54a82z>https://www.pornhub.com/view_video.php?viewkey=ph5f75b0f4b18e3zEhttps://www.pornhubpremium.com/view_video.php?viewkey=ph5f75b0f4b18e3z>https://www.pornhub.com/view_video.php?viewkey=ph5a9813bfa7156zlhttp://pornhubvybmsymdol4iibwgwtkpwmeyd6luq2gxajgjzfjvotyt5zhyd.onion/view_video.php?viewkey=ph5a9813bfa7156c                 C   s   t | j||| dd dS )Nz countdefault)r   _search_regex)r   patternr(   namer   r   r   _extract_count  s    zPornHubIE._extract_countc           !         s   |}|dpd|d  fdd}|djddd d	d
}|rtdd|}td| ddtfdddD r	  j
dd dpƈjdddd}g t i }jdddd}|rt|d}|r"|dg |dd |d}	t|d }
|d!}t|tr|D ]f}t|tshqT|d"}|rTt|tsqT|krqT| |t|d#f qTnd gd$ \}	}
tffd%d&	}fd'd(  fd)d*}sd+}|d,d-|d d}|rz| D ]L\}|d. rN|| n(tfd/d|d d$ D r, | q,std0rtd1 d2dd3s||d4d5} |d6  td7D ]2}|d8}|krΈ|d f | qd }g d[fd9d:	}D ]\}}|sRjd;|d<d d}|rR|d=d>}d?|krȈj |d@dA}t|tr |D ]F}t|tsq|t|d"}|sq|t|d#}||| q|q || q j!dBdCd@dA}jdDdEd dp|dF}fdGdH}"dIdJ}|dKdL}|dMdN}"dOdP}fdQdR}j#i d} d | dS< t$|t%|dTdU|||	|
||||dV|dW|dX|dY|dZ| S )\Nr8   zpornhub.comrX   c                    s0     d|  d  d d|  dS )Nplatformr@   z/view_video.php?viewkey=r<   z webpage)r7   rI   )rw   )r8   r   video_idr   r   
dl_webpage  s     
z+PornHubIE._real_extract.<locals>.dl_webpageZpc)zp(?s)<div[^>]+class=(["\'])(?:(?!\1).)*\b(?:removed|userMessageSection)\b(?:(?!\1).)*\1[^>]*>(?P<error>.+?)</div>zF(?s)<section[^>]+class=["\']noVideo["\'][^>]*>(?P<error>.+?)</section>zerror messageerror)rr   groupz\s+ zPornHub said: T)rF   rx   c                 3   s   | ]}t | V  qd S r   r!   r$   r'   r   r   r)   (  s     z*PornHubIE._real_extract.<locals>.<genexpr>)zclass=["\']geoBlocked["\']z/>\s*This content is unavailable in your countryztwitter:titlerq   )z:(?s)<h1[^>]+class=["\']title["\'][^>]*>(?P<title>.+?)</h1>z:<div[^>]+data-video-title=(["\'])(?P<title>(?:(?!\1).)+)\1z9shareTitle["\']\s*[=:]\s*(["\'])(?P<title>(?:(?!\1).)+)\1rZ   )r{   z"var\s+flashvars_\d+\s*=\s*({.+?});	flashvarsz{}ZclosedCaptionsFilerk   rl   )r-   rY   Z	image_urlZvideo_durationZmediaDefinitionsZvideoUrlqualityr   c                    s|   j || d|d}|si S |d}i   fdd|D ]<}| }|sLq:tdd|}|dd	\}}| |< q: S )
Nzencoded urlrq   ;c                    sT   t dd| } d| kr4| d}ttjt|S |  } |  krL |  S t	| S )Nz/\*(?:(?!\*/).)*?\*/r;   +)
r"   subrG   	functoolsreduceoperatorconcatmapstripr   )inpZinpsjs_varsparse_js_valuer   r   r   b  s    
 zHPornHubIE._real_extract.<locals>.extract_js_vars.<locals>.parse_js_valuezvar\s+r;   =r   )rs   rG   r   r"   r   )r(   rt   rr   ZassignmentsZassnZvnamevaluer4   r   r   extract_js_varsX  s&       
z0PornHubIE._real_extract.<locals>.extract_js_varsc                    s8   t | }|sd S |krd S  |d f | d S r   )r   appendadd)	video_urlZv_url)
video_urlsvideo_urls_setr   r   add_video_urlv  s    z.PornHubIE._real_extract.<locals>.add_video_urlc                    sD   j | dd}t|tsd S |D ]}t|tr" |d q"d S )NFfatalr-   )_parse_jsonr,   listdictr.   )Zquality_itemsZq_itemsitem)r   r   rx   r   r   parse_quality_items  s    

z4PornHubIE._real_extract.<locals>.parse_quality_items)mediar~   ZqualityItemsz(var\s+(?:{})_.+)|c                 3   s   | ]}  |V  qd S r   )
startswithr$   )keyr   r   r)     s     z<[^>]+\bid=["\']lockedPlayerzVideo z
 is lockedrE   tvz(var.+?mediastring.+?)</script>ZmediastringzK<a[^>]+\bclass=["\']downloadBtn\b[^>]+\bhref=(["\'])(?P<url>(?:(?!\1).)+)\1r-   c              
      s   t | }|dkr, j| ddd d S |dkrT j| ddddd	 d S |sntjd
| dd d} | t|d d|d d S )NZmpdZdashF)Zmpd_idr   Zm3u8rV   Zm3u8_nativeZhls)Zentry_protocolZm3u8_idr   z(?P<height>\d+)[pP]?_\d+[kK]heightrq   z%dp)r-   Z	format_idr   )r   extendZ_extract_mpd_formatsZ_extract_m3u8_formatsr   rs   r   r   )
format_urlr   rY   )formatsr   rx   r   r   
add_format  s>             
z+PornHubIE._real_extract.<locals>.add_formatz/(\d{6}/\d{2})/zupload data/r;   z/video/get_mediaFr   zvar\s+MODEL_PROFILE\s*=zmodel profilez~(?s)From:&nbsp;.+?<(?:a\b[^>]+\bhref=["\']/(?:(?:user|channel)s|model|pornstar)/|span\b[^>]+\bclass=["\']username)[^>]+>(.+?)<r[   rM   c                    s"     d|  dd|  df|S )Nz<span[^>]+\bclass="votesz"[^>]*>([\d,\.]+)</span>z<span[^>]+\bclass=["\']votesz"["\'][^>]*\bdata-rating=["\'](\d+))rv   )kindru   r1   r   r   extract_vote_count  s    

 z3PornHubIE._real_extract.<locals>.extract_vote_countz.<span class="count">([\d,\.]+)</span> [Vv]iewsviewZUplikeZDownZdislikez"All Comments\s*<span>\(([\d,.]+)\)commentc                    s8    j d|  d| d d}|r4dd td|D S d S )Nz(?s)<div[^>]+\bclass=["\'].*?\bzWrapper[^>]*>(.+?)</div>rq   c                 S   s   g | ]}t | qS r   )r
   r   )r%   xr   r   r   
<listcomp>  s     zAPornHubIE._real_extract.<locals>.extract_list.<locals>.<listcomp>z(?s)<a[^>]+\bhref=[^>]+>.+?</a>)rs   r"   findall)Zmeta_keydivr1   r   r   extract_list  s    
  z-PornHubIE._real_extract.<locals>.extract_listdescriptionZmodelProfileLinkz/model/rW   rd   re   Z	pornstars)rX   r[   rn   r\   rZ   ro   r^   r_   r`   ra   rb   r   rc   rd   re   rf   rm   )N)&_match_valid_urlr{   rO   r9   Z_html_search_regexr"   r   r	   r+   Zraise_geo_restrictedZ_html_search_metasetr   rs   r   r.   
setdefaultr   r   r,   r   r   strr   r   rH   joinitemsr   r#   finditerreplacerK   Z_search_jsonrv   Z_search_json_ldr   r   )!r   r-   mobjry   	error_msgrZ   rm   r}   Zsubtitle_urlro   r^   Zmedia_definitionsZ
definitionr   r   r   ZFORMAT_PREFIXESr   r   r\   r   r   Zmediasr   Zmodel_profileZvideo_uploaderr   r_   r`   ra   rb   r   infor   )	r   r   r8   r   r   rx   r   r   r(   r   _real_extract  sv   



           





	 
 
 
  

   
        

  zPornHubIE._real_extractN)rP   rQ   rR   ZIE_DESCr   rS   
_VALID_URLZ_EMBED_REGEXintr   _TESTSrv   r   r   r   r   r   rU   }   s   
    rU   c                   @   s   e Zd Zdd Zdd ZdS )PornHubPlaylistBaseIEc                 C   s   t | jd|dd dS )Nz\bpage=(\d+)pagerq   )r   rs   )r   r-   r   r   r   _extract_page  s       z#PornHubPlaylistBaseIE._extract_pagec                    s2   j d|d|d} fddttd|D S )Nz%(?s)(<div[^>]+class=["\']container.+)	containerrq   c                    s0   g | ](\}}j d   d| t |dqS )zhttp://www.r   )Zvideo_title)
url_resultrU   ie_key)r%   r   rZ   r8   r   r   r   r     s    z:PornHubPlaylistBaseIE._extract_entries.<locals>.<listcomp>zLhref="/?(view_video\.php\?.*\bviewkey=[\da-z]+[^"]*)"[^>]*\s+title="([^"]+)")rs   r   r"   r   )r   r(   r8   r   r   r   r   _extract_entries  s      z&PornHubPlaylistBaseIE._extract_entriesN)rP   rQ   rR   r   r   r   r   r   r   r     s   r   c                
   @   sl   e Zd Zdej dZddddddidd	d
dddddddddddddddddgZdd ZdS )PornHubUserIE(?P<url>https?://(?:[^/]+\.)?zN/(?:(?:user|channel)s|model|pornstar)/(?P<id>[^/?#&]+))(?:[?#&]|/(?!videos)|$)z$https://www.pornhub.com/model/zoe_phv   )r-   playlist_mincountz,https://www.pornhub.com/pornstar/liz-viciousrX   zliz-viciousr-   rh   r   z+https://www.pornhub.com/users/russianveet69Trp   z%https://www.pornhub.com/channels/povdz*https://www.pornhub.com/model/zoe_ph?abc=1z3https://www.pornhubpremium.com/pornstar/sienna-westz3https://www.pornhubpremium.com/pornstar/lily-labeauzShttps://pornhubvybmsymdol4iibwgwtkpwmeyd6luq2gxajgjzfjvotyt5zhyd.onion/model/zoe_phc                 C   sd   |  |}|d}d|d}| |d | |}|rPt|d|i}| j|t |dS )NrX   z	{}/videosr-   r8   r   )Zierx   )	r   r{   rH   r9   r   r   r   PornHubPagedVideoListIEr   )r   r-   r   Zuser_idZ
videos_urlr   r   r   r   r   =  s    


  zPornHubUserIE._real_extractN)rP   rQ   rR   r   rS   r   r   r   r   r   r   r   r     s<    !r   c                   @   s(   e Zd Zedd Zdd Zdd ZdS )PornHubPagedPlaylistBaseIEc                 C   s   t d| d k	S )Nz(?x)
                <li[^>]+\bclass=["\']page_next|
                <link[^>]+\brel=["\']next|
                <button[^>]+\bid=["\']moreDataBtn
            r!   r'   r   r   r   	_has_moreJ  s    z$PornHubPagedPlaylistBaseIE._has_morec                 #   s>   |}d}d fdd	}dd }|}|d k	}	|	r:|nd}
|	rH|
fnt|
D ]}zlz|||}W nX tk
r } z:||r||
kr||kr||d}|||d	d
}n W 5 d }~X Y nX W nB tk
r } z"||r||
krW Y  q: W 5 d }~X Y nX ||}|s q:|E d H  |sR q:qRd S )Nz/videosFc                    s*   d ||rdnd}j|  |d|idS )NzDownloading page {}{}z (switch to fallback)r;   r   query)rH   rI   )base_urlnumfallbacknoteitem_idr   r   r   download_pageX  s       z:PornHubPagedPlaylistBaseIE._entries.<locals>.download_pagec                 S   s   t | jto| jjdkS )Ni  )r,   causer   status)er   r   r   is_404]  s    z3PornHubPagedPlaylistBaseIE._entries.<locals>.is_404r   r;   T)r   )F)r   	itertoolscountr	   r   r   r   )r   r-   r8   r   r   ZVIDEOSr   r   r   Zhas_pageZ
first_pagepage_numr(   r   page_entriesr   r   r   _entriesS  s4    


z#PornHubPagedPlaylistBaseIE._entriesc                 C   sH   |  |}|d}|d}| | | | | | ||||S )Nr8   rX   r   r{   rO   r9   Zplaylist_resultr   r   r-   r   r8   r   r   r   r   r   {  s    




z(PornHubPagedPlaylistBaseIE._real_extractN)rP   rQ   rR   staticmethodr   r   r   r   r   r   r   r   I  s   
(r   c                       s  e Zd Zdej dZddddddddd	id
dddd	idddddidddddddddddddddddddddddddddddddddddddddddddddddd ddd!ddd"ddd#ddd$ddd%ddgZe fd&d'Z  Z	S )(r   zhttps?://(?:[^/]+\.)?z)/(?!playlist/)(?P<id>(?:[^/]+/)*[^/?#&]+)z+https://www.pornhub.com/model/zoe_ph/videosTrp   z.http://www.pornhub.com/users/rushandlia/videosz4https://www.pornhub.com/pornstar/jenny-blighe/videosrX   zpornstar/jenny-blighe/videos   r   z;https://www.pornhub.com/pornstar/jenny-blighe/videos?page=3(   z,https://www.pornhub.com/channels/povd/videoszchannels/povd/videosi%  z1https://www.pornhub.com/channels/povd/videos?o=raz1https://www.pornhub.com/channels/povd/videos?o=daz1https://www.pornhub.com/channels/povd/videos?o=viz1http://www.pornhub.com/users/zoe_ph/videos/publicz8https://www.pornhub.com/pornstar/liz-vicious/videos?o=mvz8https://www.pornhub.com/pornstar/liz-vicious/videos?o=trz8https://www.pornhub.com/pornstar/liz-vicious/videos?o=lgz8https://www.pornhub.com/pornstar/liz-vicious/videos?o=cmz8https://www.pornhub.com/pornstar/liz-vicious/videos/paidz;https://www.pornhub.com/pornstar/liz-vicious/videos/fanonlyzhttps://www.pornhub.com/videoz$https://www.pornhub.com/video?page=3z/https://www.pornhub.com/video/search?search=123z'https://www.pornhub.com/categories/teenz.https://www.pornhub.com/categories/teen?page=3zhttps://www.pornhub.com/hdz!https://www.pornhub.com/hd?page=3z'https://www.pornhub.com/described-videoz.https://www.pornhub.com/described-video?page=2z:https://www.pornhub.com/video/incategories/60fps-1/hd-pornzZhttps://pornhubvybmsymdol4iibwgwtkpwmeyd6luq2gxajgjzfjvotyt5zhyd.onion/model/zoe_ph/videosc                    s.   t |st|st|r"dS t |S r2   )rU   suitabler   PornHubUserVideosUploadIEr   )clsr-   r0   r   r   r     s    
z PornHubPagedVideoListIE.suitable)
rP   rQ   rR   r   rS   r   r   classmethodr   rT   r   r   r0   r   r     s      	ar   c                   @   s<   e Zd Zdej dZdddidddd	d
dd	d
gZdS )r   r   zB/(?:(?:user|channel)s|model|pornstar)/(?P<id>[^/]+)/videos/upload)z;https://www.pornhub.com/pornstar/jenny-blighe/videos/uploadrX   zjenny-blighe   r   z2https://www.pornhub.com/model/zoe_ph/videos/uploadTrp   zihttp://pornhubvybmsymdol4iibwgwtkpwmeyd6luq2gxajgjzfjvotyt5zhyd.onion/pornstar/jenny-blighe/videos/uploadN)rP   rQ   rR   r   rS   r   r   r   r   r   r   r     s    r   c                   @   sT   e Zd Zdej dZdddidddd	d
dd	d
dd	d
gZdd Zdd ZdS )PornHubPlaylistIEr   z/playlist/(?P<id>[^/?#&]+))z)https://www.pornhub.com/playlist/44121572rX   Z44121572M   )r-   rh   Zplaylist_countz(https://www.pornhub.com/playlist/4667351Trp   z'https://de.pornhub.com/playlist/4667351z.https://de.pornhub.com/playlist/4667351?page=2c           
      #   s    |d}d|dtd|d}d|dt|d d	 d
 }| } fdd}td
|d
 D ]2}	|	d
kr||	}| }|s q|E d H  qd S )NzDownloading page 1z var\s+playlistId\s*=\s*"([^"]+)"playlist_idz&var\s+itemsCount\s*=\s*([0-9]+)\s*\|\|video_countzvar\s+token\s*=\s*"([^"]+)"token$   g      D@r   c                    s0   d|  }d  d}j ||| ddS )NzDownloading page r@   z/playlist/viewChunked)rX   r   r   r   )rI   )r   r   page_urlr8   r   r   r   r   r   r   r     s    

z1PornHubPlaylistIE._entries.<locals>.download_page)rI   rs   r   mathceilr   range)
r   r-   r8   r   r(   r   Z
page_countr   r   r   r   r   r   r     s     	zPornHubPlaylistIE._entriesc                 C   sN   |  |}|d}|d}| | | | | | |d|||S )Nr8   rX   r-   r   r   r   r   r   r   .  s    




zPornHubPlaylistIE._real_extractN)	rP   rQ   rR   r   rS   r   r   r   r   r   r   r   r   r     s&    r   )$r   r   r   r   r"   commonr   Zopenloadr   Z
networkingr   Znetworking.exceptionsr   utilsr   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   rU   r   r   r   r   r   r   r   r   r   r   <module>   s(   @`   	/=j