





from __future__ import annotations

from collections import deque
from enum import Enum
from math import atana, degrees
from sys import maxsize

class 		__a							(	__UpperCamelCase      ):
       __snake_case						:   Union[str, Any]      =		1
       __snake_case						:   List[Any]      =		2
       __snake_case						:   Union[str, Any]      =		3



       def __repr__(     self	:   Optional[Any]			):
           return F'{self.__class__.__name__}.{self.name}'






def 			__UpperCamelCase				(			lowercase__	:       tuple[int, int]		,    lowercase__	:       int		,    lowercase__	:       int		)	->      float:
    '''simple docstring'''





    lowerCAmelCase_		,		lowerCAmelCase_					:	str						=   point
    return degrees(atana(y - miny		,    x - minx		)		)
def 			__UpperCamelCase				(			lowercase__	:       tuple[int, int]		,    lowercase__	:       tuple[int, int]		,    lowercase__	:       tuple[int, int]		)	->      Direction:
    '''simple docstring'''





    lowerCAmelCase_		,		lowerCAmelCase_					:	Dict						=   starting
    lowerCAmelCase_		,		lowerCAmelCase_					:	Dict						=   via
    lowerCAmelCase_		,		lowerCAmelCase_					:	int						=   target
    lowerCAmelCase_					:	Tuple						=   degrees(atana(ya - ya		,    xa - xa		)		)
    via_angle %= 360
    lowerCAmelCase_					:	Optional[int]						=   degrees(atana(ya - ya		,    xa - xa		)		)
    target_angle %= 360
    # t-
    #  \ \
    #   \ v
    #    \|
    #     s
    # via_angle is always lower than target_angle, if direction is left.
    # If they are same, it means they are on a same line of convex hull.
    if target_angle > via_angle:
        return Direction.left
    elif target_angle == via_angle:
        return Direction.straight
    else:
        return Direction.right

def 			__UpperCamelCase				(			lowercase__	:       list[tuple[int, int]]		)	->      list[tuple[int, int]]:
    '''simple docstring'''





    if len(lowercase__		) <= 2:
        # There is no convex hull
        raise ValueError("""graham_scan: argument must contain more than 3 points."""		)
    if len(lowercase__		) == 3:
        return points
    # find the lowest and the most left point
    lowerCAmelCase_					:	str						=   0
    lowerCAmelCase_		,		lowerCAmelCase_					:	List[Any]						=   maxsize, maxsize
    for i, point in enumerate(lowercase__		):
        lowerCAmelCase_					:	Optional[int]						=   point[0]
        lowerCAmelCase_					:	Dict						=   point[1]
        if y < miny:
            lowerCAmelCase_					:	List[Any]						=   y
            lowerCAmelCase_					:	Tuple						=   x
            lowerCAmelCase_					:	Dict						=   i
        if y == miny and x < minx:
            lowerCAmelCase_					:	List[Any]						=   x
            lowerCAmelCase_					:	Dict						=   i

    # remove the lowest and the most left point from points for preparing for sort
    points.pop(lowercase__		)

    lowerCAmelCase_					:	List[str]						=   sorted(lowercase__		,    key=lambda lowercase__		: angle_comparer(lowercase__		,    lowercase__		,    lowercase__		)		)
    # This insert actually costs complexity,
    # and you should instead add (minx, miny) into stack later.
    # I'm using insert just for easy understanding.
    sorted_points.insert(0		,    (minx, miny)		)

    lowerCAmelCase_					:	deque[tuple[int, int]]						=   deque()
    stack.append(sorted_points[0]		)
    stack.append(sorted_points[1]		)
    stack.append(sorted_points[2]		)
    # In any ways, the first 3 points line are towards left.
    # Because we sort them the angle from minx, miny.
    lowerCAmelCase_					:	int						=   Direction.left

    for i in range(3		,    len(lowercase__		)		):
        while True:
            lowerCAmelCase_					:	Optional[int]						=   stack[-2]
            lowerCAmelCase_					:	List[Any]						=   stack[-1]
            lowerCAmelCase_					:	Any						=   sorted_points[i]
            lowerCAmelCase_					:	List[Any]						=   check_direction(lowercase__		,    lowercase__		,    lowercase__		)

            if next_direction == Direction.left:
                lowerCAmelCase_					:	List[Any]						=   Direction.left
                break
            if next_direction == Direction.straight:
                if current_direction == Direction.left:
                    # We keep current_direction as left.
                    # Because if the straight line keeps as straight,
                    # we want to know if this straight line is towards left.
                    break
                elif current_direction == Direction.right:
                    # If the straight line is towards right,
                    # every previous points on those straigh line is not convex hull.
                    stack.pop()
            if next_direction == Direction.right:
                stack.pop()
        stack.append(sorted_points[i]		)
    return list(lowercase__		)









def 			__UpperCamelCase				(			lowercase__	:       set		,    lowercase__	:       set		)	->      set:
    '''simple docstring'''





    assert isinstance(lowercase__		,    lowercase__		), f'The input value of [set_a={set_a}] is not a set'
    assert isinstance(lowercase__		,    lowercase__		), f'The input value of [set_b={set_b}] is not a set'

    return {a + b for a in set_a for b in set_b}


if __name__ == "__main__":
  from doctest import testmod

  testmod()


