"""simple docstring"""


import string

import numpy






def     __UpperCAmelCase					(			lowercase   ,lowercase		):







  """simple docstring"""
  return b if a == 0 else greatest_common_divisor(b % a   ,_lowerCAmelCase		)


class        a				:
    _snake_case     :  Tuple     							=							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)
    _snake_case     :  Dict     							=							numpy.vectorize(lambda lowerCAmelCase_   : x % 36   )

    _snake_case     :  Optional[int]     							=							numpy.vectorize(__UpperCAmelCase   )


    def __init__(					self	:  Tuple   ,				__lowerCAmelCase	:  numpy.ndarray					):
      _UpperCAmelCase						 =      self.modulus(_lowerCamelCase					)  # mod36 calc's on the encrypt key
      self.check_determinant()  # validate the determinant of the encryption key
      _UpperCAmelCase						 =      encrypt_key.shape[0]


    def      lowerCAmelCase_  (					self	:  Optional[Any]   ,				__lowerCAmelCase	:  str					):
      return self.key_string.index(_lowerCamelCase					)


    def      lowerCAmelCase_  (					self	:  List[str]   ,				__lowerCAmelCase	:  int					):
      return self.key_string[round(_lowerCamelCase					)]


    def      lowerCAmelCase_  (					self	:  List[str]					):
      _UpperCAmelCase						 =      round(numpy.linalg.det(self.encrypt_key					)					)

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

      _UpperCAmelCase						 =      len(self.key_string					)
      if greatest_common_divisor(_lowerCamelCase   ,				len(self.key_string					)					) != 1:
        _UpperCAmelCase						 =      (
            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      lowerCAmelCase_  (					self	:  Dict   ,				__lowerCAmelCase	:  str					):
      _UpperCAmelCase						 =      [char for char in text.upper() if char in self.key_string]

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

      return "".join(_lowerCamelCase					)


    def      lowerCAmelCase_  (					self	:  Optional[int]   ,				__lowerCAmelCase	:  str					):
      _UpperCAmelCase						 =      self.process_text(text.upper()					)
      _UpperCAmelCase						 =      """"""

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

      return encrypted


    def      lowerCAmelCase_  (					self	:  str					):
      _UpperCAmelCase						 =      round(numpy.linalg.det(self.encrypt_key					)					)

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

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

      return self.to_int(self.modulus(_lowerCamelCase					)					)


    def      lowerCAmelCase_  (					self	:  Union[str, Any]   ,				__lowerCAmelCase	:  str					):
      _UpperCAmelCase						 =      self.make_decrypt_key()
      _UpperCAmelCase						 =      self.process_text(text.upper()					)
      _UpperCAmelCase						 =      """"""

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

      return decrypted






def     __UpperCAmelCase					(			):







  """simple docstring"""
  _UpperCAmelCase						 =      int(input("""Enter the order of the encryption key: """		)		)
  _UpperCAmelCase						 =      []

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

  _UpperCAmelCase						 =      HillCipher(numpy.array(_lowerCAmelCase		)		)

  print("""Would you like to encrypt or decrypt some text? (1 or 2)"""		)
  _UpperCAmelCase						 =      input("""\n1. Encrypt\n2. Decrypt\n"""		)
  if option == "1":
    _UpperCAmelCase						 =      input("""What text would you like to encrypt?: """		)
    print("""Your encrypted text is:"""		)
    print(hc.encrypt(_lowerCAmelCase		)		)
  elif option == "2":
    _UpperCAmelCase						 =      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()

"""simple docstring"""


from abc import ABC, abstractmethod
from argparse import ArgumentParser


class        a				(		lowerCAmelCase_   ):


    @staticmethod
    @abstractmethod
    def      lowerCAmelCase_  (					__lowerCAmelCase	:  ArgumentParser					):
      raise NotImplementedError()


    @abstractmethod
    def      lowerCAmelCase_  (					self	:  int					):
      raise NotImplementedError()
