






import gc
import threading
import time

import psutil
import torch


class    __lowercase   :







     '''simple docstring'''




     def __init__(					self							:      Dict					):


         """simple docstring"""



         __A       =						psutil.Process()
         __A       =						False




     def 		lowerCAmelCase_  (					self							:      List[str]					):


         """simple docstring"""



         __A       =						-1

         while True:
             __A       =						max(self.process.memory_info().rss			,						self.cpu_memory_peak					)

             # can't sleep or will not catch the peak right (this comment is here on purpose)
             if not self.peak_monitoring:
                 break




     def 		lowerCAmelCase_  (					self							:      Union[str, Any]					):


         """simple docstring"""



         __A       =						True
         __A       =						threading.Thread(target=self.peak_monitor					)
         __A       =						True
         self.thread.start()





     def 		lowerCAmelCase_  (					self							:      Union[str, Any]					):


         """simple docstring"""



         __A       =						False
         self.thread.join()
         return self.cpu_memory_peak
__a   :							Optional[int]						= PeakCPUMemory()



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





    """simple docstring"""

    __A       =						{"""time""": time.time()}

    gc.collect()
    torch.cuda.empty_cache()

    # CPU mem
    __A       =						psutil.Process().memory_info().rss
    cpu_peak_tracker.start()

    # GPU mem
    for i in range(torch.cuda.device_count()     ):
        __A       =						torch.cuda.memory_allocated(__lowercase     )
    torch.cuda.reset_peak_memory_stats()

    return measures



def       _SCREAMING_SNAKE_CASE    (			__lowercase :      List[Any]     )    ->   Optional[Any]:





    """simple docstring"""

    __A       =						{"""time""": time.time() - start_measures["""time"""]}

    gc.collect()
    torch.cuda.empty_cache()

    # CPU mem
    __A       =						(psutil.Process().memory_info().rss - start_measures["""cpu"""]) / 2**2_0
    __A       =						(cpu_peak_tracker.stop() - start_measures["""cpu"""]) / 2**2_0

    # GPU mem
    for i in range(torch.cuda.device_count()     ):
        __A       =						(torch.cuda.memory_allocated(__lowercase     ) - start_measures[str(__lowercase     )]) / 2**2_0
        __A       =						(torch.cuda.max_memory_allocated(__lowercase     ) - start_measures[str(__lowercase     )]) / 2**2_0

    return measures






def       _SCREAMING_SNAKE_CASE    (			__lowercase :      Dict      ,					__lowercase :      int     )    ->   Any:





    """simple docstring"""

    print(f"{description}:"     )
    print(f"- Time: {measures['time']:.2f}s"     )
    for i in range(torch.cuda.device_count()     ):
        print(f"- GPU {i} allocated: {measures[str(__lowercase     )]:.2f}MiB"     )
        __A       =						measures[f"{i}-peak"]
        print(f"- GPU {i} peak: {peak:.2f}MiB"     )
    print(f"- CPU RAM allocated: {measures['cpu']:.2f}MiB"     )
    print(f"- CPU RAM peak: {measures['cpu-peak']:.2f}MiB"     )












def       _SCREAMING_SNAKE_CASE    (			__lowercase :      str     )    ->   str:





    """simple docstring"""

    __A       =						""""""
    for ch in key:
        if ch == " " or ch not in key_no_dups and ch.isalpha():
            key_no_dups += ch
    return key_no_dups



def       _SCREAMING_SNAKE_CASE    (			__lowercase :      str     )    ->   dict[str, str]:





    """simple docstring"""

    __A       =						[chr(i + 6_5     ) for i in range(2_6     )]
    # Remove duplicate characters from key
    __A       =						remove_duplicates(key.upper()     )
    __A       =						len(__lowercase     )
    # First fill cipher with key characters
    __A       =						{alphabet[i]: char for i, char in enumerate(__lowercase     )}
    # Then map remaining characters in alphabet to
    # the alphabet from the beginning
    for i in range(len(__lowercase     )      ,					2_6     ):
        __A       =						alphabet[i - offset]
        # Ensure we are not mapping letters to letters previously mapped
        while char in key:
            offset -= 1
            __A       =						alphabet[i - offset]
        __A       =						char
    return cipher_alphabet



def       _SCREAMING_SNAKE_CASE    (			__lowercase :      str      ,					__lowercase :      dict[str, str]     )    ->   str:





    """simple docstring"""

    return "".join(cipher_map.get(__lowercase      ,					__lowercase     ) for ch in message.upper()     )



def       _SCREAMING_SNAKE_CASE    (			__lowercase :      str      ,					__lowercase :      dict[str, str]     )    ->   str:





    """simple docstring"""

    __A       =						{v: k for k, v in cipher_map.items()}
    return "".join(rev_cipher_map.get(__lowercase      ,					__lowercase     ) for ch in message.upper()     )



def       _SCREAMING_SNAKE_CASE    (			)    ->   None:





    """simple docstring"""

    __A       =						input("""Enter message to encode or decode: """     ).strip()
    __A       =						input("""Enter keyword: """     ).strip()
    __A       =						input("""Encipher or decipher? E/D:"""     ).strip()[0].lower()
    try:
        __A       =						{"""e""": encipher, """d""": decipher}[option]
    except KeyError:
        raise KeyError("""invalid input option"""     )
    __A       =						create_cipher_map(__lowercase     )
    print(func(__lowercase      ,					__lowercase     )     )


if __name__ == "__main__":
  import doctest

  doctest.testmod()
  main()




