"""simple docstring"""







import string

import numpy
def   __UpperCAmelCase				(    UpperCAmelCase_    :				int			,							UpperCAmelCase_    :				int  )							->			Tuple:

	'''simple docstring'''





	return b if a == 0 else greatest_common_divisor(b % a			,							__lowerCAmelCase  )

class 		UpperCamelCase			:
				UpperCAmelCase				:      List[Any]    =		string.ascii_uppercase + string.digits
				# This cipher takes alphanumerics into account
				# i.e. a total of 36 characters

				# take x and return x % len(key_string)
				UpperCAmelCase				:      Union[str, Any]    =		numpy.vectorize(lambda lowercase						: x % 36						)

				UpperCAmelCase				:      Optional[int]    =		numpy.vectorize(lowerCamelCase_						)



				def __init__(self				:      Optional[Any]	,  _A				:      numpy.ndarray)    ->	None:
					__snake_case			:							Dict      		= self.modulus(__snake_case)  # mod36 calc's on the encrypt key
					self.check_determinant()  # validate the determinant of the encryption key
					__snake_case			:							Union[str, Any]      		= encrypt_key.shape[0]



				def 					_lowercase     (self				:      Any	,  _A				:      str)    ->	int:
					return self.key_string.index(__snake_case)



				def 					_lowercase     (self				:      Tuple	,  _A				:      int)    ->	str:
					return self.key_string[round(__snake_case)]



				def 					_lowercase     (self				:      List[str])    ->	None:
					__snake_case			:							Optional[int]      		= round(numpy.linalg.det(self.encrypt_key))

					if det < 0:
						__snake_case			:							Union[str, Any]      		= det % len(self.key_string)

					__snake_case			:							Tuple      		= len(self.key_string)
					if greatest_common_divisor(__snake_case	,  len(self.key_string)) != 1:
						__snake_case			:							Optional[Any]      		= (
						    f"determinant modular {req_l} of encryption key({det}) "
						    f"is not co prime w.r.t {req_l}.\nTry another key."
						)
						raise ValueError(__snake_case)



				def 					_lowercase     (self				:      Dict	,  _A				:      str)    ->	str:
					__snake_case			:							Dict      		= [char for char in text.upper() if char in self.key_string]

					__snake_case			:							Union[str, Any]      		= chars[-1]
					while len(__snake_case) % self.break_key != 0:
						chars.append(__snake_case)

					return "".join(__snake_case)



				def 					_lowercase     (self				:      Optional[Any]	,  _A				:      str)    ->	str:
					__snake_case			:							List[Any]      		= self.process_text(text.upper())
					__snake_case			:							Any      		= ''

					for i in range(0	,  len(__snake_case) - self.break_key + 1	,  self.break_key):
						__snake_case			:							List[str]      		= text[i : i + self.break_key]
						__snake_case			:							Union[str, Any]      		= [self.replace_letters(__snake_case) for char in batch]
						__snake_case			:							List[str]      		= numpy.array([vec]).T
						__snake_case			:							Optional[int]      		= self.modulus(self.encrypt_key.dot(__snake_case)).T.tolist()[
						    0
						]
						__snake_case			:							Any      		= ''.join(
						    self.replace_digits(__snake_case) for num in batch_encrypted)
						encrypted += encrypted_batch

					return encrypted



				def 					_lowercase     (self				:      Optional[Any])    ->	numpy.ndarray:
					__snake_case			:							Tuple      		= round(numpy.linalg.det(self.encrypt_key))

					if det < 0:
						__snake_case			:							Dict      		= det % len(self.key_string)
					__snake_case			:							List[Any]      		= None
					for i in range(len(self.key_string)):
						if (det * i) % len(self.key_string) == 1:
							__snake_case			:							Optional[Any]      		= i
							break

					__snake_case			:							str      		= (
					    det_inv
					    * numpy.linalg.det(self.encrypt_key)
					    * numpy.linalg.inv(self.encrypt_key)
					)

					return self.to_int(self.modulus(__snake_case))






				def 					_lowercase     (self				:      Tuple	,  _A				:      str)    ->	str:
					__snake_case			:							Optional[int]      		= self.make_decrypt_key()
					__snake_case			:							Optional[Any]      		= self.process_text(text.upper())
					__snake_case			:							Optional[int]      		= ''

					for i in range(0	,  len(__snake_case) - self.break_key + 1	,  self.break_key):
						__snake_case			:							Any      		= text[i : i + self.break_key]
						__snake_case			:							Union[str, Any]      		= [self.replace_letters(__snake_case) for char in batch]
						__snake_case			:							Tuple      		= numpy.array([vec]).T
						__snake_case			:							List[Any]      		= self.modulus(decrypt_key.dot(__snake_case)).T.tolist()[0]
						__snake_case			:							str      		= ''.join(
						    self.replace_digits(__snake_case) for num in batch_decrypted)
						decrypted += decrypted_batch

					return decrypted







def   __UpperCAmelCase				(    )							->			Tuple:

	'''simple docstring'''





	__snake_case			:							Optional[Any]      		= int(input('Enter the order of the encryption key: '  )  )
	__snake_case			:							Any      		= []

	print('Enter each row of the encryption key with space separated integers'  )
	for _ in range(__lowerCAmelCase  ):
		__snake_case			:							str      		= [int(__lowerCAmelCase  ) for x in input().split()]
		hill_matrix.append(__lowerCAmelCase  )

	__snake_case			:							Union[str, Any]      		= HillCipher(numpy.array(__lowerCAmelCase  )  )

	print('Would you like to encrypt or decrypt some text? (1 or 2)'  )
	__snake_case			:							List[str]      		= input('\n1. Encrypt\n2. Decrypt\n'  )
	if option == "1":
		__snake_case			:							List[str]      		= input('What text would you like to encrypt?: '  )
		print('Your encrypted text is:'  )
		print(hc.encrypt(__lowerCAmelCase  )  )
	elif option == "2":
		__snake_case			:							List[str]      		= input('What text would you like to decrypt?: '  )
		print('Your decrypted text is:'  )
		print(hc.decrypt(__lowerCAmelCase  )  )


if __name__ == "__main__":
	import doctest

	doctest.testmod()

	main()









import math






def 							__lowercase   ( __lowerCAmelCase							:				int   ):
							a__             =     [True] * n
							a__             =     False
							a__             =     False
							a__             =     True

							for i in range(3					,    int(n**0.5 + 1   )					,    2   ):
														a__             =     i * 2
														while index < n:
																					a__             =     False
																					a__             =     index + i

							a__             =     [2]

							for i in range(3					,    __lowerCAmelCase					,    2   ):
														if is_prime[i]:
																					primes.append(__lowerCAmelCase   )

							return primes






def 							__lowercase   ( __lowerCAmelCase							:				int = 9_9_9_9_6_6_6_6_3_3_3_3   ):
							a__             =     math.floor(math.sqrt(__lowerCAmelCase   )   ) + 1_0_0
							a__             =     prime_sieve(__lowerCAmelCase   )

							a__             =     0
							a__             =     0
							a__             =     primes[prime_index]

							while (last_prime**2) <= limit:
														a__             =     primes[prime_index + 1]

														a__             =     last_prime**2
														a__             =     next_prime**2

														# Get numbers divisible by lps(current)
														a__             =     lower_bound + last_prime
														while upper_bound > current <= limit:
																					matches_sum += current
																					current += last_prime

														# Reset the upper_bound
														while (upper_bound - next_prime) > limit:
																					upper_bound -= next_prime

														# Add the numbers divisible by ups(current)
														a__             =     upper_bound - next_prime
														while current > lower_bound:
																					matches_sum += current
																					current -= next_prime

														# Remove the numbers divisible by both ups and lps
														a__             =     0
														while upper_bound > current <= limit:
																					if current <= lower_bound:
																												# Increment the current number
																												current += last_prime * next_prime
																												continue

																					if current > limit:
																												break

																					# Remove twice since it was added by both ups and lps
																					matches_sum -= current * 2

																					# Increment the current number
																					current += last_prime * next_prime

														# Setup for next pair
														a__             =     next_prime
														prime_index += 1

							return matches_sum


if __name__ == "__main__":
						print(solution())




