from collections.abc import Iterable from itertools import chain, combinations def clamp(n: int, min: int, max: int) -> int: if n < min: return min elif n > max: return max return n def clamp_max(n: int, max: int) -> int: return max if n > max else n def clamp_min(n: int, max: int) -> int: return min if n < min else n def digits(n: int) -> int: return len(str(n)) # NOTE: assumes A and B are equal length def xor_bytes(A: bytes, B: bytes) -> bytes: return b''.join([(a ^ b).to_bytes() for (a, b) in zip(A, B)]) def xor_str(A: str, B: str) -> str: return ''.join([chr(ord(a) ^ ord(b)) for (a, b) in zip(A, B)]) def powerset(iterable: Iterable) -> Iterable: s = list(iterable) return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))