
    IZj&              
          d 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 ddlmZ dd	lmZ d
dlmZmZ d
dlmZ  ej        d          Z eedd           Ze                    d  ed          D                       Z ed          d3dedede de!fd            Z"de#e         dede#e         fdZ$d4dedede#e         fd Z%d4dedede#e         fd!Z&d5dedede'fd#Z( ed$          d%edede#e         fd&            Z) G d' d(          Z*d)edefd*Z+d+\  Z,Z-Z.Z/ G d, d-          Z0 e0e          Z1d.eddfd/Z2d0ed1ede!fd2Z3dS )6z>Code parts dedicated to duplicate removal and text similarity.    N)SequenceMatcher)	lru_cache)blake2b)add)RLock)Any)_Element   )LRU_SIZE	Extractor)trimz\.[^/?#]{2,63}$	bit_countc                 F    t          |                               d          S )N1)bincount)xs    e/Users/jameslopez/projects/MentorCore/.venv/lib/python3.11/site-packages/trafilatura/deduplication.py<lambda>r      s    SVV\\#5F5F     c                 j    i | ]0}t          j        t          |                    d          dk    -|d1S )r   P )unicodedatacategorychr).0is     r   
<dictcomp>r      s@    eeeak>RSVWXSYSY>Z>Z[\>]ad>d>d1c>d>d>dr   i i   )maxsize      ?	reference
new_string	thresholdreturnc                     t                               d|           } t                               d|          }t          d| |                                          |k    S )zIReturn the similarity ratio between two short strings, here domain names. N)STRIP_EXTENSIONsubr   ratio)r"   r#   r$   s      r   is_similar_domainr+      sQ      ##B	22I $$R44J4J77==??9LLr   tokenstarget_lengthc                     g }t          ddd          D ]*fd| D             }t          |          |dz  k    r|c S +|S )zCHelper function to get a sample of tokens based on length criteria.   c                 :    g | ]}t          |          k    |S  )len)r   tr   s     r   
<listcomp>z)_get_sample_by_length.<locals>.<listcomp>%   s$    222s1vvzz!zzzr      )ranger3   )r,   r-   sampler   s      @r   _get_sample_by_lengthr9   !   se    F1b"  2222V222v;;-!+++MMM ,Mr   @   inputstringlengthc                     |                      t                    }d |                                D             }t          ||          S )u   
    This fallback implementation is used when the primary sample_tokens function
    generates an empty token list. This is mostly relevant for languages like
    mandarin where none latin-based punctuation is used e.g.: 。
    c                 :    g | ]}|                                 |S r2   )isalnum)r   r4   s     r   r5   z*sample_tokens_fallback.<locals>.<listcomp>3   s%    ;;;Aqyy{{;a;;;r   )	translate	PUNCT_TBLsplitr9   )r;   r<   
clean_textr,   s       r   sample_tokens_fallbackrD   +   sF     &&y11J;;))++;;;F 000r   c                 .   g }|                                  D ]J}|                    t          j                  }|                                r|                    |           Kt          ||          }t          |          dk    rt          | |          S |S )zbSplit input into list of tokens and adjust length threshold to make sure
    there is enough data.r   )	rB   stripstringpunctuationr?   appendr9   r3   rD   )r;   r<   r,   tokenr8   s        r   sample_tokensrK   7   s     F""$$ ! !F.//==?? 	!MM%   "6622F
6{{a%k6:::Mr      c                     d                     t          |                                                     }t          |                                |                                          S )z=Create a bag of words and generate a hash for a given string.r   digest_size)joinrK   rF   r   encodedigest)r;   r<   
teststrings      r   generate_bow_hashrT   H   sR    -4455;;==J:$$&&F;;;BBDDDr   i @  rJ   c                     t                               t          |                                 d                                          d          fdt          |          D             S )zFToken's contribution to a Simhash vector, cached across all instances.   rN   bigc                 (    g | ]}d |z  z  rd ndS )r
   r0   r2   )r   r   
token_hashs     r   r5   z"_vector_to_add.<locals>.<listcomp>S   s+    FFF1qAv&.AABFFFr   )int
from_bytesr   rQ   rR   r7   )rJ   r<   rY   s     @r   _vector_to_addr\   O   sZ     A F F F M M O OQVWWJFFFFfFFFFr   c            	           e Zd ZdZddgZ	 	 	 ddedededz  d	dfd
Zded	efdZd	efdZ	ded	edz  fdZ
deez  dz  d	edz  fdZdd d	efdZdd d	efdZdS )SimhashzAImplement a basic Charikar hashing approach of string similarity.hashr<   r'   r:   Nr;   existing_hashr%   c                 r    || _         |                     |          p|                     |          | _        dS )z&Store length and existing or new hash.N)r<   validatecreate_hashr_   )selfr;   r<   r`   s       r   __init__zSimhash.__init__[   s5     MM-00QD4D4D[4Q4Q			r   c                    dg| j         z  t          || j                   D ]8}t          t          t          t          || j                                       9t          fdt          | j                   D                       S )zCalculates a Charikar simhash. References used:
        https://github.com/vilda/shash/
        https://github.com/sean-public/python-hashes/blob/master/hashes/simhash.py
        Optimized for Python by @adbar.
        r   c              3   :   K   | ]}|         d k    d|z  V  dS )r   r
   Nr2   )r   r   vectors     r   	<genexpr>z&Simhash.create_hash.<locals>.<genexpr>p   s/      HHaa16HHr   )r<   rK   listmapr   r\   sumr7   )rd   r;   rJ   rh   s      @r   rc   zSimhash.create_hashe   s     t{"";<< 	P 	PE#c6>%+M+MNNOOFFHHHH5#5#5HHHHHHr   c                 :    t          | j                  dd         S )z3Convert the numerical hash to a hexadecimal string.r6   N)hexr_   rd   s    r   to_hexzSimhash.to_hexr   s    49~~abb!!r   	inputhashc                 T    	 t          |d          S # t          t          f$ r Y dS w xY w)z2Convert the hexadecimal hash to a numerical value.   N)rZ   	TypeError
ValueErrorrd   rq   s     r   _hash_to_intzSimhash._hash_to_intv   s>    	y"%%%:& 	 	 	44	s    ''c                 \   t          |t                    r,dt          t          |                    cxk    rdk    rn n|S t          |t                    rU|                                r,dt          |          cxk    rdk    rn nt          |          S |                     |          S dS )z9Validate the input hash and return it, or None otherwise.      N)
isinstancerZ   r3   strisdigitrw   rv   s     r   rb   zSimhash.validate}   s    i%% 	"C	NN0C0C*I*I*I*Ir*I*I*I*I*Ii%% 	0  "" &rS^^'A'A'A'Ar'A'A'A'A'A9~~%$$Y///tr   
other_hashc                 :    t          | j        |j        z            S )zJReturn distance between two hashes of equal length using the XOR operator.)BIN_COUNT_FUNCr_   rd   r~   s     r   hamming_distancezSimhash.hamming_distance   s    di*/9:::r   c                 L    | j         |                     |          z
  | j         z  S )zjCalculate how similar this hash is from another simhash.
        Returns a float from 0.0 to 1.0.
        )r<   r   r   s     r   
similarityzSimhash.similarity   s&     d33J???4;NNr   )r'   r:   N)__name__
__module____qualname____doc__	__slots__r|   rZ   re   rc   rp   rw   rb   r   floatr   r2   r   r   r^   r^   V   s_       GG"I $(	R RR R Tz	R
 
R R R RIs Is I I I I" " " " "c cDj    	#)d"2 	sTz 	 	 	 	;9 ; ; ; ; ;OY O5 O O O O O Or   r^   contentc                 D    t          |                                           S )zACalculate a simhash hex value for meaningful bits of the content.)r^   rp   )r   s    r   content_fingerprintr      s    7""$$$r   )r   r
   r6      c                   `    e Zd ZdZddeddfdZdedefdZd	edefd
Zd	e	deddfdZ
ddZdS )LRUCachea  
    Pure-Python Least Recently Used (LRU) cache using a circular doubly linked list
    Adapted from CPython functools.py lru_cache decorator implementation
    https://github.com/python/cpython/blob/3.9/Lib/functools.py#L524
    First adapted by https://github.com/vbarbaresi
       r    r%   Nc                     t                      | _        || _        i | _        g | _        | j        | j        d d g| j        d d <   d| _        d S )NF)r   lockr    cacherootfull)rd   r    s     r   re   zLRUCache.__init__   sI    GG	+-
!		49dD9	!!!			r   linkc                     |\  }}}}||c|t           <   |t          <   | j        t                   }|x|t           <   | j        t          <   ||t          <   | j        |t           <   |S )N)NEXTPREVr   )rd   r   	link_prev	link_next_keyresultlasts          r   
_move_linkzLRUCache._move_link   s\    -1*	9dF+4i(	$4y'++T
TYt_T
YT
r   keyc                     | j         5  | j                            |          }|r!|                     |          cddd           S 	 ddd           n# 1 swxY w Y   dS )zgTests if the key that is asked for is in the cache
        and retrieve its value from the linked list.Nr0   )r   r   getr   )rd   r   r   s      r   r   zLRUCache.get   s     Y 	- 	-:>>#&&D -t,,	- 	- 	- 	- 	- 	- 	- 	--	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- rs   1AAAvaluec                    | j         5  | j                            |          }|r+|                     |           || j        |         t          <   n| j        rq| j        }||c|t          <   |t          <   |t                   | _        | j        t                   }dx| j        t          <   | j        t          <   | j        |= || j        |<   nb| j        t                   }|| j        ||g}|x|t          <   x| j        t          <   | j        |<   t          | j                  | j        k    | _        ddd           dS # 1 swxY w Y   dS )z Stores a given key in the cache.N)r   r   r   r   RESULTr   r   KEYr   r   r3   r    )rd   r   r   r   oldrootoldkeyr   s          r   putzLRUCache.put   s    Y  	@  	@:>>#&&D @%%%*/
3''9 @"iG471GCL'&/ !(DI!Ys^F9==DIcNTYv%6
6* '.DJsOO  9T?D $)S%8DEIIDJI44:c? !$DJ4< ?DIA 	@  	@  	@  	@  	@  	@  	@  	@  	@  	@  	@  	@  	@  	@  	@  	@  	@  	@s   D"D77D;>D;c                     | j         5  | j                                         | j        | j        ddg| j        dd<   d| _        ddd           dS # 1 swxY w Y   dS )zDelete all cache content.NF)r   r   clearr   r   ro   s    r   r   zLRUCache.clear   s    Y 	 	J Ity$=DIaaaLDI	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   ;AAA)r   )r%   N)r   r   r   r   rZ   re   r   r   r   r|   r   r   r2   r   r   r   r      s         	 	 	d 	 	 	 	s s    s s    #@s #@3 #@4 #@ #@ #@ #@J     r   r   rS   c                     t                               |           }|dk    r|dz   nd}t                               | |           dS )zImplement LRU cache.r0   r
   N)LRU_TESTr   r   )rS   cachevalr   s      r   put_in_cacher      sB    ||J''H$NNHqLLELLU#####r   elementoptionsc                 F   t          d                    |                                                     }t          |          |j        k    rEt
                              |          }||j        k    r t
                              ||dz              dS t          |           dS )z(Check for duplicate text with LRU cache.r   r
   TF)
r   rP   itertextr3   min_duplcheck_sizer   r   max_repetitionsr   r   )r   r   rS   r   s       r   duplicate_testr      s    chhw//112233J
:333<<
++g---LLX\22245r   )r!   )r:   )rL   )4r   rerG   r   difflibr   	functoolsr   hashlibr   operatorr   	threadingr   typingr   
lxml.etreer	   settingsr   r   utilsr   compiler(   getattrrZ   r   r|   	maketransr7   rA   r   boolr+   rj   r9   rD   rK   bytesrT   r\   r^   r   r   r   r   r   r   r   r   r   r2   r   r   <module>r      s   @ @ 				      # # # # # #                                     ) ) ) ) ) ) ) )      "*/00k+F+FGGMMee55??eeeff	 4M M M# M% MRV M M M M$s) C DI    	1 	1 	1S 	1$s) 	1 	1 	1 	1 s C c    "E E3 E EU E E E E 5G# Gs GtCy G G G G:O :O :O :O :O :O :O :Oz% % % % % %
 % dCP P P P P P P Pf 8H%%%$S $T $ $ $ $H y T      r   