code: def convex_hull(points):
      
  
      def is_not_clockwise(p0, p1, p2):
          return 0 <= (
              (p1[0] - p0[0]) * (p2[1] - p0[1]) -
              (p1[1] - p0[1]) * (p2[0] - p0[0])
          )
  
      def go(points_):
          res = []
          for p in points_:
              while 1 < len(res) and is_not_clockwise(res[-2], res[-1], p):
                  res.pop()
              res.append(p)
  
          # The last point in each list is the first point in the other list
          res.pop()
  
          return res
  
      # Discard duplicates and sort by x then y
      points = sorted(set(points))
  
      # Algorithm needs at least two points
      hull = (
          points if len(points) < 2 else chain(go(points), go(reversed(points)))
      )
  
      return list(map(Point._make, hull))
docs: Computes the convex hull of an iterable of (x, y) coordinates.
  
      Args:
          points: iterable of (x, y) tuples.
  
      Returns:
          `list`: instances of `Point` - vertices of the convex hull in
          counter-clockwise order, starting from the vertex with the
          lexicographically smallest coordinates.
  
      Andrew's monotone chain algorithm. O(n log n) complexity.
      https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain