






import gc
import threading
import time

import psutil
import torch



class 							_UpperCamelCase			:


      def __init__(	self	)->	Union[str, Any]:
           __lowerCAmelCase								=					psutil.Process()
           __lowerCAmelCase								=					False


      def  __UpperCAmelCase		(	self	)->	Tuple:
           __lowerCAmelCase								=					-1

           while True:
                __lowerCAmelCase								=					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  __UpperCAmelCase		(	self	)->	int:
           __lowerCAmelCase								=					True
           __lowerCAmelCase								=					threading.Thread(target=self.peak_monitor	)
           __lowerCAmelCase								=					True
           self.thread.start()


      def  __UpperCAmelCase		(	self	)->	Optional[Any]:
           __lowerCAmelCase								=					False
           self.thread.join()
           return self.cpu_memory_peak

lowerCamelCase			:					Tuple         =	PeakCPUMemory()





def       __lowerCAmelCase      (						):
     # Time
     __lowerCAmelCase								=					{"time": time.time()}

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

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

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

     return measures





def       __lowerCAmelCase      (						__snake_case       ):
     # Time
     __lowerCAmelCase								=					{"time": time.time() - start_measures["time"]}

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

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

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

     return measures





def       __lowerCAmelCase      (						__snake_case					, __snake_case       ):
     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(__snake_case       )]:.2f}MiB"""       )
          __lowerCAmelCase								=					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"""       )














import random



class 							_UpperCamelCase			:


      @staticmethod
      def  __UpperCAmelCase		(	__UpperCamelCase	)->	tuple[list[int], list[int]]:
           __lowerCAmelCase								=					[ord(__UpperCamelCase	) for i in text]
           __lowerCAmelCase								=					[]
           __lowerCAmelCase								=					[]
           for i in plain:
                __lowerCAmelCase								=					random.randint(1					,						3_0_0	)
                __lowerCAmelCase								=					(i + k) * k
                cipher.append(__UpperCamelCase	)
                key.append(__UpperCamelCase	)
           return cipher, key


      @staticmethod
      def  __UpperCAmelCase		(	__UpperCamelCase					,						__UpperCamelCase	)->	str:
           __lowerCAmelCase								=					[]
           for i in range(len(__UpperCamelCase	)	):
                __lowerCAmelCase								=					int((cipher[i] - (key[i]) ** 2) / key[i]	)
                plain.append(chr(__UpperCamelCase	)	)
           return "".join(__UpperCamelCase	)


if __name__ == "__main__":
 lowerCamelCase      ,					lowerCamelCase			:					List[Any]         =	Onepad().encrypt('''Hello''')
 print(c, k)
 print(Onepad().decrypt(c, k))






