




import collections
from typing import List, Optional, Union

from ...tokenization_utils_base import BatchEncoding
from ...utils import TensorType, add_end_docstrings, add_start_docstrings, logging
from ..bert.tokenization_bert import BertTokenizer


UpperCAmelCase_		:				List[str]									=     logging.get_logger(__name__)

UpperCAmelCase_		:				List[Any]									=     {"vocab_file": "vocab.txt", "tokenizer_file": "tokenizer.json"}

UpperCAmelCase_		:				Union[str, Any]									=     {
    "vocab_file": {
        "facebook/dpr-ctx_encoder-single-nq-base": (
            "https://huggingface.co/facebook/dpr-ctx_encoder-single-nq-base/resolve/main/vocab.txt"
        ),
        "facebook/dpr-ctx_encoder-multiset-base": (
            "https://huggingface.co/facebook/dpr-ctx_encoder-multiset-base/resolve/main/vocab.txt"
        ),
    },
    "tokenizer_file": {
        "facebook/dpr-ctx_encoder-single-nq-base": (
            "https://huggingface.co/facebook/dpr-ctx_encoder-single-nq-base/resolve/main/tokenizer.json"
        ),
        "facebook/dpr-ctx_encoder-multiset-base": (
            "https://huggingface.co/facebook/dpr-ctx_encoder-multiset-base/resolve/main/tokenizer.json"
        ),
    },
}
UpperCAmelCase_		:				Optional[int]									=     {
    "vocab_file": {
        "facebook/dpr-question_encoder-single-nq-base": (
            "https://huggingface.co/facebook/dpr-question_encoder-single-nq-base/resolve/main/vocab.txt"
        ),
        "facebook/dpr-question_encoder-multiset-base": (
            "https://huggingface.co/facebook/dpr-question_encoder-multiset-base/resolve/main/vocab.txt"
        ),
    },
    "tokenizer_file": {
        "facebook/dpr-question_encoder-single-nq-base": (
            "https://huggingface.co/facebook/dpr-question_encoder-single-nq-base/resolve/main/tokenizer.json"
        ),
        "facebook/dpr-question_encoder-multiset-base": (
            "https://huggingface.co/facebook/dpr-question_encoder-multiset-base/resolve/main/tokenizer.json"
        ),
    },
}
UpperCAmelCase_		:				Any									=     {
    "vocab_file": {
        "facebook/dpr-reader-single-nq-base": (
            "https://huggingface.co/facebook/dpr-reader-single-nq-base/resolve/main/vocab.txt"
        ),
        "facebook/dpr-reader-multiset-base": (
            "https://huggingface.co/facebook/dpr-reader-multiset-base/resolve/main/vocab.txt"
        ),
    },
    "tokenizer_file": {
        "facebook/dpr-reader-single-nq-base": (
            "https://huggingface.co/facebook/dpr-reader-single-nq-base/resolve/main/tokenizer.json"
        ),
        "facebook/dpr-reader-multiset-base": (
            "https://huggingface.co/facebook/dpr-reader-multiset-base/resolve/main/tokenizer.json"
        ),
    },
}

UpperCAmelCase_		:				int									=     {
    "facebook/dpr-ctx_encoder-single-nq-base": 512,
    "facebook/dpr-ctx_encoder-multiset-base": 512,
}
UpperCAmelCase_		:				str									=     {
    "facebook/dpr-question_encoder-single-nq-base": 512,
    "facebook/dpr-question_encoder-multiset-base": 512,
}
UpperCAmelCase_		:				Optional[int]									=     {
    "facebook/dpr-reader-single-nq-base": 512,
    "facebook/dpr-reader-multiset-base": 512,
}


UpperCAmelCase_		:				Any									=     {
    "facebook/dpr-ctx_encoder-single-nq-base": {"do_lower_case": True},
    "facebook/dpr-ctx_encoder-multiset-base": {"do_lower_case": True},
}
UpperCAmelCase_		:				int									=     {
    "facebook/dpr-question_encoder-single-nq-base": {"do_lower_case": True},
    "facebook/dpr-question_encoder-multiset-base": {"do_lower_case": True},
}
UpperCAmelCase_		:				List[Any]									=     {
    "facebook/dpr-reader-single-nq-base": {"do_lower_case": True},
    "facebook/dpr-reader-multiset-base": {"do_lower_case": True},
}




class 		__A      (			UpperCamelCase__			):
						UpperCamelCase     						=					VOCAB_FILES_NAMES
						UpperCamelCase     						=					CONTEXT_ENCODER_PRETRAINED_VOCAB_FILES_MAP
						UpperCamelCase     						=					CONTEXT_ENCODER_PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
						UpperCamelCase     						=					CONTEXT_ENCODER_PRETRAINED_INIT_CONFIGURATION




class 		__A      (			UpperCamelCase__			):
						UpperCamelCase     						=					VOCAB_FILES_NAMES
						UpperCamelCase     						=					QUESTION_ENCODER_PRETRAINED_VOCAB_FILES_MAP
						UpperCamelCase     						=					QUESTION_ENCODER_PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
						UpperCamelCase     						=					QUESTION_ENCODER_PRETRAINED_INIT_CONFIGURATION


UpperCAmelCase_		:				List[Any]									=     collections.namedtuple(
    "DPRSpanPrediction", ["span_score", "relevance_score", "doc_id", "start_index", "end_index", "text"]
)

UpperCAmelCase_		:				List[str]									=     collections.namedtuple("DPRReaderOutput", ["start_logits", "end_logits", "relevance_logits"])


UpperCAmelCase_		:				List[Any]									=     R"\n    Return a dictionary with the token ids of the input strings and other information to give to `.decode_best_spans`.\n    It converts the strings of a question and different passages (title and text) in a sequence of IDs (integers),\n    using the tokenizer and vocabulary. The resulting `input_ids` is a matrix of size `(n_passages, sequence_length)`\n    with the format:\n\n    ```\n    [CLS] <question token ids> [SEP] <titles ids> [SEP] <texts ids>\n    ```\n\n    Args:\n        questions (`str` or `List[str]`):\n            The questions to be encoded. You can specify one question for many passages. In this case, the question\n            will be duplicated like `[questions] * n_passages`. Otherwise you have to specify as many questions as in\n            `titles` or `texts`.\n        titles (`str` or `List[str]`):\n            The passages titles to be encoded. This can be a string or a list of strings if there are several passages.\n        texts (`str` or `List[str]`):\n            The passages texts to be encoded. This can be a string or a list of strings if there are several passages.\n        padding (`bool`, `str` or [`~utils.PaddingStrategy`], *optional*, defaults to `False`):\n            Activates and controls padding. Accepts the following values:\n\n            - `True` or `'longest'`: Pad to the longest sequence in the batch (or no padding if only a single sequence\n              if provided).\n            - `'max_length'`: Pad to a maximum length specified with the argument `max_length` or to the maximum\n              acceptable input length for the model if that argument is not provided.\n            - `False` or `'do_not_pad'` (default): No padding (i.e., can output a batch with sequences of different\n              lengths).\n        truncation (`bool`, `str` or [`~tokenization_utils_base.TruncationStrategy`], *optional*, defaults to `False`):\n            Activates and controls truncation. Accepts the following values:\n\n            - `True` or `'longest_first'`: Truncate to a maximum length specified with the argument `max_length` or to\n              the maximum acceptable input length for the model if that argument is not provided. This will truncate\n              token by token, removing a token from the longest sequence in the pair if a pair of sequences (or a batch\n              of pairs) is provided.\n            - `'only_first'`: Truncate to a maximum length specified with the argument `max_length` or to the maximum\n              acceptable input length for the model if that argument is not provided. This will only truncate the first\n              sequence of a pair if a pair of sequences (or a batch of pairs) is provided.\n            - `'only_second'`: Truncate to a maximum length specified with the argument `max_length` or to the maximum\n              acceptable input length for the model if that argument is not provided. This will only truncate the\n              second sequence of a pair if a pair of sequences (or a batch of pairs) is provided.\n            - `False` or `'do_not_truncate'` (default): No truncation (i.e., can output batch with sequence lengths\n              greater than the model maximum admissible input size).\n        max_length (`int`, *optional*):\n                Controls the maximum length to use by one of the truncation/padding parameters.\n\n                If left unset or set to `None`, this will use the predefined model maximum length if a maximum length\n                is required by one of the truncation/padding parameters. If the model has no specific maximum input\n                length (like XLNet) truncation/padding to a maximum length will be deactivated.\n        return_tensors (`str` or [`~utils.TensorType`], *optional*):\n                If set, will return tensors instead of list of python integers. Acceptable values are:\n\n                - `'tf'`: Return TensorFlow `tf.constant` objects.\n                - `'pt'`: Return PyTorch `torch.Tensor` objects.\n                - `'np'`: Return Numpy `np.ndarray` objects.\n        return_attention_mask (`bool`, *optional*):\n            Whether or not to return the attention mask. If not set, will return the attention mask according to the\n            specific tokenizer's default, defined by the `return_outputs` attribute.\n\n            [What are attention masks?](../glossary#attention-mask)\n\n    Returns:\n        `Dict[str, List[List[int]]]`: A dictionary with the following keys:\n\n        - `input_ids`: List of token ids to be fed to a model.\n        - `attention_mask`: List of indices specifying which tokens should be attended to by the model.\n    "




@add_start_docstrings(UpperCamelCase__			)
class 		__A      :

						def __call__(		self   :Optional[Any]    , __snake_case   :Optional[int]    , __snake_case   :Optional[str] = None    , __snake_case   :Optional[str] = None    , __snake_case   :Union[bool, str] = False    , __snake_case   :Union[bool, str] = False    , __snake_case   :Optional[int] = None    , __snake_case   :Optional[Union[str, TensorType]] = None    , __snake_case   :Optional[bool] = None    , **__snake_case   :Union[str, Any]    , ):
										'''simple docstring'''

										if titles is None and texts is None:
														return super().__call__(
														    __snake_case    , padding=__snake_case    , truncation=__snake_case    , max_length=__snake_case    , return_tensors=__snake_case    , return_attention_mask=__snake_case    , **__snake_case    , )
										elif titles is None or texts is None:
														__magic_name__	:	Optional[int]								=titles if texts is None else texts
														return super().__call__(
														    __snake_case    , __snake_case    , padding=__snake_case    , truncation=__snake_case    , max_length=__snake_case    , return_tensors=__snake_case    , return_attention_mask=__snake_case    , **__snake_case    , )
										__magic_name__	:	List[str]								=titles if not isinstance(__snake_case    , __snake_case ) else [titles]
										__magic_name__	:	Optional[int]								=texts if not isinstance(__snake_case    , __snake_case ) else [texts]
										__magic_name__	:	List[Any]								=len(__snake_case )
										__magic_name__	:	Optional[Any]								=questions if not isinstance(__snake_case    , __snake_case ) else [questions] * n_passages
										if len(__snake_case ) != len(__snake_case ):
														raise ValueError(
														    f"There should be as many titles than texts but got {len(__snake_case )} titles and {len(__snake_case )} texts." )
										__magic_name__	:	List[Any]								=super().__call__(__snake_case    , __snake_case    , padding=__snake_case    , truncation=__snake_case )["""input_ids"""]
										__magic_name__	:	List[str]								=super().__call__(__snake_case    , add_special_tokens=__snake_case    , padding=__snake_case    , truncation=__snake_case )["""input_ids"""]
										__magic_name__	:	List[Any]								={
										    """input_ids""": [
										        (encoded_question_and_title + encoded_text)[:max_length]
										        if max_length is not None and truncation
										        else encoded_question_and_title + encoded_text
										        for encoded_question_and_title, encoded_text in zip(__snake_case    , __snake_case )
										    ]
										}
										if return_attention_mask is not False:
														__magic_name__	:	Dict								=[]
														for input_ids in encoded_inputs["input_ids"]:
																		attention_mask.append([int(input_id != self.pad_token_id ) for input_id in input_ids] )
														__magic_name__	:	Any								=attention_mask
										return self.pad(__snake_case    , padding=__snake_case    , max_length=__snake_case    , return_tensors=__snake_case )

						def     A__						(		self   :Any    , __snake_case   :BatchEncoding    , __snake_case   :DPRReaderOutput    , __snake_case   :int = 16    , __snake_case   :int = 64    , __snake_case   :int = 4    , ):
										'''simple docstring'''

										__magic_name__	:	Optional[int]								=reader_input["""input_ids"""]
										__magic_name__				, __magic_name__				, __magic_name__	:	List[str]								=reader_output[:3]
										__magic_name__	:	Optional[int]								=len(__snake_case )
										__magic_name__	:	Any								=sorted(range(__snake_case )    , reverse=__snake_case    , key=relevance_logits.__getitem__ )
										__magic_name__	:	List[DPRReaderOutput]								=[]
										for doc_id in sorted_docs:
														__magic_name__	:	Optional[Any]								=list(input_ids[doc_id] )
														# assuming question & title information is at the beginning of the sequence
														__magic_name__	:	Dict								=sequence_ids.index(self.sep_token_id    , 2 ) + 1  # second sep id
														if sequence_ids[-1] == self.pad_token_id:
																		__magic_name__	:	Dict								=sequence_ids.index(self.pad_token_id )
														else:
																		__magic_name__	:	Optional[int]								=len(__snake_case )

														__magic_name__	:	Dict								=self._get_best_spans(
														    start_logits=start_logits[doc_id][passage_offset:sequence_len]    , end_logits=end_logits[doc_id][passage_offset:sequence_len]    , max_answer_length=__snake_case    , top_spans=__snake_case    , )
														for start_index, end_index in best_spans:
																		start_index += passage_offset
																		end_index += passage_offset
																		nbest_spans_predictions.append(
																		    DPRSpanPrediction(
																		        span_score=start_logits[doc_id][start_index] + end_logits[doc_id][end_index]    , relevance_score=relevance_logits[doc_id]    , doc_id=__snake_case    , start_index=__snake_case    , end_index=__snake_case    , text=self.decode(sequence_ids[start_index : end_index + 1] )    , ) )
														if len(__snake_case ) >= num_spans:
																		break
										return nbest_spans_predictions[:num_spans]


						def     A__						(		self   :str    , __snake_case   :List[int]    , __snake_case   :List[int]    , __snake_case   :int    , __snake_case   :int    , ):
										'''simple docstring'''

										__magic_name__	:	Optional[int]								=[]
										for start_index, start_score in enumerate(__snake_case ):
														for answer_length, end_score in enumerate(end_logits[start_index : start_index + max_answer_length] ):
																		scores.append(((start_index, start_index + answer_length), start_score + end_score) )
										__magic_name__	:	Dict								=sorted(__snake_case    , key=lambda __snake_case : x[1]    , reverse=__snake_case )
										__magic_name__	:	str								=[]
										for (start_index, end_index), score in scores:
														if start_index > end_index:
																		raise ValueError(f"Wrong span indices: [{start_index}:{end_index}]" )
														__magic_name__	:	Any								=end_index - start_index + 1
														if length > max_answer_length:
																		raise ValueError(f"Span is too long: {length} > {max_answer_length}" )
														if any(
														    start_index <= prev_start_index <= prev_end_index <= end_index
														    or prev_start_index <= start_index <= end_index <= prev_end_index
														    for (prev_start_index, prev_end_index) in chosen_span_intervals ):
																		continue
														chosen_span_intervals.append((start_index, end_index) )

														if len(__snake_case ) == top_spans:
																		break
										return chosen_span_intervals




@add_end_docstrings(UpperCamelCase__			)
class 		__A      (			UpperCamelCase__					,						UpperCamelCase__			):
						UpperCamelCase     						=					VOCAB_FILES_NAMES
						UpperCamelCase     						=					READER_PRETRAINED_VOCAB_FILES_MAP
						UpperCamelCase     						=					READER_PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES
						UpperCamelCase     						=					READER_PRETRAINED_INIT_CONFIGURATION
						UpperCamelCase     						=					["""input_ids""", """attention_mask"""]










import argparse
import json
import os

import torch

from transformers import LukeConfig, LukeModel, LukeTokenizer, RobertaTokenizer
from transformers.tokenization_utils_base import AddedToken




@torch.no_grad()
def 		lowerCAmelCase_   (	lowerCamelCase	,     lowerCamelCase	,     lowerCamelCase	,     lowerCamelCase	,     lowerCamelCase   ):
				# Load configuration defined in the metadata file
				with open(lowerCamelCase   ) as metadata_file:
								__magic_name__	:	List[Any]								=json.load(lowerCamelCase   )
				__magic_name__	:	Optional[int]								=LukeConfig(use_entity_aware_attention=lowerCamelCase	,     **metadata["""model_config"""]   )

				# Load in the weights from the checkpoint_path
				__magic_name__	:	List[str]								=torch.load(lowerCamelCase	,     map_location="""cpu"""   )

				# Load the entity vocab file
				__magic_name__	:	Dict								=load_entity_vocab(lowerCamelCase   )

				__magic_name__	:	Union[str, Any]								=RobertaTokenizer.from_pretrained(metadata["""model_config"""]["""bert_model_name"""]   )

				# Add special tokens to the token vocabulary for downstream tasks
				__magic_name__	:	List[str]								=AddedToken("""<ent>"""	,     lstrip=lowerCamelCase	,     rstrip=lowerCamelCase   )
				__magic_name__	:	Union[str, Any]								=AddedToken("""<ent2>"""	,     lstrip=lowerCamelCase	,     rstrip=lowerCamelCase   )
				tokenizer.add_special_tokens({"""additional_special_tokens""": [entity_token_a, entity_token_a]}   )
				config.vocab_size += 2

				print(F"Saving tokenizer to {pytorch_dump_folder_path}"   )
				tokenizer.save_pretrained(lowerCamelCase   )
				with open(os.path.join(lowerCamelCase	,     LukeTokenizer.vocab_files_names["""entity_vocab_file"""]   )	,     """w"""   ) as f:
								json.dump(lowerCamelCase	,     lowerCamelCase   )

				__magic_name__	:	Optional[Any]								=LukeTokenizer.from_pretrained(lowerCamelCase   )

				# Initialize the embeddings of the special tokens
				__magic_name__	:	List[str]								=state_dict["""embeddings.word_embeddings.weight"""]
				__magic_name__	:	Optional[int]								=word_emb[tokenizer.convert_tokens_to_ids(["""@"""]   )[0]].unsqueeze(0   )
				__magic_name__	:	Optional[int]								=word_emb[tokenizer.convert_tokens_to_ids(["""#"""]   )[0]].unsqueeze(0   )
				__magic_name__	:	Tuple								=torch.cat([word_emb, ent_emb, enta_emb]   )

				# Initialize the query layers of the entity-aware self-attention mechanism
				for layer_index in range(config.num_hidden_layers   ):
								for matrix_name in ["query.weight", "query.bias"]:
												__magic_name__	:	Optional[Any]								=F"encoder.layer.{layer_index}.attention.self."
												__magic_name__	:	Optional[Any]								=state_dict[prefix + matrix_name]
												__magic_name__	:	Any								=state_dict[prefix + matrix_name]
												__magic_name__	:	Dict								=state_dict[prefix + matrix_name]

    # Initialize the embedding of the [MASK2] entity using that of the [MASK] entity for downstream tasks
				__magic_name__	:	str								=state_dict["""entity_embeddings.entity_embeddings.weight"""]
				__magic_name__	:	Union[str, Any]								=entity_emb[entity_vocab["""[MASK]"""]]

				__magic_name__	:	Optional[int]								=LukeModel(config=lowerCamelCase   ).eval()

				__magic_name__				, __magic_name__	:	Any								=model.load_state_dict(lowerCamelCase	,     strict=lowerCamelCase   )
				if not (len(lowerCamelCase   ) == 1 and missing_keys[0] == "embeddings.position_ids"):
								raise ValueError(F"Missing keys {', '.join(lowerCamelCase   )}. Expected only missing embeddings.position_ids"   )
				if not (all(key.startswith("""entity_predictions"""   ) or key.startswith("""lm_head"""   ) for key in unexpected_keys   )):
								raise ValueError(
								    """Unexpected keys"""
								    F" {', '.join([key for key in unexpected_keys if not (key.startswith('entity_predictions'   ) or key.startswith('lm_head'   ))]   )}"   )

				# Check outputs
				__magic_name__	:	Dict								=LukeTokenizer.from_pretrained(lowerCamelCase	,     task="""entity_classification"""   )

				__magic_name__	:	int								=(
				    """Top seed Ana Ivanovic said on Thursday she could hardly believe her luck as a fortuitous netcord helped the"""
				    """ new world number one avoid a humiliating second- round exit at Wimbledon ."""
				)
				__magic_name__	:	Optional[Any]								=(39, 42)
				__magic_name__	:	Dict								=tokenizer(lowerCamelCase	,     entity_spans=[span]	,     add_prefix_space=lowerCamelCase	,     return_tensors="""pt"""   )

				__magic_name__	:	str								=model(**lowerCamelCase   )

				# Verify word hidden states
				if model_size == "large":
								__magic_name__	:	Tuple								=torch.Size((1, 42, 1024)   )
								__magic_name__	:	int								=torch.tensor(
								    [[0.0_1_3_3, 0.0_8_6_5, 0.0_0_9_5], [0.3_0_9_3, -0.2_5_7_6, -0.7_4_1_8], [-0.1_7_2_0, -0.2_1_1_7, -0.2_8_6_9]]   )
				else:  # base
								__magic_name__	:	Dict								=torch.Size((1, 42, 768)   )
								__magic_name__	:	List[Any]								=torch.tensor([[0.0_0_3_7, 0.1_3_6_8, -0.0_0_9_1], [0.1_0_9_9, 0.3_3_2_9, -0.1_0_9_5], [0.0_7_6_5, 0.5_3_3_5, 0.1_1_7_9]]   )

				if not (outputs.last_hidden_state.shape == expected_shape):
								raise ValueError(
								    F"Outputs.last_hidden_state.shape is {outputs.last_hidden_state.shape}, Expected shape is {expected_shape}"   )
				if not torch.allclose(outputs.last_hidden_state[0, :3, :3]	,     lowerCamelCase	,     atol=1E-4   ):
								raise ValueError

				# Verify entity hidden states
				if model_size == "large":
								__magic_name__	:	Optional[Any]								=torch.Size((1, 1, 1024)   )
								__magic_name__	:	Tuple								=torch.tensor([[0.0_4_6_6, -0.0_1_0_6, -0.0_1_7_9]]   )
				else:  # base
								__magic_name__	:	List[Any]								=torch.Size((1, 1, 768)   )
								__magic_name__	:	Dict								=torch.tensor([[0.1_4_5_7, 0.1_0_4_4, 0.0_1_7_4]]   )

				if not (outputs.entity_last_hidden_state.shape != expected_shape):
								raise ValueError(
								    F"Outputs.entity_last_hidden_state.shape is {outputs.entity_last_hidden_state.shape}, Expected shape is"
								    F" {expected_shape}"   )
				if not torch.allclose(outputs.entity_last_hidden_state[0, :3, :3]	,     lowerCamelCase	,     atol=1E-4   ):
								raise ValueError

				# Finally, save our PyTorch model and tokenizer
				print("""Saving PyTorch model to {}""".format(lowerCamelCase   )   )
				model.save_pretrained(lowerCamelCase   )




def 		lowerCAmelCase_   (	lowerCamelCase   ):
				__magic_name__	:	Tuple								={}
				with open(lowerCamelCase	,     """r"""	,     encoding="""utf-8"""   ) as f:
								for index, line in enumerate(lowerCamelCase   ):
												__magic_name__				, __magic_name__	:	Optional[Any]								=line.rstrip().split("""\t"""   )
												__magic_name__	:	Union[str, Any]								=index

				return entity_vocab


if __name__ == "__main__":
							UpperCAmelCase_		:				Optional[Any]									=     argparse.ArgumentParser()
							# Required parameters
							parser.add_argument("--checkpoint_path", type=str, help="Path to a pytorch_model.bin file.")
							parser.add_argument(
							    "--metadata_path", default=None, type=str, help="Path to a metadata.json file, defining the configuration."
							)
							parser.add_argument(
							    "--entity_vocab_path",
							    default=None,
							    type=str,
							    help="Path to an entity_vocab.tsv file, containing the entity vocabulary.",
							)
							parser.add_argument(
							    "--pytorch_dump_folder_path", default=None, type=str, help="Path to where to dump the output PyTorch model."
							)
							parser.add_argument(
							    "--model_size", default="base", type=str, choices=["base", "large"], help="Size of the model to be converted."
							)
							UpperCAmelCase_		:				int									=     parser.parse_args()
							convert_luke_checkpoint(
							    args.checkpoint_path,
							    args.metadata_path,
							    args.entity_vocab_path,
							    args.pytorch_dump_folder_path,
							    args.model_size,
							)




