






import os
import unicodedata
from shutil import copyfile
from typing import Any, Dict, List, Optional, Tuple

import sentencepiece as spm

from ...tokenization_utils import AddedToken, PreTrainedTokenizer
from ...utils import logging


a__       =     logging.get_logger(__name__)
a__       =     {"""vocab_file""": """spiece.model"""}

a__       =     {
    """vocab_file""": {
        """albert-base-v1""": """https://huggingface.co/albert-base-v1/resolve/main/spiece.model""",
        """albert-large-v1""": """https://huggingface.co/albert-large-v1/resolve/main/spiece.model""",
        """albert-xlarge-v1""": """https://huggingface.co/albert-xlarge-v1/resolve/main/spiece.model""",
        """albert-xxlarge-v1""": """https://huggingface.co/albert-xxlarge-v1/resolve/main/spiece.model""",
        """albert-base-v2""": """https://huggingface.co/albert-base-v2/resolve/main/spiece.model""",
        """albert-large-v2""": """https://huggingface.co/albert-large-v2/resolve/main/spiece.model""",
        """albert-xlarge-v2""": """https://huggingface.co/albert-xlarge-v2/resolve/main/spiece.model""",
        """albert-xxlarge-v2""": """https://huggingface.co/albert-xxlarge-v2/resolve/main/spiece.model""",
    }
}

a__       =     {
    """albert-base-v1""": 5_1_2,
    """albert-large-v1""": 5_1_2,
    """albert-xlarge-v1""": 5_1_2,
    """albert-xxlarge-v1""": 5_1_2,
    """albert-base-v2""": 5_1_2,
    """albert-large-v2""": 5_1_2,
    """albert-xlarge-v2""": 5_1_2,
    """albert-xxlarge-v2""": 5_1_2,
}

a__       =     """▁"""


class    _lowerCAmelCase			(		lowercase_      ):



				"""simple docstring"""



				_lowercase				:   List[Any]      =  VOCAB_FILES_NAMES
				_lowercase				:   Dict      =  PRETRAINED_VOCAB_FILES_MAP
				_lowercase				:   Any      =  PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES



				def __init__(      self    :    Tuple			,		UpperCamelCase__    :    int			,		UpperCamelCase__    :    str=True			,		UpperCamelCase__    :    Optional[Any]=True			,		UpperCamelCase__    :    List[str]=False			,		UpperCamelCase__    :    Dict="[CLS]"			,		UpperCamelCase__    :    Dict="[SEP]"			,		UpperCamelCase__    :    str="<unk>"			,		UpperCamelCase__    :    List[Any]="[SEP]"			,		UpperCamelCase__    :    Optional[int]="<pad>"			,		UpperCamelCase__    :    List[str]="[CLS]"			,		UpperCamelCase__    :    str="[MASK]"			,		UpperCamelCase__    :    Optional[Dict[str, Any]] = None			,		**UpperCamelCase__    :    Optional[Any]			,		):






											'''simple docstring'''







											snake_case__	  =       (
											    AddedToken(UpperCamelCase__			,		lstrip=UpperCamelCase__			,		rstrip=UpperCamelCase__			,		normalized=UpperCamelCase__)
											    if isinstance(UpperCamelCase__			,		UpperCamelCase__)
											    else mask_token
											)

											snake_case__	  =       {} if sp_model_kwargs is None else sp_model_kwargs

											super().__init__(
											    do_lower_case=UpperCamelCase__			,		remove_space=UpperCamelCase__			,		keep_accents=UpperCamelCase__			,		bos_token=UpperCamelCase__			,		eos_token=UpperCamelCase__			,		unk_token=UpperCamelCase__			,		sep_token=UpperCamelCase__			,		pad_token=UpperCamelCase__			,		cls_token=UpperCamelCase__			,		mask_token=UpperCamelCase__			,		sp_model_kwargs=self.sp_model_kwargs			,		**UpperCamelCase__			,		)

											snake_case__	  =       do_lower_case
											snake_case__	  =       remove_space
											snake_case__	  =       keep_accents
											snake_case__	  =       vocab_file

											snake_case__	  =       spm.SentencePieceProcessor(**self.sp_model_kwargs)
											self.sp_model.Load(UpperCamelCase__)



				@property
				def 					__magic_name__							(      self    :    int):






											'''simple docstring'''







											return len(self.sp_model)



				def 					__magic_name__							(      self    :    List[Any]):






											'''simple docstring'''







											snake_case__	  =       {self.convert_ids_to_tokens(UpperCamelCase__): i for i in range(self.vocab_size)}
											vocab.update(self.added_tokens_encoder)
											return vocab



				def __getstate__(      self    :    List[Any]):






											'''simple docstring'''







											snake_case__	  =       self.__dict__.copy()
											snake_case__	  =       None
											return state



				def __setstate__(      self    :    str			,		UpperCamelCase__    :    Dict):






											'''simple docstring'''







											snake_case__	  =       d

											# for backward compatibility
											if not hasattr(self			,		"""sp_model_kwargs"""):
																		snake_case__	  =       {}

											snake_case__	  =       spm.SentencePieceProcessor(**self.sp_model_kwargs)
											self.sp_model.Load(self.vocab_file)



				def 					__magic_name__							(      self    :    Union[str, Any]			,		UpperCamelCase__    :    str):






											'''simple docstring'''







											if self.remove_space:
																		snake_case__	  =       """ """.join(inputs.strip().split())
											else:
																		snake_case__	  =       inputs
											snake_case__	  =       outputs.replace("""``"""			,		"""\"""").replace("""''"""			,		"""\"""")

											if not self.keep_accents:
																		snake_case__	  =       unicodedata.normalize("""NFKD"""			,		UpperCamelCase__)
																		snake_case__	  =       """""".join([c for c in outputs if not unicodedata.combining(UpperCamelCase__)])
											if self.do_lower_case:
																		snake_case__	  =       outputs.lower()

											return outputs



				def 					__magic_name__							(      self    :    List[str]			,		UpperCamelCase__    :    str):






											'''simple docstring'''







											snake_case__	  =       self.preprocess_text(UpperCamelCase__)
											snake_case__	  =       self.sp_model.encode(UpperCamelCase__			,		out_type=UpperCamelCase__)
											snake_case__	  =       []
											for piece in pieces:
																		if len(UpperCamelCase__) > 1 and piece[-1] == str(""",""") and piece[-2].isdigit():
																									snake_case__	  =       self.sp_model.EncodeAsPieces(piece[:-1].replace(UpperCamelCase__			,		""""""))
																									if piece[0] != SPIECE_UNDERLINE and cur_pieces[0][0] == SPIECE_UNDERLINE:
																																if len(cur_pieces[0]) == 1:
																																							snake_case__	  =       cur_pieces[1:]
																																else:
																																							snake_case__	  =       cur_pieces[0][1:]
																									cur_pieces.append(piece[-1])
																									new_pieces.extend(UpperCamelCase__)
																		else:
																									new_pieces.append(UpperCamelCase__)

											return new_pieces



				def 					__magic_name__							(      self    :    Optional[Any]			,		UpperCamelCase__    :    List[Any]):






											'''simple docstring'''







											return self.sp_model.PieceToId(UpperCamelCase__)



				def 					__magic_name__							(      self    :    Any			,		UpperCamelCase__    :    List[Any]):






											'''simple docstring'''







											return self.sp_model.IdToPiece(UpperCamelCase__)



				def 					__magic_name__							(      self    :    str			,		UpperCamelCase__    :    Any):






											'''simple docstring'''







											snake_case__	  =       []
											snake_case__	  =       """"""
											snake_case__	  =       False
											for token in tokens:
																		# make sure that special tokens are not decoded using sentencepiece model
																		if token in self.all_special_tokens:
																									if not prev_is_special:
																																out_string += " "
																									out_string += self.sp_model.decode(UpperCamelCase__) + token
																									snake_case__	  =       True
																									snake_case__	  =       []
																		else:
																									current_sub_tokens.append(UpperCamelCase__)
																									snake_case__	  =       False
											out_string += self.sp_model.decode(UpperCamelCase__)
											return out_string.strip()



				def 					__magic_name__							(      self    :    List[Any]			,		UpperCamelCase__    :    List[int]			,		UpperCamelCase__    :    Optional[List[int]] = None):






											'''simple docstring'''







											snake_case__	  =       [self.sep_token_id]
											snake_case__	  =       [self.cls_token_id]
											if token_ids_a is None:
																		return cls + token_ids_a + sep
											return cls + token_ids_a + sep + token_ids_a + sep



				def 					__magic_name__							(      self    :    Any			,		UpperCamelCase__    :    List[int]			,		UpperCamelCase__    :    Optional[List[int]] = None			,		UpperCamelCase__    :    bool = False):






											'''simple docstring'''







											if already_has_special_tokens:
																		return super().get_special_tokens_mask(
																		    token_ids_a=UpperCamelCase__			,		token_ids_a=UpperCamelCase__			,		already_has_special_tokens=UpperCamelCase__)

											if token_ids_a is not None:
																		return [1] + ([0] * len(UpperCamelCase__)) + [1] + ([0] * len(UpperCamelCase__)) + [1]
											return [1] + ([0] * len(UpperCamelCase__)) + [1]



				def 					__magic_name__							(      self    :    int			,		UpperCamelCase__    :    List[int]			,		UpperCamelCase__    :    Optional[List[int]] = None):






											'''simple docstring'''







											snake_case__	  =       [self.sep_token_id]
											snake_case__	  =       [self.cls_token_id]

											if token_ids_a is None:
																		return len(cls + token_ids_a + sep) * [0]
											return len(cls + token_ids_a + sep) * [0] + len(token_ids_a + sep) * [1]



				def 					__magic_name__							(      self    :    int			,		UpperCamelCase__    :    str			,		UpperCamelCase__    :    Optional[str] = None):






											'''simple docstring'''







											if not os.path.isdir(UpperCamelCase__):
																		logger.error(F'''Vocabulary path ({save_directory}) should be a directory''')
																		return
											snake_case__	  =       os.path.join(
											    UpperCamelCase__			,		(filename_prefix + """-""" if filename_prefix else """""") + VOCAB_FILES_NAMES["""vocab_file"""])

											if os.path.abspath(self.vocab_file) != os.path.abspath(UpperCamelCase__) and os.path.isfile(self.vocab_file):
																		copyfile(self.vocab_file			,		UpperCamelCase__)
											elif not os.path.isfile(self.vocab_file):
																		with open(UpperCamelCase__			,		"""wb""") as fi:
																									snake_case__	  =       self.sp_model.serialized_model_proto()
																									fi.write(UpperCamelCase__)

											return (out_vocab_file,)








from math import factorial

a__       =     {str(digit): factorial(digit) for digit in range(1_0)}

def _UpperCAmelCase   (	a						:	int ):
							if not isinstance(a  ,					a ):
														raise TypeError("""Parameter number must be int""" )

							if number < 0:
														raise ValueError("""Parameter number must be greater than or equal to 0""" )

							# Converts number in string to iterate on its digits and adds its factorial.
							return sum(DIGIT_FACTORIAL[digit] for digit in str(a ) )

def _UpperCAmelCase   (	a						:	int = 60  ,					a						:	int = 100_0000 ):

							if not isinstance(a  ,					a ) or not isinstance(a  ,					a ):
														raise TypeError("""Parameters chain_length and number_limit must be int""" )

							if chain_length <= 0 or number_limit <= 0:
														raise ValueError(
														    """Parameters chain_length and number_limit must be greater than 0""" )

							# the counter for the chains with the exact desired length
							snake_case__	  =       0
							# the cached sizes of the previous chains
							snake_case__	  =       {}

							for start_chain_element in range(1  ,					a ):
														# The temporary set will contain the elements of the chain
														snake_case__	  =       set()
														snake_case__	  =       0

														# Stop computing the chain when you find a cached size, a repeating item or the
														# length is greater then the desired one.
														snake_case__	  =       start_chain_element
														while (
														    chain_element not in chain_sets_lengths
														    and chain_element not in chain_set
														    and chain_set_length <= chain_length
														):
																					chain_set.add(a )
																					chain_set_length += 1
																					snake_case__	  =       digit_factorial_sum(a )

														if chain_element in chain_sets_lengths:
																					chain_set_length += chain_sets_lengths[chain_element]

														snake_case__	  =       chain_set_length

														# If chain contains the exact amount of elements increase the counter
														if chain_set_length == chain_length:
																					chains_counter += 1

							return chains_counter


if __name__ == "__main__":
	import doctest

	doctest.testmod()
	print(F'''{solution()}''')
