def all(iterable):
    for i in iterable:
        if not i:
            return False
    return True

def any(iterable):
    for i in iterable:
        if i:
            return True
    return False

def enumerate(iterable, start=0):
    n = start
    for elem in iterable:
        yield n, elem
        n += 1

def __minmax_reduce(op, args):
    if len(args) == 2:  # min(1, 2)
        return args[0] if op(args[0], args[1]) else args[1]
    if len(args) == 0:  # min()
        raise TypeError('expected 1 arguments, got 0')
    if len(args) == 1:  # min([1, 2, 3, 4]) -> min(1, 2, 3, 4)
        args = args[0]
    args = iter(args)
    try:
        res = next(args)
    except StopIteration:
        raise ValueError('args is an empty sequence')
    while True:
        try:
            i = next(args)
        except StopIteration:
            break
        if op(i, res):
            res = i
    return res

def min(*args, key=None):
    key = key or (lambda x: x)
    return __minmax_reduce(lambda x,y: key(x)<key(y), args)

def max(*args, key=None):
    key = key or (lambda x: x)
    return __minmax_reduce(lambda x,y: key(x)>key(y), args)

def sum(iterable):
    res = 0
    for i in iterable:
        res += i
    return res

def map(f, iterable):
    for i in iterable:
        yield f(i)

def filter(f, iterable):
    for i in iterable:
        if f(i):
            yield i

def zip(a, b):
    a = iter(a)
    b = iter(b)
    while True:
        try:
            ai = next(a)
            bi = next(b)
        except StopIteration:
            break
        yield ai, bi

def reversed(iterable):
    a = list(iterable)
    a.reverse()
    return a

def sorted(iterable, key=None, reverse=False):
    a = list(iterable)
    a.sort(key=key, reverse=reverse)
    return a

##### str #####
def __format_string(self: str, *args, **kwargs) -> str:
    def tokenizeString(s: str):
        tokens = []
        L, R = 0,0
        
        mode = None
        curArg = 0
        # lookingForKword = False
        
        while(R<len(s)):
            curChar = s[R]
            nextChar = s[R+1] if R+1<len(s) else ''
            
            # Invalid case 1: stray '}' encountered, example: "ABCD EFGH {name} IJKL}", "Hello {vv}}", "HELLO {0} WORLD}"
            if curChar == '}' and nextChar != '}':
                raise ValueError("Single '}' encountered in format string")        
            
            # Valid Case 1: Escaping case, we escape "{{ or "}}" to be "{" or "}", example: "{{}}", "{{My Name is {0}}}"
            if (curChar == '{' and nextChar == '{') or (curChar == '}' and nextChar == '}'):
                
                if (L<R): # Valid Case 1.1: make sure we are not adding empty string
                    tokens.append(s[L:R]) # add the string before the escape
                
                
                tokens.append(curChar) # Valid Case 1.2: add the escape char
                L = R+2 # move the left pointer to the next char
                R = R+2 # move the right pointer to the next char
                continue
            
            # Valid Case 2: Regular command line arg case: example:  "ABCD EFGH {} IJKL", "{}", "HELLO {} WORLD"
            elif curChar == '{' and nextChar == '}':
                if mode is not None and mode != 'auto':
                    # Invalid case 2: mixing automatic and manual field specifications -- example: "ABCD EFGH {name} IJKL {}", "Hello {vv} {}", "HELLO {0} WORLD {}" 
                    raise ValueError("Cannot switch from manual field numbering to automatic field specification")
                
                mode = 'auto'
                if(L<R): # Valid Case 2.1: make sure we are not adding empty string
                    tokens.append(s[L:R]) # add the string before the special marker for the arg
                
                tokens.append("{"+str(curArg)+"}") # Valid Case 2.2: add the special marker for the arg
                curArg+=1 # increment the arg position, this will be used for referencing the arg later
                
                L = R+2 # move the left pointer to the next char
                R = R+2 # move the right pointer to the next char
                continue
            
            # Valid Case 3: Key-word arg case: example: "ABCD EFGH {name} IJKL", "Hello {vv}", "HELLO {name} WORLD"
            elif (curChar == '{'):
                
                if mode is not None and mode != 'manual':
                    # # Invalid case 2: mixing automatic and manual field specifications -- example: "ABCD EFGH {} IJKL {name}", "Hello {} {1}", "HELLO {} WORLD {name}"
                    raise ValueError("Cannot switch from automatic field specification to manual field numbering")
                
                mode = 'manual'
                
                if(L<R): # Valid case 3.1: make sure we are not adding empty string
                    tokens.append(s[L:R]) # add the string before the special marker for the arg
                
                # We look for the end of the keyword          
                kwL = R # Keyword left pointer
                kwR = R+1 # Keyword right pointer
                while(kwR<len(s) and s[kwR]!='}'):
                    if s[kwR] == '{': # Invalid case 3: stray '{' encountered, example: "ABCD EFGH {n{ame} IJKL {", "Hello {vv{}}", "HELLO {0} WOR{LD}"
                        raise ValueError("Unexpected '{' in field name")
                    kwR += 1
                
                # Valid case 3.2: We have successfully found the end of the keyword
                if kwR<len(s) and s[kwR] == '}':
                    tokens.append(s[kwL:kwR+1]) # add the special marker for the arg
                    L = kwR+1
                    R = kwR+1
                    
                # Invalid case 4: We didn't find the end of the keyword, throw error
                else:
                    raise ValueError("Expected '}' before end of string")
                continue
            
            R = R+1
        
        
        # Valid case 4: We have reached the end of the string, add the remaining string to the tokens 
        if L<R:
            tokens.append(s[L:R])
                
        # print(tokens)
        return tokens

    tokens = tokenizeString(self)
    argMap = {}
    for i, a in enumerate(args):
        argMap[str(i)] = a
    final_tokens = []
    for t in tokens:
        if t[0] == '{' and t[-1] == '}':
            key = t[1:-1]
            argMapVal = argMap.get(key, None)
            kwargsVal = kwargs.get(key, None)
                                    
            if argMapVal is None and kwargsVal is None:
                raise ValueError("No arg found for token: "+t)
            elif argMapVal is not None:
                final_tokens.append(str(argMapVal))
            else:
                final_tokens.append(str(kwargsVal))
        else:
            final_tokens.append(t)
    
    return ''.join(final_tokens)

str.format = __format_string
del __format_string


def help(obj):
    if hasattr(obj, '__func__'):
        obj = obj.__func__
    # print(obj.__signature__)
    if obj.__doc__:
        print(obj.__doc__)

def complex(real, imag=0):
    import cmath
    return cmath.complex(real, imag)


class set:
    def __init__(self, iterable=None):
        iterable = iterable or []
        self._a = {}
        self.update(iterable)

    def add(self, elem):
        self._a[elem] = None
        
    def discard(self, elem):
        self._a.pop(elem, None)

    def remove(self, elem):
        del self._a[elem]
        
    def clear(self):
        self._a.clear()

    def update(self, other):
        for elem in other:
            self.add(elem)

    def __len__(self):
        return len(self._a)
    
    def copy(self):
        return set(self._a.keys())
    
    def __and__(self, other):
        return {elem for elem in self if elem in other}

    def __sub__(self, other):
        return {elem for elem in self if elem not in other}
    
    def __or__(self, other):
        ret = self.copy()
        ret.update(other)
        return ret

    def __xor__(self, other): 
        _0 = self - other
        _1 = other - self
        return _0 | _1

    def union(self, other):
        return self | other

    def intersection(self, other):
        return self & other

    def difference(self, other):
        return self - other

    def symmetric_difference(self, other):      
        return self ^ other
    
    def __eq__(self, other):
        if not isinstance(other, set):
            return NotImplemented
        return len(self ^ other) == 0
    
    def __ne__(self, other):
        if not isinstance(other, set):
            return NotImplemented
        return len(self ^ other) != 0

    def isdisjoint(self, other):
        return len(self & other) == 0
    
    def issubset(self, other):
        return len(self - other) == 0
    
    def issuperset(self, other):
        return len(other - self) == 0

    def __contains__(self, elem):
        return elem in self._a
    
    def __repr__(self):
        if len(self) == 0:
            return 'set()'
        return '{'+ ', '.join([repr(i) for i in self._a.keys()]) + '}'
    
    def __iter__(self):
        return iter(self._a.keys())