#
# Sort large text files in a minimum amount of memory
#
import argparse
import os


class 					__SCREAMING_SNAKE_CASE:
							_UpperCAmelCase	      =    "block_{0}.dat"
							def __init__(       self: Tuple    ,		UpperCamelCase: List[str]  )						->						int:
											snake_case__													=       filename
											snake_case__													=       []
							def lowerCAmelCase_	(       self: Optional[Any]    ,		UpperCamelCase: Tuple    ,		UpperCamelCase: Union[str, Any]  )						->						Tuple:
											snake_case__													=       self.BLOCK_FILENAME_FORMAT.format(UpperCamelCase  )
											with open(UpperCamelCase    ,		'w'  ) as file:
															file.write(UpperCamelCase  )
											self.block_filenames.append(UpperCamelCase  )
							def lowerCAmelCase_	(       self: Dict  )						->						Tuple:
											return self.block_filenames
							def lowerCAmelCase_	(       self: Union[str, Any]    ,		UpperCamelCase: List[Any]    ,		UpperCamelCase: Any=None  )						->						Optional[int]:
											snake_case__													=       0
											with open(self.filename  ) as file:
															while True:
																			snake_case__													=       file.readlines(UpperCamelCase  )

																			if lines == []:
																							break

																			if sort_key is None:
																							lines.sort()
																			else:
																							lines.sort(key=UpperCamelCase  )

																			self.write_block(''.join(UpperCamelCase  )    ,		UpperCamelCase  )
																			i += 1


							def lowerCAmelCase_	(       self: List[Any]  )						->						Optional[Any]:
											map(os.remove    ,		self.block_filenames  )


class 					__SCREAMING_SNAKE_CASE:
							def lowerCAmelCase_	(       self: Union[str, Any]    ,		UpperCamelCase: Tuple  )						->						Tuple:
											snake_case__													=       -1
											snake_case__													=       None

											for i in range(len(UpperCamelCase  )  ):
															if min_str is None or choices[i] < min_str:
																			snake_case__													=       i

											return min_index


class 					__SCREAMING_SNAKE_CASE:
							def __init__(       self: List[Any]    ,		UpperCamelCase: List[Any]  )						->						Any:
											snake_case__													=       files
											snake_case__													=       set()
											snake_case__													=       len(UpperCamelCase  )
											snake_case__													=       {i: None for i in range(self.num_buffers  )}
							def lowerCAmelCase_	(       self: Any  )						->						List[Any]:
											return {
											    i: self.buffers[i] for i in range(self.num_buffers  ) if i not in self.empty
											}
							def lowerCAmelCase_	(       self: List[Any]  )						->						Optional[Any]:
											for i in range(self.num_buffers  ):
															if self.buffers[i] is None and i not in self.empty:
																			snake_case__													=       self.files[i].readline()

																			if self.buffers[i] == "":
																							self.empty.add(UpperCamelCase  )
																							self.files[i].close()

											if len(self.empty  ) == self.num_buffers:
															return False

											return True


							def lowerCAmelCase_	(       self: Tuple    ,		UpperCamelCase: Tuple  )						->						Optional[Any]:
											snake_case__													=       self.buffers[index]
											snake_case__													=       None

											return value


class 					__SCREAMING_SNAKE_CASE:
							def __init__(       self: Optional[int]    ,		UpperCamelCase: List[Any]  )						->						Dict:
											snake_case__													=       merge_strategy
							def lowerCAmelCase_	(       self: Optional[int]    ,		UpperCamelCase: Optional[int]    ,		UpperCamelCase: Dict    ,		UpperCamelCase: str  )						->						Tuple:
											snake_case__													=       FilesArray(self.get_file_handles(UpperCamelCase    ,		UpperCamelCase  )  )
											with open(UpperCamelCase    ,		'w'    ,		UpperCamelCase  ) as outfile:
															while buffers.refresh():
																			snake_case__													=       self.merge_strategy.select(buffers.get_dict()  )
																			outfile.write(buffers.unshift(UpperCamelCase  )  )


							def lowerCAmelCase_	(       self: int    ,		UpperCamelCase: List[str]    ,		UpperCamelCase: Optional[Any]  )						->						Any:
											snake_case__													=       {}

											for i in range(len(UpperCamelCase  )  ):
															snake_case__													=       open(filenames[i]    ,		'r'    ,		UpperCamelCase  )  # noqa: UP015

											return files


class 					__SCREAMING_SNAKE_CASE:
							def __init__(       self: List[Any]    ,		UpperCamelCase: Optional[Any]  )						->						Union[str, Any]:
											snake_case__													=       block_size
							def lowerCAmelCase_	(       self: Dict    ,		UpperCamelCase: int    ,		UpperCamelCase: Optional[Any]=None  )						->						Any:
											snake_case__													=       self.get_number_blocks(UpperCamelCase    ,		self.block_size  )
											snake_case__													=       FileSplitter(UpperCamelCase  )
											splitter.split(self.block_size    ,		UpperCamelCase  )

											snake_case__													=       FileMerger(NWayMerge()  )
											snake_case__													=       self.block_size / (num_blocks + 1)
											merger.merge(splitter.get_block_filenames()    ,		filename + '.out'    ,		UpperCamelCase  )

											splitter.cleanup()


							def lowerCAmelCase_	(       self: List[str]    ,		UpperCamelCase: Optional[Any]    ,		UpperCamelCase: Optional[int]  )						->						str:
											return (os.stat(UpperCamelCase  ).st_size / block_size) + 1


def        a_	( _A					)     ->     int:







				"""simple docstring"""
				if string[-1].lower() == "k":
								return int(string[:-1]					) * 1024
				elif string[-1].lower() == "m":
								return int(string[:-1]					) * 1024 * 1024
				elif string[-1].lower() == "g":
								return int(string[:-1]					) * 1024 * 1024 * 1024
				else:
								return int(_A					)
def        a_	( )     ->     Any:







				"""simple docstring"""
				snake_case__													=       argparse.ArgumentParser()
				parser.add_argument(
				    '-m' ,				'--mem' ,				help='amount of memory to use for sorting' ,				default='100M'					)
				parser.add_argument(
				    'filename' ,				metavar='<filename>' ,				nargs=1 ,				help='name of file to sort'					)
				snake_case__													=       parser.parse_args()

				snake_case__													=       ExternalSort(parse_memory(args.mem					)					)
				sorter.sort(args.filename[0]					)


if __name__ == "__main__":
							main()












def        a_	( _A ,				_A					)     ->     Union[str, Any]:







				"""simple docstring"""
				snake_case__													=       1
				while b > 0:
								if b & 1:
												res *= a

								a *= a
								b >>= 1

				return res
def        a_	( _A ,				_A ,				_A					)     ->     Dict:







				"""simple docstring"""
				snake_case__													=       1
				while b > 0:
								if b & 1:
												snake_case__													=       ((res % c) * (a % c)) % c

								a *= a
								b >>= 1

				return res




