



from collections import deque
from math import floor
from random import random
from time import time
class 					_snake_case      :




				def __init__(    self       :    Union[str, Any]    ):
							lowercase__       	=					{}




				def 				A__   (    self       :    Tuple,       __lowercase       :    Optional[int],       __lowercase       :    List[Any],       __lowercase       :    Any=1    ):






							if self.graph.get(UpperCamelCase__    ):
										if self.graph[u].count([w, v]    ) == 0:
													self.graph[u].append([w, v]    )
							else:
										lowercase__       	=					[[w, v]]
							if not self.graph.get(UpperCamelCase__    ):
										lowercase__       	=					[]




				def 				A__   (    self       :    Optional[Any]    ):
							return list(self.graph    )




				def 				A__   (    self       :    Tuple,       __lowercase       :    List[str],       __lowercase       :    Optional[Any]    ):






							if self.graph.get(UpperCamelCase__    ):
										for _ in self.graph[u]:
													if _[1] == v:
																self.graph[u].remove(UpperCamelCase__    )




				def 				A__   (    self       :    Optional[Any],       __lowercase       :    Tuple=-2,       __lowercase       :    Any=-1    ):






							if s == d:
										return []
							lowercase__       	=					[]
							lowercase__       	=					[]
							if s == -2:
										lowercase__       	=					list(self.graph    )[0]
							stack.append(UpperCamelCase__    )
							visited.append(UpperCamelCase__    )
							lowercase__       	=					s

							while True:
										# check if there is any non isolated nodes
										if len(self.graph[s]    ) != 0:
													lowercase__       	=					s
													for node in self.graph[s]:
																if visited.count(node[1]    ) < 1:
																			if node[1] == d:
																						visited.append(UpperCamelCase__    )
																						return visited
																			else:
																						stack.append(node[1]    )
																						visited.append(node[1]    )
																						lowercase__       	=					node[1]
																						break

																			# check if all the children are visited
										if s == ss:
													stack.pop()
													if len(UpperCamelCase__    ) != 0:
																lowercase__       	=					stack[len(UpperCamelCase__    ) - 1]
										else:
													lowercase__       	=					ss

										# check if se have reached the starting point
										if len(UpperCamelCase__    ) == 0:
													return visited




				def 				A__   (    self       :    Optional[Any],       __lowercase       :    Union[str, Any]=-1    ):






							if c == -1:
										lowercase__       	=					floor(random() * 1_0000    ) + 10
							for i in range(UpperCamelCase__    ):
										# every vertex has max 100 edges
										for _ in range(floor(random() * 102    ) + 1    ):
													lowercase__       	=					floor(random() * c    ) + 1
													if n != i:
																self.add_pair(UpperCamelCase__,       UpperCamelCase__,       1    )




				def 				A__   (    self       :    int,       __lowercase       :    List[Any]=-2    ):
							lowercase__       	=					deque()
							lowercase__       	=					[]
							if s == -2:
										lowercase__       	=					list(self.graph    )[0]
							d.append(UpperCamelCase__    )
							visited.append(UpperCamelCase__    )
							while d:
										lowercase__       	=					d.popleft()
										if len(self.graph[s]    ) != 0:
													for node in self.graph[s]:
																if visited.count(node[1]    ) < 1:
																			d.append(node[1]    )
																			visited.append(node[1]    )
							return visited




				def 				A__   (    self       :    List[Any],       __lowercase       :    Optional[int]    ):
							lowercase__       	=					0
							for x in self.graph:
										for y in self.graph[x]:
													if y[1] == u:
																count += 1
							return count




				def 				A__   (    self       :    str,       __lowercase       :    Optional[int]    ):
							return len(self.graph[u]    )




				def 				A__   (    self       :    Optional[Any],       __lowercase       :    str=-2    ):
							lowercase__       	=					[]
							lowercase__       	=					[]
							if s == -2:
										lowercase__       	=					list(self.graph    )[0]
							stack.append(UpperCamelCase__    )
							visited.append(UpperCamelCase__    )
							lowercase__       	=					s
							lowercase__       	=					[]

							while True:
										# check if there is any non isolated nodes
										if len(self.graph[s]    ) != 0:
													lowercase__       	=					s
													for node in self.graph[s]:
																if visited.count(node[1]    ) < 1:
																			stack.append(node[1]    )
																			visited.append(node[1]    )
																			lowercase__       	=					node[1]
																			break

																			# check if all the children are visited
										if s == ss:
													sorted_nodes.append(stack.pop()    )
													if len(UpperCamelCase__    ) != 0:
																lowercase__       	=					stack[len(UpperCamelCase__    ) - 1]
										else:
													lowercase__       	=					ss

										# check if se have reached the starting point
										if len(UpperCamelCase__    ) == 0:
													return sorted_nodes




				def 				A__   (    self       :    Tuple    ):
							lowercase__       	=					[]
							lowercase__       	=					[]
							lowercase__       	=					list(self.graph    )[0]
							stack.append(UpperCamelCase__    )
							visited.append(UpperCamelCase__    )
							lowercase__       	=					-2
							lowercase__       	=					[]
							lowercase__       	=					s
							lowercase__       	=					False
							lowercase__       	=					set()

							while True:
										# check if there is any non isolated nodes
										if len(self.graph[s]    ) != 0:
													lowercase__       	=					s
													for node in self.graph[s]:
																if (
																    visited.count(node[1]    ) > 0
																    and node[1] != parent
																    and indirect_parents.count(node[1]    ) > 0
																    and not on_the_way_back
																):
																			lowercase__       	=					len(UpperCamelCase__    ) - 1
																			while len_stack >= 0:
																						if stack[len_stack] == node[1]:
																									anticipating_nodes.add(node[1]    )
																									break
																						else:
																									anticipating_nodes.add(stack[len_stack]    )
																									len_stack -= 1
																if visited.count(node[1]    ) < 1:
																			stack.append(node[1]    )
																			visited.append(node[1]    )
																			lowercase__       	=					node[1]
																			break

																			# check if all the children are visited
										if s == ss:
													stack.pop()
													lowercase__       	=					True
													if len(UpperCamelCase__    ) != 0:
																lowercase__       	=					stack[len(UpperCamelCase__    ) - 1]
										else:
													lowercase__       	=					False
													indirect_parents.append(UpperCamelCase__    )
													lowercase__       	=					s
													lowercase__       	=					ss

										# check if se have reached the starting point
										if len(UpperCamelCase__    ) == 0:
													return list(UpperCamelCase__    )




				def 				A__   (    self       :    List[Any]    ):
							lowercase__       	=					[]
							lowercase__       	=					[]
							lowercase__       	=					list(self.graph    )[0]
							stack.append(UpperCamelCase__    )
							visited.append(UpperCamelCase__    )
							lowercase__       	=					-2
							lowercase__       	=					[]
							lowercase__       	=					s
							lowercase__       	=					False
							lowercase__       	=					set()

							while True:
										# check if there is any non isolated nodes
										if len(self.graph[s]    ) != 0:
													lowercase__       	=					s
													for node in self.graph[s]:
																if (
																    visited.count(node[1]    ) > 0
																    and node[1] != parent
																    and indirect_parents.count(node[1]    ) > 0
																    and not on_the_way_back
																):
																			lowercase__       	=					len(UpperCamelCase__    ) - 1
																			while len_stack_minus_one >= 0:
																						if stack[len_stack_minus_one] == node[1]:
																									anticipating_nodes.add(node[1]    )
																									break
																						else:
																									return True
																if visited.count(node[1]    ) < 1:
																			stack.append(node[1]    )
																			visited.append(node[1]    )
																			lowercase__       	=					node[1]
																			break

																			# check if all the children are visited
										if s == ss:
													stack.pop()
													lowercase__       	=					True
													if len(UpperCamelCase__    ) != 0:
																lowercase__       	=					stack[len(UpperCamelCase__    ) - 1]
										else:
													lowercase__       	=					False
													indirect_parents.append(UpperCamelCase__    )
													lowercase__       	=					s
													lowercase__       	=					ss

										# check if se have reached the starting point
										if len(UpperCamelCase__    ) == 0:
													return False




				def 				A__   (    self       :    str,       __lowercase       :    Optional[int]=-2,       __lowercase       :    Optional[int]=-1    ):
							lowercase__       	=					time()
							self.dfs(UpperCamelCase__,       UpperCamelCase__    )
							lowercase__       	=					time()
							return end - begin




				def 				A__   (    self       :    List[str],       __lowercase       :    int=-2    ):
							lowercase__       	=					time()
							self.bfs(UpperCamelCase__    )
							lowercase__       	=					time()
							return end - begin
class 					_snake_case      :




				def __init__(    self       :    Tuple    ):
							lowercase__       	=					{}




				def 				A__   (    self       :    Optional[Any],       __lowercase       :    Optional[Any],       __lowercase       :    Optional[int],       __lowercase       :    Optional[int]=1    ):






							if self.graph.get(UpperCamelCase__    ):
										# if there already is a edge
										if self.graph[u].count([w, v]    ) == 0:
													self.graph[u].append([w, v]    )
							else:
										# if u does not exist
										lowercase__       	=					[[w, v]]
							# add the other way
							if self.graph.get(UpperCamelCase__    ):
										# if there already is a edge
										if self.graph[v].count([w, u]    ) == 0:
													self.graph[v].append([w, u]    )
							else:
										# if u does not exist
										lowercase__       	=					[[w, u]]




				def 				A__   (    self       :    str,       __lowercase       :    Tuple,       __lowercase       :    Optional[int]    ):






							if self.graph.get(UpperCamelCase__    ):
										for _ in self.graph[u]:
													if _[1] == v:
																self.graph[u].remove(UpperCamelCase__    )
													# the other way round
							if self.graph.get(UpperCamelCase__    ):
										for _ in self.graph[v]:
													if _[1] == u:
																self.graph[v].remove(UpperCamelCase__    )




				def 				A__   (    self       :    Dict,       __lowercase       :    List[Any]=-2,       __lowercase       :    int=-1    ):






							if s == d:
										return []
							lowercase__       	=					[]
							lowercase__       	=					[]
							if s == -2:
										lowercase__       	=					list(self.graph    )[0]
							stack.append(UpperCamelCase__    )
							visited.append(UpperCamelCase__    )
							lowercase__       	=					s

							while True:
										# check if there is any non isolated nodes
										if len(self.graph[s]    ) != 0:
													lowercase__       	=					s
													for node in self.graph[s]:
																if visited.count(node[1]    ) < 1:
																			if node[1] == d:
																						visited.append(UpperCamelCase__    )
																						return visited
																			else:
																						stack.append(node[1]    )
																						visited.append(node[1]    )
																						lowercase__       	=					node[1]
																						break

																			# check if all the children are visited
										if s == ss:
													stack.pop()
													if len(UpperCamelCase__    ) != 0:
																lowercase__       	=					stack[len(UpperCamelCase__    ) - 1]
										else:
													lowercase__       	=					ss

										# check if se have reached the starting point
										if len(UpperCamelCase__    ) == 0:
													return visited




				def 				A__   (    self       :    List[Any],       __lowercase       :    Optional[Any]=-1    ):






							if c == -1:
										lowercase__       	=					floor(random() * 1_0000    ) + 10
							for i in range(UpperCamelCase__    ):
										# every vertex has max 100 edges
										for _ in range(floor(random() * 102    ) + 1    ):
													lowercase__       	=					floor(random() * c    ) + 1
													if n != i:
																self.add_pair(UpperCamelCase__,       UpperCamelCase__,       1    )




				def 				A__   (    self       :    Union[str, Any],       __lowercase       :    Tuple=-2    ):
							lowercase__       	=					deque()
							lowercase__       	=					[]
							if s == -2:
										lowercase__       	=					list(self.graph    )[0]
							d.append(UpperCamelCase__    )
							visited.append(UpperCamelCase__    )
							while d:
										lowercase__       	=					d.popleft()
										if len(self.graph[s]    ) != 0:
													for node in self.graph[s]:
																if visited.count(node[1]    ) < 1:
																			d.append(node[1]    )
																			visited.append(node[1]    )
							return visited




				def 				A__   (    self       :    Tuple,       __lowercase       :    Optional[Any]    ):
							return len(self.graph[u]    )




				def 				A__   (    self       :    Union[str, Any]    ):
							lowercase__       	=					[]
							lowercase__       	=					[]
							lowercase__       	=					list(self.graph    )[0]
							stack.append(UpperCamelCase__    )
							visited.append(UpperCamelCase__    )
							lowercase__       	=					-2
							lowercase__       	=					[]
							lowercase__       	=					s
							lowercase__       	=					False
							lowercase__       	=					set()

							while True:
										# check if there is any non isolated nodes
										if len(self.graph[s]    ) != 0:
													lowercase__       	=					s
													for node in self.graph[s]:
																if (
																    visited.count(node[1]    ) > 0
																    and node[1] != parent
																    and indirect_parents.count(node[1]    ) > 0
																    and not on_the_way_back
																):
																			lowercase__       	=					len(UpperCamelCase__    ) - 1
																			while len_stack >= 0:
																						if stack[len_stack] == node[1]:
																									anticipating_nodes.add(node[1]    )
																									break
																						else:
																									anticipating_nodes.add(stack[len_stack]    )
																									len_stack -= 1
																if visited.count(node[1]    ) < 1:
																			stack.append(node[1]    )
																			visited.append(node[1]    )
																			lowercase__       	=					node[1]
																			break

																			# check if all the children are visited
										if s == ss:
													stack.pop()
													lowercase__       	=					True
													if len(UpperCamelCase__    ) != 0:
																lowercase__       	=					stack[len(UpperCamelCase__    ) - 1]
										else:
													lowercase__       	=					False
													indirect_parents.append(UpperCamelCase__    )
													lowercase__       	=					s
													lowercase__       	=					ss

										# check if se have reached the starting point
										if len(UpperCamelCase__    ) == 0:
													return list(UpperCamelCase__    )




				def 				A__   (    self       :    List[Any]    ):
							lowercase__       	=					[]
							lowercase__       	=					[]
							lowercase__       	=					list(self.graph    )[0]
							stack.append(UpperCamelCase__    )
							visited.append(UpperCamelCase__    )
							lowercase__       	=					-2
							lowercase__       	=					[]
							lowercase__       	=					s
							lowercase__       	=					False
							lowercase__       	=					set()

							while True:
										# check if there is any non isolated nodes
										if len(self.graph[s]    ) != 0:
													lowercase__       	=					s
													for node in self.graph[s]:
																if (
																    visited.count(node[1]    ) > 0
																    and node[1] != parent
																    and indirect_parents.count(node[1]    ) > 0
																    and not on_the_way_back
																):
																			lowercase__       	=					len(UpperCamelCase__    ) - 1
																			while len_stack_minus_one >= 0:
																						if stack[len_stack_minus_one] == node[1]:
																									anticipating_nodes.add(node[1]    )
																									break
																						else:
																									return True
																if visited.count(node[1]    ) < 1:
																			stack.append(node[1]    )
																			visited.append(node[1]    )
																			lowercase__       	=					node[1]
																			break

																			# check if all the children are visited
										if s == ss:
													stack.pop()
													lowercase__       	=					True
													if len(UpperCamelCase__    ) != 0:
																lowercase__       	=					stack[len(UpperCamelCase__    ) - 1]
										else:
													lowercase__       	=					False
													indirect_parents.append(UpperCamelCase__    )
													lowercase__       	=					s
													lowercase__       	=					ss

										# check if se have reached the starting point
										if len(UpperCamelCase__    ) == 0:
													return False




				def 				A__   (    self       :    List[str]    ):
							return list(self.graph    )




				def 				A__   (    self       :    str,       __lowercase       :    Union[str, Any]=-2,       __lowercase       :    int=-1    ):
							lowercase__       	=					time()
							self.dfs(UpperCamelCase__,       UpperCamelCase__    )
							lowercase__       	=					time()
							return end - begin




				def 				A__   (    self       :    Optional[Any],       __lowercase       :    str=-2    ):
							lowercase__       	=					time()
							self.bfs(UpperCamelCase__    )
							lowercase__       	=					time()
							return end - begin






import html

from ...feature_extraction_utils import BatchFeature, FeatureExtractionMixin
from ...utils import is_bsa_available, logging, requires_backends


if is_bsa_available():
    import bsa
    from bsa import BeautifulSoup


__lowerCAmelCase     :	int       			=  logging.get_logger(__name__)




class 			UpperCAmelCase_     (					_A	):


  '''simple docstring'''







  def __init__(					self     :					Union[str, Any]     ,				**UpperCamelCase__     :					Union[str, Any]       )     ->      Union[str, Any]:







    """simple docstring"""






    requires_backends(self     ,				["""bs4"""]       )
    super().__init__(**UpperCamelCase__       )
  def 				_lowercase				(					self     :					Dict     ,				UpperCamelCase__     :					Union[str, Any]       )     ->      Optional[Any]:







    """simple docstring"""






    __magic_name__								=			[]
    __magic_name__								=			[]
    __magic_name__								=			element if element.name else element.parent
    for parent in child.parents:  # type: bs4.element.Tag
      __magic_name__								=			parent.find_all(child.name     ,				recursive=UpperCamelCase__       )
      xpath_tags.append(child.name       )
      xpath_subscripts.append(
          0 if 1 == len(UpperCamelCase__       ) else next(i for i, s in enumerate(UpperCamelCase__     ,				1       ) if s is child       )       )
      __magic_name__								=			parent
    xpath_tags.reverse()
    xpath_subscripts.reverse()
    return xpath_tags, xpath_subscripts
  def 				_lowercase				(					self     :					Union[str, Any]     ,				UpperCamelCase__     :					List[Any]       )     ->      str:







    """simple docstring"""






    __magic_name__								=			BeautifulSoup(UpperCamelCase__     ,				"""html.parser"""       )

    __magic_name__								=			[]
    __magic_name__								=			[]
    __magic_name__								=			[]

    for element in html_code.descendants:
      if type(UpperCamelCase__       ) == bsa.element.NavigableString:
        if type(element.parent       ) != bsa.element.Tag:
          continue

        __magic_name__								=			html.unescape(UpperCamelCase__       ).strip()
        if not text_in_this_tag:
          continue

        all_doc_strings.append(UpperCamelCase__       )

        __magic_name__	,       __magic_name__								=			self.xpath_soup(UpperCamelCase__       )
        stringaxtag_seq.append(UpperCamelCase__       )
        stringaxsubs_seq.append(UpperCamelCase__       )

    if len(UpperCamelCase__       ) != len(UpperCamelCase__       ):
      raise ValueError("""Number of doc strings and xtags does not correspond"""       )
    if len(UpperCamelCase__       ) != len(UpperCamelCase__       ):
      raise ValueError("""Number of doc strings and xsubs does not correspond"""       )

    return all_doc_strings, stringaxtag_seq, stringaxsubs_seq
  def 				_lowercase				(					self     :					List[Any]     ,				UpperCamelCase__     :					Dict     ,				UpperCamelCase__     :					List[Any]       )     ->      Optional[Any]:







    """simple docstring"""






    __magic_name__								=			""""""
    for tagname, subs in zip(UpperCamelCase__     ,				UpperCamelCase__       ):
      xpath += F'''/{tagname}'''
      if subs != 0:
        xpath += F'''[{subs}]'''
    return xpath





  def __call__(					self     :					str     ,				UpperCamelCase__     :					Tuple       )     ->      BatchFeature:







    """simple docstring"""






    __magic_name__								=			False

    # Check that strings has a valid type
    if isinstance(UpperCamelCase__     ,				UpperCamelCase__       ):
      __magic_name__								=			True
    elif isinstance(UpperCamelCase__     ,				(list, tuple)       ):
      if len(UpperCamelCase__       ) == 0 or isinstance(html_strings[0]     ,				UpperCamelCase__       ):
        __magic_name__								=			True

    if not valid_strings:
      raise ValueError(
          """HTML strings must of type `str`, `List[str]` (batch of examples), """
          F'''but is of type {type(UpperCamelCase__       )}.'''       )

    __magic_name__								=			bool(isinstance(UpperCamelCase__     ,				(list, tuple)       ) and (isinstance(html_strings[0]     ,				UpperCamelCase__       ))       )

    if not is_batched:
      __magic_name__								=			[html_strings]

    # Get nodes + xpaths
    __magic_name__								=			[]
    __magic_name__								=			[]
    for html_string in html_strings:
      __magic_name__	,       __magic_name__	,       __magic_name__								=			self.get_three_from_single(UpperCamelCase__       )
      nodes.append(UpperCamelCase__       )
      __magic_name__								=			[]
      for node, tag_list, sub_list in zip(UpperCamelCase__     ,				UpperCamelCase__     ,				UpperCamelCase__       ):
        __magic_name__								=			self.construct_xpath(UpperCamelCase__     ,				UpperCamelCase__       )
        xpath_strings.append(UpperCamelCase__       )
      xpaths.append(UpperCamelCase__       )

    # return as Dict
    __magic_name__								=			{"""nodes""": nodes, """xpaths""": xpaths}
    __magic_name__								=			BatchFeature(data=UpperCamelCase__     ,				tensor_type=UpperCamelCase__       )

    return encoded_inputs

