text: """
  A simple   Line   class.
  NOTE: This is NOT rosegraphics -- it is your OWN Line class.
  
  Authors: David Mutchler, Vibha Alangar, Dave Fisher, Amanda Stouder,
           their colleagues and Shamus Sparling.
  """  # done: 1. PUT YOUR NAME IN THE ABOVE LINE.
  
  import math
  import m1t_test_Line as m1t
  
  ########################################################################
  # IMPORTANT:
  #   Your instructor will help you get started on this exercise.
  ########################################################################
  
  # ----------------------------------------------------------------------
  # done: 2. With your instructor, READ THE INSTRUCTIONS
  #   in file  m0_INSTRUCTIONS.txt, asking questions as needed.
  #   Once you understand the instructions, mark this TO DO as DONE.
  #
  # Also go ahead and mark the src as a Sources Root (right click src folder
  #   Mark Directory as --> Sources Root.  Expand the imports above
  #   and notice the red line go away from the m1t_test_Line module.
  #   This step is not critically important this time, but still good to do.
  # ----------------------------------------------------------------------
  
  ########################################################################
  # NOTE: For ALL of the methods that you implement, the method is allowed
  # to have additional side effects as needed by it and/or other methods.
  ########################################################################
  
  
  def main():
      """
      Calls the   TEST   functions in this module, but ONLY if the method
      to be tested has at least a partial implementation.  That is,
      a  TEST   function will not be called until you begin work
      on the code that it is testing.
      """
      if m1t.is_implemented('__init__'):
          run_test_init()
      if m1t.is_implemented('clone'):
          run_test_clone()
      if m1t.is_implemented('reverse'):
          run_test_reverse()
      if m1t.is_implemented('slope'):
          run_test_slope()
      if m1t.is_implemented('length'):
          run_test_length()
      if m1t.is_implemented('get_number_of_clones'):
          run_test_get_number_of_clones()
      if m1t.is_implemented('line_plus'):
          run_test_line_plus()
      if m1t.is_implemented('line_minus'):
          run_test_line_minus()
      if m1t.is_implemented('midpoint'):
          run_test_midpoint()
      if m1t.is_implemented('is_parallel'):
          run_test_is_parallel()
      if m1t.is_implemented('reset'):
          run_test_reset()
  
  ########################################################################
  # Students:
  #   Do NOT touch the following  Point  class - it has no TO DO.
  #   Do NOT copy code from the methods in this Point class.
  #
  #   DO  ** READ **  this Point class,
  #     asking questions about any of it that you do not understand.
  #
  #   DO  ** CALL **  methods in this Point class as needed
  #     in implementing and testing the methods of the  ** Line **  class.
  #
  #   IMPORTANT, IMPORTANT, IMPORTANT:
  #     *** In your  ** Line **  class methods, you should NEVER have code
  #     *** that a  ** Point **  class method could do for you.
  ########################################################################
  # The   Point   class (and its methods) begins here.
  ########################################################################
  
  
  class Point(object):
      """ Represents a point in 2-dimensional space. """
  
      def __init__(self, x, y):
          """
          Sets instance variables  x  and  y  to the given coordinates.
          """
          self.x = x
          self.y = y
  
      def __repr__(self):
          """
          Returns a string representation of this Point.
          For each coordinate (x and y), the representation
            - uses no decimal points if the number is close to an integer,
            - else it uses decimal_places places after the decimal point, where decimal_places = 2.
          Examples:
             Point(10, 3.14)
             Point(3.01, 2.99)
          """
          decimal_places = 2  # Use 2 places after the decimal point
  
          formats = []
          numbers = []
          for coordinate in (self.x, self.y):
              if abs(coordinate - round(coordinate)) < (10 ** -decimal_places):
                  # Treat it as an integer:
                  formats.append('{}')
                  numbers.append(round(coordinate))
              else:
                  # Treat it as a float to decimal_places decimal places:
                  formats.append('{:.' + str(decimal_places) + 'f}')
                  numbers.append(round(coordinate, decimal_places))
  
          format_string = 'Point(' + formats[0] + ', ' + formats[1] + ')'
          return format_string.format(numbers[0], numbers[1])
  
      def __eq__(self, p2):
          """
          Defines == for Points:  a == b   is equivalent to  a.__eq__(b).
          Treats two numbers as "equal" if they are within 6 decimal
          places of each other for both x and y coordinates.
          """
  
          return (round(self.x, 6) == round(p2.x, 6) and
                  round(self.y, 6) == round(p2.y, 6))
  
      def clone(self):
          """  Returns a new Point at the same (x, y) as this Point. """
          return Point(self.x, self.y)
  
      def distance_from(self, p2):
          """ Returns the distance this Point is from the given Point. """
          dx_squared = (self.x - p2.x) ** 2
          dy_squared = (self.y - p2.y) ** 2
  
          return math.sqrt(dx_squared + dy_squared)
  
      def halfway_to(self, p2):
          """
          Given another Point object p2, returns a new Point
          that is half-way between this Point and the given Point (p2).
          """
          return Point((self.x + p2.x) / 2,
                       (self.y + p2.y) / 2)
  
      def plus(self, p2):
          """
          Returns a Point whose coordinates are those of this Point
          plus the given Point.  For example:
              p1 = Point(500, 20)
              p2 = Point(100, 13)
              p3 = p1.plus(p2)
              print(p3)
          would print:   Point(600, 33)
          """
          return Point(self.x + p2.x, self.y + p2.y)
  
      def minus(self, p2):
          """
          Returns a Point whose coordinates are those of this Point
          minus the given Point.  For example:
              p1 = Point(500, 20)
              p2 = Point(100, 13)
              p3 = p1.minus(p2)
              print(p3)
          would print:   Point(400, 7)
          """
          return Point(self.x - p2.x, self.y - p2.y)
  
  
  ########################################################################
  # The   Line   class (and its methods) begins here.
  ########################################################################
  class Line(object):
      """ Represents a line segment in 2-dimensional space. """
  
      def __init__(self, start, end):
          """
          What comes in:
            -- self
            -- a Point object named  start
            -- a Point object named  end
          where the two Points are to be the initial start and end points,
          respectively, of this Line.
  
          What goes out: Nothing (i.e., None).
  
          Side effects:  MUTATEs this Line by setting two instance
          variables named:
            -- start
            -- end
          to CLONES of the two Point arguments, respectively.
          Other methods must maintain those instance variables as needed
          so that they always indicate the CURRENT start and end points
          of this Line.
  
          Also, initializes other instance variables as needed
          by other Line methods.
  
          Example:  This   __init__  method runs when one constructs
          a Line.  So the 3rd of the following statements
          invokes the   __init__   method of this Line class:
              p1 = Point(30, 17)
              p2 = Point(50, 80)
              line = Line(p1, p2)        # Causes __init__ to run
  
              print(line.start)          # Should print Point(30, 17)
              print(line.end)            # Should print Point(50, 80)
              print(line.start == p1)    # Should print True
              print(line.start is p1)    # Should print False
  
          Type hints:
            :type start: Point
            :type end:   Point
          """
          # --------------------------------------------------------------
          # done: 3.
          #   a. READ the above specification, including the Example.
          #        ** ASK QUESTIONS AS NEEDED. **
          #        ** Be sure you understand it, ESPECIALLY the Example.
          #   b. Implement and test this method.
          #        The tests are already written (below).
          #        They include the Example in the above doc-string.
          # --------------------------------------------------------------
  
          self.start = start.clone()
          self.end = end.clone()
          self.clones = 0
          self.start_og = start.clone()
          self.end_og = end.clone()
  
      def __repr__(self):
          """
          What comes in:
            -- self
          What goes out: Returns a string representation of this Line,
          in the form:
             Line[(x1, y1), (x2, y2)]
          Side effects: None.
          Note:  print(BLAH)  causes BLAH's __repr__ to be called.
                 BLAH's __repr__ returns a string,
                 which the  print  function then prints.
  
          Example:  Since the  print  function calls __repr__ on the
          object to be printed:
              p1 = Point(30, 17)
              p2 = Point(50, 80)
              line = Line(p1, p2)  # Causes __init__ to run
  
              # The following statement causes __repr__ to run,
              # hence should print: Line[(30, 17), (50, 80)]
              print(line)
  
          Type hints:
            :rtype: str
          """
          # --------------------------------------------------------------
          # We have already implemented this  __repr__  function for you.
          # Do NOT modify it.
          # --------------------------------------------------------------
          start = repr(self.start).replace('Point', '')
          end = repr(self.end).replace('Point', '')
          return 'Line[{}, {}]'.format(start, end)
  
      def __eq__(self, line2):
          """
          What comes in:
            -- self
            -- a Line object
          What goes out: Returns  True  if:
               this Line's start point is equal to line2's start point AND
               this Line's end point is equal to line2's end point.
             Returns  False  otherwise.
          Side effects: None.
          Note:  a == b   is equivalent to  a.__eq__(b).
  
          Examples:
              p1 = Point(30, 17)
              p2 = Point(50, 80)
  
              line1 = Line(p1, p2)
              line2 = Line(p1, p2)
              line3 = Line(p2, p1)
  
              print(line1 == line1)   # Should print: True
              print(line1 == line2)   # Should print: True
              print(line1 == line3)   # Should print: False
  
              line1.start = Point(0, 0)
              print(line1 == line2)   # Should now print: False
  
          Type hints:
            :type  line2: Line
            :rtype: bool
          """
          # --------------------------------------------------------------
          # We have already implemented this  __eq__  function for you.
          # Do NOT modify it.
          # --------------------------------------------------------------
          return (self.start == line2.start) and (self.end == line2.end)
  
      def clone(self):
          """
          What comes in:
            -- self
          What goes out: Returns a new Line whose START is a clone of
            this Line's START and whose END is a clone of this Line's END.
          Side effects: None.
  
          Example:
              p1 = Point(30, 17)
              p2 = Point(50, 80)
              line1 = Line(p1, p2)
              line2 = line1.clone()
  
              print(line1)  # Should print: Line[(30, 17), (50, 80)]
              print(line2)  # Should print: Line[(30, 17), (50, 80)]
              print(line1 == line2)              # Should print: True
              print(line1 is line2)              # Should print: False
              print(line1.start is line2.start)  # Should print: False
              print(line1.end is line2.end)      # Should print: False
  
              line1.start = Point(11, 12)
              print(line1)  # Should print: Line[(11, 12), (50, 80)]
              print(line2)  # Should print: Line[(30, 17), (50, 80)]
              print(line1 == line2)  # Should now print: False
  
          Type hints:
            :rtype: Line
          """
          # --------------------------------------------------------------
          # done: 4.
          #   a. READ the above specification, including the Example.
          #        ** ASK QUESTIONS AS NEEDED. **
          #        ** Be sure you understand it, ESPECIALLY the Example.
          #   b. Implement and test this method.
          #        The tests are already written (below).
          #        They include the Example in the above doc-string.
          # --------------------------------------------------------------
          clone = Line(self.start, self.end)
          self.clones = self.clones + 1
          return clone
  
      def reverse(self):
          """
          What comes in:
            -- self
          What goes out: Nothing (i.e., None).
          Side effects: MUTATES this Line so that its direction is
          reversed (that is, its start and end points are swapped).
  
          Examples:
              p1 = Point(30, 17)
              p2 = Point(50, 80)
              line1 = Line(p1, p2)
              line2 = line1.clone()
  
              print(line1)  # Should print: Line[(30, 17), (50, 80)]
  
              line1.reverse()
              print(line1)  # Should print: Line[(50, 80), (30, 17)]
              print(line1 == line2)    # Should print: False
  
              line1.reverse()
              print(line1 == line2)    # Should now print: True
          """
          # --------------------------------------------------------------
          # done: 5.
          #   a. READ the above specification, including the Example.
          #        ** ASK QUESTIONS AS NEEDED. **
          #        ** Be sure you understand it, ESPECIALLY the Example.
          #   b. Implement and test this method.
          #        The tests are already written (below).
          #        They include the Example in the above doc-string.
          # --------------------------------------------------------------
          x = self.end
          y = self.start
          self.start = x
          self.end = y
          reverse = Line(self.start, self.end)
          return reverse
  
      def slope(self):
          """
          What comes in:
            -- self
          What goes out: Returns the slope of this Line.
          If the line is vertical (i.e., has "infinite" slope), returns
             math.inf
          Side effects: None.
  
          Examples:
              p1 = Point(30, 3)
              p2 = Point(50, 8)
              line1 = Line(p1, p2)
  
              # Since the slope is (8 - 3) / (50 - 30) , which is 0.25:
              print(line1.slope())    # Should print [approximately]: 0.25
  
              line2 = Line(Point(10, 10), Point(10, 5))
              print(line2.slope())    # Should print:  inf
  
              # math.inf is NOT the STRING 'inf', so:
              print(line2.slope() == 'inf')   # Should print False
  
          Type hints:
            :rtype: float
          """
          # --------------------------------------------------------------
          # done: 6.
          #   a. READ the above specification, including the Example.
          #        ** ASK QUESTIONS AS NEEDED. **
          #        ** Be sure you understand it, ESPECIALLY the Example.
          #   b. Implement and test this method.
          #        The tests are already written (below).
          #        They include the Example in the above doc-string.
          # --------------------------------------------------------------
          if (self.start.x - self.end.x) == 0:
              return math.inf
          else:
              slope = (self.start.y - self.end.y)/(self.start.x - self.end.x)
              return slope
  
      def length(self):
          """
          What comes in:
            -- self
          What goes out: Returns the length of this Line.
          Side effects: None.
  
          Example:
              p1 = Point(166, 10)
              p2 = Point(100, 10)
              line1 = Line(p1, p2)
  
              # Since the distance from p1 to p2 is 66:
              print(line1.length())  # Should print: 66.0
  
              p3 = Point(0, 0)
              p4 = Point(3, 4)
              line2 = Line(p3, p4)
              print(line2.length())  # Should print about 5.0
  
          Type hints:
            :rtype: float
          """
          # --------------------------------------------------------------
          # done: 7.
          #   a. READ the above specification, including the Example.
          #        ** ASK QUESTIONS AS NEEDED. **
          #        ** Be sure you understand it, ESPECIALLY the Example.
          #   b. Implement and test this method.
          #        The tests are already written (below).
          #        They include the Example in the above doc-string.
          # --------------------------------------------------------------
          return self.start.distance_from(self.end)
  
      def get_number_of_clones(self):
          """
          What comes in:
            -- self
          What goes out:
            -- Returns the number of times that this Line has been cloned
                 (via the   clone   method).
          Side effects: None.
  
          Example:
              line1 = Line(Point(500, 20), Point(100, 8))
              line2 = line1.clone()
              line3 = line1.clone()
              line4 = line3.clone()
              line5 = line1.clone()
              print(line1.get_number_of_clones())
              print(line2.get_number_of_clones())
              print(line3.get_number_of_clones())
              print(line4.get_number_of_clones())
              print(line5.get_number_of_clones())
          would print:
              3    [since there are three   line1.clone()  statements]
              0    [since there are no      line2.clone()  statements]
              1    [since there is one      line3.clone()  statement]
              0    [since there are no      line4.clone()  statements]
              0    [since there are no      line5.clone()  statements]
  
          Type hints:
            :rtype: int:
          """
          # --------------------------------------------------------------
          # done: 8.
          #   a. READ the above specification, including the Example.
          #        ** ASK QUESTIONS AS NEEDED. **
          #        ** Be sure you understand it, ESPECIALLY the Example.
          #   b. Implement and test this method.
          #        The tests are already written (below).
          #        They include the Example in the above doc-string.
          # --------------------------------------------------------------
          return self.clones
  
      def line_plus(self, other_line):
          """
          What comes in:
            -- self
            -- another Line object
          What goes out:
            -- Returns a Line whose:
                -- start is the sum of this Line's start (a Point)
                     and the other_line's start (another Point).
                -- end is the sum of this Line's end (a Point)
                     and the other_line's end (another Point).
          Side effects: None.
  
          Example:
              line1 = Line(Point(500, 20), Point(100, 8))
              line2 = Line(Point(100, 13), Point(400, 8))
              line3 = line1.line_plus(line2)
              print(line3)
          would print:   Line[(600, 33), (500, 16)]
  
          Type hints:
            :type  other_line: Line
            :rtype: Line:
          """
          # --------------------------------------------------------------
          # done: 9.
          #   a. READ the above specification, including the Example.
          #        ** ASK QUESTIONS AS NEEDED. **
          #        ** Be sure you understand it, ESPECIALLY the Example.
          #   b. Implement and test this method.
          #        The tests are already written (below).
          #        They include the Example in the above doc-string.
          # --------------------------------------------------------------
          return Line(self.start.plus(other_line.start), self.end.plus(other_line.end))
  
      def line_minus(self, other_line):
          """
          What comes in:
            -- self
            -- another Line object
          What goes out:
            -- Returns a Line whose:
                -- start is this Line's start (a Point)
                     minus the other_line's start (another Point).
                -- end is this Line's end (a Point)
                     minus the other_line's end (another Point).
          Side effects: None.
  
          Example:
              line1 = Line(Point(500, 20), Point(100, 8))
              line2 = Line(Point(100, 13), Point(400, 8))
              line3 = line1.line_minus(line2)
              print(line3)
          would print:   Line[(400, 7), (-300, 0)]
  
          Type hints:
            :type  other_line: Line
            :rtype: Line:
          """
          # --------------------------------------------------------------
          # done: 10.
          #   a. READ the above specification, including the Example.
          #        ** ASK QUESTIONS AS NEEDED. **
          #        ** Be sure you understand it, ESPECIALLY the Example.
          #   b. Implement and test this method.
          #        The tests are already written (below).
          #        They include the Example in the above doc-string.
          # --------------------------------------------------------------
          return Line(self.start.minus(other_line.start), self.end.minus(other_line.end))
  
      def midpoint(self):
          """
          What comes in:
            -- self
          What goes out: returns a Point at the midpoint of this Line.
          Side effects: None.
  
          Example:
              p1 = Point(3, 10)
              p2 = Point(9, 20)
              line1 = Line(p1, p2)
  
              print(line1.midpoint())  # Should print: Point(6, 15)
  
          Type hints:
            :rtype: Point
          """
          # --------------------------------------------------------------
          # done: 11.
          #   a. READ the above specification, including the Example.
          #        ** ASK QUESTIONS AS NEEDED. **
          #        ** Be sure you understand it, ESPECIALLY the Example.
          #   b. Implement and test this method.
          #        The tests are already written (below).
          #        They include the Example in the above doc-string.
          # --------------------------------------------------------------
          return self.start.halfway_to(self.end)
  
      def is_parallel(self, line2):
          """
          What comes in:
            -- self
            -- another Line object (line2)
          What goes out: Returns  True  if this Line is parallel to the
            given Line (line2).  Returns  False  otherwise.
          Side effects: None.
  
          Examples:
              line1 = Line(Point(15, 30), Point(17, 50))  # slope is 10.0
              line2 = Line(Point(10, 10), Point(15, 60))  # slope is 10.0
              line3 = Line(Point(10, 10), Point(80, 80))  # slope is  7.0
              line4 = Line(Point(10, 10), Point(10, 20))  # slope is inf
  
              print(line1.is_parallel(line2))   # Should print: True
              print(line2.is_parallel(line1))   # Should print: True
              print(line1.is_parallel(line3))   # Should print: False
              print(line1.is_parallel(line4))   # Should print: False
              print(line1.is_parallel(line1))   # Should print: True
              print(line4.is_parallel(line4))   # Should print: True
  
          Type hints:
            :type  line2: Line
            :rtype: bool
          """
          # --------------------------------------------------------------
          # done: 12.
          #   a. READ the above specification, including the Example.
          #        ** ASK QUESTIONS AS NEEDED. **
          #        ** Be sure you understand it, ESPECIALLY the Example.
          #   b. Implement and test this method.
          #        The tests are already written (below).
          #        They include the Example in the above doc-string.
          # --------------------------------------------------------------
          ################################################################
          #
          # IMPORTANT: When you test whether two FLOATING POINT numbers
          #   are "equal", you must ROUND each to (say) 12 decimal places.
          #   Otherwise, you risk the imprecision of floating-point
          #   arithmetic biting you.  For example, in REAL arithmetic,
          #         1 / (24 * math.pi - 20 * math.pi)
          #   and
          #         3 / (72 * math.pi - 60 * math.pi)
          #   are equal.  But in FLOATING point arithmetic, they are:
          #         0.07957747154594767
          #   and
          #         0.07957747154594765
          #   respectively (hence NOT equal).
          #   Try it out if you don't believe me!
          #
          # IMPORTANT BOTTOM-LINE:  When you want to test whether
          # two FLOATING POINT numbers  a  and  b  are the same,
          #   DON'T use:               a == b
          #   INSTEAD use:  round(a, 12) == round(b, 12)
          #
          # The latter compares the numbers rounded to 12 decimal places
          # which (usually) is adequate to ignore floating-point errors
          # and (usually) adequate to distinguish numbers that really
          # are different from each other.
          ################################################################
          slope1 = round(self.slope(), 12)
          slope2 = round(line2.slope(), 12)
          if slope1 == slope2:
              return True
          else:
              return False
  
      def reset(self):
          """
          What comes in:
            -- self
          What goes out: Nothing (i.e., None).
          Side effects: MUTATES this Line so that its start and end points
            revert to what they were when this Line was constructed.
  
          Examples:
              p1 = Point(-3, -4)
              p2 = Point(3, 4)
              line1 = Line(p1, p2)
              line2 = Line(Point(0, 1), Point(10, 20))
  
                ... [various actions, including some like these:]
              line1.start = Point(100, 300)
              line2.end = Point(99, 4)
              line1.reverse()
  
              # Should print: Line[(x1, y1), (x2, y2)] where (x1, y1) and
              # (x2, y2) are the CURRENT coordinates of line1's endpoints.
              print(line1)
              print(line2)  # Similarly for line2
  
              line1.reset()
              line2.reset()
              print(line1)  # Should print: Line[(-3, -4), (3, 4)]
              print(line2)  # Should print: Line[(0, 1), (10, 20)]
          """
          # --------------------------------------------------------------
          # TODO: 13.
          #   a. READ the above specification, including the Example.
          #        ** ASK QUESTIONS AS NEEDED. **
          #        ** Be sure you understand it, ESPECIALLY the Example.
          #   b. Implement and test this method.
          #        The tests are already written (below).
          #        They include the Example in the above doc-string.
          # --------------------------------------------------------------
          self.start = self.start_og
          self.end = self.end_og
  
  ########################################################################
  # The TEST functions for the  Line  class begin here.
  #
  # We have already written the TEST functions.  They all take the form:
  #   -- m1t.run_test_BLAH()  # This runs OUR tests.
  #   -- One more test (or tests) that came directly from the Example
  #        in the specification.
  ########################################################################
  
  
  def run_test_init():
      """ Tests the   __init__   method of the Line class. """
      m1t.run_test_init()  # This runs OUR tests.
      # ------------------------------------------------------------------
      # One ADDITIONAL test (or set of tests).
      # ------------------------------------------------------------------
      p1 = Point(30, 17)
      p2 = Point(50, 80)
      line = Line(p1, p2)  # Causes __init__ to run
  
      print(line.start)  # Should print Point(30, 17)
      print(line.end)  # Should print Point(50, 80)
      print(line.start == p1)  # Should print True
      print(line.start is p1)  # Should print False
  
      print('The above should print:')
      print('  Point(30, 17)')
      print('  Point(50, 80)')
      print('  True')
      print('  False')
  
  
  def run_test_clone():
      """ Tests the   clone   method of the Line class. """
      m1t.run_test_clone()  # This runs OUR tests.
      # ------------------------------------------------------------------
      # One ADDITIONAL test (or set of tests).
      # ------------------------------------------------------------------
      p1 = Point(30, 17)
      p2 = Point(50, 80)
      line1 = Line(p1, p2)
      line2 = line1.clone()
  
      print(line1)  # Should print: Line[(30, 17), (50, 80)]
      print(line2)  # Should print: Line[(30, 17), (50, 80)]
      print(line1 == line2)  # Should print: True
      print(line1 is line2)  # Should print: False
      print(line1.start is line2.start)  # Should print: False
      print(line1.end is line2.end)  # Should print: False
  
      line1.start = Point(11, 12)
      print(line1)  # Should print: Line[(11, 12), (50, 80)]
      print(line2)  # Should print: Line[(30, 17), (50, 80)]
      print(line1 == line2)  # Should now print: False
  
      print('The above should print:')
      print('  Line[(30, 17), (50, 80)]')
      print('  Line[(30, 17), (50, 80)]')
      print('  True')
      print('  False')
      print('  False')
      print('  False')
      print('  Line[(11, 12), (50, 80)]')
      print('  Line[(30, 17), (50, 80)')
      print('  False')
  
  
  def run_test_reverse():
      """ Tests the   reverse   method of the Line class. """
      m1t.run_test_reverse()  # This runs OUR tests.
      # ------------------------------------------------------------------
      # One ADDITIONAL test (or set of tests).
      # ------------------------------------------------------------------
      p1 = Point(30, 17)
      p2 = Point(50, 80)
      line1 = Line(p1, p2)
      line2 = line1.clone()
  
      print(line1)  # Should print: Line[(30, 17), (50, 80)]
  
      line1.reverse()
      print(line1)  # Should print: Line[(50, 80), (30, 17)]
      print(line1 == line2)  # Should print: False
  
      line1.reverse()
      print(line1 == line2)  # Should now print: True
  
      print('The above should print:')
      print('  Line[(30, 17), (50, 80)]')
      print('  Line[(50, 80), (30, 17)')
      print('  False')
      print('  True')
  
  
  def run_test_slope():
      """ Tests the   slope   method of the Line class. """
      m1t.run_test_slope()  # This runs OUR tests.
      # ------------------------------------------------------------------
      # One ADDITIONAL test (or set of tests).
      # ------------------------------------------------------------------
      p1 = Point(30, 3)
      p2 = Point(50, 8)
      line1 = Line(p1, p2)
  
      # Since the slope is (8 - 3) / (50 - 30) , which is 0.25:
      print(line1.slope())  # Should print [approximately]: 0.25
  
      line2 = Line(Point(10, 10), Point(10, 5))
      print(line2.slope())  # Should print:  inf
  
      # math.inf is NOT the STRING 'inf', so:
      print(line2.slope() == 'inf')  # Should print False
  
      print('The above should print:')
      print('  0.25 (approximately)')
      print('  inf')
      print('  False')
  
  
  def run_test_length():
      """ Tests the   length   method of the Line class. """
      m1t.run_test_length()  # This runs OUR tests.
      # ------------------------------------------------------------------
      # One ADDITIONAL test (or set of tests).
      # ------------------------------------------------------------------
      p1 = Point(166, 10)
      p2 = Point(100, 10)
      line1 = Line(p1, p2)
  
      # Since the distance from p1 to p2 is 66:
      print(line1.length())  # Should print: 66.0
  
      p3 = Point(0, 0)
      p4 = Point(3, 4)
      line2 = Line(p3, p4)
      print(line2.length())  # Should print about 5.0
  
      print('The above should print:')
      print('  66.0')
      print('  5.0 (approximately)')
  
  
  def run_test_get_number_of_clones():
      """ Tests the   get_number_of_clones   method of the Line class. """
      m1t.run_test_get_number_of_clones()  # This runs OUR tests.
      # ------------------------------------------------------------------
      # One ADDITIONAL test (or set of tests).
      # ------------------------------------------------------------------
      line1 = Line(Point(500, 20), Point(100, 8))
      line2 = line1.clone()
      line3 = line1.clone()
      line4 = line3.clone()
      line5 = line1.clone()
      print(line1.get_number_of_clones())
      print(line2.get_number_of_clones())
      print(line3.get_number_of_clones())
      print(line4.get_number_of_clones())
      print(line5.get_number_of_clones())
      print('The above should print 3, then 0, then 1, then 0, then 0.')
  
  
  def run_test_line_plus():
      """ Tests the   line_plus   method of the Line class. """
      m1t.run_test_line_plus()  # This runs OUR tests.
      # ------------------------------------------------------------------
      # One ADDITIONAL test (or set of tests).
      # ------------------------------------------------------------------
      line1 = Line(Point(500, 20), Point(100, 8))
      line2 = Line(Point(100, 13), Point(400, 8))
      line3 = line1.line_plus(line2)
      print(line3)
      print('The above should print:  Line[(600, 33), (500, 16)]')
  
  
  def run_test_line_minus():
      """ Tests the   line_minus   method of the Line class. """
      m1t.run_test_line_minus()  # This runs OUR tests.
      # ------------------------------------------------------------------
      # One ADDITIONAL test (or set of tests).
      # ------------------------------------------------------------------
      line1 = Line(Point(500, 20), Point(100, 8))
      line2 = Line(Point(100, 13), Point(400, 8))
      line3 = line1.line_minus(line2)
      print(line3)
      print('The above should print:  Line[(400, 7), (-300, 0)]')
  
  
  def run_test_midpoint():
      """ Tests the   midpoint   method of the Line class. """
      m1t.run_test_midpoint()  # This runs OUR tests.
      # ------------------------------------------------------------------
      # One ADDITIONAL test (or set of tests).
      # ------------------------------------------------------------------
      p1 = Point(3, 10)
      p2 = Point(9, 20)
      line1 = Line(p1, p2)
  
      print(line1.midpoint())  # Should print: Point(6, 15)
  
      print('The above should print:  Point(6, 15)')
  
  
  def run_test_is_parallel():
      """ Tests the   is_parallel   method of the Line class. """
      m1t.run_test_is_parallel()  # This runs OUR tests.
      # ------------------------------------------------------------------
      # One ADDITIONAL test (or set of tests).
      # ------------------------------------------------------------------
      line1 = Line(Point(15, 30), Point(17, 50))  # slope is 10.0
      line2 = Line(Point(10, 10), Point(15, 60))  # slope is 10.0
      line3 = Line(Point(10, 10), Point(80, 80))  # slope is  7.0
      line4 = Line(Point(10, 10), Point(10, 20))  # slope is inf
  
      print(line1.is_parallel(line2))  # Should print: True
      print(line2.is_parallel(line1))  # Should print: True
      print(line1.is_parallel(line3))  # Should print: False
      print(line1.is_parallel(line4))  # Should print: False
      print(line1.is_parallel(line1))  # Should print: True
      print(line4.is_parallel(line4))  # Should print: True
  
      print('The above should print:')
      print('  True,  True,  False,  False,  True,  True')
  
  
  def run_test_reset():
      """ Tests the   reset   method of the Line class. """
      m1t.run_test_reset()  # This runs OUR tests.
      # ------------------------------------------------------------------
      # One ADDITIONAL test (or set of tests).
      # ------------------------------------------------------------------
      p1 = Point(-3, -4)
      p2 = Point(3, 4)
      line1 = Line(p1, p2)
      line2 = Line(Point(0, 1), Point(10, 20))
  
      line1.start = Point(100, 300)
      line2.end = Point(99, 4)
      line1.reverse()
  
      # Should print: Line[(x1, y1), (x2, y2)] where (x1, y1) and
      # (x2, y2) are the CURRENT coordinates of line1's endpoints.
      print(line1)
      print(line2)  # Similarly for line2
  
      line1.reset()
      line2.reset()
      print(line1)  # Should print: Line[(-3, -4), (3, 4)]
      print(line2)  # Should print: Line[(0, 1), (10, 20)]
  
      print('The above should print:')
      print('  Line[(3, 4), (100, 300)]')
      print('  Line[(0, 1), (99, 4)]')
      print('  Line[(-3, -4), (3, 4)]')
      print('  Line[(0, 1), (10, 20)]')
  
  
  # ----------------------------------------------------------------------
  # If this module is running at the top level (as opposed to being
  # imported by another module), then call the 'main' function.
  # ----------------------------------------------------------------------
  if __name__ == '__main__':
      main()
  