



import string

import numpy

def 	_lowerCAmelCase (    A__    ,	A__						):
      return b if a == 0 else greatest_common_divisor(b % a    ,	A__						)



class    UpperCAmelCase__:

   '''simple docstring'''




   A     :	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)
   A     :	Tuple												=     numpy.vectorize(lambda lowerCamelCase						: x % 36						)

   A     :	Any												=     numpy.vectorize(lowerCamelCase						)


   def __init__(    self	:      Union[str, Any]      ,					lowerCAmelCase	:      numpy.ndarray)						->					None:




         """simple docstring"""

         lowercase__  =	self.modulus(lowerCAmelCase)  # mod36 calc's on the encrypt key
         self.check_determinant()  # validate the determinant of the encryption key
         lowercase__  =	encrypt_key.shape[0]


   def       UpperCAmelCase		(    self	:      Tuple      ,					lowerCAmelCase	:      str)						->					int:




         """simple docstring"""

         return self.key_string.index(lowerCAmelCase)


   def       UpperCAmelCase		(    self	:      str      ,					lowerCAmelCase	:      int)						->					str:




         """simple docstring"""

         return self.key_string[round(lowerCAmelCase)]


   def       UpperCAmelCase		(    self	:      List[str])						->					None:




         """simple docstring"""

         lowercase__  =	round(numpy.linalg.det(self.encrypt_key))

         if det < 0:
               lowercase__  =	det % len(self.key_string)

         lowercase__  =	len(self.key_string)
         if greatest_common_divisor(lowerCAmelCase      ,					len(self.key_string)) != 1:
               lowercase__  =	(
                   f'''determinant modular {req_l} of encryption key({det}) '''
                   f'''is not co prime w.r.t {req_l}.\nTry another key.'''
               )
               raise ValueError(lowerCAmelCase)


   def       UpperCAmelCase		(    self	:      str      ,					lowerCAmelCase	:      str)						->					str:




         """simple docstring"""

         lowercase__  =	[char for char in text.upper() if char in self.key_string]

         lowercase__  =	chars[-1]
         while len(lowerCAmelCase) % self.break_key != 0:
               chars.append(lowerCAmelCase)

         return "".join(lowerCAmelCase)


   def       UpperCAmelCase		(    self	:      str      ,					lowerCAmelCase	:      str)						->					str:




         """simple docstring"""

         lowercase__  =	self.process_text(text.upper())
         lowercase__  =	''

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

         return encrypted


   def       UpperCAmelCase		(    self	:      Union[str, Any])						->					numpy.ndarray:




         """simple docstring"""

         lowercase__  =	round(numpy.linalg.det(self.encrypt_key))

         if det < 0:
               lowercase__  =	det % len(self.key_string)
         lowercase__  =	None
         for i in range(len(self.key_string)):
               if (det * i) % len(self.key_string) == 1:
                     lowercase__  =	i
                     break

         lowercase__  =	(
             det_inv
             * numpy.linalg.det(self.encrypt_key)
             * numpy.linalg.inv(self.encrypt_key)
         )

         return self.to_int(self.modulus(lowerCAmelCase))



   def       UpperCAmelCase		(    self	:      Union[str, Any]      ,					lowerCAmelCase	:      str)						->					str:




         """simple docstring"""

         lowercase__  =	self.make_decrypt_key()
         lowercase__  =	self.process_text(text.upper())
         lowercase__  =	''

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

         return decrypted

def 	_lowerCAmelCase (    ):
      lowercase__  =	int(input('Enter the order of the encryption key: '						)						)
      lowercase__  =	[]

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

      lowercase__  =	HillCipher(numpy.array(A__						)						)

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


if __name__ == "__main__":
       import doctest

       doctest.testmod()

       main()





from math import sqrt

def 	_lowerCAmelCase (    A__						):
      assert isinstance(A__    ,	A__						) and (
          number >= 0
      ), "'number' must been an int and positive"

      lowercase__  =	True

      # 0 and 1 are none primes.
      if number <= 1:
            lowercase__  =	False

      for divisor in range(2    ,	int(round(sqrt(A__						)						)						) + 1						):
            # if 'number' divisible by 'divisor' then sets 'status'
            # of false and break up the loop.
            if number % divisor == 0:
                  lowercase__  =	False
                  break

    # precondition
      assert isinstance(A__    ,	A__						), "'status' must been from type bool"

      return status

def 	_lowerCAmelCase (    A__						):
      assert isinstance(A__    ,	A__						) and (n > 2), "'N' must been an int and > 2"

      # beginList: contains all natural numbers from 2 up to N
      lowercase__  =	list(range(2    ,	n + 1						)						)

      lowercase__  =	[]  # this list will be returns.

      # actual sieve of erathostenes
      for i in range(len(A__						)						):
            for j in range(i + 1    ,	len(A__						)						):
                  if (begin_list[i] != 0) and (begin_list[j] % begin_list[i] == 0):
                        lowercase__  =	0

    # filters actual prime numbers.
      lowercase__  =	[x for x in begin_list if x != 0]

      # precondition
      assert isinstance(A__    ,	A__						), "'ans' must been from type list"

      return ans

def 	_lowerCAmelCase (    A__						):
      assert isinstance(A__    ,	A__						) and (n > 2), "'N' must been an int and > 2"

      lowercase__  =	[]

      # iterates over all numbers between 2 up to N+1
      # if a number is prime then appends to list 'ans'
      for number in range(2    ,	n + 1						):
            if is_prime(A__						):
                  ans.append(A__						)

    # precondition
      assert isinstance(A__    ,	A__						), "'ans' must been from type list"

      return ans

def 	_lowerCAmelCase (    A__						):
      assert isinstance(A__    ,	A__						) and number >= 0, "'number' must been an int and >= 0"

      lowercase__  =	[]  # this list will be returns of the function.

      # potential prime number factors.

      lowercase__  =	2

      lowercase__  =	number

      if number == 0 or number == 1:
            ans.append(A__						)

      # if 'number' not prime then builds the prime factorization of 'number'
      elif not is_prime(A__						):
            while quotient != 1:
                  if is_prime(A__						) and (quotient % factor == 0):
                        ans.append(A__						)
                        quotient /= factor
                  else:
                        factor += 1

      else:
            ans.append(A__						)

      # precondition
      assert isinstance(A__    ,	A__						), "'ans' must been from type list"

      return ans

def 	_lowerCAmelCase (    A__						):
      assert isinstance(A__    ,	A__						) and (
          number >= 0
      ), "'number' bust been an int and >= 0"

      lowercase__  =	0

      # prime factorization of 'number'
      lowercase__  =	prime_factorization(A__						)

      lowercase__  =	max(A__						)

      # precondition
      assert isinstance(A__    ,	A__						), "'ans' must been from type int"

      return ans

def 	_lowerCAmelCase (    A__						):
      assert isinstance(A__    ,	A__						) and (
          number >= 0
      ), "'number' bust been an int and >= 0"

      lowercase__  =	0

      # prime factorization of 'number'
      lowercase__  =	prime_factorization(A__						)

      lowercase__  =	min(A__						)

      # precondition
      assert isinstance(A__    ,	A__						), "'ans' must been from type int"

      return ans

def 	_lowerCAmelCase (    A__						):
      assert isinstance(A__    ,	A__						), "'number' must been an int"
      assert isinstance(number % 2 == 0    ,	A__						), "compare bust been from type bool"

      return number % 2 == 0

def 	_lowerCAmelCase (    A__						):
      assert isinstance(A__    ,	A__						), "'number' must been an int"
      assert isinstance(number % 2 != 0    ,	A__						), "compare bust been from type bool"

      return number % 2 != 0

def 	_lowerCAmelCase (    A__						):
      assert (
          isinstance(A__    ,	A__						) and (number > 2) and is_even(A__						)
      ), "'number' must been an int, even and > 2"

      lowercase__  =	[]  # this list will returned

      # creates a list of prime numbers between 2 up to 'number'
      lowercase__  =	get_prime_numbers(A__						)
      lowercase__  =	len(A__						)

      # run variable for while-loops.
      lowercase__  =	0
      lowercase__  =	None

      # exit variable. for break up the loops
      lowercase__  =	True

      while i < len_pn and loop:
            lowercase__  =	i + 1

            while j < len_pn and loop:
                  if prime_numbers[i] + prime_numbers[j] == number:
                        lowercase__  =	False
                        ans.append(prime_numbers[i]						)
                        ans.append(prime_numbers[j]						)

                  j += 1

            i += 1

      # precondition
      assert (
          isinstance(A__    ,	A__						)
          and (len(A__						) == 2)
          and (ans[0] + ans[1] == number)
          and is_prime(ans[0]						)
          and is_prime(ans[1]						)
      ), "'ans' must contains two primes. And sum of elements must been eq 'number'"

      return ans

def 	_lowerCAmelCase (    A__    ,	A__						):
      assert (
          isinstance(A__    ,	A__						)
          and isinstance(A__    ,	A__						)
          and (numbera >= 0)
          and (numbera >= 0)
      ), "'number1' and 'number2' must been positive integer."

      lowercase__  =	0

      while numbera != 0:
            lowercase__  =	numbera % numbera
            lowercase__  =	numbera
            lowercase__  =	rest

      # precondition
      assert isinstance(A__    ,	A__						) and (
          numbera >= 0
      ), "'number' must been from type int and positive"

      return numbera

def 	_lowerCAmelCase (    A__    ,	A__						):
      assert (
          isinstance(A__    ,	A__						)
          and isinstance(A__    ,	A__						)
          and (numbera >= 1)
          and (numbera >= 1)
      ), "'number1' and 'number2' must been positive integer."

      lowercase__  =	1  # actual answer that will be return.

      # for kgV (x,1)
      if numbera > 1 and numbera > 1:
            # builds the prime factorization of 'number1' and 'number2'
            lowercase__  =	prime_factorization(A__						)
            lowercase__  =	prime_factorization(A__						)

      elif numbera == 1 or numbera == 1:
            lowercase__  =	[]
            lowercase__  =	[]
            lowercase__  =	max(A__    ,	A__						)

      lowercase__  =	0
      lowercase__  =	0

      lowercase__  =	[]  # captured numbers int both 'primeFac1' and 'primeFac2'

      # iterates through primeFac1
      for n in prime_fac_a:
            if n not in done:
                  if n in prime_fac_a:
                        lowercase__  =	prime_fac_a.count(A__						)
                        lowercase__  =	prime_fac_a.count(A__						)

                        for _ in range(max(A__    ,	A__						)						):
                              ans *= n

                  else:
                        lowercase__  =	prime_fac_a.count(A__						)

                        for _ in range(A__						):
                              ans *= n

                  done.append(A__						)

    # iterates through primeFac2
      for n in prime_fac_a:
            if n not in done:
                  lowercase__  =	prime_fac_a.count(A__						)

                  for _ in range(A__						):
                        ans *= n

                  done.append(A__						)

    # precondition
      assert isinstance(A__    ,	A__						) and (
          ans >= 0
      ), "'ans' must been from type int and positive"

      return ans

def 	_lowerCAmelCase (    A__						):
      assert isinstance(A__    ,	A__						) and (n >= 0), "'number' must been a positive int"

      lowercase__  =	0
      lowercase__  =	2  # this variable holds the answer

      while index < n:
            index += 1

            ans += 1  # counts to the next number

            # if ans not prime then
            # runs to the next prime number.
            while not is_prime(A__						):
                  ans += 1

    # precondition
      assert isinstance(A__    ,	A__						) and is_prime(
          A__						), "'ans' must been a prime number and from type int"

      return ans

def 	_lowerCAmelCase (    A__    ,	A__						):
      assert (
          is_prime(A__						) and is_prime(A__						) and (p_number_a < p_number_a)
      ), "The arguments must been prime numbers and 'pNumber1' < 'pNumber2'"

      lowercase__  =	p_number_a + 1  # jump to the next number

      lowercase__  =	[]  # this list will be returns.

      # if number is not prime then
      # fetch the next prime number.
      while not is_prime(A__						):
            number += 1

      while number < p_number_a:
            ans.append(A__						)

            number += 1

            # fetch the next prime number.
            while not is_prime(A__						):
                  number += 1

    # precondition
      assert (
          isinstance(A__    ,	A__						)
          and ans[0] != p_number_a
          and ans[len(A__						) - 1] != p_number_a
      ), "'ans' must been a list without the arguments"

      # 'ans' contains not 'pNumber1' and 'pNumber2' !
      return ans

def 	_lowerCAmelCase (    A__						):
      assert isinstance(A__    ,	A__						) and (n >= 1), "'n' must been int and >= 1"

      lowercase__  =	[]  # will be returned.

      for divisor in range(1    ,	n + 1						):
            if n % divisor == 0:
                  ans.append(A__						)

    # precondition
      assert ans[0] == 1 and ans[len(A__						) - 1] == n, "Error in function getDivisiors(...)"

      return ans

def 	_lowerCAmelCase (    A__						):
      assert isinstance(A__    ,	A__						) and (
          number > 1
      ), "'number' must been an int and >= 1"

      lowercase__  =	get_divisors(A__						)

      # precondition
      assert (
          isinstance(A__    ,	A__						)
          and (divisors[0] == 1)
          and (divisors[len(A__						) - 1] == number)
      ), "Error in help-function getDivisiors(...)"

      # summed all divisors up to 'number' (exclusive), hence [:-1]
      return sum(divisors[:-1]						) == number

def 	_lowerCAmelCase (    A__    ,	A__						):
      assert (
          isinstance(A__    ,	A__						)
          and isinstance(A__    ,	A__						)
          and (denominator != 0)
      ), "The arguments must been from type int and 'denominator' != 0"

      # build the greatest common divisor of numerator and denominator.
      lowercase__  =	gcd(abs(A__						)    ,	abs(A__						)						)

      # precondition
      assert (
          isinstance(A__    ,	A__						)
          and (numerator % gcd_of_fraction == 0)
          and (denominator % gcd_of_fraction == 0)
      ), "Error in function gcd(...,...)"

      return (numerator // gcd_of_fraction, denominator // gcd_of_fraction)

def 	_lowerCAmelCase (    A__						):
      assert isinstance(A__    ,	A__						) and (n >= 0), "'n' must been a int and >= 0"

      lowercase__  =	1  # this will be return.

      for factor in range(1    ,	n + 1						):
            ans *= factor

      return ans

def 	_lowerCAmelCase (    A__						):
      assert isinstance(A__    ,	A__						) and (n >= 0), "'n' must been an int and >= 0"

      lowercase__  =	0
      lowercase__  =	1
      lowercase__  =	1  # this will be return

      for _ in range(n - 1						):
            lowercase__  =	ans
            ans += fiba
            lowercase__  =	tmp

      return ans
