

from __future__ import annotations

from collections.abc import Callable
from typing import Generic, TypeVar

a						=TypeVar("""T""")
a						=TypeVar("""U""")






class 			A_						(			Generic[T, U]							):
							def __init__(						self						:     str  ,SCREAMING_SNAKE_CASE__						:     Tuple  ,SCREAMING_SNAKE_CASE__						:     Optional[int]):
								__lowerCamelCase							:							Optional[int]   			=					key
								__lowerCamelCase							:							Union[str, Any]   			=					val
								__lowerCamelCase							:							DoubleLinkedListNode[T, U] | None   			=					None
								__lowerCamelCase							:							DoubleLinkedListNode[T, U] | None   			=					None


							def __repr__(						self						:     int):
								return (
								    F"Node: key: {self.key}, val: {self.val}, "
								    F"has next: {bool(self.next)}, has prev: {bool(self.prev)}"
								)






class 			A_						(			Generic[T, U]							):
							def __init__(						self						:     Tuple):
								__lowerCamelCase							:							DoubleLinkedListNode[T, U]   			=					DoubleLinkedListNode(SCREAMING_SNAKE_CASE__  ,SCREAMING_SNAKE_CASE__)
								__lowerCamelCase							:							DoubleLinkedListNode[T, U]   			=					DoubleLinkedListNode(SCREAMING_SNAKE_CASE__  ,SCREAMING_SNAKE_CASE__)
								__lowerCamelCase							:							Tuple   			=					self.rear, self.head
							def __repr__(						self						:     Tuple):
								__lowerCamelCase							:							int   			=					['DoubleLinkedList']
								__lowerCamelCase							:							Optional[int]   			=					self.head
								while node.next is not None:
									rep.append(str(SCREAMING_SNAKE_CASE__))
									__lowerCamelCase							:							int   			=					node.next
								rep.append(str(self.rear))
								return ",\n    ".join(SCREAMING_SNAKE_CASE__)
							def        lowerCAmelCase	(						self						:     Any  ,SCREAMING_SNAKE_CASE__						:     Optional[Any]):
								__lowerCamelCase							:							List[Any]   			=					self.rear.prev

								# All nodes other than self.head are guaranteed to have non-None previous
								assert previous is not None

								__lowerCamelCase							:							Union[str, Any]   			=					node
								__lowerCamelCase							:							Dict   			=					previous
								__lowerCamelCase							:							Union[str, Any]   			=					node
								__lowerCamelCase							:							Union[str, Any]   			=					self.rear


							def        lowerCAmelCase	(						self						:     Optional[int]  ,SCREAMING_SNAKE_CASE__						:     Dict):

								if node.prev is None or node.next is None:
									return None

								__lowerCamelCase							:							Union[str, Any]   			=					node.next
								__lowerCamelCase							:							Union[str, Any]   			=					node.prev
								__lowerCamelCase							:							Tuple   			=					None
								__lowerCamelCase							:							int   			=					None
								return node






class 			A_						(			Generic[T, U]							):
							_UpperCAmelCase       :    dict[Callable[[T], U], LRUCache[T, U]]		 = {}
							def __init__(						self						:     List[str]  ,SCREAMING_SNAKE_CASE__						:     List[str]):
								__lowerCamelCase							:							DoubleLinkedList[T, U]   			=					DoubleLinkedList()
								__lowerCamelCase							:							Optional[Any]   			=					capacity
								__lowerCamelCase							:							Optional[Any]   			=					0
								__lowerCamelCase							:							str   			=					0
								__lowerCamelCase							:							Optional[Any]   			=					0
								__lowerCamelCase							:							dict[T, DoubleLinkedListNode[T, U]]   			=					{}
							def __repr__(						self						:     int):
								return (
								    F"CacheInfo(hits={self.hits}, misses={self.miss}, "
								    F"capacity={self.capacity}, current size={self.num_keys})"
								)
							def __contains__(						self						:     List[str]  ,SCREAMING_SNAKE_CASE__						:     Optional[int]):
								return key in self.cache
							def        lowerCAmelCase	(						self						:     Dict  ,SCREAMING_SNAKE_CASE__						:     str):

								if key in self.cache:
									self.hits += 1
									__lowerCamelCase							:							DoubleLinkedListNode[T, U]   			=					self.cache[key]
									__lowerCamelCase							:							List[Any]   			=					self.list.remove(self.cache[key])
									assert node == value_node

									# node is guaranteed not None because it is in self.cache
									assert node is not None
									self.list.add(SCREAMING_SNAKE_CASE__)
									return node.val
								self.miss += 1
								return None
							def        lowerCAmelCase	(						self						:     List[Any]  ,SCREAMING_SNAKE_CASE__						:     Dict  ,SCREAMING_SNAKE_CASE__						:     Dict):

								if key not in self.cache:
									if self.num_keys >= self.capacity:
										# delete first node (oldest) when over capacity
										__lowerCamelCase							:							List[str]   			=					self.list.head.next

										# guaranteed to have a non-None first node when num_keys > 0
										# explain to type checker via assertions
										assert first_node is not None
										assert first_node.key is not None
										assert (
										    self.list.remove(SCREAMING_SNAKE_CASE__) is not None
										)  # node guaranteed to be in list assert node.key is not None

										del self.cache[first_node.key]
										self.num_keys -= 1
									__lowerCamelCase							:							Union[str, Any]   			=					DoubleLinkedListNode(SCREAMING_SNAKE_CASE__  ,SCREAMING_SNAKE_CASE__)
									self.list.add(self.cache[key])
									self.num_keys += 1

								else:
									# bump node to the end of the list, update value
									__lowerCamelCase							:							int   			=					self.list.remove(self.cache[key])
									assert node is not None  # node guaranteed to be in list
									__lowerCamelCase							:							str   			=					value
									self.list.add(SCREAMING_SNAKE_CASE__)


							@classmethod
							def        lowerCAmelCase	(						cls						:     List[Any]  ,SCREAMING_SNAKE_CASE__						:     Union[str, Any] = 1_2_8):

								def cache_decorator_inner(SCREAMING_SNAKE_CASE__						:     Tuple) -> Callable[..., U]:
									def cache_decorator_wrapper(*SCREAMING_SNAKE_CASE__						:     str) -> U:
										if func not in cls.decorator_function_to_instance_map:
											__lowerCamelCase							:							int   			=					LRUCache(SCREAMING_SNAKE_CASE__)

										__lowerCamelCase							:							Optional[int]   			=					cls.decorator_function_to_instance_map[func].get(args[0])
										if result is None:
											__lowerCamelCase							:							List[Any]   			=					func(*SCREAMING_SNAKE_CASE__)
											cls.decorator_function_to_instance_map[func].put(args[0]  ,SCREAMING_SNAKE_CASE__)
										return result

									def cache_info() -> LRUCache[T, U]:
										return cls.decorator_function_to_instance_map[func]

									setattr(SCREAMING_SNAKE_CASE__  ,'cache_info'  ,SCREAMING_SNAKE_CASE__)  # noqa: B010

									return cache_decorator_wrapper

								return cache_decorator_inner


if __name__ == "__main__":
					import doctest

					doctest.testmod()








from maths.prime_factors import prime_factors



def 							UpperCamelCase_( lowerCamelCase_					)       ->		int:
    if not isinstance(lowerCamelCase_				,					lowerCamelCase_					):
        _lowercase			:				str 						=						F'''Input value of [number={number}] must be an integer'''
        raise TypeError(lowerCamelCase_					)
    if number < 1:
        raise ValueError('Input must be a positive integer'					)
    return -1 if len(prime_factors(lowerCamelCase_					)					) % 2 else 1


if __name__ == "__main__":
 import doctest

 doctest.testmod()


