🧑‍🏫 Open Source Video Curriculum for Mathematics. For the 21st Century.

import json
from pathlib import Path
from sophialib.constants.directories import SCENES_FOLDER
from sophialib.filehelpers.load_sophia_scenes import get_module_manim_sophiascene_classes
from sophialib.page_prototypes.prototype import PagePrototype, PagePrototypeVideo, get_page_prototype_variables
from sophialib.styles.sophiascene import SophiaScene
from typing import Type, Tuple

def find_manim_scenes_in_directory():
    classes:list[Tuple[Path,Type[SophiaScene]]] = []

    for pf in Path(SCENES_FOLDER).glob("**/*.py"):
        scene_classes = get_module_manim_sophiascene_classes(pf, add_parent_folder_to_sys_path=True) # we need relative like imports from the same folder
        for scene_class in scene_classes:
            classes.append((pf, scene_class))

    return classes

def find_page_prototypes_in_directory():
    all_prototypes: list[Tuple[Path, Type[PagePrototype]]] = []

    for pf in Path(SCENES_FOLDER).glob("**/*.py"):
        prototypes = get_page_prototype_variables(pf, add_parent_folder_to_sys_path=True) # we need relative like imports from the same folder
        for pt in prototypes:
            all_prototypes.append((pf, pt))

    return all_prototypes

prototypes_per_dir = find_page_prototypes_in_directory()

############### TEMPORARY ################
# for every scene, check if it has a corresponding prototype, otherwise add one
scenes_per_dir = find_manim_scenes_in_directory()

for path, scene_class in scenes_per_dir:
    potential_prototype = PagePrototypeVideo.from_scene(scene_class)

    if not any(pt.prototypeID == potential_prototype.prototypeID for _, pt in prototypes_per_dir):
        prototypes_per_dir.append((path, potential_prototype))

##########################################

# ensure that every prototype ID is unique, otherwise raise an error that indicates the paths to the conflicting prototypes
all_prototype_ids = [pt.prototypeID for _, pt in prototypes_per_dir]
if len(all_prototype_ids) != len(set(all_prototype_ids)):
    # find all duplicate prototype ids
    duplicate_prototype_ids = set([x for x in all_prototype_ids if all_prototype_ids.count(x) > 1])

    # for each duplicate prototype id, print out ALL path where it was found
    for duplicate_prototype_id in duplicate_prototype_ids:
        duplicate_prototype_paths = [path for path, pt in prototypes_per_dir if pt.prototypeID == duplicate_prototype_id]
        print(f"Found duplicate prototype id {duplicate_prototype_id} in: ")
        for path in duplicate_prototype_paths:
            print(f"    {path}")

    # raise an error that indicates the paths to the conflicting prototypes
    raise Exception(f"Found duplicate prototype ids: {duplicate_prototype_ids} in {duplicate_prototype_paths}")

overview_json = []

# go through all scenes and add an entry to the overview json
for path, pt in prototypes_per_dir:
    overview_json.append({
        "folder": path.parent.name,
        **pt.to_json()
    })

# write the overview json to the file
with open("prototypes.json", "w") as f:
    f.write(json.dumps(overview_json, indent=4))

get_prototypes_json.py
Sophia-Edu-Labs/sophia-math
from sophialib.constants.directories import RENDER_RESULTS_FOLDER
from sophiarenderlib.render.filehelpers import RENDER_RESULTS_MEDIA_FOLDER, find_repository_scene_module_paths
from sophiarenderlib.render.scenes import render_scene_modules


if __name__ == "__main__":
    found_scene_modules = find_repository_scene_module_paths()
    
    
    ########################################################
    ######################## DEBUG #########################
    ###### Use this to only render particular scenes #######
    ########################################################
    #print(found_scene_modules)
    #print("--------")
    filenames_to_render = ["Func_7_3.py"]
    # filenames_no_render = ["Func3_1.py", "Func3_2.py", "Func3_3.py"]
    found_scene_modules = [m for m in found_scene_modules if any(filename in m.name for filename in filenames_to_render)]
    # found_scene_modules = [m for m in found_scene_modules if not any(filename in m.name for filename in filenames_no_render)]
    print (f"-------- [ found the following  (n={len(found_scene_modules)}) modules ] --------")
    for m in found_scene_modules:
        print(f"  {m}")
    ########################################################

    # render
    # if test_run_with_last_frame is True, then it will only render the last frame of each scene, and will not render the full scene (that makes it faster, even though still quite slow for a lot of scenes, to get an idea whether the scenes are working or not)
    render_scene_modules(found_scene_modules, output_dir=RENDER_RESULTS_FOLDER, media_parent_folder=RENDER_RESULTS_MEDIA_FOLDER, parallelize=False, test_run_with_last_frame=False)
    
    
                


renderall.py
Sophia-Edu-Labs/sophia-math
# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, format_text_group)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition


# Function to create piecewise linear function based on given points
def create_piecewise_linear(points):
    def piecewise_linear(x):
        # Sort the points based on x-coordinate
        sorted_points = sorted(points, key=lambda p: p[0])

        # Find the closest two points for interpolation
        left_point, right_point = None, None
        for point in sorted_points:
            if x < point[0]:
                right_point = point
                break
            left_point = point

        # Extrapolate if x is outside the range of points
        if right_point is None:
            return sorted_points[-1][1]
        if left_point is None:
            return sorted_points[0][1]

        # Linear interpolation
        x1, y1 = left_point
        x2, y2 = right_point
        slope = (y2 - y1) / (x2 - x1)
        interpolated_value = y1 + slope * (x - x1)

        return interpolated_value

    return piecewise_linear

###########################################
###########################################
# Topic: Repetition - What is a Term?
class Func_1_2_I_1(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        apple = ImageMobject(assets_folder / "img" / "apple.png").scale(0.4).shift(UP*1.2+LEFT*1.2)

        # Add title to the scene
        self.add_title("Terms")

        term1 = MathTex("2x+3", color=c1t).shift(UP*1.5)
        term2 = MathTex("x^2-2", color=c1t).next_to(term1, DOWN)
        term3 = MathTex("x+3=7", color=c1t).next_to(term2, DOWN)
        left, right = term3.get_left()[0], term3.get_right()[0]
        top, bottom = term3.get_top()[1], term3.get_bottom()[1]
        strikeA = Line([left, bottom, 0], [right, top, 0], color=RED, stroke_width=5)
        strikeB = Line([left, top, 0], [right, bottom, 0], color=RED, stroke_width=5)
        appleCost = Tex(": $2$ Euro/Piece", color=c1t, font_size=fs2).next_to(apple, RIGHT).shift(DOWN*0.3+LEFT*0.4)

        explainers = format_text_group(["$x$: Number of apples", ["$\\rightarrow$ The term $2x$", "describes total cost"]], font_size=fs3)

        # Action Sequence
        with self.voiceover(
                text="""
                <prosody rate="110%">
                Quick reminder: Do you remember what a term is?
                A term is an expression that consists of numbers, variables, and operators.
                For example, <bookmark mark="term1"/>two times x plus three is a term,
                <bookmark mark="term2"/> or x squared minus two.<bookmark mark="term3"/>
                However, the expression x plus three equals seven is not a term, because it contains an equals sign.
                Terms are useful because they can be used to describe relationships.
                <bookmark mark="unwriteTerms"/>
                For instance, if we buy <bookmark mark="apple"/> x apples for two euros each, we can
                <bookmark mark="appleCost"/>calculate the total cost using the term two times x.
                This assigns a cost to each value of x, which represents the quantity of purchased apples.
                We calculate this cost using two times x.
                Functions work in a similar way.
                Just like terms, functions assign a value of y to each value of x.
                </prosody>
                """
        ) as tracker:

            self.wait_until_bookmark("term1")
            self.play(Write(term1), run_time=1)

            self.wait_until_bookmark("term2")
            self.play(Write(term2), run_time=1)

            self.wait_until_bookmark("term3")
            self.play(Write(term3), run_time=1)
            self.wait(0.5)
            self.play(Write(strikeA), Write(strikeB), run_time=1)

            self.wait_until_bookmark("unwriteTerms")
            self.play(Unwrite(term1), Unwrite(term2), Unwrite(term3), Unwrite(strikeA), Unwrite(strikeB), run_time=1)
            
            self.wait_until_bookmark("apple")
            self.play(FadeIn(apple), run_time=1)
            self.play(Write(appleCost), run_time=1)

            self.wait_until_bookmark("appleCost")
            self.play(FadeIn(explainers), run_time=1)


        # Wait for 4 seconds at the end of animation
        self.wait(4)

###########################################
###########################################
class Func_1_2_I_2(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        self.add_title("From Term to Function")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 6],
                               x_labels=[-3, 0, 3], y_labels=[-6, 0, 6]).shift(DOWN)
        plane = cords[0]
        redx = plane.x_axis.copy().set_color(RED).set_stroke(width=4)
        self.add(cords)

        # Initialize a cursor
        xo, yo, _ = plane.c2p(0, 0)
        cursor = AltCursor(stroke_width=0.0, idle=True).move_to([xo, yo, 0])
        cursor.autoFadeBackground = True

        self.add(cursor)

        func = MathTex("2x-2", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.8)
        func2 = MathTex("f(x)=2x-2", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.8)
        def f(x):
            return 2*x-2
        f_plotted = plane.plot(f, color=c3)

        # Action Sequence
        with self.voiceover(
                text="""
                <prosody rate="110%">
                So, now we're learning how to go from a term to a function.
                 <bookmark mark="term"/>
                Consider the term two times x minus two.
                
                First, we choose a set on which we want to examine the function.
                This set is called the domain. <bookmark mark="domain"/>
                For example, here we choose all values that lie <bookmark mark="xaxis"/> on the x-axis. So, all values between minus three and three.
                
                <bookmark mark="plot"/>
                Now we substitute each value of x into the term to get a value for y.
                We then plot this value on a coordinate plane.
                
                <bookmark mark="func"/>
                Connecting the points, we obtain a representation of a function, because the line assigns a point
                on the x-axis to a point on the y-axis.

                To get the y-value corresponding to an x-value, we can either substitute the x-value <bookmark mark="xTerm"/> into the term,
                <bookmark mark="xFunc"/> or we can locate the x-value on the x-axis and then read the y-value on the y-axis.
                
                In this case, since the term describes a function, we call it a function term.
                <bookmark mark="termToFunc"/>
                We also write it as f of x equals two times x minus two, so we put f of x equals in front of the term.
                </prosody>
                """
        ) as tracker:

            self.wait_until_bookmark("term")
            self.play(Write(func), run_time=1)

            self.wait_until_bookmark("xaxis")
            self.play(Write(redx), run_time=3)

            self.wait_until_bookmark("plot")
            cursor.idle = False
            x, y, _ = cursor.get_center()
            self.play(CursorMoveResize(cursor, x, y, 0.15, 0.15), run_time=0.5)
            for x in [-3, -2, -1, 0, 1, 2, 3]:
                self.play(cursor.animate.move_to(plane.c2p(x, f(x))), run_time=0.5)
                self.add(cursor.copy().set_opacity(0.5).set_color(c3))
                self.wait(0.5)
            self.play(CursorMoveResize(cursor, xo, yo, 0.2, 0.2), run_time=0.5)

            self.wait_until_bookmark("func")
            self.add_pencil_sound(3)
            self.play(Write(f_plotted), run_time=3)

            self.wait_until_bookmark("xTerm")
            self.play(func.animate.scale(2), run_time=1)
            self.play(func.animate.scale(0.5), run_time=1)

            self.wait_until_bookmark("xFunc")
            xx, xy, _ = plane.c2p(2, 0)
            yx, yy, _ = plane.c2p(2, f(2))
            l = Line([xx, xy, 0], [yx, yy, 0], color=RED)
            self.play(CursorMoveResize(cursor, xx, xy, 0.2, 0.2), run_time=0.5)
            self.play(CursorMoveResize(cursor, yx, yy, 0.2, 0.2), run_time=0.5)
            self.play(Write(l), run_time=0.5)
            self.play(CursorMoveResize(cursor, xo, yo, 0.2, 0.2), run_time=0.5)

            self.wait_until_bookmark("termToFunc")
            self.play(TransformMatchingTex(func, func2), run_time=2)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

############################################
############################################
##### Practice Part ########################
############################################
############################################


# Topic: How do we get from a Term to a function?
class FuncTermQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        self.add_title("Term \& Function")

        # Create the coordinate system
        plane = self.cords[0]
        self.add(self.cords)

        # Initialize a cursor
        xo, yo, _ = plane.c2p(0, 0)
        cursor = AltCursor(stroke_width=0.0, idle=True).move_to([xo, yo, 0])
        cursor.autoFadeBackground = True
        self.add(cursor)

        func = MathTex(self.term, color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.5)
        fs_plotted = [plane.plot(self.fs[0], color=c3), plane.plot(self.fs[1], color=c4), plane.plot(self.fs[2], color=c5)]
        self.add(func)

        # Action Sequence
        with self.voiceover(
                text=f"""
                We're starting with a function term and we want to find the corresponding graph.
                The term we want to find the graph for <bookmark mark="term"/>is {self.termInWords}.
                Now tell me: <bookmark mark="findGraph"/>
                Which of the following graphs describes the function of the given term?
                <bookmark mark="blue"/> Is it the blue graph?<break time="1s"/>

                <bookmark mark="orange"/> Or is it the orange graph?<break time="1s"/>

                <bookmark mark="lila"/> Or is it the purple graph?<break time="1s"/>
                """
        ) as tracker:

            self.wait_until_bookmark("term")
            x,y,_ = func.get_center()
            cursor.idle=False
            self.play(CursorMoveResize(cursor, x, y, func.get_width()+0.2, func.get_height()+0.2), run_time=0.5)

            self.wait_until_bookmark("blue")
            self.add_pencil_sound(2)
            self.play(Write(fs_plotted[0]), CursorMoveResize(cursor, xo, yo, 0.2, 0.2),  run_time=2)
            cursor.idle=True

            self.wait_until_bookmark("orange")
            self.add_pencil_sound(2)
            self.play(Write(fs_plotted[1]), run_time=2)

            self.wait_until_bookmark("lila")
            self.add_pencil_sound(2)
            self.play(Write(fs_plotted[2]), run_time=2)

        # Wait for 4 seconds at the end of animation
        self.wait(4)


# Topic: How do we get from a Term to a function?
class FuncTermAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        self.add_title("Term \& Function")

        # Create the coordinate system
        self.cords.shift(DOWN)
        plane = self.cords[0]
        self.add(self.cords)

        # Initialize a cursor
        xo, yo, _ = plane.c2p(0, 0)
        cursor = AltCursor(stroke_width=0.0, idle=True).move_to([xo, yo, 0])
        cursor.autoFadeBackground = True
        self.add(cursor)

        func = MathTex(self.term, color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.5)
        fs_plotted = [plane.plot(self.fs[0], color=c3), plane.plot(self.fs[1], color=c4), plane.plot(self.fs[2], color=c5)]
        self.add(func)


        plugInTexts = ""
        for i in range(len(self.vals)):
            if i < 2:
                plugInTexts += f"""<bookmark mark="val{i+1}"/> The {nums_ordinal[i+1]} value we plug in is {get_num(self.vals[i])}, and the value of the function at this point is {get_num(self.fs[self.idx_correct](self.vals[i]))} -"""
            elif i < len(self.vals) - 1:
                plugInTexts += f"""<bookmark mark="val{i+1}"/> For the x-value {get_num(self.vals[i])}, we obtain the y-value {get_num(self.fs[self.idx_correct](self.vals[i]))}, """
            else:
                plugInTexts += f"""<bookmark mark="val{i+1}"/> and for the x-value {get_num(self.vals[i])}, we finally get the y-value {get_num(self.fs[self.idx_correct](self.vals[i]))}."""

        introText = ""
        if self.idx_selected == self.idx_correct:
            introText = "Great, that's correct!"
        else:
            introText = "Unfortunately, that's incorrect."

        # Action Sequence
        with self.voiceover(
                text=f"""
                {introText}
                We want to determine the function graph for the <bookmark mark="show_term"/>term {self.termInWords}.
                We proceed as follows:
                <bookmark mark="plugIn"/>
                We consider points from our domain one by one.
                Then, we plug these points into the term and obtain the corresponding function values.
                And then, we <bookmark mark="addPoints"/> plot these points in a coordinate system.
                So, let's turn to our example:
                {plugInTexts}
                Now, we connect the points we've plotted
                <bookmark mark="connect"/>
                and thus obtain the function graph.
                """
        ) as tracker:
            
            self.wait_until_bookmark("show_term")
            x,y,_ = func.get_center()
            cursor.idle=False
            self.play(CursorMoveResize(cursor, x, y, func.get_width()+0.2, func.get_height()+0.2), run_time=0.5)

            self.wait_until_bookmark("addPoints")
            cursor.idle = False
            for i in range(len(self.vals)):
                self.wait_until_bookmark(f"val{i+1}")
                x,y,_ = plane.c2p(self.vals[i], self.fs[self.idx_correct](self.vals[i]))
                self.play(CursorMoveResize(cursor,x,y,0.2,0.2), run_time=1)
                self.add(cursor.copy().set_color(c3))

            self.wait_until_bookmark("connect")
            self.add_pencil_sound(2)
            self.play(Write(fs_plotted[self.idx_correct]), run_time=2)

        # Wait for 4 seconds at the end of animation
        self.wait(4)


############################################
############################################
##### Instruction Part #####################
############################################
############################################

###########################################
###########################################
TASK_Func_1_2_I_2_1_q = SophiaTaskDefinition(
    answerOptions = ["The blue graph", "The orange graph", "The purple graph"],
    correctAnswerIndex = 1,
    questionText = "Which of these graphs describes the corresponding function?"
)

class Func_1_2_I_2_1_q(FuncTermQuestionScene):
    def construct(self):
        self.term = "f(x)=-x"
        self.termInWords = "f of x equals negative x"
        self.cords = self.add_cords([-2, 2, 1], [-6, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-6, 0, 10],
                        x_labels=[-2, 0, 2], y_labels=[-6, 0, 10])
        def f1(x):
            return x/2 - 2
        def f2(x):
            return -x
        def f3(x):
            return 3
        self.fs = [f1, f2, f3]
        self.idx_correct = 1
        super().construct()

class Func_1_2_I_2_1_a(FuncTermAnswerScene):

    def construct(self):
        self.term = "f(x)=-x"
        self.termInWords = "f of x equals negative x"
        self.cords = self.add_cords([-2, 2, 1], [-6, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-6, 0, 10],
                        x_labels=[-2, 0, 2], y_labels=[-6, 0, 10])
        def f1(x):
            return x/2 - 2
        def f2(x):
            return -x
        def f3(x):
            return 3
        self.fs = [f1, f2, f3]
        self.idx_correct = 1
        self.idx_selected = 0
        self.vals = [-2,-1,0,1,2]
        super().construct()

class Func_1_2_I_2_1_b(FuncTermAnswerScene):

    def construct(self):
        self.term = "f(x)=-x"
        self.termInWords = "f of x equals negative x"
        self.cords = self.add_cords([-2, 2, 1], [-6, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-6, 0, 10],
                        x_labels=[-2, 0, 2], y_labels=[-6, 0, 10])
        def f1(x):
            return x/2 - 2
        def f2(x):
            return -x
        def f3(x):
            return 3
        self.fs = [f1, f2, f3]
        self.idx_correct = 1
        self.idx_selected = 1
        self.vals = [-2,-1,0,1,2]
        super().construct()

class Func_1_2_I_2_1_c(FuncTermAnswerScene):

    def construct(self):
        self.term = "f(x)=-x"
        self.termInWords = "f of x equals negative x"
        self.cords = self.add_cords([-2, 2, 1], [-6, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-6, 0, 10],
                        x_labels=[-2, 0, 2], y_labels=[-6, 0, 10])
        def f1(x):
            return x/2 - 2
        def f2(x):
            return -x
        def f3(x):
            return 3
        self.fs = [f1, f2, f3]
        self.idx_correct = 1
        self.idx_selected = 2
        self.vals = [-2,-1,0,1,2]
        super().construct()


# Class for creating the animation scene
# Topic: How do we get from a Term to a Function?
class Func_1_2_I_3(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):

        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        self.add_title("Functions: Concepts")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 6],
                               x_labels=[-3, 0, 3], y_labels=[-6, 0, 6]).shift(DOWN)
        plane = cords[0]
        redx = plane.x_axis.copy().set_color(RED).set_stroke(width=4)
        self.add(cords)

        # Initialize a cursor
        xo, yo, _ = plane.c2p(0, 0)
        cursor = AltCursor(stroke_width=0.0, idle=True).move_to([xo, yo, 0])
        cursor.autoFadeBackground = True

        self.add(cursor)

        func = MathTex("f(x)=x^2-3", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.5)
        def f(x):
            return x**2-3
        f_plotted = plane.plot(f, color=c3)

        # Action Sequence
        with self.voiceover(
                text="""
                <prosody rate="110%">
                Now, let's talk about some important concepts related to functions.
                <bookmark mark="term"/>
                Let's start with the concept of the function term...
                <break time="1s"/>
                As we already know, the term of a function describes how we go from an x-value to a y-value.
                <break time="1s"/>
                That means, we plug each value of x into the term to obtain the corresponding y-value.
                <bookmark mark="show_term"/>
                The function term is typically written as "f of x equals", followed by the term. For example, here it is written as f of x equals x squared minus three.
                <break time="1s"/>
                <bookmark mark="graph"/>
                The next concept is that of the graph of a function.
                <break time="1s"/>
                The graph of a function describes how the function looks.
                To obtain a function's graph, we simply plot some points that we can calculate using the function term onto a coordinate plane.
                And because we don't have the time to plot an infinite number of points, we typically choose just a few points
                Then, we connect the points to obtain the graph. Sometimes, we need to draw many points to get an accurate graph, other times only a few points are enough.
                </prosody>
                """
        ) as tracker:
            
            self.wait_until_bookmark("term")
            self.wait(1)
            self.play(Write(func), run_time=2)

            self.wait_until_bookmark("show_term")
            x,y,_ = func.get_center()
            cursor.idle=False
            self.play(CursorMoveResize(cursor, x, y, func.get_width()+0.2, func.get_height()+0.2), run_time=0.5)

            self.wait_until_bookmark("graph")
            self.wait(1)
            self.play(CursorMoveResize(cursor,xo,yo,0.2,0.2), Write(f_plotted), run_time=4)
            cursor.ide=True

        # Wait for 4 seconds at the end of animation
        self.wait(4)


# Class for creating the animation scene
# Topic: How do we get from a Term to a Function?
class Func_1_2_I_4(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):

        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        self.add_title("Function - Concepts")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 6],
                               x_labels=[-3, 0, 3], y_labels=[-6, 0, 6]).shift(DOWN)
        plane = cords[0]
        redx = plane.x_axis.copy().set_color(RED).set_stroke(width=4)
        y_min, y_max = plane.y_axis.n2p(-3)[1], plane.y_axis.n2p(6)[1]
        redy = Line([0, y_min, 0], [0, y_max, 0]).set_color(RED).set_stroke(width=4)
        self.add(cords)

        # Initialize a cursor
        xo, yo, _ = plane.c2p(0, 0)
        cursor = AltCursor(stroke_width=0.0, idle=True).move_to([xo, yo, 0])
        cursor.autoFadeBackground = True

        self.add(cursor)

        func = MathTex("f(x)=x^2-3", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.5)
        def f(x):
            return x**2-3
        f_plotted = plane.plot(f, color=c3)

        domain = Tex("Domain:\\\\ All values that we can \\\\ plug in for $x$.", color=c3t, font_size=fs3, tex_environment="flushleft").next_to(func, DOWN, buff=.6)
        range = Tex("Range:\\\\ All values that we \\\\ obtain for $y$.", color=c3t, font_size=fs3, tex_environment="flushleft").next_to(func, DOWN, buff=.6)
        range.shift(LEFT*(range.get_left()-domain.get_left()))
        self.add(func, f_plotted)

        # Action Sequence
        with self.voiceover(
                text="""
                <prosody rate="110%">
                Two more important concepts related to functions: The domain and the range.
                <break time="1s"/>
                The domain <bookmark mark="domain_in"/>is the set of all values that we can substitute for x.
                So, it's the set of all x-values that we can use for the function.
                <bookmark mark="show_def"/>
                <break time="1s"/>
                In this case, the domain is the interval which includes all values between negative three and three.
                <break time="1s"/>
                The next concept is that<bookmark mark="range_in"/> of the range.
                <break time="1s"/>
                The range is the set of all values that we can obtain for y.
                <bookmark mark="show_val"/> 
                In this case, the range is the interval that includes all values between minus three and six.
                <break time="1s"/>
                Because we get the lowest value at x equals zero, which is minus three.
                And we get the highest value at x equals three, which is six. So, the range is the interval between minus three and six.
                </prosody>
                """
        ) as tracker:
            
            self.wait_until_bookmark("domain_in")
            self.play(Write(domain), run_time=1)
            
            self.wait_until_bookmark("show_def")
            self.play(Write(redx), run_time=2)

            self.wait_until_bookmark("range_in")
            self.play(Transform(domain, range), run_time=.5)

            self.wait_until_bookmark("show_val")
            self.play(Write(redy), run_time=2)


        # Wait for 4 seconds at the end of animation
        self.wait(4)





############################################
############################################
##### Exercises ############################
############################################
############################################



TASK_Func_1_2_P_1_1_q = SophiaTaskDefinition(
    answerOptions = ["The blue graph", "The orange graph", "The purple graph"],
    correctAnswerIndex = 0,
    questionText = "Which of these graphs describes the corresponding function?"
)

class Func_1_2_P_1_1_q(FuncTermQuestionScene):

    def construct(self):

        self.term = "f(x)=x^2-3"
        self.termInWords = "f of x is equal to x squared minus three"
        self.cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 6],
                        x_labels=[-3, 0, 3], y_labels=[-6, 0, 6])
        def f1(x):
            return x**2-3
        def f2(x):
            return x**2
        def f3(x):
            return 3-x**2
        self.fs = [f1, f2, f3]
        self.idx_correct = 0

        super().construct()

class Func_1_2_P_1_1_a(FuncTermAnswerScene):

    def construct(self):
        self.term = "f(x)=x^2-3"
        self.termInWords = "f of x equals x squared minus three"
        self.cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 6],
                        x_labels=[-3, 0, 3], y_labels=[-6, 0, 6])
        def f1(x):
            return x**2-3
        def f2(x):
            return x**2
        def f3(x):
            return 3-x**2
        self.fs = [f1, f2, f3]
        self.idx_correct = 0
        self.idx_selected = 0
        self.vals = [-3,-2,-1,0,1,2,3]

        super().construct()

class Func_1_2_P_1_1_b(FuncTermAnswerScene):

    def construct(self):
        self.term = "f(x)=x^2-3"
        self.termInWords = "f of x is equal to x squared minus three"
        self.cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 6],
                        x_labels=[-3, 0, 3], y_labels=[-6, 0, 6])
        def f1(x):
            return x**2-3
        def f2(x):
            return x**2
        def f3(x):
            return 3-x**2
        self.fs = [f1, f2, f3]
        self.idx_correct = 0
        self.idx_selected = 1
        self.vals = [-3,-2,-1,0,1,2,3]

        super().construct()

class Func_1_2_P_1_1_c(FuncTermAnswerScene):

    def construct(self):
        self.term = "f(x)=x^2-3"
        self.termInWords = "f of x is equal to x squared minus three"
        self.cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 6],
                        x_labels=[-3, 0, 3], y_labels=[-6, 0, 6])
        def f1(x):
            return x**2-3
        def f2(x):
            return x**2
        def f3(x):
            return 3-x**2
        self.fs = [f1, f2, f3]
        self.idx_correct = 0
        self.idx_selected = 2
        self.vals = [-3,-2,-1,0,1,2,3]

        super().construct()


#################################################
#################################################


TASK_Func_1_2_P_1_2_q = SophiaTaskDefinition(
    answerOptions = ["The blue graph", "The orange graph", "The purple graph"],
    correctAnswerIndex = 1,
    questionText = "Which of these graphs describes the corresponding function?"
)
class Func_1_2_P_1_2_q(FuncTermQuestionScene):
    def construct(self):
        self.term = "f(x)=x^3"
        self.termInWords = "f of x is equal to x cubed"
        self.cords = self.add_cords([-3, 3, 1], [-27, 27, 9], x_ticks=[-3, 0, 3], y_ticks=[-27, 0, 27],
                        x_labels=[-3, 0, 3], y_labels=[-27, 0, 27])
        def f1(x):
            return x**2
        def f2(x):
            return x**3
        def f3(x):
            return x+3
        self.fs = [f1, f2, f3]
        self.idx_correct = 1
        super().construct()

class Func_1_2_P_1_2_a(FuncTermAnswerScene):
    def construct(self):
        self.term = "f(x)=x^3"
        self.termInWords = "f of x is equal to x cubed"
        self.cords = self.add_cords([-3, 3, 1], [-27, 27, 9], x_ticks=[-3, 0, 3], y_ticks=[-27, 0, 27],
                        x_labels=[-3, 0, 3], y_labels=[-27, 0, 27])
        def f1(x):
            return x**2
        def f2(x):
            return x**3
        def f3(x):
            return x+3
        self.fs = [f1, f2, f3]
        self.idx_correct = 1
        self.idx_selected = 0
        self.vals = [-3,-2,-1,0,1,2,3]
        super().construct()

class Func_1_2_P_1_2_b(FuncTermAnswerScene):
    def construct(self):
        self.term = "f(x)=x^3"
        self.termInWords = "f of x is equal to x cubed"
        self.cords = self.add_cords([-3, 3, 1], [-27, 27, 9], x_ticks=[-3, 0, 3], y_ticks=[-27, 0, 27],
                        x_labels=[-3, 0, 3], y_labels=[-27, 0, 27])
        def f1(x):
            return x**2
        def f2(x):
            return x**3
        def f3(x):
            return x+3
        self.fs = [f1, f2, f3]
        self.idx_correct = 1
        self.idx_selected = 1
        self.vals = [-3,-2,-1,0,1,2,3]
        super().construct()

class Func_1_2_P_1_2_c(FuncTermAnswerScene):
    def construct(self):
        self.term = "f(x)=x^3"
        self.termInWords = "f of x is equal to x cubed"
        self.cords = self.add_cords([-3, 3, 1], [-27, 27, 9], x_ticks=[-3, 0, 3], y_ticks=[-27, 0, 27],
                        x_labels=[-3, 0, 3], y_labels=[-27, 0, 27])
        def f1(x):
            return x**2
        def f2(x):
            return x**3
        def f3(x):
            return x+3
        self.fs = [f1, f2, f3]
        self.idx_correct = 1
        self.idx_selected = 2
        self.vals = [-3,-2,-1,0,1,2,3]
        super().construct()

#################################################
#################################################

TASK_Func_1_2_P_1_3_q = SophiaTaskDefinition(
    answerOptions = ["The blue graph", "The orange graph", "The purple graph"],
    correctAnswerIndex = 0,
    questionText = "Which of these graphs describes the corresponding function?"
)

class Func_1_2_P_1_3_q(FuncTermQuestionScene):
    def construct(self):
        self.term = "f(x)=2x^2 + 1"
        self.termInWords = "f of x equals two times x squared plus one"
        self.cords = self.add_cords([-2, 2, 1], [-6, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-6, 0, 10],
                        x_labels=[-2, 0, 2], y_labels=[-6, 0, 10])
        def f1(x):
            return 2*x**2 + 1
        def f2(x):
            return x**2
        def f3(x):
            return 2*x + 1
        self.fs = [f1, f2, f3]
        self.idx_correct = 0
        super().construct()

class Func_1_2_P_1_3_a(FuncTermAnswerScene):
    def construct(self):
        self.term = "f(x)=2x^2 + 1"
        self.termInWords = "f of x is equal to two times x squared plus one"
        self.cords = self.add_cords([-2, 2, 1], [-6, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-6, 0, 10],
                        x_labels=[-2, 0, 2], y_labels=[-6, 0, 10])
        def f1(x):
            return 2*x**2 + 1
        def f2(x):
            return x**2
        def f3(x):
            return 2*x + 1
        self.fs = [f1, f2, f3]
        self.idx_correct = 0
        self.idx_selected = 0
        self.vals = [-3,-2,-1,0,1,2,3]
        super().construct()

class Func_1_2_P_1_3_b(FuncTermAnswerScene):
    def construct(self):
        self.term = "f(x)=2x^2 + 1"
        self.termInWords = "f of x is equal to two times x squared plus one"
        self.cords = self.add_cords([-2, 2, 1], [-6, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-6, 0, 10],
                        x_labels=[-2, 0, 2], y_labels=[-6, 0, 10])
        def f1(x):
            return 2*x**2 + 1
        def f2(x):
            return x**2
        def f3(x):
            return 2*x + 1
        self.fs = [f1, f2, f3]
        self.idx_correct = 0
        self.idx_selected = 1
        self.vals = [-3,-2,-1,0,1,2,3]
        super().construct()

class Func_1_2_P_1_3_c(FuncTermAnswerScene):
    def construct(self):
        self.term = "f(x)=2x^2 + 1"
        self.termInWords = "f of x is equal to two times x squared plus one"
        self.cords = self.add_cords([-2, 2, 1], [-6, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-6, 0, 10],
                        x_labels=[-2, 0, 2], y_labels=[-6, 0, 10])
        def f1(x):
            return 2*x**2 + 1
        def f2(x):
            return x**2
        def f3(x):
            return 2*x + 1
        self.fs = [f1, f2, f3]
        self.idx_correct = 0
        self.idx_selected = 2
        self.vals = [-3,-2,-1,0,1,2,3]
        super().construct()

#################################################
#################################################

TASK_Func_1_2_P_1_4_q = SophiaTaskDefinition(
    answerOptions = ["The blue graph", "The orange graph", "The purple graph"],
    correctAnswerIndex = 2,
    questionText = "Which of these graphs describes the corresponding function?"
)

class Func_1_2_P_1_4_q(FuncTermQuestionScene):
    def construct(self):
        self.term = "f(x)=3x^2 - x"
        self.termInWords = "f of x is equal to three times x squared minus x"
        self.cords = self.add_cords([-2, 2, 1], [-6, 18, 3], x_ticks=[-2, 0, 2], y_ticks=[-6, 0, 6, 12, 18],
                        x_labels=[-2, 0, 2], y_labels=[-6, 0, 6, 12, 18])
        def f3(x):
            return 3*x**2 - x
        def f2(x):
            return x**2
        def f1(x):
            return x - 3
        self.fs = [f1, f2, f3]
        self.idx_correct = 2
        super().construct()

class Func_1_2_P_1_4_a(FuncTermAnswerScene):
    def construct(self):
        self.term = "f(x)=3x^2 - x"
        self.termInWords = "f of x is equal to three times x squared minus x"
        self.cords = self.add_cords([-2, 2, 1], [-6, 18, 3], x_ticks=[-2, 0, 2], y_ticks=[-6, 0, 6, 12, 18],
                        x_labels=[-2, 0, 2], y_labels=[-6, 0, 6, 12, 18])
        def f3(x):
            return 3*x**2 - x
        def f2(x):
            return x**2
        def f1(x):
            return x - 3
        self.fs = [f1, f2, f3]
        self.idx_correct = 2
        self.idx_selected = 0
        self.vals = [-3,-2,-1,0,1,2,3]
        super().construct()

class Func_1_2_P_1_4_b(FuncTermAnswerScene):
    def construct(self):
        self.term = "f(x)=3x^2 - x"
        self.termInWords = "f of x is equal to three times x squared minus x"
        self.cords = self.add_cords([-2, 2, 1], [-6, 18, 3], x_ticks=[-2, 0, 2], y_ticks=[-6, 0, 6, 12, 18],
                        x_labels=[-2, 0, 2], y_labels=[-6, 0, 6, 12, 18])
        def f3(x):
            return 3*x**2 - x
        def f2(x):
            return x**2
        def f1(x):
            return x - 3
        self.fs = [f1, f2, f3]
        self.idx_correct = 2
        self.idx_selected = 1
        self.vals = [-3,-2,-1,0,1,2,3]
        super().construct()

class Func_1_2_P_1_4_c(FuncTermAnswerScene):
    def construct(self):
        self.term = "f(x)=3x^2 - x"
        self.termInWords = "f of x is equal to three times x squared minus x"
        self.cords = self.add_cords([-2, 2, 1], [-6, 18, 3], x_ticks=[-2, 0, 2], y_ticks=[-6, 0, 6, 12, 18],
                        x_labels=[-2, 0, 2], y_labels=[-6, 0, 6, 12, 18])
        def f3(x):
            return 3*x**2 - x
        def f2(x):
            return x**2
        def f1(x):
            return x - 3
        self.fs = [f1, f2, f3]
        self.idx_correct = 2
        self.idx_selected = 2
        self.vals = [-3,-2,-1,0,1,2,3]
        super().construct()


#################################################
#################################################
# New Exercise Type
#################################################
#################################################


# This class presents a function and then asks what
# the corresponding domain and what the corresponding
# range is. It's in German for now.
class FuncDefinitionsQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):

        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()


        # Add title to the scene
        self.add_title("Domain \& Range")

        # Create the coordinate system
        self.cords.shift(DOWN*0.4)
        plane = self.cords[0]
        self.add(self.cords)

        # Initialize a cursor
        xo, yo, _ = plane.c2p(0, 0)
        cursor = AltCursor(stroke_width=0.0, idle=True).move_to([xo, yo, 0])
        cursor.autoFadeBackground = True
        self.add(cursor)

        func = MathTex(self.funcTex, color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.5)
        f_plotted = plane.plot(self.f, color=c3)
        self.add(func)

        domain = Tex("$\\Rightarrow$ What's the domain?", color=c3t, font_size=fs3).next_to(func, DOWN, buff=.6)
        range = Tex("$\\Rightarrow$ What's the range?", color=c3t, font_size=fs3).next_to(domain, DOWN, buff=.2)

        # Action Sequence
        with self.voiceover(
            text=f"""
            <prosody rate="110%">
            Alright. We're now looking at the <bookmark mark="Func"/> function {self.funcSpoken}.
            Specifically, we're examining it on the given coordinate system here.
            Now, here's the question for you:
            In this example, what is the <bookmark mark="domain"/> domain of the function?
            And, what is the <bookmark mark="range"/> range?
            </prosody>
            """
        ) as tracker:

            self.wait_until_bookmark("Func")
            self.add_pencil_sound(2)
            self.play(Write(f_plotted), run_time=2)

            self.wait_until_bookmark("domain")
            self.play(Write(domain), run_time=.5)

            self.wait_until_bookmark("range")
            self.play(Write(range), run_time=.5)

        # Wait for 4 seconds at the end of animation
        self.wait(4)


class FuncDefinitionsAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):

        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        def get_num(x):
            if x < 0:
                return "Minus " + nums[abs(x)]
            else:
                return nums[x]

        
        # Add title to the scene
        title = "Incorrect!"
        if self.isTrue:
            title = "Correct!"
        self.add_title("Domain \& Range")

        # Create the coordinate system
        plane = self.cords[0]
        self.add(self.cords)

        redx = plane.x_axis.copy().set_color(RED).set_stroke(width=4)
        y_min, y_max = plane.y_axis.n2p(self.range[0])[1], plane.y_axis.n2p(self.range[1])[1]
        redy = Line([0, y_min, 0], [0, y_max, 0]).set_color(RED).set_stroke(width=4)

        # Initialize a cursor
        xo, yo, _ = plane.c2p(0, 0)
        cursor = AltCursor(stroke_width=0.0, idle=True).move_to([xo, yo, 0])
        cursor.autoFadeBackground = True
        self.add(cursor)

        func = MathTex(self.funcTex, color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.5)
        f_plotted = plane.plot(self.f, color=c3)
        self.add(func, f_plotted)
        domain = VGroup(Tex("Domain: Input x-values", color=c3t, font_size=fs3), Tex(f"$\\rightarrow[{self.domain[0]},{self.domain[1]}]$.", color=c3t, font_size=fs3)).arrange(DOWN, buff=.2, aligned_edge=RIGHT)
        range = VGroup(Tex("Range: Output y-values", color=c3t, font_size=fs3), Tex(f"$\\rightarrow[{self.range[0]},{self.range[1]}]$.", color=c3t, font_size=fs3)).arrange(DOWN, buff=.2, aligned_edge=RIGHT)
        dr = VGroup(domain, range).arrange(DOWN, buff=.6, aligned_edge=RIGHT).next_to(func, DOWN, buff=.6)

        intro = "Unfortunately, that's incorrect!"
        if self.isTrue:
            intro = "Great job, that's correct!"
        # Action Sequence
        with self.voiceover(
                text=f"""
                <prosody rate="110%">
                {intro}
                <bookmark mark="define_domain"/>
                The domain is the set of all x-values we plug into the function.
                <break time="1s"/>
                In this example, we plug in all values on the x-axis, so all values from <bookmark mark="domain"/> {get_num(self.domain[0])} to {get_num(self.domain[1])}.
                So this is our domain.
                <break time="1s"/><bookmark mark="define_range"/>
                The range on the other hand is the set of all y-values we get from the function.
                <break time="1s"/>
                We can simply read off the values we get on the y-axis.
                From the graph, we can see that we get all values from <bookmark mark="range"/> {get_num(self.range[0])} to {get_num(self.range[1])},
                so that is the range of the function.
                </prosody>
                """
        ) as tracker:
            
            self.wait_until_bookmark("define_domain")
            self.play(Write(domain[0]), run_time=.5)

            self.wait_until_bookmark("domain")
            self.play(Write(domain[1]), run_time=.5)
            self.play(Write(redx), run_time=2)

            self.wait_until_bookmark("define_range")
            self.play(Write(range[0]), run_time=.5)

            self.wait_until_bookmark("range")
            self.play(Write(range[1]), run_time=.5)
            self.play(Write(redy), run_time=2)

        # Wait for 4 seconds at the end of animation
        self.wait(4)



#################################################
#################################################

TASK_Func_1_2_P_2_1_q = SophiaTaskDefinition(
    answerOptions = ["$D=[-3,3],\,W=[-3,6]$", "$D=[-3,6],\,W=[-3,6]$", "$D=[-3,3],\,W=[-3,3]$", "$D=[-3,6],\,W=[-3,3]$"],
    correctAnswerIndex = 0,
    questionText = "What are the domain D and range W?"
)

class Func_1_2_P_2_1_q(FuncDefinitionsQuestionScene):

    def construct(self):

        # Setting up the specific function
        self.funcTex = "f(x)=x^2-3"
        self.f = lambda x: x**2-3
        self.funcSpoken = "f of x equals x squared minus three"
        self.cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 6],
                               x_labels=[-3, 0, 3], y_labels=[-6, 0, 6])

        # Adding initial components to the scene
        super().construct()

class Func_1_2_P_2_1_a(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2-3"
        self.f = lambda x: x**2-3
        self.funcSpoken = "f of x equals x squared minus three"
        self.cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 6],
                               x_labels=[-3, 0, 3], y_labels=[-6, 0, 6])
        self.isTrue = True
        self.domain = [-3,3]
        self.range = [-3,6]
        super().construct()

class Func_1_2_P_2_1_b(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2-3"
        self.f = lambda x: x**2-3
        self.funcSpoken = "f of x equals x squared minus three"
        self.cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 6],
                               x_labels=[-3, 0, 3], y_labels=[-6, 0, 6])
        self.isTrue = False
        self.domain = [-3,3]
        self.range = [-3,6]
        super().construct()

class Func_1_2_P_2_1_c(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2-3"
        self.f = lambda x: x**2-3
        self.funcSpoken = "f of x equals x squared minus three"
        self.cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 6],
                               x_labels=[-3, 0, 3], y_labels=[-6, 0, 6])
        self.isTrue = False
        self.domain = [-3,3]
        self.range = [-3,6]
        super().construct()

class Func_1_2_P_2_1_d(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2-3"
        self.f = lambda x: x**2-3
        self.funcSpoken = "f of x equals x squared minus three"
        self.cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 6],
                               x_labels=[-3, 0, 3], y_labels=[-6, 0, 6])
        self.isTrue = False
        self.domain = [-3,3]
        self.range = [-3,6]
        super().construct()



#################################################
#################################################

TASK_Func_1_2_P_2_2_q = SophiaTaskDefinition(
    answerOptions = ["$D=[-10,6],\,W=[-2,2]$", "$D=[-1,2],\,W=[1,3]$", "$D=[-2,2],\,W=[-6,10]$", "$D=[-2,2],\,W=[-10,6]$"],
    correctAnswerIndex = 2,
    questionText = "What are the domain D and range W?"
)

class Func_1_2_P_2_2_q(FuncDefinitionsQuestionScene):

    def construct(self):
        # Setting up the specific function
        self.funcTex = "f(x)=x^3+2"
        self.f = lambda x: x**3+2
        self.funcSpoken = "f of x equals x cubed plus two"
        self.cords = self.add_cords([-2, 2, 1], [-8, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-8, 0, 10],
                               x_labels=[-2, 0, 2], y_labels=[-8, 0, 10])
        # Adding initial components to the scene
        super().construct()

class Func_1_2_P_2_2_a(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^3+2"
        self.f = lambda x: x**3+2
        self.funcSpoken = "f of x equals x cubed plus two"
        self.cords = self.add_cords([-2, 2, 1], [-8, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-8, 0, 10],
                               x_labels=[-2, 0, 2], y_labels=[-8, 0, 10])
        self.isTrue = False
        self.domain = [-1,9]
        self.range = [-2,2]
        super().construct()

class Func_1_2_P_2_2_b(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^3+2"
        self.f = lambda x: x**3+2
        self.funcSpoken = "f of x equals x cubed plus two"
        self.cords = self.add_cords([-2, 2, 1], [-8, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-8, 0, 10],
                               x_labels=[-2, 0, 2], y_labels=[-8, 0, 10])
        self.isTrue = False
        self.domain = [-1,9]
        self.range = [-2,2]
        super().construct()

class Func_1_2_P_2_2_c(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^3+2"
        self.f = lambda x: x**3+2
        self.funcSpoken = "f of x equals x cubed plus two"
        self.cords = self.add_cords([-2, 2, 1], [-8, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-8, 0, 10],
                               x_labels=[-2, 0, 2], y_labels=[-8, 0, 10])
        self.isTrue = True
        self.domain = [-1,9]
        self.range = [-2,2]
        super().construct()

class Func_1_2_P_2_2_d(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^3+2"
        self.f = lambda x: x**3+2
        self.funcSpoken = "f of x equals x cubed plus two"
        self.cords = self.add_cords([-2, 2, 1], [-8, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-8, 0, 10],
                               x_labels=[-2, 0, 2], y_labels=[-8, 0, 10])
        self.isTrue = False
        self.domain = [-1,9]
        self.range = [-2,2]
        super().construct()

#################################################
#################################################

TASK_Func_1_2_P_2_3_q = SophiaTaskDefinition(
    answerOptions = ["$D=[-3,3],\,W=[-4,4]$", "$D=[-2,2],\,W=[-4,4]$", "$D=[-4,4],\,W=[-2,2]$", "$D=[-4,4],\,W=[-3,3]$"],
    correctAnswerIndex = 1,
    questionText = "What are the domain D and range W?"
)

class Func_1_2_P_2_3_q(FuncDefinitionsQuestionScene):

    def construct(self):
        # Setting up the specific function
        self.funcTex = "f(x)=2x"
        self.f = lambda x: 2*x
        self.funcSpoken = "f of x equals two times x"
        self.cords = self.add_cords([-2, 2, 1], [-4, 4, 1], x_ticks=[-2, 0, 2], y_ticks=[-4, 0, 4],
                               x_labels=[-2, 0, 2], y_labels=[-4, 0, 4])
        # Adding initial components to the scene
        super().construct()

class Func_1_2_P_2_3_a(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=2x"
        self.f = lambda x: 2*x
        self.funcSpoken = "f of x equals two times x"
        self.cords = self.add_cords([-2, 2, 1], [-4, 4, 1], x_ticks=[-2, 0, 2], y_ticks=[-4, 0, 4],
                               x_labels=[-2, 0, 2], y_labels=[-4, 0, 4])
        self.isTrue = True  # Set to True for the correct answer
        self.domain = [-2,2]
        self.range = [-4,4]
        super().construct()

class Func_1_2_P_2_3_b(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=2x"
        self.f = lambda x: 2*x
        self.funcSpoken = "f of x equals two times x"
        self.cords = self.add_cords([-2, 2, 1], [-4, 4, 1], x_ticks=[-2, 0, 2], y_ticks=[-4, 0, 4],
                               x_labels=[-2, 0, 2], y_labels=[-4, 0, 4])
        self.isTrue = False
        self.domain = [-2,2]
        self.range = [-4,4]
        super().construct()

class Func_1_2_P_2_3_c(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=2x"
        self.f = lambda x: 2*x
        self.funcSpoken = "f of x equals two times x"
        self.cords = self.add_cords([-2, 2, 1], [-4, 4, 1], x_ticks=[-2, 0, 2], y_ticks=[-4, 0, 4],
                               x_labels=[-2, 0, 2], y_labels=[-4, 0, 4])
        self.isTrue = False
        self.domain = [-2,2]
        self.range = [-4,4]
        super().construct()

class Func_1_2_P_2_3_d(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=2x"
        self.f = lambda x: 2*x
        self.funcSpoken = "f of x equals two times x"
        self.cords = self.add_cords([-2, 2, 1], [-4, 4, 1], x_ticks=[-2, 0, 2], y_ticks=[-4, 0, 4],
                               x_labels=[-2, 0, 2], y_labels=[-4, 0, 4])
        self.isTrue = False
        self.domain = [-2,2]
        self.range = [-4,4]
        super().construct()


#################################################
#################################################

TASK_Func_1_2_P_2_4_q = SophiaTaskDefinition(
    answerOptions = ["$D=[-3,3],\,W=[-17,7]$", "$D=[-17,7],\,W=[-3,3]$", "$D=[-3,3],\,W=[-3,3]$", "$D=[-17,17],\,W=[-3,3]$"],
    correctAnswerIndex = 0,
    questionText = "What are the domain D and range W?"
)

class Func_1_2_P_2_4_q(FuncDefinitionsQuestionScene):

    def construct(self):
        # Setting up the specific function
        self.funcTex = "f(x)=4x-5"
        self.f = lambda x: 4*x - 5
        self.funcSpoken = "f of x equals four times x minus five"
        self.cords = self.add_cords([-3, 3, 1], [-12, 12, 4], x_ticks=[-3, 0, 3], y_ticks=[-12, 0, 12],
                               x_labels=[-3, 0, 3], y_labels=[-12, 0, 12])
        # Adding initial components to the scene
        super().construct()

class Func_1_2_P_2_4_a(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=4x-5"
        self.f = lambda x: 4*x - 5
        self.funcSpoken = "f of x equals four times x minus five"
        self.cords = self.add_cords([-3, 3, 1], [-12, 12, 4], x_ticks=[-3, 0, 3], y_ticks=[-12, 0, 12],
                               x_labels=[-3, 0, 3], y_labels=[-12, 0, 12])
        self.isTrue = True  # Set to True for the correct answer
        self.domain = [-3,3]
        self.range = [-17,7]
        super().construct()

class Func_1_2_P_2_4_b(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=4x-5"
        self.f = lambda x: 4*x - 5
        self.funcSpoken = "f of x equals four times x minus five"
        self.cords = self.add_cords([-3, 3, 1], [-12, 12, 4], x_ticks=[-3, 0, 3], y_ticks=[-12, 0, 12],
                               x_labels=[-3, 0, 3], y_labels=[-12, 0, 12])
        self.isTrue = False
        self.domain = [-3,3]
        self.range = [-3,3]
        super().construct()

class Func_1_2_P_2_4_c(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=4x-5"
        self.f = lambda x: 4*x - 5
        self.funcSpoken = "f of x equals four times x minus five"
        self.cords = self.add_cords([-3, 3, 1], [-12, 12, 4], x_ticks=[-3, 0, 3], y_ticks=[-12, 0, 12],
                               x_labels=[-3, 0, 3], y_labels=[-12, 0, 12])
        self.isTrue = False
        self.domain = [-3,3]
        self.range = [-3,3]
        super().construct()

class Func_1_2_P_2_4_d(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=4x-5"
        self.f = lambda x: 4*x - 5
        self.funcSpoken = "f of x equals four times x minus five"
        self.cords = self.add_cords([-3, 3, 1], [-12, 12, 4], x_ticks=[-3, 0, 3], y_ticks=[-12, 0, 12],
                               x_labels=[-3, 0, 3], y_labels=[-12, 0, 12])
        self.isTrue = False
        self.domain = [-3,3]
        self.range = [-3,3]
        super().construct()


#################################################
#################################################

TASK_Func_1_2_P_2_5_q = SophiaTaskDefinition(
    answerOptions = ["$D=[-3,3],\,W=[-10,10]$", "$D=[-10,10],\,W=[-4,4]$", "$D=[-3,10],\,W=[4,10]$", "$D=[-3,3],\,W=[-4,10]$"],
    correctAnswerIndex = 3,
    questionText = "What are the domain D and range W?"   
)

class Func_1_2_P_2_5_q(FuncDefinitionsQuestionScene):

    def construct(self):
        # Setting up the specific function
        self.funcTex = "f(x)=x^2+x-2"
        self.f = lambda x: x**2 + x - 2
        self.funcSpoken = "f of x equals x squared plus x minus two"
        self.cords = self.add_cords([-3, 3, 1], [-6, 10, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 10],
                               x_labels=[-3, 0, 3], y_labels=[-6, 0, 10])
        # Adding initial components to the scene
        super().construct()

class Func_1_2_P_2_5_a(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2+x-2"
        self.f = lambda x: x**2 + x - 2
        self.funcSpoken = "f of x equals x squared plus x minus two"
        self.cords = self.add_cords([-3, 3, 1], [-6, 10, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 10],
                               x_labels=[-3, 0, 3], y_labels=[-6, 0, 10])
        self.isTrue = False
        self.domain = [-3,3]
        self.range = [-10,10]
        super().construct()

class Func_1_2_P_2_5_b(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2+x-2"
        self.f = lambda x: x**2 + x - 2
        self.funcSpoken = "f of x equals x squared plus x minus two"
        self.cords = self.add_cords([-3, 3, 1], [-6, 10, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 10],
                               x_labels=[-3, 0, 3], y_labels=[-6, 0, 10])
        self.isTrue = False
        self.domain = [-3,3]
        self.range = [-3,10]
        super().construct()

class Func_1_2_P_2_5_c(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2+x-2"
        self.f = lambda x: x**2 + x - 2
        self.funcSpoken = "f of x equals x squared plus x minus two"
        self.cords = self.add_cords([-3, 3, 1], [-6, 10, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 10],
                               x_labels=[-3, 0, 3], y_labels=[-6, 0, 10])
        self.isTrue = False
        self.domain = [-3,3]
        self.range = [-3,10]
        super().construct()

class Func_1_2_P_2_5_d(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2+x-2"
        self.f = lambda x: x**2 + x - 2
        self.funcSpoken = "f of x equals x squared plus x minus two"
        self.cords = self.add_cords([-3, 3, 1], [-6, 10, 2], x_ticks=[-3, 0, 3], y_ticks=[-6, 0, 10],
                               x_labels=[-3, 0, 3], y_labels=[-6, 0, 10])
        self.isTrue = True  # Set to True for the correct answer
        self.domain = [-3,3]
        self.range = [-4,10]
        super().construct()


#################################################
#################################################

TASK_Func_1_2_P_2_6_q = SophiaTaskDefinition(
    answerOptions = ["$D=[-2,3],\,W=[9,17]$", "$D=[-2,2],\,W=[-1,12]$", "$D=[-10,10],\,W=[9,17]$", "$D=[0,10],\,W=[-3,3]$"],
    correctAnswerIndex = 0,
    questionText = "What are the domain D and range W?"
)

class Func_1_2_P_2_6_q(FuncDefinitionsQuestionScene):

    def construct(self):
        # Setting up the specific function
        self.funcTex = "f(x)=3x^2-2x+1"
        self.f = lambda x: 3*x**2 - 2*x + 1
        self.funcSpoken = "f of x equals three times x squared minus two times x plus one"
        self.cords = self.add_cords([-2, 2, 1], [-2, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-2, 0, 10],
                               x_labels=[-2, 0, 2], y_labels=[-2, 0, 10])
        # Adding initial components to the scene
        super().construct()

class Func_1_2_P_2_6_a(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=3x^2-2x+1"
        self.f = lambda x: 3*x**2 - 2*x + 1
        self.funcSpoken = "f of x equals three times x squared minus two times x plus one"
        self.cords = self.add_cords([-2, 2, 1], [-2, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-2, 0, 10],
                               x_labels=[-2, 0, 2], y_labels=[-2, 0, 10])
        self.isTrue = True  # Set to True for the correct answer
        self.domain = [-2,3]
        self.range = [9,17]
        super().construct()

class Func_1_2_P_2_6_b(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=3x^2-2x+1"
        self.f = lambda x: 3*x**2 - 2*x + 1
        self.funcSpoken = "f of x equals three times x squared minus two times x plus one"
        self.cords = self.add_cords([-2, 2, 1], [-2, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-2, 0, 10],
                               x_labels=[-2, 0, 2], y_labels=[-2, 0, 10])
        self.isTrue = False
        self.domain = [-2,3]
        self.range = [-1,12]
        super().construct()

class Func_1_2_P_2_6_c(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=3x^2-2x+1"
        self.f = lambda x: 3*x**2 - 2*x + 1
        self.funcSpoken = "f of x equals three times x squared minus two times x plus one"
        self.cords = self.add_cords([-2, 2, 1], [-2, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-2, 0, 10],
                               x_labels=[-2, 0, 2], y_labels=[-2, 0, 10])
        self.isTrue = False
        self.domain = [-2,3]
        self.range = [9,17]
        super().construct()

class Func_1_2_P_2_6_d(FuncDefinitionsAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=3x^2-2x+1"
        self.f = lambda x: 3*x**2 - 2*x + 1
        self.funcSpoken = "f of x equals three times x squared minus two times x plus one"
        self.cords = self.add_cords([-2, 2, 1], [-2, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-2, 0, 10],
                               x_labels=[-2, 0, 2], y_labels=[-2, 0, 10])
        self.isTrue = False
        self.domain = [-2,3]
        self.range = [-3,3]
        super().construct()







# Add the scene to prototypes
PROTOTYPES = [
    PagePrototypeVideo.from_scene(Func_1_2_I_1),
    PagePrototypeVideo.from_scene(Func_1_2_I_2),
    PagePrototypeVideo.from_scene(Func_1_2_I_2_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_2_I_2_1_q, Func_1_2_I_2_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_2_I_2_1_a),
    PagePrototypeVideo.from_scene(Func_1_2_I_2_1_b),
    PagePrototypeVideo.from_scene(Func_1_2_I_2_1_c),
    PagePrototypeVideo.from_scene(Func_1_2_I_3),
    PagePrototypeVideo.from_scene(Func_1_2_I_4),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_2_P_1_1_q, Func_1_2_P_1_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_1_a),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_1_b),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_1_c),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_2_P_1_2_q, Func_1_2_P_1_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_2_a),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_2_b),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_2_c),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_2_P_1_3_q, Func_1_2_P_1_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_3_a),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_3_b),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_3_c),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_2_P_1_4_q, Func_1_2_P_1_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_4_a),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_4_b),
    PagePrototypeVideo.from_scene(Func_1_2_P_1_4_c),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_2_P_2_1_q, Func_1_2_P_2_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_1_a),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_1_b),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_1_c),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_1_d),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_2_P_2_2_q, Func_1_2_P_2_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_2_a),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_2_b),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_2_c),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_2_d),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_2_P_2_3_q, Func_1_2_P_2_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_3_a),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_3_b),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_3_c),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_3_d),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_2_P_2_4_q, Func_1_2_P_2_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_4_a),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_4_b),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_4_c),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_4_d),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_5_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_2_P_2_5_q, Func_1_2_P_2_5_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_5_a),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_5_b),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_5_c),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_5_d),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_6_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_2_P_2_6_q, Func_1_2_P_2_6_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_6_a),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_6_b),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_6_c),
    PagePrototypeVideo.from_scene(Func_1_2_P_2_6_d),
]
scenes/Func/Func_1: Intro Functions/Func1_2.py
Sophia-Edu-Labs/sophia-math
# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import *
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition

#####################################
#####################################

TASK_Func_1_3_I_1_q = SophiaTaskDefinition(
    answerOptions = ["$-1$", "$0$", "$1$", "$2$"],
    correctAnswerIndex = 2,
    questionText = "At which $x$ value is the zero crossing of the red function?"
)

class Func_1_3_I_1_q(SophiaCursorScene):
    def construct(self):
        super().construct()
        self.add_mathgrid()

        cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, -1, 1, 3], y_ticks=[-6, -3, 3, 6]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        self.add_title("Intersections")

        funcBlue = lambda x: 3 - x
        funcRed = lambda x: 2 * x - 2
        graphBlue = plane.plot(funcBlue, color=c3)
        graphRed = plane.plot(funcRed, color=c2)

        with self.voiceover(
            text=f"""
            So, now we are learning something new about functions: intersections with the axes.
            Remember, there are two axes: The <bookmark mark='axis_x'/> x-axis and the <bookmark mark='axis_y'/>
            y axis.
            <break time="1s"/>
            First, we are interested in the intersection point of a function with the <bookmark mark='axis_x_2'/> x-axis. 
            This point is also called the "zero", or the "zero crossing", because the value of y is always zero there.
            <break time="1s"/>
            Look at the <bookmark mark="funcBlue"/> blue function. The intersection point with the x-axis is at the position
            <bookmark mark="x1"/> x equals three. This means the zero crossing is three.
            <break time="1s"/>
            Now look at the <bookmark mark="funcRed"/> red function.
            <break time="1s"/>
            What is the value of x at the zero crossing of this function?
            """
        ) as tracker:
            self.wait_until_bookmark("axis_x")
            plane.x_axis.set_color(RED)

            self.wait_until_bookmark("axis_y")
            plane.y_axis.set_color(RED)
            plane.x_axis.set_color(c1)
            self.wait(1)
            plane.y_axis.set_color(c1)

            self.wait_until_bookmark("axis_x_2")
            plane.x_axis.set_color(RED)
            self.wait(1)
            plane.x_axis.set_color(c1)

            self.wait_until_bookmark("funcBlue")
            self.play(Write(graphBlue))

            self.wait_until_bookmark("x1")
            x1 = plane.x_axis.n2p(3)
            circ1 = Circle(radius=0.1, color=c3).move_to(x1)
            self.play(Write(circ1))

            self.wait_until_bookmark("funcRed")
            self.play(Write(graphRed))

        self.wait(4)

class Func_1_3_I_1_a(SophiaCursorScene):
    def construct(self):
        super().construct()
        self.add_mathgrid()

        cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, -1, 1, 3], y_ticks=[-6, -3, 3, 6]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        self.add_title("Zero Crossing")

        funcRed = lambda x: 2 * x - 2
        graphRed = plane.plot(funcRed, color=c2)
        self.add(graphRed)

        b = Bubble(texts = ["Zero crossing", "at $x=1$"], center=np.array([.6,-1.6, 0]), start_point=plane.c2p(1,0)+[.2,-0.2,0], width=2.5, height = 0.8, loc="t2")

        with self.voiceover(
            text=f"""
            That's not correct.
            The zero crossing is the point where the graph intersects the<bookmark mark="axis_x"/> x-axis.
            <break time="1s"/>
            As we can see from the graph, the point where the graph of the red function intersects
            the x-axis, is at the position <bookmark mark="x1"/> x equals one.
            <break time="1s"/>
            <bookmark mark="bubble"/>
            So the zero crossing of the red function is at the position x equals one.
            """
        ) as tracker:


            self.wait_until_bookmark("axis_x")
            plane.x_axis.set_color(RED)
            self.wait(1)
            plane.x_axis.set_color(c1)

            self.wait_until_bookmark("x1")
            circ = Circle(radius=0.1, color=c2).move_to(plane.x_axis.n2p(1))
            self.play(Write(circ))

            self.wait_until_bookmark("bubble")
            self.add_pencil_sound(1.5)
            self.play(Create(b), Create(b.text))

        self.wait(4)

class Func_1_3_I_1_b(SophiaCursorScene):
    def construct(self):
        super().construct()
        self.add_mathgrid()

        cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, -1, 1, 3], y_ticks=[-6, -3, 3, 6]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        self.add_title("Zero Crossing")

        funcRed = lambda x: 2 * x - 2
        graphRed = plane.plot(funcRed, color=c2)
        self.add(graphRed)

        b = Bubble(texts = ["Zero crossing", "at $x=1$"], center=np.array([.6,-1.6, 0]), start_point=plane.c2p(1,0)+[.2,-0.2,0], width=2.5, height = 0.8, loc="t2")

        with self.voiceover(
            text=f"""
            That's not correct.
            The zero crossing is the point where the graph intersects the<bookmark mark="axis_x"/> x-axis.
            <break time="1s"/>
            As we can see from the graph, the point where the graph of the red function intersects
            the x-axis, is at the position <bookmark mark="x1"/> x equals one.
            <break time="1s"/>
            <bookmark mark="bubble"/>
            So the zero crossing of the red function is at the position x equals one.
            """
        ) as tracker:


            self.wait_until_bookmark("axis_x")
            plane.x_axis.set_color(RED)
            self.wait(1)
            plane.x_axis.set_color(c1)

            self.wait_until_bookmark("x1")
            circ = Circle(radius=0.1, color=c2).move_to(plane.x_axis.n2p(1))
            self.play(Write(circ))

            self.wait_until_bookmark("bubble")
            self.add_pencil_sound(1.5)
            self.play(Create(b), Create(b.text))

        self.wait(4)

class Func_1_3_I_1_c(SophiaCursorScene):
    def construct(self):
        super().construct()
        self.add_mathgrid()

        cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, -1, 1, 3], y_ticks=[-6, -3, 3, 6]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        self.add_title("Zero Crossing")

        funcRed = lambda x: 2 * x - 2
        graphRed = plane.plot(funcRed, color=c2)
        self.add(graphRed)

        b = Bubble(texts = ["Zero crossing", "at $x=1$"], center=np.array([.6,-1.6, 0]), start_point=plane.c2p(1,0)+[.2,-0.2,0], width=2.5, height = 0.8, loc="t2")

        with self.voiceover(
            text=f"""
            That's correct, nice job.
            The zero crossing is the point where the graph intersects the<bookmark mark="axis_x"/> x-axis.
            <break time="1s"/>
            As we can see from the graph, the point where the graph of the red function intersects
            the x-axis, is at the position <bookmark mark="x1"/> x equals one.
            <break time="1s"/>
            <bookmark mark="bubble"/>
            So the zero crossing of the red function is at the position x equals one.
            """
        ) as tracker:


            self.wait_until_bookmark("axis_x")
            plane.x_axis.set_color(RED)
            self.wait(1)
            plane.x_axis.set_color(c1)

            self.wait_until_bookmark("x1")
            circ = Circle(radius=0.1, color=c2).move_to(plane.x_axis.n2p(1))
            self.play(Write(circ))

            self.wait_until_bookmark("bubble")
            self.add_pencil_sound(1.5)
            self.play(Create(b), Create(b.text))

        self.wait(4)

class Func_1_3_I_1_d(SophiaCursorScene):
    def construct(self):
        super().construct()
        self.add_mathgrid()

        cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, -1, 1, 3], y_ticks=[-6, -3, 3, 6]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        self.add_title("Zero Crossing")

        funcRed = lambda x: 2 * x - 2
        graphRed = plane.plot(funcRed, color=c2)
        self.add(graphRed)

        b = Bubble(texts = ["Zero crossing", "at $x=1$"], center=np.array([.6,-1.6, 0]), start_point=plane.c2p(1,0)+[.2,-0.2,0], width=2.5, height = 0.8, loc="t2")

        with self.voiceover(
            text=f"""
            That's not correct.
            The zero crossing is the point where the graph intersects the<bookmark mark="axis_x"/> x-axis.
            <break time="1s"/>
            As we can see from the graph, the point where the graph of the red function intersects
            the x-axis, is at the position <bookmark mark="x1"/> x equals one.
            <break time="1s"/>
            <bookmark mark="bubble"/>
            So the zero crossing of the red function is at the position x equals one.
            """
        ) as tracker:


            self.wait_until_bookmark("axis_x")
            plane.x_axis.set_color(RED)
            self.wait(1)
            plane.x_axis.set_color(c1)

            self.wait_until_bookmark("x1")
            circ = Circle(radius=0.1, color=c2).move_to(plane.x_axis.n2p(1))
            self.play(Write(circ))

            self.wait_until_bookmark("bubble")
            self.add_pencil_sound(1.5)
            self.play(Create(b), Create(b.text))

        self.wait(4)


#####################################
#####################################
class Func_1_3_I_2(SophiaCursorScene):

    def construct(self):
        super().construct()
        self.add_mathgrid()

        cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3, -1, 1, 3], y_ticks=[-6, -3, 3, 6]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        self.add_title("Intersections")
        funcPink = lambda x: 2
        funcBlue = lambda x: 3 - x
        funcRed = lambda x: 2 * x - 2
        funcPurple = lambda x: x**2 + 1
        funcGreen = lambda x: (x - 1) * (x + 1) -2
        graphBlue = plane.plot(funcBlue, color=c3)
        graphRed = plane.plot(funcRed, color=c2)
        graphPurple = plane.plot(funcPurple, color=PURPLE)
        graphGreen = plane.plot(funcGreen, color=GREEN)
        graphPink = plane.plot(funcPink, color=PINK)
        self.add(graphBlue, graphRed)

        with self.voiceover(
            text=f"""
            So, the red and blue functions were both straight lines, and
            Straight lines always have exactly one zero crossing, unless they are parallel to the x-axis.
            <break time="1s"/>
            <bookmark mark="funcPink"/> The pink function is parallel to the x-axis and therefore has no zero crossing.
            <break time="1s"/>
            Now, consider <bookmark mark="funcPurple"/> the purple function.
            The function is curved and has no zero crossing.
            <break time="1s"/>
            Or look at the <bookmark mark="funcGreen"/> green function.
            It's also curved, but it has two zero crossings.
            So, as we can see: Functions can have zero,<break time=".5s"/> one, <break time=".5s"/>or multiple zero crossings.
            """
        ) as tracker:
            
            self.wait_until_bookmark("funcPink")
            self.play( Unwrite(graphRed), Unwrite(graphBlue), run_time=0.5)
            self.play( Write(graphPink), run_time=1)

            self.wait_until_bookmark("funcPurple")
            self.play(Unwrite(graphPink), run_time=0.5)
            self.play(Write(graphPurple))

            self.wait_until_bookmark("funcGreen")
            self.play(Write(graphGreen))

        self.wait(4)


#####################################
#####################################
class Func_1_3_I_3(SophiaCursorScene):

    def construct(self):
        super().construct()
        self.add_mathgrid()

        cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2, 2], y_ticks=[-3, -1, 1, 3]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        self.add_title("Determining Zero Crossings")

        funcBlue = lambda x: x - 1
        funcSquared = lambda x: (x - 1) * (x + 1)
        graphBlue = plane.plot(funcBlue, color=c3)
        graphGreen = plane.plot(funcSquared, color=GREEN)

        term0 = MathTex("f(x) = x - 1", color=c1t, font_size=fs1).next_to(plane, DOWN)
        term1 = MathTex("x - 1 = 0", color=c1t, font_size=fs1).move_to(term0)
        xval = MathTex("\\rightarrow x = 1", color=c1t, font_size=fs1).next_to(term1, DOWN)
        self.add(graphGreen)

        with self.voiceover(
            text=f"""
            So, the question now is: <bookmark mark="findZeros"/> How do I find the zero crossings of a function?
            
            We have already learned how to do this graphically.
            We simply look for all the points where the graph <bookmark mark="zeros"/> intersects the x-axis.
            Those are the points where the function value is equal to zero.
            
            The other way is: We set the function expression equal to zero and calculate the value of x.
            <bookmark mark="clear"/>
            For example, consider the function <bookmark mark="func"/> f of x equals x minus one.
            
            Then we follow two steps:
            <bookmark mark="findZero1"/> First, we set the function expression equal to zero. <bookmark mark="equal0"/>
            This gives us x minus one equals zero.
            <bookmark mark="findZero2"/> Then we solve the equation for x <bookmark mark="findX"/> and obtain x equals one.
            As we can also verify graphically, <bookmark mark="showZero"/> this is our zero crossing.
            """
        ) as tracker:

            self.wait_until_bookmark("zeros")
            circ1 = Circle(radius=0.1, color=GREEN).move_to(plane.c2p(1, 0))
            circ2 = Circle(radius=0.1, color=GREEN).move_to(plane.c2p(-1, 0))
            self.play(Write(circ2))
            self.wait(1)
            self.play(Write(circ1))

            self.wait_until_bookmark("clear")
            self.play(Unwrite(circ1), Unwrite(circ2), Unwrite(graphGreen), run_time=1)

            self.wait_until_bookmark("func")
            self.play(Write(graphBlue), Write(term0))

            self.wait_until_bookmark("equal0")
            self.play(TransformMatchingTex(term0, term1))

            self.wait_until_bookmark("findX")
            self.play(Write(xval))

            self.wait_until_bookmark("showZero")
            circ3 = Circle(radius=0.1, color=BLUE).move_to(plane.c2p(1, 0))
            self.play(Write(circ3))

        self.wait(4)


#####################################
#####################################
TASK_Func_1_3_I_4_q = SophiaTaskDefinition(
    answerOptions=["$-2,\\,2$", "$-1,\\,1$", "$1$", "$2$"],
    correctAnswerIndex=1,
    questionText="At which $x$ value is/are the zero crossing(s)?"
)

class Func_1_3_I_4_q(SophiaCursorScene):

    def construct(self):
        super().construct()
        self.add_mathgrid()

        self.add_title("Determine Zero Crossings")

        cursor = AltCursor(stroke_width=0.0, idle=False)

        mic = ImageMobject(assets_folder / "img" / "mic.png").scale(0.8).move_to([-5, 1.6, 0])
        term0 = MathTex("f(x)=x^2-1", color=c1t, font_size=fs1).next_to(mic, DOWN, buff=.6).shift(RIGHT*5)

        with self.voiceover(
            text=f"""
            Now, <bookmark mark="mic"/>it's your turn.
            We're looking at the function <bookmark mark="func"/> f of x equals x squared minus one.
            <break time="1s"/><bookmark mark="q"/>
            What are the zero crossings of that function?<break time="1s"/>
            Quick Reminder: To find the zero crossings, set the function equal to zero and solve for x.
            """
        ) as tracker:
            self.wait_until_bookmark("mic")
            self.add_shift_sound(0.5)
            self.play(mic.animate.shift(RIGHT*5), run_time=0.5)
            
            self.wait_until_bookmark("func")
            self.play(Write(term0))

            self.wait_until_bookmark("q")
            self.draw_qmark(cursor, DOWN*2.4, run_time=3)

        self.wait(4)
    
class Func_1_3_I_4_a(SophiaCursorScene):

    def construct(self):
        super().construct()
        self.add_mathgrid()

        cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,-1,1,3]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        self.add_title("Determine Zero Crossings")

        funcBlue = lambda x: x**2-1
        graphBlue = plane.plot(funcBlue, color=c3)

        term0 = MathTex("f(x)=x^2-1", color=c1t, font_size=fs2).next_to(cords, DOWN)
        term1 = MathTex("x^2-1=0", color=c1t, font_size=fs2).next_to(cords, DOWN)
        xval = MathTex("x=-1,\\, x=1", color=c1t, font_size=fs2).next_to(term1, DOWN)

        self.add(term0)

        with self.voiceover(
            text=f"""
            Hmm, that's not correct. But how do we get the right answer?
            <break time="1s"/>
            First, we <bookmark mark="note1"/> set the function's expression equal to zero.
            This gives us<bookmark mark="eq0"/> x squared minus one equals zero.
            <break time="1s"/>
            Next, we <bookmark mark="solveX"/> solve for x, and directly obtain two values for x:
            <bookmark mark="xeq"/> x equals minus one or x equals one.
            <bookmark mark="zeros"/> These are the two zero crossings of the function.
            And that's our solution!
            <break time="1s"/>
            When we look at the <bookmark mark="plot"/> graph of the function,
            we can confirm that the zero crossings are at <bookmark mark="visualZeros"/> x equals minus one and x equals one.
            """
        ) as tracker:

            self.wait_until_bookmark("eq0")
            self.play(TransformMatchingTex(term0, term1))

            self.wait_until_bookmark("xeq")
            self.play(Write(xval))

            self.wait_until_bookmark("plot")
            self.play(Write(graphBlue))

            self.wait_until_bookmark("visualZeros")
            circ1 = Circle(radius=0.1, color=BLUE).move_to(plane.c2p(-1,0))
            circ2 = Circle(radius=0.1, color=BLUE).move_to(plane.c2p(1,0))
            self.play(Write(circ1))
            self.play(Write(circ2))

        self.wait(4)

class Func_1_3_I_4_b(SophiaCursorScene):

    def construct(self):
        super().construct()
        self.add_mathgrid()

        cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,-1,1,3]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        self.add_title("Determine Zero Crossings")

        funcBlue = lambda x: x**2-1
        graphBlue = plane.plot(funcBlue, color=c3)

        term0 = MathTex("f(x)=x^2-1", color=c1t, font_size=fs2).next_to(cords, DOWN)
        term1 = MathTex("x^2-1=0", color=c1t, font_size=fs2).next_to(cords, DOWN)
        xval = MathTex("x=-1,\\, x=1", color=c1t, font_size=fs2).next_to(term1, DOWN)

        self.add(term0)

        with self.voiceover(
            text=f"""
            Great, that's correct!
            <break time="1s"/>
            First, we <bookmark mark="note1"/> set the function's expression equal to zero.
            This gives us<bookmark mark="eq0"/> x squared minus one equals zero.
            <break time="1s"/>
            Next, we <bookmark mark="solveX"/> solve for x, and directly obtain two values for x:
            <bookmark mark="xeq"/> x equals minus one or x equals one.
            <bookmark mark="zeros"/> These are the two zero crossings of the function.
            And that's our solution!
            <break time="1s"/>
            When we look at the <bookmark mark="plot"/> graph of the function,
            we can confirm that the zero crossings are at <bookmark mark="visualZeros"/> x equals minus one and x equals one.
            """
        ) as tracker:

            self.wait_until_bookmark("eq0")
            self.play(TransformMatchingTex(term0, term1))

            self.wait_until_bookmark("xeq")
            self.play(Write(xval))

            self.wait_until_bookmark("plot")
            self.play(Write(graphBlue))

            self.wait_until_bookmark("visualZeros")
            circ1 = Circle(radius=0.1, color=BLUE).move_to(plane.c2p(-1,0))
            circ2 = Circle(radius=0.1, color=BLUE).move_to(plane.c2p(1,0))
            self.play(Write(circ1))
            self.play(Write(circ2))

        self.wait(4)


class Func_1_3_I_4_c(SophiaCursorScene):

    def construct(self):
        super().construct()
        self.add_mathgrid()

        cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,-1,1,3]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        self.add_title("Determine Zero Crossings")

        funcBlue = lambda x: x**2-1
        graphBlue = plane.plot(funcBlue, color=c3)

        term0 = MathTex("f(x)=x^2-1", color=c1t, font_size=fs2).next_to(cords, DOWN)
        term1 = MathTex("x^2-1=0", color=c1t, font_size=fs2).next_to(cords, DOWN)
        xval = MathTex("x=-1,\\, x=1", color=c1t, font_size=fs2).next_to(term1, DOWN)

        self.add(term0)

        with self.voiceover(
            text=f"""
            Hmm, that's not correct. But how do we get the right answer?
            <break time="1s"/>
            First, we <bookmark mark="note1"/> set the function's expression equal to zero.
            This gives us<bookmark mark="eq0"/> x squared minus one equals zero.
            <break time="1s"/>
            Next, we <bookmark mark="solveX"/> solve for x, and directly obtain two values for x:
            <bookmark mark="xeq"/> x equals minus one or x equals one.
            <bookmark mark="zeros"/> These are the two zero crossings of the function.
            And that's our solution!
            <break time="1s"/>
            When we look at the <bookmark mark="plot"/> graph of the function,
            we can confirm that the zero crossings are at <bookmark mark="visualZeros"/> x equals minus one and x equals one.
            """
        ) as tracker:

            self.wait_until_bookmark("eq0")
            self.play(TransformMatchingTex(term0, term1))

            self.wait_until_bookmark("xeq")
            self.play(Write(xval))

            self.wait_until_bookmark("plot")
            self.play(Write(graphBlue))

            self.wait_until_bookmark("visualZeros")
            circ1 = Circle(radius=0.1, color=BLUE).move_to(plane.c2p(-1,0))
            circ2 = Circle(radius=0.1, color=BLUE).move_to(plane.c2p(1,0))
            self.play(Write(circ1))
            self.play(Write(circ2))

        self.wait(4)


class Func_1_3_I_4_d(SophiaCursorScene):

    def construct(self):
        super().construct()
        self.add_mathgrid()

        cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,-1,1,3]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        self.add_title("Determine Zero Crossings")

        funcBlue = lambda x: x**2-1
        graphBlue = plane.plot(funcBlue, color=c3)

        term0 = MathTex("f(x)=x^2-1", color=c1t, font_size=fs2).next_to(cords, DOWN)
        term1 = MathTex("x^2-1=0", color=c1t, font_size=fs2).next_to(cords, DOWN)
        xval = MathTex("x=-1,\\, x=1", color=c1t, font_size=fs2).next_to(term1, DOWN)

        self.add(term0)

        with self.voiceover(
            text=f"""
            Hmm, that's not correct. But how do we get the right answer?
            <break time="1s"/>
            First, we <bookmark mark="note1"/> set the function's expression equal to zero.
            This gives us<bookmark mark="eq0"/> x squared minus one equals zero.
            <break time="1s"/>
            Next, we <bookmark mark="solveX"/> solve for x, and directly obtain two values for x:
            <bookmark mark="xeq"/> x equals minus one or x equals one.
            <bookmark mark="zeros"/> These are the two zero crossings of the function.
            And that's our solution!
            <break time="1s"/>
            When we look at the <bookmark mark="plot"/> graph of the function,
            we can confirm that the zero crossings are at <bookmark mark="visualZeros"/> x equals minus one and x equals one.
            """
        ) as tracker:

            self.wait_until_bookmark("eq0")
            self.play(TransformMatchingTex(term0, term1))

            self.wait_until_bookmark("xeq")
            self.play(Write(xval))

            self.wait_until_bookmark("plot")
            self.play(Write(graphBlue))

            self.wait_until_bookmark("visualZeros")
            circ1 = Circle(radius=0.1, color=BLUE).move_to(plane.c2p(-1,0))
            circ2 = Circle(radius=0.1, color=BLUE).move_to(plane.c2p(1,0))
            self.play(Write(circ1))
            self.play(Write(circ2))

        self.wait(4)

#####################################
#####################################
class Func_1_3_I_5(SophiaCursorScene):

    def construct(self):
        super().construct()
        self.add_mathgrid()


        cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,-1,1,3]).shift(0.4*DOWN)
        plane = cords[0]
        self.add(cords)

        self.add_title("Intersection with y-axis")

        funcBlue = lambda x: x**2-1
        graphBlue = plane.plot(funcBlue, color=c3)
        funcGreen = lambda x: x+2
        graphGreen = plane.plot(funcGreen, color=GREEN)

        instruct = VGroup(Tex("a) Plug $x=0$ into the\\\\function expression", color=c1t, font_size=fs3, tex_environment="flushright"), Tex("b) Find the intersection\\\\graphically", color=c1t, font_size=fs3, tex_environment="flushright")).arrange(DOWN, buff=.4, aligned_edge=LEFT).next_to(cords, DOWN, buff=.6)

        # "", "b) Read the intersection point graphically."

        termBlue = MathTex("f(x)=x^2-1", color=c1t, font_size=fs2)
        termBlueZero = MathTex("f(0)=0^2-1=-1", color=c1t, font_size=fs2)
        blue_terms = VGroup(termBlue, termBlueZero).arrange(DOWN, buff=.2, aligned_edge=LEFT).next_to(cords, DOWN, buff=.6)
        termGreen = MathTex("g(x)=x+2", color=c1t, font_size=fs2)
        termGreenZero = MathTex("g(0)=0+2=2", color=c1t, font_size=fs2)
        green_terms = VGroup(termGreen, termGreenZero).arrange(DOWN, buff=.2, aligned_edge=LEFT).next_to(cords, DOWN, buff=.6)

        with self.voiceover(
            text=f"""
            Now, let's focus on the intersection points with the y axis.
            One way to find the intersection points with the y-axis is to <bookmark mark="instruct_1"/>plug x equals zero into the function expression.
            <break time="1s"/>
            Another way to find the intersection point with the y-axis is, <bookmark mark="instruct_2"/> to read it off from the graph.
            <break time="1s"/>
            Let's practice using two examples.
            <break time="1s"/>Example Number one. <bookmark mark="clear"/>
            Consider the function f of x equals x squared minus one.
            To find the intersection point with the y axis, we simply plug in <bookmark mark="substitute"/> x equals zero.
            We get f of zero equals zero squared minus one, which equals negative one. So the intersection point is at y equals minus one.
            <bookmark mark="blue"/> We can confirm this visually: The graph intersects the y axis at <bookmark mark="cross1"/> y equals minus one.
            <break time="1s"/>Example Number Two.
            Look at the function <bookmark mark="green1"/> g of x equals x plus two.
            Plugging in <bookmark mark="subGreen"/> x equals zero gives us the value two, which is also the intersection point with the y axis.
            Again, we can <bookmark mark="green2"/> visually confirm this: The graph intersects the y axis at <bookmark mark="cross2"/> y equals two.
            """
        ) as tracker:
            
            self.wait_until_bookmark("instruct_1")
            self.play(Write(instruct[0]))

            self.wait_until_bookmark("instruct_2")
            self.play(Write(instruct[1]))

            self.wait_until_bookmark("clear")
            self.play(Unwrite(instruct), run_time=.3)
            self.wait(1)
            self.play(Write(termBlue))

            self.wait_until_bookmark("substitute")
            self.play(Write(termBlueZero))

            self.wait_until_bookmark("blue")
            self.add_pencil_sound(1)
            self.play(Write(graphBlue), run_time=1)

            self.wait_until_bookmark("cross1")
            circ = Circle(radius=0.1, color=BLUE).move_to(plane.c2p(0,-1))
            self.play(Write(circ))

            self.wait_until_bookmark("green1")
            self.play(TransformMatchingTex(termBlue, termGreen), Unwrite(graphBlue), Unwrite(termBlueZero), Unwrite(circ))

            self.wait_until_bookmark("subGreen")
            self.play(Write(termGreenZero))

            self.wait_until_bookmark("green2")
            self.add_pencil_sound(1)
            self.play(Write(graphGreen), run_time=1)

            self.wait_until_bookmark("cross2")
            circ = Circle(radius=0.1, color=GREEN).move_to(plane.c2p(0,2))
            self.play(Write(circ))

        self.wait(4)



#####################################
#####################################
### Practice Part
#####################################
#####################################

#####################################
#####################################

class xCrossingQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    @abstractmethod
    def construct(self):
        super().construct()
        self.add_mathgrid()

        func = MathTex(self.funcTex, color=c1t, font_size=fs1).shift(UP)
        cursor = AltCursor(stroke_width=0.0, idle=False)

        self.add_title("Intersecting Axes")

        with self.voiceover(
            text=f"""
            {self.intro}
            Consider the function <bookmark mark="writeFunc"/> {self.funcText}.
            <bookmark mark="zero"/>
            Where is the zero crossing of this function? If there's more than one:
            Where are the zero crossings?
            """
        ) as tracker:
            self.wait_until_bookmark("writeFunc")
            self.play(Write(func))

            self.wait_until_bookmark("zero")
            self.draw_qmark(cursor, DOWN*1.6, run_time=3)
            

        self.wait(4)

class xCrossingAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    @abstractmethod
    def construct(self):
        super().construct()
        self.add_mathgrid()

        func = MathTex(self.funcTex, color=c1t, font_size=fs1)
        setToZero = Tex("$\\rightarrow$ Set function equal to zero", color=RED, font_size=fs3)
        func_Zeroed = MathTex(self.funcZero, color=c1t, font_size=fs1)
        solve = Tex("$\\rightarrow$ Solve for $x$", color=RED, font_size=fs3)
        func_Zeros = MathTex(self.funcZeros, color=c1t, font_size=fs1)
        explanation = VGroup(func, setToZero, func_Zeroed, solve, func_Zeros).arrange(DOWN, buff=.2, aligned_edge=LEFT)

        self.cords.shift(DOWN)
        plane = self.cords[0]
        plot = plane.plot(self.func, color=BLUE)

        self.add_title("Intersecting Axes")

        with self.voiceover(
            text=f"""
            {self.intro}
            So, we start with the function <bookmark mark="writeFunc"/> {self.funcText}.
            <break time="1s"/>
            First, we <bookmark mark="setToZero1"/> set this function equal to zero, which gives us <bookmark mark="setToZero2"/> {self.ZeroText}.
            Then, <bookmark mark="solve1"/> we solve the equation for x, and <bookmark mark="solve2"/> we obtain {self.ZerosText}.
            <break time="1s"/>
            We can also <bookmark mark="clear"/> graphically verify this solution.
            <break time="1s"/>
            <bookmark mark="plot"/>Here's the graph of our function.
            As you can see <bookmark mark="crossing"/>, the graph intersects the x-axis at {self.ZerosText}.
            """
        ) as tracker:
            self.wait_until_bookmark("writeFunc")
            self.play(Write(func))

            self.wait_until_bookmark("setToZero1")
            self.play(Write(setToZero), run_time=0.5)

            self.wait_until_bookmark("setToZero2")
            self.play(Write(func_Zeroed))

            self.wait_until_bookmark("solve1")
            self.play(Write(solve), run_time=0.5)

            self.wait_until_bookmark("solve2")
            self.play(Write(func_Zeros))

            self.wait_until_bookmark("clear")
            self.play(Unwrite(func), Unwrite(setToZero), Unwrite(func_Zeroed), Unwrite(solve), Unwrite(func_Zeros), run_time=0.5)

            self.wait_until_bookmark("plot")
            self.play(Write(self.cords), run_time=0.5)
            self.play(Write(plot))

            self.wait_until_bookmark("crossing")
            for x in self.zeros:
                self.play(Write(Circle(radius=0.1, color=BLUE).move_to(plane.coords_to_point(x,0))))
                self.wait(0.5)

        self.wait(4)

#####################################
#####################################
## Concrete Questions
#####################################
#####################################

TASK_Func_1_3_P_1_1_q = SophiaTaskDefinition(
    answerOptions = ["$-1", "$1$", "$-1,\\,0,\\,1$", "$-1,\\,1$"],
    correctAnswerIndex = 3,
    questionText = "What is/are the zero crossing(s) of the function $f(x)=x^2-1$?"
)

class Func_1_3_P_1_1_q(xCrossingQuestionScene):

    def construct(self):

        self.funcTex = "f(x)=x^2-1"
        self.func = lambda x: x**2-1
        self.funcText = "f of x equals x squared minus one"
        self.intro = "So, now let's practice intersection points."

        super().construct()

class Func_1_3_P_1_1_a(xCrossingAnswerScene):
        
    def construct(self):
        self.funcTex = "f(x)=x^2-1"
        self.funcZero = "x^2-1=0"
        self.funcZeros = "x=-1,\\, x=1"
        self.func = lambda x: x**2-1
        self.funcText = "f of x equals x squared minus one"
        self.ZeroText = "x squared minus one equals zero"
        self.ZerosText = "x equals minus one and x equals one"
        self.intro = "Unfortunately, that's not quite right..."
        self.isCorrect = False
        self.zeros = [-1,1]
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,-1,1,3],
                               x_labels=[-2,2], y_labels=[-3,-1,1,3])
        
        super().construct()

class Func_1_3_P_1_1_b(xCrossingAnswerScene):
        
    def construct(self):
        self.funcTex = "f(x)=x^2-1"
        self.funcZero = "x^2-1=0"
        self.funcZeros = "x=-1,\\, x=1"
        self.func = lambda x: x**2-1
        self.funcText = "f of x equals x squared minus one"
        self.ZeroText = "x squared minus one equals zero"
        self.ZerosText = "x equals minus one and x equals one"
        self.intro = "Unfortunately, that's not quite right..."
        self.isCorrect = False
        self.zeros = [-1,1]
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,-1,1,3],
                               x_labels=[-2,2], y_labels=[-3,-1,1,3])
        
        super().construct()

class Func_1_3_P_1_1_c(xCrossingAnswerScene):
        
    def construct(self):
        self.funcTex = "f(x)=x^2-1"
        self.funcZero = "x^2-1=0"
        self.funcZeros = "x=-1,\\, x=1"
        self.func = lambda x: x**2-1
        self.funcText = "f of x equals x squared minus one"
        self.ZeroText = "x squared minus one equals zero"
        self.ZerosText = "x equals minus one and x equals one"
        self.intro = "Unfortunately, that's not quite right..."
        self.isCorrect = False
        self.zeros = [-1,1]
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,-1,1,3],
                               x_labels=[-2,2], y_labels=[-3,-1,1,3])
        
        super().construct()

class Func_1_3_P_1_1_d(xCrossingAnswerScene):
        
    def construct(self):
        self.funcTex = "f(x)=x^2-1"
        self.funcZero = "x^2-1=0"
        self.funcZeros = "x=-1,\\, x=1"
        self.func = lambda x: x**2-1
        self.funcText = "f of x equals x squared minus one"
        self.ZeroText = "x squared minus one equals zero"
        self.ZerosText = "x equals minus one and x equals one"
        self.intro = "That's correct, well done."
        self.isCorrect = True
        self.zeros = [-1,1]
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,-1,1,3],
                               x_labels=[-2,2], y_labels=[-3,-1,1,3])
        
        super().construct()




#####################################
#####################################

TASK_Func_1_3_P_1_2_q = SophiaTaskDefinition(
    answerOptions = ["$-2$", "$2$", "$-2,\\,2$", "$-2,\\,0,\\,2$"],
    correctAnswerIndex = 2,
    questionText = "What is/are the zero crossing(s) of the function $f(x)=x^2-4$?"
)

class Func_1_3_P_1_2_q(xCrossingQuestionScene):

    def construct(self):

        self.funcTex = "f(x)=x^2-4"
        self.func = lambda x: x**2-4
        self.funcText = "f of x equals x squared minus four"
        self.intro = "Let's try again with a different function."

        super().construct()

class Func_1_3_P_1_2_a(xCrossingAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2-4"
        self.funcZero = "x^2-4=0"
        self.funcZeros = "x=-2,\\, x=2"
        self.func = lambda x: x**2-4
        self.funcText = "f of x equals x squared minus four"
        self.ZeroText = "x squared minus four equals zero"
        self.ZerosText = "x equals minus two and x equals two"
        self.intro = "Unfortunately, that's not quite right..."
        self.isCorrect = False
        self.zeros = [-2,2]
        self.cords = self.add_cords([-3, 3, 1], [-5, 5, 1], x_ticks=[-3,3], y_ticks=[-5,0,5],
                               x_labels=[-3,3], y_labels=[-5,0,5])
        
        super().construct()

class Func_1_3_P_1_2_b(xCrossingAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2-4"
        self.funcZero = "x^2-4=0"
        self.funcZeros = "x=-2,\\, x=2"
        self.func = lambda x: x**2-4
        self.funcText = "f of x equals x squared minus four"
        self.ZeroText = "x squared minus four equals zero"
        self.ZerosText = "x equals minus two and x equals two"
        self.intro = "Unfortunately, that's not quite right..."
        self.isCorrect = False
        self.zeros = [-2,2]
        self.cords = self.add_cords([-3, 3, 1], [-5, 5, 1], x_ticks=[-3,3], y_ticks=[-5,0,5],
                               x_labels=[-3,3], y_labels=[-5,0,5])
        
        super().construct()

class Func_1_3_P_1_2_c(xCrossingAnswerScene):
        
    def construct(self):
        self.funcTex = "f(x)=x^2-4"
        self.funcZero = "x^2-4=0"
        self.funcZeros = "x=-2,\\, x=2"
        self.func = lambda x: x**2-4
        self.funcText = "f of x equals x squared minus four"
        self.ZeroText = "x squared minus four equals zero"
        self.ZerosText = "x equals minus two and x equals two"
        self.intro = "That's correct, well done."
        self.isCorrect = True
        self.zeros = [-2,2]
        self.cords = self.add_cords([-3, 3, 1], [-5, 5, 1], x_ticks=[-3,3], y_ticks=[-5,0,5],
                               x_labels=[-3,3], y_labels=[-5,0,5])
        
        super().construct()

class Func_1_3_P_1_2_d(xCrossingAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2-4"
        self.funcZero = "x^2-4=0"
        self.funcZeros = "x=-2,\\, x=2"
        self.func = lambda x: x**2-4
        self.funcText = "f of x equals x squared minus four"
        self.ZeroText = "x squared minus four equals zero"
        self.ZerosText = "x equals minus two and x equals two"
        self.intro = "Unfortunately, that's not quite right..."
        self.isCorrect = False
        self.zeros = [-2,2]
        self.cords = self.add_cords([-3, 3, 1], [-5, 5, 1], x_ticks=[-3,3], y_ticks=[-5,0,5],
                               x_labels=[-3,3], y_labels=[-5,0,5])
        
        super().construct()


#####################################
#####################################
TASK_Func_1_3_P_1_3_q = SophiaTaskDefinition(
    answerOptions = ["$0$", "$2$", "$-2,\\,2$", "$-2,\\,0,\\,2$"],
    correctAnswerIndex = 0,
    questionText = "What is/are the zero crossing(s) of the function $f(x)=x^3$?"   
)

class Func_1_3_P_1_3_q(xCrossingQuestionScene):

    def construct(self):

        self.funcTex = "f(x)=x^3"
        self.func = lambda x: x**3
        self.funcText = "function f of x equals x cubed"
        self.intro = "Let's move on to a cubic function."

        super().construct()

class Func_1_3_P_1_3_a(xCrossingAnswerScene):
        
    def construct(self):
        self.funcTex = "f(x)=x^3"
        self.funcZero = "x^3=0"
        self.funcZeros = "x=0"
        self.func = lambda x: x**3
        self.funcText = "function f of x equals x cubed"
        self.ZeroText = "x cubed equals zero"
        self.ZerosText = "x equals zero"
        self.intro = "That's correct, well done."
        self.isCorrect = True
        self.zeros = [0]
        self.cords = self.add_cords([-3, 3, 1], [-8, 8, 1], x_ticks=[-3,0,3], y_ticks=[-8,0,8],
                               x_labels=[-3,0,3], y_labels=[-8,0,8])
        
        super().construct()

class Func_1_3_P_1_3_b(xCrossingAnswerScene):
        

    def construct(self):
        self.funcTex = "f(x)=x^3"
        self.funcZero = "x^3=0"
        self.funcZeros = "x=0"
        self.func = lambda x: x**3
        self.funcText = "function f of x equals x cubed"
        self.ZeroText = "x cubed equals zero"
        self.ZerosText = "x equals zero"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [0]
        self.cords = self.add_cords([-3, 3, 1], [-8, 8, 1], x_ticks=[-3,0,3], y_ticks=[-8,0,8],
                               x_labels=[-3,0,3], y_labels=[-8,0,8])
        
        super().construct()

class Func_1_3_P_1_3_c(xCrossingAnswerScene):
        

    def construct(self):
        self.funcTex = "f(x)=x^3"
        self.funcZero = "x^3=0"
        self.funcZeros = "x=0"
        self.func = lambda x: x**3
        self.funcText = "function f of x equals x cubed"
        self.ZeroText = "x cubed equals zero"
        self.ZerosText = "x equals zero"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [0]
        self.cords = self.add_cords([-3, 3, 1], [-8, 8, 1], x_ticks=[-3,0,3], y_ticks=[-8,0,8],
                               x_labels=[-3,0,3], y_labels=[-8,0,8])
        
        super().construct()

class Func_1_3_P_1_3_d(xCrossingAnswerScene):
        

    def construct(self):
        self.funcTex = "f(x)=x^3"
        self.funcZero = "x^3=0"
        self.funcZeros = "x=0"
        self.func = lambda x: x**3
        self.funcText = "function f of x equals x cubed"
        self.ZeroText = "x cubed equals zero"
        self.ZerosText = "x equals zero"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [0]
        self.cords = self.add_cords([-3, 3, 1], [-8, 8, 1], x_ticks=[-3,0,3], y_ticks=[-8,0,8],
                               x_labels=[-3,0,3], y_labels=[-8,0,8])
        
        super().construct()

#####################################
#####################################
TASK_Func_1_3_P_1_4_q = SophiaTaskDefinition(
    answerOptions = ["$-1$", "$0$", "$-1,\\,0$", "$0,\\,1$"],
    correctAnswerIndex = 1,
    questionText = "What is/are the zero crossing(s) of the function $f(x)=x$?"   
)

class Func_1_3_P_1_4_q(xCrossingQuestionScene):

    def construct(self):

        self.funcTex = "f(x)=x"
        self.func = lambda x: x
        self.funcText = "function f of x equals x"
        self.intro = "And now we move on to the linear function."

        super().construct()

class Func_1_3_P_1_4_a(xCrossingAnswerScene):
        

    def construct(self):
        self.funcTex = "f(x)=x"
        self.funcZero = "x=0"
        self.funcZeros = "x=0"
        self.func = lambda x: x
        self.funcText = "function f of x equals x"
        self.ZeroText = "x equals zero"
        self.ZerosText = "x equals zero"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [0]
        self.cords = self.add_cords([-3, 3, 1], [-3, 3, 1], x_ticks=[-3,0,3], y_ticks=[-3,0,3],
                               x_labels=[-3,0,3], y_labels=[-3,0,3])
        
        super().construct()

class Func_1_3_P_1_4_b(xCrossingAnswerScene):
        
    def construct(self):
        self.funcTex = "f(x)=x"
        self.funcZero = "x=0"
        self.funcZeros = "x=0"
        self.func = lambda x: x
        self.funcText = "function f of x equals x"
        self.ZeroText = "x equals zero"
        self.ZerosText = "x equals zero"
        self.intro = "That's correct, well done."
        self.isCorrect = True
        self.zeros = [0]
        self.cords = self.add_cords([-3, 3, 1], [-3, 3, 1], x_ticks=[-3,0,3], y_ticks=[-3,0,3],
                               x_labels=[-3,0,3], y_labels=[-3,0,3])
        
        super().construct()

class Func_1_3_P_1_4_c(xCrossingAnswerScene):
        

    def construct(self):
        self.funcTex = "f(x)=x"
        self.funcZero = "x=0"
        self.funcZeros = "x=0"
        self.func = lambda x: x
        self.funcText = "function f of x equals x"
        self.ZeroText = "x equals zero"
        self.ZerosText = "x equals zero"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [0]
        self.cords = self.add_cords([-3, 3, 1], [-3, 3, 1], x_ticks=[-3,0,3], y_ticks=[-3,0,3],
                               x_labels=[-3,0,3], y_labels=[-3,0,3])
        
        super().construct()

class Func_1_3_P_1_4_d(xCrossingAnswerScene):
        

    def construct(self):
        self.funcTex = "f(x)=x"
        self.funcZero = "x=0"
        self.funcZeros = "x=0"
        self.func = lambda x: x
        self.funcText = "function f of x equals x"
        self.ZeroText = "x equals zero"
        self.ZerosText = "x equals zero"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [0]
        self.cords = self.add_cords([-3, 3, 1], [-3, 3, 1], x_ticks=[-3,0,3], y_ticks=[-3,0,3],
                               x_labels=[-3,0,3], y_labels=[-3,0,3])
        
        super().construct()

#####################################
#####################################
TASK_Func_1_3_P_1_5_q = SophiaTaskDefinition(
    answerOptions = ["$-3$", "$3$", "$-3,\\,3$", "$-3,\\,0,\\,3$"],
    correctAnswerIndex = 2,
    questionText = "What is/are the zero crossing(s) of the function $f(x)=x^2-9$?"   
)

class Func_1_3_P_1_5_q(xCrossingQuestionScene):

    def construct(self):

        self.funcTex = "f(x)=x^2-9"
        self.func = lambda x: x**2-9
        self.funcText = "function f of x equals x squared minus nine"
        self.intro = "Let's try this with another function."

        super().construct()

class Func_1_3_P_1_5_a(xCrossingAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2-9"
        self.funcZero = "x^2-9=0"
        self.funcZeros = "x=-3,\\, x=3"
        self.func = lambda x: x**2-9
        self.funcText = "function f of x equals x squared minus nine"
        self.ZeroText = "x squared minus nine equals zero"
        self.ZerosText = "x equals minus three and x equals three"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [-3,3]
        self.cords = self.add_cords([-4, 4, 1], [-10, 10, 1], x_ticks=[-4,4], y_ticks=[-10,0,10],
                               x_labels=[-4,4], y_labels=[-10,0,10])
        
        super().construct()

class Func_1_3_P_1_5_b(xCrossingAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2-9"
        self.funcZero = "x^2-9=0"
        self.funcZeros = "x=-3,\\, x=3"
        self.func = lambda x: x**2-9
        self.funcText = "function f of x equals x squared minus nine"
        self.ZeroText = "x squared minus nine equals zero"
        self.ZerosText = "x equals minus three and x equals three"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [-3,3]
        self.cords = self.add_cords([-4, 4, 1], [-10, 10, 1], x_ticks=[-4,4], y_ticks=[-10,0,10],
                               x_labels=[-4,4], y_labels=[-10,0,10])
        
        super().construct()

class Func_1_3_P_1_5_c(xCrossingAnswerScene):
        
    def construct(self):
        self.funcTex = "f(x)=x^2-9"
        self.funcZero = "x^2-9=0"
        self.funcZeros = "x=-3,\\, x=3"
        self.func = lambda x: x**2-9
        self.funcText = "function f of x equals x squared minus nine"
        self.ZeroText = "x squared minus nine equals zero"
        self.ZerosText = "x equals minus three and x equals three"
        self.intro = "That's correct, well done."
        self.isCorrect = True
        self.zeros = [-3,3]
        self.cords = self.add_cords([-4, 4, 1], [-10, 10, 1], x_ticks=[-4,4], y_ticks=[-10,0,10],
                               x_labels=[-4,4], y_labels=[-10,0,10])
        
        super().construct()

class Func_1_3_P_1_5_d(xCrossingAnswerScene):

    def construct(self):
        self.funcTex = "f(x)=x^2-9"
        self.funcZero = "x^2-9=0"
        self.funcZeros = "x=-3,\\, x=3"
        self.func = lambda x: x**2-9
        self.funcText = "function f of x equals x squared minus nine"
        self.ZeroText = "x squared minus nine equals zero"
        self.ZerosText = "x equals minus three and x equals three"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [-3,3]
        self.cords = self.add_cords([-4, 4, 1], [-10, 10, 1], x_ticks=[-4,4], y_ticks=[-10,0,10],
                               x_labels=[-4,4], y_labels=[-10,0,10])
        
        super().construct()

#####################################
#####################################

TASK_Func_1_3_P_1_6_q = SophiaTaskDefinition(
    answerOptions = ["$-4$", "$4$", "$-4,\\,4$", "$-4,\\,0,\\,4$"],
    correctAnswerIndex = 2,
    questionText = "What is/are the zero crossing(s) of the function $f(x)=x^2-16$?"   
)

class Func_1_3_P_1_6_q(xCrossingQuestionScene):

    def construct(self):

        self.funcTex = "f(x)=x^2-16"
        self.func = lambda x: x**2-16
        self.funcText = "function f of x equals x squared minus sixteen"
        self.intro = "Let's consider another function."

        super().construct()

class Func_1_3_P_1_6_a(xCrossingAnswerScene):
        

    def construct(self):
        self.funcTex = "f(x)=x^2-16"
        self.funcZero = "x^2-16=0"
        self.funcZeros = "x=-4,\\, x=4"
        self.func = lambda x: x**2-16
        self.funcText = "function f of x equals x squared minus sixteen"
        self.ZeroText = "x squared minus sixteen equals zero"
        self.ZerosText = "x equals minus four and x equals four"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [-4,4]
        self.cords = self.add_cords([-5, 5, 1], [-17, 17, 1], x_ticks=[-5,5], y_ticks=[-17,0,17],
                               x_labels=[-5,5], y_labels=[-17,0,17])
        
        super().construct()

class Func_1_3_P_1_6_b(xCrossingAnswerScene):
        

    def construct(self):
        self.funcTex = "f(x)=x^2-16"
        self.funcZero = "x^2-16=0"
        self.funcZeros = "x=-4,\\, x=4"
        self.func = lambda x: x**2-16
        self.funcText = "function f of x equals x squared minus sixteen"
        self.ZeroText = "x squared minus sixteen equals zero"
        self.ZerosText = "x equals minus four and x equals four"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [-4,4]
        self.cords = self.add_cords([-5, 5, 1], [-17, 17, 1], x_ticks=[-5,5], y_ticks=[-17,0,17],
                               x_labels=[-5,5], y_labels=[-17,0,17])
        
        super().construct()

class Func_1_3_P_1_6_c(xCrossingAnswerScene):
        
    def construct(self):
        self.funcTex = "f(x)=x^2-16"
        self.funcZero = "x^2-16=0"
        self.funcZeros = "x=-4,\\, x=4"
        self.func = lambda x: x**2-16
        self.funcText = "function f of x equals x squared minus sixteen"
        self.ZeroText = "x squared minus sixteen equals zero"
        self.ZerosText = "x equals minus four and x equals four"
        self.intro = "That's correct, well done."
        self.isCorrect = True
        self.zeros = [-4,4]
        self.cords = self.add_cords([-5, 5, 1], [-17, 17, 1], x_ticks=[-5,5], y_ticks=[-17,0,17],
                               x_labels=[-5,5], y_labels=[-17,0,17])
        
        super().construct()

class Func_1_3_P_1_6_d(xCrossingAnswerScene):
        

    def construct(self):
        self.funcTex = "f(x)=x^2-16"
        self.funcZero = "x^2-16=0"
        self.funcZeros = "x=-4,\\, x=4"
        self.func = lambda x: x**2-16
        self.funcText = "function f of x equals x squared minus sixteen"
        self.ZeroText = "x squared minus sixteen equals zero"
        self.ZerosText = "x equals minus four and x equals four"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [-4,4]
        self.cords = self.add_cords([-5, 5, 1], [-17, 17, 1], x_ticks=[-5,5], y_ticks=[-17,0,17],
                               x_labels=[-5,5], y_labels=[-17,0,17])
        
        super().construct()

#####################################
#####################################

TASK_Func_1_3_P_1_7_q = SophiaTaskDefinition(
    answerOptions = ["$-5$", "$5$", "$-5,\\,5$", "$-5,\\,0,\\,5$"],
    correctAnswerIndex = 2,
    questionText = "What is/are the zero crossing(s) of the function $f(x)=x^2-25$?"   
)

class Func_1_3_P_1_7_q(xCrossingQuestionScene):

    def construct(self):

        self.funcTex = "f(x)=x^2-25"
        self.func = lambda x: x**2-25
        self.funcText = "function f of x equals x squared minus twenty-five"
        self.intro = "Let's try another function."

        super().construct()

class Func_1_3_P_1_7_a(xCrossingAnswerScene):
        

    def construct(self):
        self.funcTex = "f(x)=x^2-25"
        self.funcZero = "x^2-25=0"
        self.funcZeros = "x=-5,\\, x=5"
        self.func = lambda x: x**2-25
        self.funcText = "function f of x equals x squared minus twenty-five"
        self.ZeroText = "x squared minus twenty-five equals zero"
        self.ZerosText = "x equals minus five and x equals five"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [-5,5]
        self.cords = self.add_cords([-6, 6, 1], [-26, 26, 1], x_ticks=[-6,6], y_ticks=[-26,0,26],
                               x_labels=[-6,6], y_labels=[-26,0,26])
        
        super().construct()

class Func_1_3_P_1_7_b(xCrossingAnswerScene):
        

    def construct(self):
        self.funcTex = "f(x)=x^2-25"
        self.funcZero = "x^2-25=0"
        self.funcZeros = "x=-5,\\, x=5"
        self.func = lambda x: x**2-25
        self.funcText = "function f of x equals x squared minus twenty-five"
        self.ZeroText = "x squared minus twenty-five equals zero"
        self.ZerosText = "x equals minus five and x equals five"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [-5,5]
        self.cords = self.add_cords([-6, 6, 1], [-26, 26, 1], x_ticks=[-6,6], y_ticks=[-26,0,26],
                               x_labels=[-6,6], y_labels=[-26,0,26])
        
        super().construct()

class Func_1_3_P_1_7_c(xCrossingAnswerScene):
        
    def construct(self):
        self.funcTex = "f(x)=x^2-25"
        self.funcZero = "x^2-25=0"
        self.funcZeros = "x=-5,\\, x=5"
        self.func = lambda x: x**2-25
        self.funcText = "function f of x equals x squared minus twenty-five"
        self.ZeroText = "x squared minus twenty-five equals zero"
        self.ZerosText = "x equals minus five and x equals five"
        self.intro = "That's correct, well done."
        self.isCorrect = True
        self.zeros = [-5,5]
        self.cords = self.add_cords([-6, 6, 1], [-26, 26, 1], x_ticks=[-6,6], y_ticks=[-26,0,26],
                               x_labels=[-6,6], y_labels=[-26,0,26])
        
        super().construct()

class Func_1_3_P_1_7_d(xCrossingAnswerScene):
        

    def construct(self):
        self.funcTex = "f(x)=x^2-25"
        self.funcZero = "x^2-25=0"
        self.funcZeros = "x=-5,\\, x=5"
        self.func = lambda x: x**2-25
        self.funcText = "function f of x equals x squared minus twenty-five"
        self.ZeroText = "x squared minus twenty-five equals zero"
        self.ZerosText = "x equals minus five and x equals five"
        self.intro = "Unfortunately, that's incorrect. Too bad."
        self.isCorrect = False
        self.zeros = [-5,5]
        self.cords = self.add_cords([-6, 6, 1], [-26, 26, 1], x_ticks=[-6,6], y_ticks=[-26,0,26],
                               x_labels=[-6,6], y_labels=[-26,0,26])
        
        super().construct()


#####################################
#####################################
# New Q-Type: Intersect Y-Axis
#####################################
#####################################

class yCrossingQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        cursor = AltCursor(stroke_width=0.0, idle=False)

        func = MathTex(self.funcTex, color=c1t, font_size=fs1).shift(UP)

        # Add title to the scene
        self.add_title("Intersection with the y-Axis")

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro}
                Consider the function <bookmark mark="writeFunc"/> {self.funcText}.
                <bookmark mark="zero"/>
                Where is the intersection of the function with the y axis?
                """
        ) as tracker:
            
            self.wait_until_bookmark("writeFunc")
            self.play(Write(func))

            self.wait_until_bookmark("zero")
            self.draw_qmark(cursor, DOWN)

        self.wait(4)

#####################################
#####################################
class yCrossingAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()


        func = MathTex(self.funcTex, color=c1t, font_size=fs2)
        plugInZero = Tex("$\\Rightarrow$ Substitute $x=0$", color=RED, font_size=fs3)
        func_Zeroed = MathTex(self.funcZero, color=c1t, font_size=fs2)
        explanation = VGroup(func, plugInZero, func_Zeroed).arrange(DOWN, buff=0.2, aligned_edge=LEFT)

        # Create the coordinate system

        plane = self.cords[0]
        plot = plane.plot(self.func, color=BLUE)


        # Add title to the scene
        self.add_title("Intersection with the y-Axis")
        
        # Initialize a cursor
        # cursor = AltCursor(stroke_width=0.0, blinking=True).shift(LEFT)
        # cursor.autoFadeBackground = True

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro}
                So, we are considering the function <bookmark mark="writeFunc"/> {self.funcText}.
                To obtain the intersection point with the y axis <bookmark mark="setToZero1"/>,
                we simply plug x equals 0 into the function term.
                Then we get <bookmark mark="setToZero2"/> {self.ZeroText}. <bookmark mark="noteChange"/>
                And then we already have the y-value of the intersection point with the y-axis.
                
                Now, let's verify this using <bookmark mark="clear"/> the graph.
                Here's the graph of the function. <bookmark mark="plot"/>
                We can see that the intersection point with the y-axis <bookmark mark="ycirc"/>
                lies at  y equal to {self.y_cross_text}.
                """
        ) as tracker:
            
            self.wait_until_bookmark("writeFunc")
            self.play(Write(func))

            self.wait_until_bookmark("setToZero1")
            self.play(Write(plugInZero))

            self.wait_until_bookmark("setToZero2")
            self.play(Write(func_Zeroed))

            self.wait_until_bookmark("noteChange")

            self.wait_until_bookmark("clear")
            self.play(Unwrite(plugInZero), Unwrite(func_Zeroed), Unwrite(func), run_time=0.5)

            self.wait_until_bookmark("plot")
            self.play(Write(self.cords), run_time=0.5)
            self.play(Write(plot))

            self.wait_until_bookmark("ycirc")
            self.play(Write(Circle(radius=0.1, color=BLUE).move_to(plane.coords_to_point(0,self.y_cross))))

        self.wait(4)



#####################################
#####################################
#Concrete Questions
#####################################
#####################################
TASK_Func_1_3_P_2_1_q = SophiaTaskDefinition(
    answerOptions = ["$0$", "$1$", "$-1$", "$2$"],
    correctAnswerIndex = 2,
    questionText = "Where does the function intersect the $y$-axis?"   
)

class Func_1_3_P_2_1_q(yCrossingQuestionScene):
    
    def construct(self):

        self.funcTex = "f(x)=x^2-1"
        self.func = lambda x: x**2-1
        self.funcText = "f of x equals x squared minus one"
        self.intro = "So, now we practice with intersections."
        super().construct()

class Func_1_3_P_2_1_a(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2-1"
        self.funcZero = "f(0)=0^2-1=-1"
        self.func = lambda x: x**2-1
        self.funcText = "f of x equals x squared minus one"
        self.ZeroText = "f of zero equals zero squared minus one equals minus one"

        self.intro = "Unfortunately, that's incorrect."
        self.isCorrect = False
        self.y_cross = -1
        self.y_cross_text = "negative one"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,-1,1,3],
                               x_labels=[-2,2], y_labels=[-3,-1,1,3])
        
        super().construct()


class Func_1_3_P_2_1_b(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2-1"
        self.funcZero = "f(0)=0^2-1=-1"
        self.func = lambda x: x**2-1
        self.funcText = "f of x equals x squared minus one"
        self.ZeroText = "f of zero equals zero squared minus one equals minus one"

        self.intro = "Unfortunately, that's incorrect."
        self.isCorrect = False
        self.y_cross = -1
        self.y_cross_text = "negative one"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,-1,1,3],
                               x_labels=[-2,2], y_labels=[-3,-1,1,3])
        
        super().construct()


class Func_1_3_P_2_1_c(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2-1"
        self.funcZero = "f(0)=0^2-1=-1"
        self.func = lambda x: x**2-1
        self.funcText = "f of x equals x squared minus one"
        self.ZeroText = "f of zero equals zero squared minus one equals minus one"

        self.intro = "That's correct, well done."
        self.isCorrect = True
        self.y_cross = -1
        self.y_cross_text = "negative one"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,-1,1,3],
                               x_labels=[-2,2], y_labels=[-3,-1,1,3])
        
        super().construct()

class Func_1_3_P_2_1_d(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2-1"
        self.funcZero = "f(0)=0^2-1=-1"
        self.func = lambda x: x**2-1
        self.funcText = "f of x equals x squared minus one"
        self.ZeroText = "f of zero equals zero squared minus one equals minus one"

        self.intro = "Unfortunately, that's incorrect."
        self.isCorrect = False
        self.y_cross = -1
        self.y_cross_text = "negative one"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,-1,1,3],
                               x_labels=[-2,2], y_labels=[-3,-1,1,3])
        
        super().construct()

#####################################
#####################################
TASK_Func_1_3_P_2_2_q = SophiaTaskDefinition(
    answerOptions = ["$0$", "$1$", "$-1$", "$2$"],
    correctAnswerIndex = 0,
    questionText = "Where does the function intersect the $y$-axis?"   
)

class Func_1_3_P_2_2_q(yCrossingQuestionScene):
    
    def construct(self):

        self.funcTex = "f(x)=x^2"
        self.func = lambda x: x**2
        self.funcText = "f of x equals x squared"
        self.intro = "Let's continue practicing with intersections."
        super().construct()

class Func_1_3_P_2_2_a(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2"
        self.funcZero = "f(0)=0^2=0"
        self.func = lambda x: x**2
        self.funcText = "f of x equals x squared"
        self.ZeroText = "f of zero equals zero squared equals zero"

        self.intro = "That's correct, excellent job."
        self.isCorrect = True
        self.y_cross = 0
        self.y_cross_text = "zero"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,0,1,3],
                               x_labels=[-2,2], y_labels=[-3,0,1,3])
        
        super().construct()

class Func_1_3_P_2_2_b(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2"
        self.funcZero = "f(0)=0^2=0"
        self.func = lambda x: x**2
        self.funcText = "f of x equals x squared"
        self.ZeroText = "f of zero equals zero squared equals zero"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = 0
        self.y_cross_text = "zero"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,0,1,3],
                               x_labels=[-2,2], y_labels=[-3,0,1,3])
        
        super().construct()

class Func_1_3_P_2_2_c(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2"
        self.funcZero = "f(0)=0^2=0"
        self.func = lambda x: x**2
        self.funcText = "f of x equals x squared"
        self.ZeroText = "f of zero equals zero squared equals zero"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = 0
        self.y_cross_text = "zero"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,0,1,3],
                               x_labels=[-2,2], y_labels=[-3,0,1,3])
        
        super().construct()

class Func_1_3_P_2_2_d(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2"
        self.funcZero = "f(0)=0^2=0"
        self.func = lambda x: x**2
        self.funcText = "f of x equals x squared"
        self.ZeroText = "f of zero equals zero squared equals zero"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = 0
        self.y_cross_text = "zero"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,0,1,3],
                               x_labels=[-2,2], y_labels=[-3,0,1,3])
        
        super().construct()


#####################################
#####################################
#####################################
#####################################
TASK_Func_1_3_P_2_3_q = SophiaTaskDefinition(
    answerOptions = ["$0$", "$1$", "$-1$", "$2$"],
    correctAnswerIndex = 1,
    questionText = "Where does the function intersect the $y$-axis?"   
)

class Func_1_3_P_2_3_q(yCrossingQuestionScene):
    
    def construct(self):

        self.funcTex = "f(x)=x+1"
        self.func = lambda x: x+1
        self.funcText = "f of x equals x plus one"
        self.intro = "Let's keep going with intersections."
        super().construct()

class Func_1_3_P_2_3_a(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x+1"
        self.funcZero = "f(0)=0+1=1"
        self.func = lambda x: x+1
        self.funcText = "f of x equals x plus one"
        self.ZeroText = "f of zero equals zero plus one equals one"

        self.intro = "Unfortunately, that's incorrect."
        self.isCorrect = False
        self.y_cross = 1
        self.y_cross_text = "one"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,1,3],
                               x_labels=[-2,2], y_labels=[-3,1,3])
        
        super().construct()

class Func_1_3_P_2_3_b(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x+1"
        self.funcZero = "f(0)=0+1=1"
        self.func = lambda x: x+1
        self.funcText = "f of x equals x plus one"
        self.ZeroText = "f of zero equals zero plus one equals one"

        self.intro = "Correct, well done."
        self.isCorrect = True
        self.y_cross = 1
        self.y_cross_text = "one"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,1,3],
                               x_labels=[-2,2], y_labels=[-3,1,3])
        
        super().construct()

class Func_1_3_P_2_3_c(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x+1"
        self.funcZero = "f(0)=0+1=1"
        self.func = lambda x: x+1
        self.funcText = "f of x equals x plus one"
        self.ZeroText = "f of zero equals zero plus one equals one"

        self.intro = "Unfortunately, that's incorrect."
        self.isCorrect = False
        self.y_cross = 1
        self.y_cross_text = "one"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,1,3],
                               x_labels=[-2,2], y_labels=[-3,1,3])
        
        super().construct()

class Func_1_3_P_2_3_d(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x+1"
        self.funcZero = "f(0)=0+1=1"
        self.func = lambda x: x+1
        self.funcText = "f of x equals x plus one"
        self.ZeroText = "f of zero equals zero plus one equals one"

        self.intro = "Unfortunately, that's incorrect."
        self.isCorrect = False
        self.y_cross = 1
        self.y_cross_text = "one"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,1,3],
                               x_labels=[-2,2], y_labels=[-3,1,3])
        
        super().construct()

#####################################
#####################################
TASK_Func_1_3_P_2_4_q = SophiaTaskDefinition(
    answerOptions = ["$0$", "$1$", "$-1$", "$2$"],
    correctAnswerIndex = 3,
    questionText = "Where does the function intersect the $y$-axis?"   
)

class Func_1_3_P_2_4_q(yCrossingQuestionScene):
    
    def construct(self):

        self.funcTex = "f(x)=x^2+2"
        self.func = lambda x: x**2+2
        self.funcText = "f of x equals x squared plus two"
        self.intro = "Let's continue with intersections."
        super().construct()

class Func_1_3_P_2_4_a(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2+2"
        self.funcZero = "f(0)=0^2+2=2"
        self.func = lambda x: x**2+2
        self.funcText = "f of x equals x squared plus two"
        self.ZeroText = "f of zero equals zero squared plus two equals two"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = 2
        self.y_cross_text = "two"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,2,3],
                               x_labels=[-2,2], y_labels=[-3,2,3])
        
        super().construct()

class Func_1_3_P_2_4_b(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2+2"
        self.funcZero = "f(0)=0^2+2=2"
        self.func = lambda x: x**2+2
        self.funcText = "f of x equals x squared plus two"
        self.ZeroText = "f of zero equals zero squared plus two equals two"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = 2
        self.y_cross_text = "two"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,2,3],
                               x_labels=[-2,2], y_labels=[-3,2,3])
        
        super().construct()

class Func_1_3_P_2_4_c(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2+2"
        self.funcZero = "f(0)=0^2+2=2"
        self.func = lambda x: x**2+2
        self.funcText = "f of x equals x squared plus two"
        self.ZeroText = "f of zero equals zero squared plus two equals two"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = 2
        self.y_cross_text = "two"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,2,3],
                               x_labels=[-2,2], y_labels=[-3,2,3])
        
        super().construct()

class Func_1_3_P_2_4_d(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2+2"
        self.funcZero = "f(0)=0^2+2=2"
        self.func = lambda x: x**2+2
        self.funcText = "f of x equals x squared plus two"
        self.ZeroText = "f of zero equals zero squared plus two equals two"

        self.intro = "Very good, that's correct."
        self.isCorrect = True
        self.y_cross = 2
        self.y_cross_text = "two"
        self.cords = self.add_cords([-2, 2, 1], [-3, 3, 1], x_ticks=[-2,2], y_ticks=[-3,2,3],
                               x_labels=[-2,2], y_labels=[-3,2,3])
        
        super().construct()


#####################################
#####################################
TASK_Func_1_3_P_2_5_q = SophiaTaskDefinition(
    answerOptions = ["$0$", "$1$", "$-2$", "$3$"],
    correctAnswerIndex = 2,
    questionText = "Where does the function intersect the $y$-axis?"   
)

class Func_1_3_P_2_5_q(yCrossingQuestionScene):
    
    def construct(self):

        self.funcTex = "f(x)=x^3+x^2-2"
        self.func = lambda x: x**3 + x**2 - 2
        self.funcText = "f of x equals x cubed plus x squared minus two"
        self.intro = "Let's move on to more complex intersections."
        super().construct()

class Func_1_3_P_2_5_a(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^3+x^2-2"
        self.funcZero = "f(0)=0^3+0^2-2=-2"
        self.func = lambda x: x**3 + x**2 - 2
        self.funcText = "f of x equals x cubed plus x squared minus two"
        self.ZeroText = "f of zero equals zero cubed plus zero squared minus two equals minus two"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = -2
        self.y_cross_text = "minus two"
        self.cords = self.add_cords([-2, 2, 1], [-10, 10, 2], x_ticks=[-2,2], y_ticks=[-6,-2,2,6],
                               x_labels=[-2,2], y_labels=[-6,-2,2,6])
        
        super().construct()

class Func_1_3_P_2_5_b(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^3+x^2-2"
        self.funcZero = "f(0)=0^3+0^2-2=-2"
        self.func = lambda x: x**3 + x**2 - 2
        self.funcText = "f of x equals x cubed plus x squared minus two"
        self.ZeroText = "f of zero equals zero cubed plus zero squared minus two equals minus two"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = -2
        self.y_cross_text = "minus two"
        self.cords = self.add_cords([-2, 2, 1], [-10, 10, 2], x_ticks=[-2,2], y_ticks=[-6,-2,2,6],
                               x_labels=[-2,2], y_labels=[-6,-2,2,6])
        
        super().construct()

class Func_1_3_P_2_5_c(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^3+x^2-2"
        self.funcZero = "f(0)=0^3+0^2-2=-2"
        self.func = lambda x: x**3 + x**2 - 2
        self.funcText = "f of x equals x cubed plus x squared minus two"
        self.ZeroText = "f of zero equals zero cubed plus zero squared minus two equals minus two"

        self.intro = "That's correct, excellent!"
        self.isCorrect = True
        self.y_cross = -2
        self.y_cross_text = "minus two"
        self.cords = self.add_cords([-2, 2, 1], [-10, 10, 2], x_ticks=[-2,2], y_ticks=[-6,-2,2,6],
                               x_labels=[-2,2], y_labels=[-6,-2,2,6])
        
        super().construct()

class Func_1_3_P_2_5_d(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^3+x^2-2"
        self.funcZero = "f(0)=0^3+0^2-2=-2"
        self.func = lambda x: x**3 + x**2 - 2
        self.funcText = "f of x equals x cubed plus x squared minus two"
        self.ZeroText = "f of zero equals zero cubed plus zero squared minus two equals minus two"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = -2
        self.y_cross_text = "minus two"
        self.cords = self.add_cords([-2, 2, 1], [-10, 10, 2], x_ticks=[-2,2], y_ticks=[-6,-2,2,6],
                               x_labels=[-2,2], y_labels=[-6,-2,2,6])
        
        super().construct()

#####################################
#####################################
TASK_Func_1_3_P_2_6_q = SophiaTaskDefinition(
    answerOptions = ["$-1$", "$1$", "$0$", "$2$"],
    correctAnswerIndex = 0,
    questionText = "Where does the function intersect the $y$-axis?"   
)

class Func_1_3_P_2_6_q(yCrossingQuestionScene):
    
    def construct(self):

        self.funcTex = "f(x)=x^4-1"
        self.func = lambda x: x**4 - 1
        self.funcText = "f of x equals x to the power of four minus one"
        self.intro = "Let's consider a more challenging function."
        super().construct()

class Func_1_3_P_2_6_a(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^4-1"
        self.funcZero = "f(0)=0^4-1=-1"
        self.func = lambda x: x**4 - 1
        self.funcText = "f of x equals x to the power of four minus one"
        self.ZeroText = "f of zero equals zero to the power of four minus one equals minus one"

        self.intro = "Absolutely correct, well done!"
        self.isCorrect = True
        self.y_cross = -1
        self.y_cross_text = "minus one"
        self.cords = self.add_cords([-2, 2, 1], [-16, 16,4], x_ticks=[-2,2], y_ticks=[-12,-4,4,12],
                               x_labels=[-2,2], y_labels=[-12,-4,4,12])
        
        super().construct()

class Func_1_3_P_2_6_b(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^4-1"
        self.funcZero = "f(0)=0^4-1=-1"
        self.func = lambda x: x**4 - 1
        self.funcText = "f of x equals x to the power of four minus one"
        self.ZeroText = "f of zero equals zero to the power of four minus one equals minus one"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = -1
        self.y_cross_text = "minus one"
        self.cords = self.add_cords([-2, 2, 1], [-16, 16,4], x_ticks=[-2,2], y_ticks=[-12,-4,4,12],
                               x_labels=[-2,2], y_labels=[-12,-4,4,12])
        
        super().construct()

class Func_1_3_P_2_6_c(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^4-1"
        self.funcZero = "f(0)=0^4-1=-1"
        self.func = lambda x: x**4 - 1
        self.funcText = "f of x equals x to the power of four minus one"
        self.ZeroText = "f of zero equals zero to the power of four minus one equals minus one"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = -1
        self.y_cross_text = "minus one"
        self.cords = self.add_cords([-2, 2, 1], [-16, 16,4], x_ticks=[-2,2], y_ticks=[-12,-4,4,12],
                               x_labels=[-2,2], y_labels=[-12,-4,4,12])
        
        super().construct()

class Func_1_3_P_2_6_d(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^4-1"
        self.funcZero = "f(0)=0^4-1=-1"
        self.func = lambda x: x**4 - 1
        self.funcText = "f of x equals x to the power of four minus one"
        self.ZeroText = "f of zero equals zero to the power of four minus one equals minus one"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = -1
        self.y_cross_text = "minus one"
        self.cords = self.add_cords([-2, 2, 1], [-16, 16,4], x_ticks=[-2,2], y_ticks=[-12,-4,4,12],
                               x_labels=[-2,2], y_labels=[-12,-4,4,12])
        
        super().construct()

#####################################
#####################################
TASK_Func_1_3_P_2_7_q = SophiaTaskDefinition(
    answerOptions = ["$-1$", "$1$", "$2$", "$3$"],
    correctAnswerIndex = 1,
    questionText = "Where does the function intersect the $y$-axis?"   
)

class Func_1_3_P_2_7_q(yCrossingQuestionScene):
    
    def construct(self):

        self.funcTex = "f(x)=x^2+2x+1"
        self.func = lambda x: x**2 + 2*x + 1
        self.funcText = "f of x equals x squared plus two x plus one"
        self.intro = "Here's another complex function."
        super().construct()

class Func_1_3_P_2_7_a(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2+2x+1"
        self.funcZero = "f(0)=0^2+2*0+1=1"
        self.func = lambda x: x**2 + 2*x + 1
        self.funcText = "f of x equals x squared plus two x plus one"
        self.ZeroText = "f of zero equals zero squared plus two times zero plus one equals one"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = 1
        self.y_cross_text = "one"
        self.cords = self.add_cords([-2, 2, 1], [-4, 8, 2], x_ticks=[-2,2], y_ticks=[-2,2,6],
                               x_labels=[-2,2], y_labels=[-2,2,6])
        
        super().construct()

class Func_1_3_P_2_7_b(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2+2x+1"
        self.funcZero = "f(0)=0^2+2*0+1=1"
        self.func = lambda x: x**2 + 2*x + 1
        self.funcText = "f of x equals x squared plus two x plus one"
        self.ZeroText = "f of zero equals zero squared plus two times zero plus one equals one"

        self.intro = "Exactly, that's correct."
        self.isCorrect = True
        self.y_cross = 1
        self.y_cross_text = "one"
        self.cords = self.add_cords([-2, 2, 1], [-4, 8, 2], x_ticks=[-2,2], y_ticks=[-2,2,6],
                               x_labels=[-2,2], y_labels=[-2,2,6])
        
        super().construct()

class Func_1_3_P_2_7_c(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2+2x+1"
        self.funcZero = "f(0)=0^2+2*0+1=1"
        self.func = lambda x: x**2 + 2*x + 1
        self.funcText = "f of x equals x squared plus two x plus one"
        self.ZeroText = "f of zero equals zero squared plus two times zero plus one equals one"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = 1
        self.y_cross_text = "one"
        self.cords = self.add_cords([-2, 2, 1], [-4, 8, 2], x_ticks=[-2,2], y_ticks=[-2,2,6],
                               x_labels=[-2,2], y_labels=[-2,2,6])
        
        super().construct()

class Func_1_3_P_2_7_d(yCrossingAnswerScene):

    def construct(self):

        self.funcTex = "f(x)=x^2+2x+1"
        self.funcZero = "f(0)=0^2+2*0+1=1"
        self.func = lambda x: x**2 + 2*x + 1
        self.funcText = "f of x equals x squared plus two x plus one"
        self.ZeroText = "f of zero equals zero squared plus two times zero plus one equals one"

        self.intro = "Unfortunately, that's not correct."
        self.isCorrect = False
        self.y_cross = 1
        self.y_cross_text = "one"
        self.cords = self.add_cords([-2, 2, 1], [-4, 8, 2], x_ticks=[-2,2], y_ticks=[-2,2,6],
                               x_labels=[-2,2], y_labels=[-2,2,6])
        
        super().construct()



PROTOTYPES = [
    PagePrototypeVideo.from_scene(Func_1_3_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_I_1_q, Func_1_3_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_I_1_a),
    PagePrototypeVideo.from_scene(Func_1_3_I_1_b),
    PagePrototypeVideo.from_scene(Func_1_3_I_1_c),
    PagePrototypeVideo.from_scene(Func_1_3_I_1_d),
    PagePrototypeVideo.from_scene(Func_1_3_I_2),
    PagePrototypeVideo.from_scene(Func_1_3_I_3),
    PagePrototypeVideo.from_scene(Func_1_3_I_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_I_4_q, Func_1_3_I_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_I_4_a),
    PagePrototypeVideo.from_scene(Func_1_3_I_4_b),
    PagePrototypeVideo.from_scene(Func_1_3_I_4_c),
    PagePrototypeVideo.from_scene(Func_1_3_I_4_d),
    PagePrototypeVideo.from_scene(Func_1_3_I_5),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_1_1_q, Func_1_3_P_1_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_1_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_1_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_1_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_1_d),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_1_2_q, Func_1_3_P_1_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_2_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_2_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_2_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_2_d),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_1_3_q, Func_1_3_P_1_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_3_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_3_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_3_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_3_d),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_1_4_q, Func_1_3_P_1_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_4_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_4_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_4_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_4_d),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_5_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_1_5_q, Func_1_3_P_1_5_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_5_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_5_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_5_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_5_d),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_6_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_1_6_q, Func_1_3_P_1_6_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_6_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_6_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_6_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_6_d),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_7_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_1_7_q, Func_1_3_P_1_7_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_7_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_7_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_7_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_1_7_d),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_2_1_q, Func_1_3_P_2_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_1_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_1_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_1_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_1_d),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_2_2_q, Func_1_3_P_2_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_2_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_2_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_2_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_2_d),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_2_3_q, Func_1_3_P_2_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_3_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_3_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_3_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_3_d),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_2_4_q, Func_1_3_P_2_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_4_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_4_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_4_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_4_d),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_5_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_2_5_q, Func_1_3_P_2_5_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_5_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_5_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_5_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_5_d),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_6_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_2_6_q, Func_1_3_P_2_6_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_6_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_6_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_6_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_6_d),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_7_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_3_P_2_7_q, Func_1_3_P_2_7_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_7_a),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_7_b),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_7_c),
    PagePrototypeVideo.from_scene(Func_1_3_P_2_7_d),
]
scenes/Func/Func_1: Intro Functions/Func1_3.py
Sophia-Edu-Labs/sophia-math
# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, Bubble, CursorMarkAxis)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition

##################################################################

# Function to create piecewise linear function based on given points
def create_piecewise_linear(points):
    def piecewise_linear(x):
        # Sort the points based on x-coordinate
        sorted_points = sorted(points, key=lambda p: p[0])

        # Find the closest two points for interpolation
        left_point, right_point = None, None
        for point in sorted_points:
            if x < point[0]:
                right_point = point
                break
            left_point = point

        # Extrapolate if x is outside the range of points
        if right_point is None:
            return sorted_points[-1][1]
        if left_point is None:
            return sorted_points[0][1]

        # Linear interpolation
        x1, y1 = left_point
        x2, y2 = right_point
        slope = (y2 - y1) / (x2 - x1)
        interpolated_value = y1 + slope * (x - x1)

        return interpolated_value

    return piecewise_linear


#####################################
#####################################
TASK_Func_1_1_I_1_q = SophiaTaskDefinition(
    answerOptions = ["The blue representation", "The red representation"],
    correctAnswerIndex = 0,
    questionText = "Which representation describes a realistic temperature trend?"
)

# Class for creating the animation scene
class Func_1_1_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Load and position images
        picnic = ImageMobject(assets_folder / "img" / "picnic.png")
        picnic = picnic.scale(3.5/picnic.get_width()).move_to([-5.2, 1, 0])
        wetter = ImageMobject(assets_folder / "img" / "weatherreport.png")
        wetter = wetter.scale(3.5/wetter.get_width()).move_to([-5, 1, 0])
        q = ImageMobject(assets_folder / "img" / "qmark.png")
        q = q.scale(2.5/q.get_width()).move_to([-5.2, 1, 0])

        # Create a notepad with texts

        # Create the coordinate system
        cords = self.add_cords([6, 24, 3], [5, 25, 5], x_ticks=[6, 12, 18, 24], y_ticks=[10, 15, 20, 25],
                               x_labels=[6, 12, 18, 24], y_labels=[5, 10, 15, 20, 25]).shift(DOWN*1.4)
        plane = cords[0]
        # self.add(cords)

        # Add title to the scene
        self.add_title("Functions")

        # Create and plot piecewise linear function
        func = create_piecewise_linear([[6, 9], [8, 12], [10, 17], [12, 19], [14, 22], [16, 18], [18, 13], [20, 11], [22, 8], [24, 7]])
        func_plotted = plane.plot(func, color=BLUE)
        func_plotted_wrong = plane.plot(func, color=RED).rotate(90 * DEGREES)

        # Initialize a cursor
        xo, yo, _ = plane.x_axis.n2p(6)
        cursor = AltCursor(stroke_width=0.0)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])
        cursor.add_updater(lambda m, dt: self.bring_to_front(cursor))

        # Action Sequence
        with self.voiceover(
                text="""
                <prosody rate="110%">
                So, what is a function? <bookmark mark="qOut"/>
                
                Imagine you're planning a
                <bookmark mark="picnicIn"/>
                picnic with your friends today.
                
                To have a great picnic, it's
                
                <bookmark mark="picnicOut"/>
                crucial that the temperature is just right.

                <bookmark mark="WetterIn"/>
                So you check the weather report.
                

                <bookmark mark="CordsInWetterOut"/>
                This report consists of a representation where
                
                <bookmark mark="ShowXAxis"/>
                the x-axis represents the time in hours, and

                <bookmark mark="ShowYAxis"/>
                the y-axis represents the temperature in degrees Celsius.

                <bookmark mark="ResetCursor1"/>
                This helps you understand how the weather will change throughout the day.
                Now, we're going to show you two possible representations.
                
                Think about which one of them depicts a realistic temperature trend.
                
                <bookmark mark="BlueFuncIn"/>
                Is it the blue representation?
                <break time="1.4s"/>
                <bookmark mark="RedFuncIn"/>
                Or is it the red representation?
                </prosody>
                """
        ) as tracker:
            
            self.add_shift_sound(0.5)
            self.play(q.animate.shift(RIGHT*5), run_time=0.5)

            self.wait_until_bookmark("qOut")
            self.add_shift_sound(0.5)
            self.play(q.animate.shift(RIGHT*5), run_time=0.5)

            # Animate the picnic image moving to the right.
            self.wait_until_bookmark("picnicIn")
            self.add_shift_sound(0.5)
            self.play(picnic.animate.shift(RIGHT*5), run_time=0.5)

            # Animate the wetter image moving to the right.
            self.wait_until_bookmark("WetterIn")
            self.add_shift_sound(0.5)
            self.play(wetter.animate.shift(RIGHT*5), picnic.animate.shift(RIGHT*5), run_time=0.5)

            # Change note colors to highlight first Block and animate wetter image moving out while writing cords.
            self.wait_until_bookmark("CordsInWetterOut")
            self.add_shift_sound(0.5)
            self.play(wetter.animate(run_time=0.5).shift(RIGHT*5), Write(cords), run_time=0.8)
            cursor.idle = True

            # Highlight the x-axis using the cursor
            self.wait_until_bookmark("ShowXAxis")
            cursor.idle = False
            self.add_move_sound("forward", duration = 0.5, target_volume=0.1)
            self.play(CursorMoveResize(cursor, plane.x_axis.n2p(15)[0], yo, 2.6, 0.3), run_time=0.5)

            # Highlight the y-axis using the cursor
            self.wait_until_bookmark("ShowYAxis")
            self.add_move_sound("forward", duration = 0.5, target_volume=0.1)
            self.play(CursorMoveResize(cursor, xo, plane.y_axis.n2p(15)[1], 0.3, 2.6), run_time=0.5)

            # Reset the cursor size and position after "ResetCursor1" bookmark.
            self.wait_until_bookmark("ResetCursor1")
            self.add_move_sound("backward", duration = 0.5, target_volume=0.1)
            self.play(CursorMoveResize(cursor, xo, yo, 0.2, 0.2), run_time=0.5)
            cursor.idle=True

            # Draw the blue function plot after "BlueFuncIn" bookmark.
            self.wait_until_bookmark("BlueFuncIn")
            cursor.idle = False
            x,y,_ = func_plotted.get_start()
            self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(func_plotted.get_end()))._start_fading(1.5))
            self.add_pencil_sound(1)
            cursor.set_opacity(c_bg_opacity)
            self.play(Create(func_plotted), run_time=1)

            # Draw the red function plot (incorrect one) after "RedFuncIn" bookmark.
            self.wait_until_bookmark("RedFuncIn")
            x,y,_ = func_plotted_wrong.get_start()
            cursor.set_opacity(c_fg_opacity)
            self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(func_plotted_wrong.get_end()))._start_fading(1.5))
            self.add_pencil_sound(1)
            cursor.idle=True
            self.play(Create(func_plotted_wrong), run_time=1)


        # Wait for 4 seconds at the end of animation
        self.wait(4)



class Func_1_1_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()


        # Create the coordinate system
        cords = self.add_cords([6, 24, 3], [5, 25, 5], x_ticks=[6, 12, 18], y_ticks=[10, 15, 20, 25],
                               axisLabelX="Time", axisLabelY="Temperature").shift(DOWN*1.4)
        plane = cords[0]


        # Add title to the scene
        self.add_title("Correct!")

        # Create and plot piecewise linear function
        func = create_piecewise_linear([[6, 9], [8, 12], [10, 17], [12, 19], [14, 22], [16, 18], [18, 13], [20, 11], [22, 8], [24, 7]])
        func_plotted = plane.plot(func, color=BLUE)
        func_plotted_wrong = plane.plot(func, color=RED).rotate(90 * DEGREES)

        # Initialize a cursor
        xo, yo, _ = plane.c2p(6,9)
        cursor = AltCursor(stroke_width=0.0)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])
        cursor.add_updater(lambda m, dt: self.bring_to_front(cursor))

        # Action Sequence
        with self.voiceover(
                text="""
                Exactly right! <bookmark mark="BlueFuncIn"/> The blue representation is correct...
                <break time="1s"/>
                On the left side of the x-axis, in the morning, the value of the blue representation is low.
                That makes sense because it's cooler in the morning....
                <break time="1s"/>
                As <bookmark mark="MoveAlongFunc"/>the day progresses, the value of the blue representation increases. This also fits, as it gets warmer.
                And in the evening, on the right side of the x-axis, the value of the blue representation is low again as it gets colder.
                <bookmark mark="RedFuncIn"/>
                <break time="1s"/>
                Now why can't it be the red representation?
                <break time="1s"/>
                Consider <bookmark mark="notRed"/> the temperature at two o'clock.
                <break time="0.5s"/>
                Let's draw a line
                <bookmark mark="VertLine" /> from the x-axis, that is, from two o'clock, upwards.
                This line intersects the red representation at exactly two points:
                <bookmark mark="intersect1"/>
                Once at eight degrees and
                <bookmark mark="intersect2"/>
                Once at sixteen point five degrees.
                <break time="0.4s"/>
                This would mean that it's both eight degrees and sixteen point five degrees at the same time.
                But there can only be one temperature at a given time.
                So, the red representation is not correct...
                <break time="1s"/>
                In summary: <bookmark mark="blueRecap"/>The blue representation is correct, because it assigns to each x-value, so to each
                point in time one y-value, so one temperature.
                The <bookmark mark="redRecap"/> red representation on the other hand is not correct, because there are x-value, so points
                in time to which it assigns two y-values, so two temperatures. This is not possible.
                """
        ) as tracker:
            
            # Animate the coordinate system being created
            self.play(Write(cords), run_time=0.5)
            self.add(cursor)

            # Draw the blue function plot after "BlueFuncIn" bookmark.
            self.wait_until_bookmark("BlueFuncIn")
            self.add_pencil_sound(1.5)
            cursor.idle=False
            c2 = cursor.copy().add_updater(lambda m: m.move_to(func_plotted.get_end()))._start_fading(1.5)
            self.add(c2)
            self.play(Write(func_plotted))

            # Follow the function with the cursor
            self.wait_until_bookmark("MoveAlongFunc")
            self.play(MoveAlongPath(cursor, func_plotted), run_time=14, rate_func=linear)
            cursor.idle=True

            # Draw the red function plot (incorrect one) after "RedFuncIn" bookmark.
            self.wait_until_bookmark("RedFuncIn")
            self.play(Unwrite(func_plotted))
            self.wait(0.2)
            self.add_pencil_sound(1.5)
            self.play(Write(func_plotted_wrong))

            self.wait_until_bookmark("notRed")
            x1, y1, _ = plane.c2p(14, 5)
            cursor.idle=False
            self.play(CursorMoveTo(cursor, x1, y1), run_time=0.5)
            cursor.idle=True

            self.wait_until_bookmark("VertLine")
            l = Line([x1, y1, 0], [x1, y1 + 2.4, 0], stroke_width=1.5, color=BLACK)
            self.add_pencil_sound(3)
            self.play(Write(l), run_time=3)

            self.wait_until_bookmark("intersect1")
            x1, y1, _ = plane.c2p(14, 8)
            cursor.idle=False
            self.play(CursorMoveTo(cursor, x1, y1), run_time=0.5)

            self.wait_until_bookmark("intersect2")
            x1, y1, _ = plane.c2p(14, 16.5)
            self.play(CursorMoveTo(cursor, x1, y1), run_time=0.5)
            self.wait(.5)
            cursor.idle = True

            self.play(Unwrite(func_plotted_wrong), Unwrite(l), run_time=0.5)
            func_plotted = plane.plot(func, color=BLUE)
            func_plotted_wrong = plane.plot(func, color=RED).rotate(90 * DEGREES)

            self.wait_until_bookmark("blueRecap")
            cursor.idle=False
            self.add_pencil_sound(0.5)
            self.play(Write(func_plotted), CursorMoveTo(cursor,0,1), run_time=0.5)
            b = Bubble(texts = ["Blue representation", "is correct"], center=np.array([0,2.3, 0]), start_point=np.array([0,1,0]), width=2.5, height = 0.8)
            self.wait(0.2)
            self.add_bubble_sound(1.5)
            cursor.add_updater(lambda m: m.move_to(b.get_end()))
            self.play(Create(b), Create(b.text))
            cursor.idle=True
            cursor.remove_updater(lambda m: m.move_to(b.get_end()))

            self.wait_until_bookmark("redRecap")
            cursor.idle=False
            self.add_pencil_sound(0.5)
            self.play(Write(func_plotted_wrong), CursorMoveTo(cursor,-.2,-1), run_time=0.5)
            b = Bubble(texts = ["$2$ temperatures at once", "$\\Rightarrow$ incorrect"], center=np.array([-.5,-2.5, 0]), start_point=np.array([-.2,-1,0]), loc="t1", width=2.8, height=0.8)
            self.add_bubble_sound(1.5)
            cursor.add_updater(lambda m: m.move_to(b.get_end()))
            self.play(Create(b), Create(b.text))
            cursor.idle=True
            cursor.remove_updater(lambda m: m.move_to(b.get_end()))


        # Wait for 4 seconds at the end of animation
        self.wait(4)



class Func_1_1_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create the coordinate system
        cords = self.add_cords([6, 24, 3], [5, 25, 5], x_ticks=[6, 12, 18, 24], y_ticks=[10, 15, 20, 25],
                               axisLabelX="Time", axisLabelY="Temperature").shift(DOWN*1.4)
        plane = cords[0]

        # Add title to the scene
        self.add_title("Careful!")

        # Create and plot piecewise linear function
        func = create_piecewise_linear([[6, 9], [8, 12], [10, 17], [12, 19], [14, 22], [16, 18], [18, 13], [20, 11], [22, 8], [24, 7]])
        func_plotted = plane.plot(func, color=BLUE)
        func_plotted_wrong = plane.plot(func, color=RED).rotate(90 * DEGREES)

        # Initialize a cursor
        xo, yo, _ = plane.c2p(6,9)
        cursor = AltCursor(stroke_width=0.0, idle=True, x=xo, y=yo)
        cursor.autoFadeBackground = True
        cursor.add_updater(lambda m, dt: self.bring_to_front(cursor))

        # Action Sequence
        with self.voiceover(
                text="""
                <prosody rate="110%">
                Unfortunately, the answer was incorrect.
                <bookmark mark="RedFuncIn"/>
                Why can't it be the red representation??
                Consider <bookmark mark="notRed"/> the temperature at two o'clock.
                Let's draw a line
                <bookmark mark="VertLine" /> from the x-axis, that is, from two o'clock, upwards.
                This line intersects the red representation at exactly two points,
                <bookmark mark="intersect1"/>
                once at eight degrees and
                <bookmark mark="intersect2"/>
                once at sixteen point five degrees.
                This would mean that it's both eight degrees and sixteen point five degrees at the same time.
                But there can only be one temperature at a given time.
                So, the red representation is not <bookmark mark="BlueFuncIn"/> correct.
                On the other hand, the blue representation describes the temperature throughout the day
                and is therefore correct.
                On the left side of the x-axis, in the morning, the value of the blue representation is low.
                This makes sense, as the temperature is also low in the morning.
                <bookmark mark="MoveAlongFunc"/>
                As the day progresses, the value of the blue representation increases. This also fits, as it gets warmer.
                And in the evening, on the right side of the x-axis, the value of the blue representation is low again, as it gets colder.
                Therefore, the blue representation is correct.
                </prosody>
                """
        ) as tracker:
            
            # Animate the coordinate system being created
            self.play(Write(cords), run_time=0.5)
            self.add(cursor)

            # Draw the red function plot (incorrect one) after "RedFuncIn" bookmark.
            self.wait_until_bookmark("RedFuncIn")
            self.add_pencil_sound(1.5)
            self.play(Write(func_plotted_wrong))

            self.wait_until_bookmark("notRed")
            x1, y1, _ = plane.c2p(14, 5)
            cursor.idle = False
            self.play(CursorMoveTo(cursor, x1, y1), run_time=0.5)

            self.wait_until_bookmark("VertLine")
            l = Line([x1, y1, 0], [x1, y1 + 2.4, 0], stroke_width=1.5, color=BLACK)
            self.add_pencil_sound(3)
            self.play(Write(l), run_time=3)

            self.wait_until_bookmark("intersect1")
            x1, y1, _ = plane.c2p(14, 8)
            self.play(CursorMoveTo(cursor, x1, y1), run_time=0.5)

            self.wait_until_bookmark("intersect2")
            x1, y1, _ = plane.c2p(14, 16.5)
            self.play(CursorMoveTo(cursor, x1, y1), run_time=0.5)
            self.wait(2)
            cursor.idle = True

            # Draw the blue function plot after "BlueFuncIn" bookmark.
            self.wait_until_bookmark("BlueFuncIn")
            cursor.idle=False
            self.add_pencil_sound(1.5)
            self.play(Unwrite(func_plotted_wrong), Unwrite(l), Write(func_plotted), CursorMoveTo(cursor, xo, yo))

            # Follow the func with the cursor
            self.wait_until_bookmark("MoveAlongFunc")
            self.play(MoveAlongPath(cursor, func_plotted), run_time=13, rate_func=linear)
            cursor.idle=True

        # Wait for 4 seconds at the end of animation
        self.wait(4)


#####################################
#####################################
class Func_1_1_I_2(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        cords = self.add_cords([6, 24, 3], [5, 25, 5], x_ticks=[6, 12, 18, 24], y_ticks=[10, 15, 20, 25],
                               axisLabelX="Time", axisLabelY="Temperature").shift(DOWN*1.4)
        plane = cords[0]

        # Add title to the scene
        self.add_title("The Function")

        # Create and plot piecewise linear function
        func = create_piecewise_linear([[6, 9], [8, 12], [10, 17], [12, 19], [14, 22], [16, 18], [18, 13], [20, 11], [22, 8], [24, 7]])
        func_plotted = plane.plot(func, color=BLUE)
        func_plotted_wrong = plane.plot(func, color=RED).rotate(90 * DEGREES)

        # Initialize a cursor
        xo, yo, _ = plane.c2p(6,9)
        cursor = AltCursor(stroke_width=0.0, idle=True, x=xo, y=yo)
        cursor.autoFadeBackground = True
        cursor.add_updater(lambda m, dt: self.bring_to_front(cursor))

        xToY = MathTex("x", "\,\,\,\\rightarrow\,\,\,", "y", color=c1t).next_to(cords, DOWN, buff=0.5)

        # Action Sequence
        with self.voiceover(
                text="""
                <prosody rate="110%">
                <bookmark mark="BlueFuncIn"/>
                Ok... now the blue representation is a great example of a function.
                A function is a mapping that assigns <bookmark mark="map1"/> exactly  one <bookmark mark="map2"/> y-value to each x-value.
                
                <bookmark mark="MoveAlongFunc"/>
                So, the blue representation assigns to each x-value, that is, each point in time, a y-value, which is a temperature.
                This makes sense, as at each point in time, there's one temperature.
                <break time="1s"/>
                The fact, that it can only be one temperature at any given time is also the reason why <bookmark mark="RedFuncIn"/>the red representation is not a function.
                It assigns to an x-value, that is, a time, <bookmark mark="VertLine" /> for example, two y-values, which means two temperatures.
                This can't be correct, as there's only one temperature at each time.
                
                <bookmark mark="Memorize"/>
                So remember: <break time="1s"/>A function is a mapping that assigns exactly <bookmark mark="aY"/> one y-value to each
                <bookmark mark="aX"/> x-value.
                </prosody>
                """
        ) as tracker:
            
            # Animate the coordinate system being created
            self.play(Write(cords), run_time=0.5)
            self.add(cursor)

            # Draw the blue function plot after "BlueFuncIn" bookmark.
            self.wait_until_bookmark("BlueFuncIn")
            self.add_pencil_sound(1.5)
            self.play(Write(func_plotted))
            
            self.wait_until_bookmark("map1")
            self.play(Write(xToY[2]), run_time=0.5)
            cursor.idle=True

            self.wait_until_bookmark("map2")
            self.play(Write(xToY[0]), Write(xToY[1]), run_time=0.5)

            self.wait_until_bookmark("MoveAlongFunc")
            cursor.idle=False
            self.play(MoveAlongPath(cursor, func_plotted), run_time=12, rate_func=linear)
            self.wait(1)
            cursor.idle=True

            # Follow the func with the cursor
            self.wait_until_bookmark("RedFuncIn")
            self.add_pencil_sound(1.5)
            self.play(Write(func_plotted_wrong), Unwrite(func_plotted))

            self.wait_until_bookmark("VertLine")
            x1, y1, _ = plane.c2p(14, 5)
            l = Line([x1, y1, 0], [x1, y1 + 2.4, 0], stroke_width=1.5, color=BLACK)
            self.add_pencil_sound(3)
            self.play(Write(l), run_time=3)

            self.wait_until_bookmark("Memorize")
            self.wait(1)
            cursor.idle=False

            self.wait_until_bookmark("aY")
            x,y,_ = xToY[2].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("aX")
            x,y,_ = xToY[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)
            
        # Wait for 4 seconds at the end of animation
        self.wait(4)


#####################################
#####################################
class Func_1_1_I_3(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create the coordinate system
        cords = self.add_cords([-2,2,1], [0, 4, 1], x_ticks=[-2,2], x_labels=[-2,2], y_ticks=[2,4], y_labels=[2,4]).shift(.6*DOWN)
        plane = cords[0]

        # Add title to the scene
        self.add_title("The Function")

        # Create and plot piecewise linear function
        def f(x):
            return x**2
        func_plotted = plane.plot(f, color=ORANGE)
        func_plotted2 = plane.plot(f, color=ORANGE)
        func_plotted_wrong = plane.plot(f, color=GREEN).rotate(90 * DEGREES)

        # Initialize a cursor
        xo, yo, _ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, idle=True, x=xo, y=yo)
        cursor.autoFadeBackground = True
        cursor.add_updater(lambda m, dt: self.bring_to_front(cursor))

        xToY = MathTex("x", "\,\,\,\\rightarrow\,\,\,", "y", color=c1t).next_to(cords, DOWN, buff=0.5)
        func_def = Tex("A function assigns\\\\ exactly one y-value\\\\ to each x-value.", color=c3t, font_size=fs3, tex_environment="flushleft").next_to(xToY, DOWN, buff=.7)

        # Action Sequence
        with self.voiceover(
                text="""
                <prosody rate="110%">
                Remember: <bookmark mark="Memorize"/>
                A function is a mapping that assigns <bookmark mark="map1"/> exactly one <bookmark mark="map2"/> y-value to each x-value.
                
                <bookmark mark="OrangeFuncIn"/>
                So, the orange representation is an example of a function.
                
                It <bookmark mark="orangeX"/> assigns to each x-value <bookmark mark="orangeY"/>
                exactly one y-value. <bookmark mark="MoveAlongFunc"/>
                
                This means, that each x-value has a corresponding y-value assigned to it.
                
                <bookmark mark="GreenFuncIn"/>
                That's also the reason why the green representation is not a function.
                It assigns to some x-values, for example, <bookmark mark="VertLine" /> to the x value x equals zero, two y-values.
                
                So, we remember: <bookmark mark="TrueFct"/>
                A function is a mapping that assigns exactly one y-value to each x-value.
                </prosody>
                """
        ) as tracker:
            
            # Animate the coordinate system being created
            self.play(Write(cords), run_time=0.5)
            self.add(cursor)

            self.wait_until_bookmark("Memorize")
            self.play(Create(func_def), run_time=.5)

            self.wait_until_bookmark("map1")
            self.play(Write(xToY[2]), run_time=0.5)

            self.wait_until_bookmark("map2")
            self.play(Write(xToY[0]), Write(xToY[1]), run_time=0.5)

            # Draw the blue function plot after "BlueFuncIn" bookmark.
            self.wait_until_bookmark("OrangeFuncIn")
            self.add_pencil_sound(1.5)
            self.play(Write(func_plotted))

            self.wait_until_bookmark("orangeX")
            cursor.idle=False
            x,y,_ = xToY[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("orangeY")
            x,y,_ = xToY[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("MoveAlongFunc")
            xs, ys, _ = plane.c2p(-2, 4)
            self.play(CursorMoveTo(cursor, xs, ys), run_time=.5)
            self.play(MoveAlongPath(cursor, func_plotted), run_time=3.5, rate_func=linear)
            self.wait(1)
            cursor.idle=True

            # Follow the func with the cursor
            self.wait_until_bookmark("GreenFuncIn")
            self.add_pencil_sound(1.5)
            self.play(Write(func_plotted_wrong), Unwrite(func_plotted))
            x1, y1, _ = plane.c2p(0, 0)
            cursor.idle=False
            self.play(CursorMoveTo(cursor, x1, y1), run_time=0.5)
            cursor.idle=True

            self.wait_until_bookmark("VertLine")
            l = Line([x1, y1, 0], [x1, y1 + 2.4, 0], stroke_width=3, color=RED)
            self.add_pencil_sound(2)
            self.play(Write(l), run_time=2)
            cx1, cy1, _ = plane.c2p(0, 0.6)
            cx2, cy2, _ = plane.c2p(0, 3.35)
            circ1, circ2 = Circle(radius=0.1, color=RED).move_to([cx1, cy1, 0]), Circle(radius=0.1, color=RED).move_to([cx2, cy2, 0])
            self.play(Write(circ1), Write(circ2), run_time=2)

            self.wait_until_bookmark("TrueFct")
            self.play(Unwrite(l), Unwrite(circ1), Unwrite(circ2), Unwrite(func_plotted_wrong), Write(func_plotted2), run_time=0.8)
            cursor.idle=False
            self.play(CursorMoveTo(cursor, xs, ys), run_time=0.5)
            self.play(MoveAlongPath(cursor, func_plotted2), run_time=5, rate_func=linear)
            cursor.idle=True

        # Wait for 4 seconds at the end of animation
        self.wait(4)


################################
################################
########## Practice Part #######
################################
################################

class ValueTableQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):

        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create the coordinate system
        plane = self.cords[0]

        # Add title to the scene
        self.add_title(self.title)

        # Create and plot piecewise linear function
        f1 = create_piecewise_linear(list(zip(self.xvals, self.yvals[0])))
        f2 = create_piecewise_linear(list(zip(self.xvals, self.yvals[1])))
        f3 = create_piecewise_linear(list(zip(self.xvals, self.yvals[2])))
        func_plotted1 = plane.plot(f1, color=ORANGE)
        func_plotted2 = plane.plot(f2, color=BLUE)
        func_plotted3 = plane.plot(f3, color=GREEN)

        tab = Table([[str(val) for val in self.xvals], [str(val) for val in self.yvals[self.correcty]]],
                    color=BLACK, line_config={"color":BLACK}, element_to_mobject_config={"color":BLACK},
                    row_labels=[Text(self.labels[0], color=BLACK, font_size = fs1), Text(self.labels[1], color=BLACK, font_size = fs1)])
        tab = tab.scale(3.3/tab.get_width()).next_to(plane, DOWN, buff=0.35)

        # Initialize a cursor
        xo, yo, _ = plane.c2p(*self.cursorStart)
        cursor = AltCursor(stroke_width=0.0, idle=True, x=xo, y=yo)
        cursor.autoFadeBackground = True

        # Action Sequence
        with self.voiceover(
                text=f"""
                <prosody rate="110%">
                Imagine, <bookmark mark="action"/>
                {self.intro}. <bookmark mark="values"/>
                
                The values are entered in this table.
                
                Now the question is:
                Which function corresponds to the values in the table?

                <bookmark mark="orange"/>
                Is it the orange function?

                <bookmark mark="blue"/>
                Or is it the blue function?

                <bookmark mark="green"/>
                Or perhaps the green function?

                </prosody>
                """
        ) as tracker:
            
            # Highlight first Text
            self.wait_until_bookmark("action")
            self.add_shift_sound(0.5)
            self.play(self.introImg.animate.shift(5*RIGHT), run_time=0.5)

            # Animate the coordinate system being created
            self.wait_until_bookmark("values")
            self.play(Write(tab))

            # Show the orange function
            self.wait_until_bookmark("orange")
            self.add_shift_sound(0.5)
            self.play(self.introImg.animate.shift(5*RIGHT), Write(self.cords), run_time=0.5)
            self.add_pencil_sound(1.5)
            self.play(Write(func_plotted1))

            # Show the blue function
            self.wait_until_bookmark("blue")
            self.add_pencil_sound(1.5)
            self.play(Write(func_plotted2))

            # Show the green function
            self.wait_until_bookmark("green")
            self.add_pencil_sound(1.5)
            self.play(Write(func_plotted3))

        # Wait for 4 seconds at the end of animation
        self.wait(4)

class ValueTableSolutionScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):


        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create the coordinate system
        plane = self.cords[0]

        # Add title to the scene
        self.add_title(self.title)

        # Create and plot piecewise linear function
        f1 = create_piecewise_linear(list(zip(self.xvals, self.yvals[0])))
        f2 = create_piecewise_linear(list(zip(self.xvals, self.yvals[1])))
        f3 = create_piecewise_linear(list(zip(self.xvals, self.yvals[2])))
        fcorrect = create_piecewise_linear(list(zip(self.xvals, self.yvals[self.correcty])))
        func_plotted1 = plane.plot(f1, color=ORANGE)
        func_plotted2 = plane.plot(f2, color=BLUE)
        func_plotted3 = plane.plot(f3, color=GREEN)
        func_plotted_correct = plane.plot(fcorrect, color=RED)


        colors = ["Orange", "Blue", "Green"]
        funcs = [func_plotted1, func_plotted2, func_plotted3]

        tab = Table([[str(val) for val in self.xvals], [str(val) for val in self.yvals[self.correcty]]],
                    color=BLACK, line_config={"color":BLACK}, element_to_mobject_config={"color":BLACK},
                    row_labels=[Text(self.labels[0], color=BLACK, font_size = fs1), Text(self.labels[1], color=BLACK, font_size = fs1)])
        tab = tab.scale(3.3/tab.get_width()).next_to(plane, DOWN, buff=0.6)

        # Initialize a cursor
        xo, yo, _ = plane.c2p(*self.cursorStart)
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])
        first_bit = f"That's not correct. The {colors[self.idx_selected]} function is not the correct one."
        if self.idx_selected == self.correcty:
            first_bit = f"That's correct, great job!"

        # Action Sequence
        with self.voiceover(
                text=f"""
                <prosody rate="110%">
                {first_bit}
                So you selected the <bookmark mark="Func"/>{colors[self.idx_selected]} function.
                To check if this is correct, let's enter the values from the table into the coordinate system, one after the other.
                In this example, the <bookmark mark="xaxis"/> x-axis represents {self.Textlabels[0]} and the <bookmark mark="yaxis"/>
                y-axis represents {self.Textlabels[1]}.

                <bookmark mark="val1"/>
                The first value has {nums[self.xvals[0]]} as its x-value and {nums[self.yvals[self.correcty][0]]} as its y-value.

                <bookmark mark="val2"/>
                The second value has {nums[self.xvals[1]]} as its x-value and {nums[self.yvals[self.correcty][1]]} as its y-value.

                <bookmark mark="val3"/>
                The third value has coordinates {nums[self.xvals[2]]} and {nums[self.yvals[self.correcty][2]]}.

                <bookmark mark="val4"/>
                The fourth value has coordinates {nums[self.xvals[3]]} and {nums[self.yvals[self.correcty][3]]}.

                <bookmark mark="val5"/>
                And the fifth value has coordinates {nums[self.xvals[4]]} and {nums[self.yvals[self.correcty][4]]}.

                If we connect these values, <bookmark mark="TrueFunc"/>we can see that the {colors[self.correcty]} function
                is the correct one.
                </prosody>
                """
        ) as tracker:
            
            # Create the Coordinate System
            self.play(Write(self.cords), Write(tab))

            # Highlight first Text
            self.wait_until_bookmark("Func")
            self.play(Write(funcs[self.idx_selected]))
            self.add(cursor)

            # Highlight x-Axis
            self.wait_until_bookmark("xaxis")
            cursor.idle=False
            self.play(CursorMarkAxis(cursor, plane, 'x'), run_time=0.5)

            # Highlight y-Axis
            self.wait_until_bookmark("yaxis")
            self.play(CursorMarkAxis(cursor, plane, 'y'), run_time=0.5)

            # Create first Value
            self.wait_until_bookmark("val1")
            x,y,_ = plane.c2p(self.xvals[0], self.yvals[self.correcty][0])
            self.play(CursorMoveResize(cursor, x, y, 0.2, 0.2))
            c2 = cursor.copy()
            self.add(c2)

            # Create second Value
            self.wait_until_bookmark("val2")
            x,y,_ = plane.c2p(self.xvals[1], self.yvals[self.correcty][1])
            self.play(CursorMoveTo(cursor, x, y))
            c3 = cursor.copy()
            self.add(c3)

            # Create third Value
            self.wait_until_bookmark("val3")
            x,y,_ = plane.c2p(self.xvals[2], self.yvals[self.correcty][2])
            self.play(CursorMoveTo(cursor, x, y))
            c4 = cursor.copy()
            self.add(c4)

            # Create fourth Value
            self.wait_until_bookmark("val4")
            x,y,_ = plane.c2p(self.xvals[3], self.yvals[self.correcty][3])
            self.play(CursorMoveTo(cursor, x, y))
            c5 = cursor.copy()
            self.add(c5)

            # Create fifth Value
            self.wait_until_bookmark("val5")
            x,y,_ = plane.c2p(self.xvals[4], self.yvals[self.correcty][4])
            self.play(CursorMoveTo(cursor, x, y))
            c6 = cursor.copy()
            self.add(c6)

            # Create the function
            self.wait_until_bookmark("TrueFunc")
            self.play(Write(func_plotted_correct), run_time=3)

        # Wait for 4 seconds at the end of animation
        self.wait(4)




#############################################
#               Hike Question               #
#############################################

TASK_Func_1_1_P_1_q = SophiaTaskDefinition(
    answerOptions = ["The orange function", "The blue function", "The green function"],
    correctAnswerIndex = 0,
    questionText = "Which function matches the values?"   
)

class Func_1_1_P_1_q(ValueTableQuestionScene):

    def construct(self):
        self.intro="""We're going on a mountain hike.
                
                During this, we measure our altitude at each full hour."""
        self.texts=[["Imagine this:", "We're hiking through the mountains"], "We measure our altitude hourly", "$\\rightarrow$Which function fits this scenario?"]
        self.xvals = [0,1,2,3,4]
        self.yvals = [[4,1,0,1,4],[2,0,1,1,3],[1,3,4,1,2]]
        self.cords = self.add_cords([0,4,1], [0, 4, 1], x_ticks=[0,2,4], x_labels=[0,2,4], y_ticks=[2,4], y_labels=[2,4], height=2).shift(0.4*DOWN)
        self.title="Mountain Hike"
        self.cursorStart = [0,0]
        self.correcty = 0
        self.introImg = ImageMobject(assets_folder / "img" / "matterhorn.png")
        self.introImg = self.introImg.scale(7/self.introImg.get_width()).move_to([-5, 1, 0])
        self.labels=["Time", "Altitude"]
        super().construct()


class Func_1_1_P_1_a(ValueTableSolutionScene):

    def construct(self):

        self.correcty = 0
        self.idx_selected = 0
        self.xvals = [0,1,2,3,4]
        self.yvals = [[4,1,0,1,4],[2,0,1,1,3],[1,3,4,1,2]]
        self.cords = self.add_cords([0,4,1], [0, 4, 1], x_ticks=[0,2,4], x_labels=[0,2,4], y_ticks=[2,4], y_labels=[2,4], height=2).shift(0.4*DOWN)
        self.title = "Mountain Hike"
        self.cursorStart = [0,0]
        self.labels = ["Time", "Altitude"]
        self.Textlabels = ["The time", "The altitude"]

        super().construct()

class Func_1_1_P_1_b(ValueTableSolutionScene):

    def construct(self):

        self.correcty = 0
        self.idx_selected = 1
        self.xvals = [0,1,2,3,4]
        self.yvals = [[4,1,0,1,4],[2,0,1,1,3],[1,3,4,1,2]]
        self.cords = self.add_cords([0,4,1], [0, 4, 1], x_ticks=[0,2,4], x_labels=[0,2,4], y_ticks=[2,4], y_labels=[2,4], height=2).shift(0.4*DOWN)
        self.title = "Mountain Hike"
        self.cursorStart = [0,0]
        self.labels = ["Time", "Altitude"]
        self.Textlabels = ["The time", "The altitude"]

        super().construct()

class Func_1_1_P_1_c(ValueTableSolutionScene):

    def construct(self):

        self.correcty = 0
        self.idx_selected = 2
        self.xvals = [0,1,2,3,4]
        self.yvals = [[4,1,0,1,4],[2,0,1,1,3],[1,3,4,1,2]]
        self.cords = self.add_cords([0,4,1], [0, 4, 1], x_ticks=[0,2,4], x_labels=[0,2,4], y_ticks=[2,4], y_labels=[2,4], height=2).shift(0.4*DOWN)
        self.title = "Mountain Hike"
        self.cursorStart = [0,0]
        self.labels = ["Time", "Altitude"]
        self.Textlabels = ["The time", "The altitude"]

        super().construct()



#############################################
#               Rain Question               #
#############################################


TASK_Func_1_1_P_2_q = SophiaTaskDefinition(
    answerOptions = ["The orange function", "The blue function", "The green function"],
    correctAnswerIndex = 2,
    questionText = "Which function matches the values?"   
)

class Func_1_1_P_2_q(ValueTableQuestionScene):

    def construct(self):
        self.intro = """It's rainy season.
                
                We want to know how much precipitation there is and measure the amount of rain daily."""
        self.texts = [["Imagine:", "It's raining heavily"], "We measure the amount of rain daily", "$\\rightarrow$Which function matches this?"]
        self.xvals = [1,2,3,4,5]
        self.yvals = [[10, 20, 30, 40, 20], [30, 10, 40, 20, 30], [20, 30, 10, 40, 30]]
        self.cords = self.add_cords([1,5,1], [0, 40, 10], x_ticks=[1,3,5], x_labels=[1,3,5], y_ticks=[10,20,30,40], y_labels=[10,20,30,40], height=2).shift(0.4*DOWN)
        self.title = "Rainy Weather"
        self.cursorStart = [1,0]
        self.correcty = 2
        self.introImg = ImageMobject(assets_folder / "img" / "rain.png").scale(0.35).move_to([-5, 1, 0])
        self.labels = ["Day", "mm"]
        super().construct()

class Func_1_1_P_2_a(ValueTableSolutionScene):

    def construct(self):

        self.correcty = 2
        self.idx_selected = 0
        self.xvals = [1,2,3,4,5]
        self.yvals = [[10, 20, 30, 40, 20], [30, 10, 40, 20, 30], [20, 30, 10, 40, 30]]
        self.cords = self.add_cords([1,5,1], [0, 40, 10], x_ticks=[1,3,5], x_labels=[1,3,5], y_ticks=[10,20,30,40], y_labels=[10,20,30,40], height=2).shift(0.4*DOWN)
        self.title = "Rainy Weather"
        self.cursorStart = [1,0]
        self.Textlabels = ["The day, numbered from one to five", "The amount of rain in millimeters"]
        self.labels = ["Day", "mm"]

        super().construct()

class Func_1_1_P_2_b(ValueTableSolutionScene):

    def construct(self):

        self.correcty = 2
        self.idx_selected = 1
        self.xvals = [1,2,3,4,5]
        self.yvals = [[10, 20, 30, 40, 20], [30, 10, 40, 20, 30], [20, 30, 10, 40, 30]]
        self.cords = self.add_cords([1,5,1], [0, 40, 10], x_ticks=[1,3,5], x_labels=[1,3,5], y_ticks=[10,20,30,40], y_labels=[10,20,30,40], height=2).shift(0.4*DOWN)
        self.title = "Rainy Weather"
        self.cursorStart = [1,0]
        self.Textlabels = ["The day, numbered from one to five", "The amount of rain in millimeters"]
        self.labels = ["Day", "mm"]

        super().construct()

class Func_1_1_P_2_c(ValueTableSolutionScene):

    def construct(self):

        self.correcty = 2
        self.idx_selected = 1
        self.xvals = [1,2,3,4,5]
        self.yvals = [[10, 20, 30, 40, 20], [30, 10, 40, 20, 30], [20, 30, 10, 40, 30]]
        self.cords = self.add_cords([1,5,1], [0, 40, 10], x_ticks=[1,3,5], x_labels=[1,3,5], y_ticks=[10,20,30,40], y_labels=[10,20,30,40], height=2).shift(0.4*DOWN)
        self.title = "Rainy Weather"
        self.cursorStart = [1,0]
        self.Textlabels = ["The day, numbered from one to five", "The amount of rain in millimeters"]
        self.labels = ["Day", "mm"]

        super().construct()

#############################################
#               Snow Question               #
#############################################

TASK_Func_1_1_P_3_q = SophiaTaskDefinition(
    answerOptions = ["The orange function", "The blue function", "The green function"],
    correctAnswerIndex = 1,
    questionText = "Which function matches the values?"   
)

class Func_1_1_P_3_q(ValueTableQuestionScene):

    def construct(self):
        self.intro = """It's winter time.
                
                We want to know how much snow is falling and measure the amount of snow daily."""
        self.texts = [["Imagine:", "It's snowing heavily"], "We measure the amount of snow daily", "$\\rightarrow$Which function matches this?"]
        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[5, 10, 15, 10, 5], [10, 5, 15, 10, 15], [10, 15, 5, 15, 10]]
        self.cords = self.add_cords([1, 5, 1], [0, 15, 5], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[5, 10, 15], y_labels=[5, 10, 15], height=2).shift(0.4*DOWN)
        self.title = "Snowy Weather"
        self.cursorStart = [1, 0]
        self.correcty = 1
        self.introImg = ImageMobject(assets_folder / "img" / "snow.png")
        self.introImg = self.introImg.scale(2.5/self.introImg.get_width()).move_to([-5, 1, 0])
        self.labels = ["Day", "cm"]
        super().construct()

class Func_1_1_P_3_a(ValueTableSolutionScene):

    def construct(self):
        self.correcty = 1
        self.idx_selected = 0
        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[5, 10, 15, 10, 5], [10, 5, 15, 10, 15], [10, 15, 5, 15, 10]]
        self.cords = self.add_cords([1, 5, 1], [0, 15, 5], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[5, 10, 15], y_labels=[5, 10, 15], height=2).shift(0.4*DOWN)
        self.title = "Snowy Weather"
        self.cursorStart = [1, 0]
        self.correcty = 1
        self.introImg = ImageMobject(assets_folder / "img" / "snow.png")
        self.introImg = self.introImg.scale(2.5/self.introImg.get_width()).move_to([-5, 1, 0])
        self.labels = ["Day", "cm"]
        self.Textlabels = ["The day, numbered from one to five", "The amount of snow in centimeters"]

        super().construct()

class Func_1_1_P_3_b(ValueTableSolutionScene):

    def construct(self):
        self.correcty = 1
        self.idx_selected = 1
        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[5, 10, 15, 10, 5], [10, 5, 15, 10, 15], [10, 15, 5, 15, 10]]
        self.cords = self.add_cords([1, 5, 1], [0, 15, 5], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[5, 10, 15], y_labels=[5, 10, 15], height=2).shift(0.4*DOWN)
        self.title = "Snowy Weather"
        self.cursorStart = [1, 0]
        self.correcty = 1
        self.introImg = ImageMobject(assets_folder / "img" / "snow.png")
        self.introImg = self.introImg.scale(2.5/self.introImg.get_width()).move_to([-5, 1, 0])
        self.labels = ["Day", "cm"]
        self.Textlabels = ["The day, numbered from one to five", "The amount of snow in centimeters"]

        super().construct()

class Func_1_1_P_3_c(ValueTableSolutionScene):

    def construct(self):
        self.correcty = 1
        self.idx_selected = 2
        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[5, 10, 15, 10, 5], [10, 5, 15, 10, 15], [10, 15, 5, 15, 10]]
        self.cords = self.add_cords([1, 5, 1], [0, 15, 5], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[5, 10, 15], y_labels=[5, 10, 15], height=2).shift(0.4*DOWN)
        self.title = "Snowy Weather"
        self.cursorStart = [1, 0]
        self.correcty = 1
        self.introImg = ImageMobject(assets_folder / "img" / "snow.png")
        self.introImg = self.introImg.scale(2.5/self.introImg.get_width()).move_to([-5, 1, 0])
        self.labels = ["Day", "cm"]
        self.Textlabels = ["The day, numbered from one to five", "The amount of snow in centimeters"]

        super().construct()

    

# Similar Answer Scenes for SnowQuestionScene can be created like RainAnswerScene1, RainAnswerScene2 and RainAnswerScene3


#############################################
#           Sunshine Hours Question         #
#############################################

    
TASK_Func_1_1_P_4_q = SophiaTaskDefinition(
    answerOptions = ["The orange function", "The blue function", "The green function"],
    correctAnswerIndex = 0,
    questionText = "Which function fits the values?"   
)

class Func_1_1_P_4_q(ValueTableQuestionScene):

    def construct(self):
        self.intro = """It's summer time.
                
                We want to know how many hours of sunshine we get, so we measure the number of hours of sunshine daily."""
        self.texts = [["Imagine:", "The sun is shining all day"], "We measure the daily hours of sunshine", "$\\rightarrow$Which function fits this?"]
        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[12, 10, 11, 12, 10], [10, 12, 10, 11, 12], [11, 12, 10, 12, 11]]
        self.cords = self.add_cords([1, 5, 1], [10, 12, 1], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[10, 11, 12], y_labels=[10, 11, 12], height=2).shift(0.4*DOWN)
        self.title = "Sunshine Duration"
        self.cursorStart = [1, 0]
        self.correcty = 0
        self.introImg = ImageMobject(assets_folder / "img" / "sun.png")
        self.introImg = self.introImg.scale(3/self.introImg.get_width()).move_to([-5, 1, 0])
        self.labels = ["Day", "Hours"]
        super().construct()

class Func_1_1_P_4_a(ValueTableSolutionScene):

    def construct(self):

        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[12, 10, 11, 12, 10], [10, 12, 10, 11, 12], [11, 12, 10, 12, 11]]
        self.cords = self.add_cords([1, 5, 1], [10, 12, 1], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[10, 11, 12], y_labels=[10, 11, 12], height=2).shift(0.4*DOWN)
        self.title = "Sunshine Duration"
        self.cursorStart = [1, 10]
        self.correcty = 0
        self.idx_selected=0
        self.labels = ["Day", "Hours"]
        self.Textlabels = ["The day, numbered from one to five", "The amount of hours of sunshine"]

        super().construct()

class Func_1_1_P_4_b(ValueTableSolutionScene):

    def construct(self):

        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[12, 10, 11, 12, 10], [10, 12, 10, 11, 12], [11, 12, 10, 12, 11]]
        self.cords = self.add_cords([1, 5, 1], [10, 12, 1], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[10, 11, 12], y_labels=[10, 11, 12], height=2).shift(0.4*DOWN)
        self.title = "Sunshine Duration"
        self.cursorStart = [1, 10]
        self.correcty = 0
        self.idx_selected=1
        self.labels = ["Day", "Hours"]
        self.Textlabels = ["The day, numbered from one to five", "The amount of hours of sunshine"]

        super().construct()

class Func_1_1_P_4_c(ValueTableSolutionScene):

    def construct(self):

        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[12, 10, 11, 12, 10], [10, 12, 10, 11, 12], [11, 12, 10, 12, 11]]
        self.cords = self.add_cords([1, 5, 1], [10, 12, 1], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[10, 11, 12], y_labels=[10, 11, 12], height=2).shift(0.4*DOWN)
        self.title = "Sunshine Duration"
        self.cursorStart = [1, 10]
        self.correcty = 0
        self.idx_selected=2
        self.labels = ["Day", "Hours"]
        self.Textlabels = ["The day, numbered from one to five", "The amount of hours of sunshine"]

        super().construct()


#############################################
#           Wind Speed Question             #
#############################################

TASK_Func_1_1_P_5_q = SophiaTaskDefinition(
    answerOptions = ["The orange function", "The blue function", "The green function"],
    correctAnswerIndex = 2,
    questionText = "Which function fits the values?"   
)

class Func_1_1_P_5_q(ValueTableQuestionScene):

    def construct(self):
        self.intro = """It's a stormy day.
                
                That's great news for us, because we operate a park with wind turbines that produce renewable energy.
                We want to know how fast the wind is blowing and measure the wind speed hourly."""
        self.texts = [["Imagine:", "The wind is blowing very strongly"], "We measure the wind speed hourly", "$\\rightarrow$Which function fits this?"]
        self.xvals = [1, 2, 3, 4, 5, 6]
        self.yvals = [[20, 30, 40, 50, 40, 30], [30, 20, 50, 40, 30, 50], [30, 40, 20, 50, 40, 30]]
        self.cords = self.add_cords([1, 6, 1], [0, 50, 10], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[20, 30, 40, 50], y_labels=[20, 30, 40, 50], height=2).shift(0.4*DOWN)
        self.title = "Wind Speed"
        self.cursorStart = [1, 20]
        self.correcty = 2
        self.introImg = ImageMobject(assets_folder / "img" / "wind.png").scale(0.35).move_to([-5, 1, 0])
        self.labels = ["Hour", "km/h"]
        super().construct()

class Func_1_1_P_5_a(ValueTableSolutionScene):

    def construct(self):
        self.xvals = [1, 2, 3, 4, 5, 6]
        self.yvals = [[20, 30, 40, 50, 40, 30], [30, 20, 50, 40, 30, 50], [30, 40, 20, 50, 40, 30]]
        self.cords = self.add_cords([1, 6, 1], [0, 50, 10], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[20, 30, 40, 50], y_labels=[20, 30, 40, 50], height=2).shift(0.4*DOWN)
        self.title = "Wind Speed"
        self.cursorStart = [1, 20]
        self.correcty = 2
        self.idx_selected=0
        self.labels = ["Hour", "km/h"]
        self.Textlabels = ["The hour, numbered from one to six", "The wind speed in kilometers per hour"]
        super().construct()

class Func_1_1_P_5_b(ValueTableSolutionScene):

    def construct(self):
        self.xvals = [1, 2, 3, 4, 5, 6]
        self.yvals = [[20, 30, 40, 50, 40, 30], [30, 20, 50, 40, 30, 50], [30, 40, 20, 50, 40, 30]]
        self.cords = self.add_cords([1, 6, 1], [0, 50, 10], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[20, 30, 40, 50], y_labels=[20, 30, 40, 50], height=2).shift(0.4*DOWN)
        self.title = "Wind Speed"
        self.cursorStart = [1, 20]
        self.correcty = 2
        self.idx_selected=1
        self.labels = ["Hour", "km/h"]
        self.Textlabels = ["The hour, numbered from one to six", "The wind speed in kilometers per hour"]
        super().construct()

class Func_1_1_P_5_c(ValueTableSolutionScene):

    def construct(self):
        self.xvals = [1, 2, 3, 4, 5, 6]
        self.yvals = [[20, 30, 40, 50, 40, 30], [30, 20, 50, 40, 30, 50], [30, 40, 20, 50, 40, 30]]
        self.cords = self.add_cords([1, 6, 1], [0, 50, 10], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[20, 30, 40, 50], y_labels=[20, 30, 40, 50], height=2).shift(0.4*DOWN)
        self.title = "Wind Speed"
        self.cursorStart = [1, 20]
        self.correcty = 2
        self.idx_selected=2
        self.labels = ["Hour", "km/h"]
        self.Textlabels = ["The hour, numbered from one to six", "The wind speed in kilometers per hour"]
        super().construct()

#############################################
#            Temperature Question           #
#############################################

TASK_Func_1_1_P_6_q = SophiaTaskDefinition(
    answerOptions = ["The orange function", "The blue function", "The green function"],
    correctAnswerIndex = 0,
    questionText = "Which function fits the values?"   
)

class Func_1_1_P_6_q(ValueTableQuestionScene):

    def construct(self):
        self.intro = """It's spring.
                
                We want to know how the temperature changes and measure the temperature daily."""
        self.texts = [["Imagine:", "The temperatures rise and fall"], "We measure the temperature daily", "$\\rightarrow$Which function fits this?"]
        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[10, 15, 12, 14, 13], [15, 10, 14, 13, 15], [13, 14, 10, 15, 14]]
        self.cords = self.add_cords([1, 5, 1], [10, 15, 1], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[10, 12, 14], y_labels=[10, 12, 14], height=2).shift(0.4*DOWN)
        self.title = "Temperature Change"
        self.cursorStart = [1, 10]
        self.correcty = 0
        self.introImg = ImageMobject(assets_folder / "img" / "spring.png").scale(0.35).move_to([-5, -0.3, 0])
        self.labels = ["Day", "°C"]
        super().construct()

class Func_1_1_P_6_a(ValueTableSolutionScene):

    def construct(self):
        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[10, 15, 12, 14, 13], [15, 10, 14, 13, 15], [13, 14, 10, 15, 14]]
        self.cords = self.add_cords([1, 5, 1], [10, 15, 1], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[10, 12, 14], y_labels=[10, 12, 14], height=2).shift(0.4*DOWN)
        self.title = "Temperature Change"
        self.cursorStart = [1, 10]
        self.correcty = 0
        self.idx_selected = 0
        self.labels = ["Day", "°C"]
        self.Textlabels = ["The day", "The temperature in degrees Celsius"]
        super().construct()

class Func_1_1_P_6_b(ValueTableSolutionScene):

    def construct(self):
        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[10, 15, 12, 14, 13], [15, 10, 14, 13, 15], [13, 14, 10, 15, 14]]
        self.cords = self.add_cords([1, 5, 1], [10, 15, 1], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[10, 12, 14], y_labels=[10, 12, 14], height=2).shift(0.4*DOWN)
        self.title = "Temperature Change"
        self.cursorStart = [1, 10]
        self.correcty = 0
        self.idx_selected = 1
        self.labels = ["Day", "°C"]
        self.Textlabels = ["The day", "The temperature in degrees Celsius"]
        super().construct()

class Func_1_1_P_6_c(ValueTableSolutionScene):

    def construct(self):
        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[10, 15, 12, 14, 13], [15, 10, 14, 13, 15], [13, 14, 10, 15, 14]]
        self.cords = self.add_cords([1, 5, 1], [10, 15, 1], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[10, 12, 14], y_labels=[10, 12, 14], height=2).shift(0.4*DOWN)
        self.title = "Temperature Change"
        self.cursorStart = [1, 10]
        self.correcty = 0
        self.idx_selected = 2
        self.labels = ["Day", "°C"]
        self.Textlabels = ["The day", "The temperature in degrees Celsius"]
        super().construct()

#############################################
#             Humidity Question             #
#############################################

TASK_Func_1_1_P_7_q = SophiaTaskDefinition(
    answerOptions = ["The orange function", "The blue function", "The green function"],
    correctAnswerIndex = 1,
    questionText = "Which function fits the values?"   
)

class Func_1_1_P_7_q(ValueTableQuestionScene):

    def construct(self):
        self.intro = """It's a humid day.
                
                We want to know how high the humidity is and measure it hourly."""
        self.texts = [["Imagine:", "The humidity is very high"], "We measure the humidity hourly", "$\\rightarrow$Which function fits this?"]
        self.xvals = [1, 2, 3, 4, 5, 6]
        self.yvals = [[70, 75, 80, 85, 80, 75], [75, 70, 85, 80, 75, 85], [75, 80, 70, 85, 80, 75]]
        self.cords = self.add_cords([1, 6, 1], [70, 90, 10], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[70, 75, 80, 85], y_labels=[70, 75, 80, 85], height=2).shift(0.4*DOWN)
        self.title = "Humidity"
        self.cursorStart = [1, 0]
        self.correcty = 1
        self.introImg = ImageMobject(assets_folder / "img" / "palmtree.png").scale(0.15).move_to([-5, 1.9, 0])
        self.labels = ["Hour", "%"]
        super().construct()

class Func_1_1_P_7_a(ValueTableSolutionScene):

    def construct(self):
        self.xvals = [1, 2, 3, 4, 5, 6]
        self.yvals = [[70, 75, 80, 85, 80, 75], [75, 70, 85, 80, 75, 85], [75, 80, 70, 85, 80, 75]]
        self.cords = self.add_cords([1, 6, 1], [70, 90, 10], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[70, 75, 80, 85], y_labels=[70, 75, 80, 85], height=2).shift(0.4*DOWN)
        self.title = "Humidity"
        self.cursorStart = [1, 0]
        self.correcty = 1
        self.idx_selected = 0
        self.labels = ["Hour", "%"]
        self.Textlabels = ["The hour", "The humidity in percentage"]
        super().construct()

class Func_1_1_P_7_b(ValueTableSolutionScene):

    def construct(self):
        self.xvals = [1, 2, 3, 4, 5, 6]
        self.yvals = [[70, 75, 80, 85, 80, 75], [75, 70, 85, 80, 75, 85], [75, 80, 70, 85, 80, 75]]
        self.cords = self.add_cords([1, 6, 1], [70, 90, 10], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[70, 75, 80, 85], y_labels=[70, 75, 80, 85], height=2).shift(0.4*DOWN)
        self.title = "Humidity"
        self.cursorStart = [1, 0]
        self.correcty = 1
        self.idx_selected = 1
        self.labels = ["Hour", "%"]
        self.Textlabels = ["The hour", "The humidity in percentage"]
        super().construct()

class Func_1_1_P_7_c(ValueTableSolutionScene):

    def construct(self):
        self.xvals = [1, 2, 3, 4, 5, 6]
        self.yvals = [[70, 75, 80, 85, 80, 75], [75, 70, 85, 80, 75, 85], [75, 80, 70, 85, 80, 75]]
        self.cords = self.add_cords([1, 6, 1], [70, 90, 10], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[70, 75, 80, 85], y_labels=[70, 75, 80, 85], height=2).shift(0.4*DOWN)
        self.title = "Humidity"
        self.cursorStart = [1, 0]
        self.correcty = 1
        self.idx_selected = 2
        self.labels = ["Hour", "%"]
        self.Textlabels = ["The hour", "The humidity in percentage"]
        super().construct()

#############################################
#             Apple Picking Question        #
#############################################

TASK_Func_1_1_P_8_q = SophiaTaskDefinition(
    answerOptions = ["The orange function", "The blue function", "The green function"],
    correctAnswerIndex = 1,
    questionText = "Which function fits the values?"   
)

class Func_1_1_P_8_q(ValueTableQuestionScene):

    def construct(self):
        self.intro = """It's harvest time.
                
                We want to know how many apples we collect and count the number of picked apples daily."""
        self.texts = [["Imagine:", "It's apple harvest time"], "We count the harvested apples daily", "$\\rightarrow$Which function fits this?"]
        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[15, 30, 20, 25, 18], [20, 15, 25, 18, 30], [25, 20, 15, 30, 18]]
        self.cords = self.add_cords([1, 5, 1], [0, 30, 5], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[10, 20, 30], y_labels=[10, 20, 30], height=2).shift(0.4*DOWN)
        self.title = "Apple Harvest"
        self.cursorStart = [1, 0]
        self.correcty = 1
        self.introImg = ImageMobject(assets_folder / "img" / "apple.png").scale(0.5).move_to([-5, 1, 0])
        self.labels = ["Day", "Apples"]
        super().construct()

class Func_1_1_P_8_a(ValueTableSolutionScene):

    def construct(self):
        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[15, 30, 20, 25, 18], [20, 15, 25, 18, 30], [25, 20, 15, 30, 18]]
        self.cords = self.add_cords([1, 5, 1], [0, 30, 5], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[10, 20, 30], y_labels=[10, 20, 30], height=2).shift(0.4*DOWN)
        self.title = "Apple Harvest"
        self.cursorStart = [1, 0]
        self.correcty = 1
        self.idx_selected = 0
        self.labels = ["Day", "Apples"]
        self.Textlabels = ["The day", "The number of harvested apples"]
        super().construct()

class Func_1_1_P_8_b(ValueTableSolutionScene):

    def construct(self):
        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[15, 30, 20, 25, 18], [20, 15, 25, 18, 30], [25, 20, 15, 30, 18]]
        self.cords = self.add_cords([1, 5, 1], [0, 30, 5], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[10, 20, 30], y_labels=[10, 20, 30], height=2).shift(0.4*DOWN)
        self.title = "Apple Harvest"
        self.cursorStart = [1, 0]
        self.correcty = 1
        self.idx_selected = 1
        self.labels = ["Day", "Apples"]
        self.Textlabels = ["The day", "The number of harvested apples"]
        super().construct()

class Func_1_1_P_8_c(ValueTableSolutionScene):

    def construct(self):
        self.xvals = [1, 2, 3, 4, 5]
        self.yvals = [[15, 30, 20, 25, 18], [20, 15, 25, 18, 30], [25, 20, 15, 30, 18]]
        self.cords = self.add_cords([1, 5, 1], [0, 30, 5], x_ticks=[1, 3, 5], x_labels=[1, 3, 5], y_ticks=[10, 20, 30], y_labels=[10, 20, 30], height=2).shift(0.4*DOWN)
        self.title = "Apple Harvest"
        self.cursorStart = [1, 0]
        self.correcty = 1
        self.idx_selected = 2
        self.labels = ["Day", "Apples"]
        self.Textlabels = ["The day", "The number of harvested apples"]
        super().construct()



# Add the scene to prototypes
PROTOTYPES = [
    PagePrototypeVideo.from_scene(Func_1_1_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_1_I_1_q, Func_1_1_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_1_I_1_a),
    PagePrototypeVideo.from_scene(Func_1_1_I_1_b),
    PagePrototypeVideo.from_scene(Func_1_1_I_2),
    PagePrototypeVideo.from_scene(Func_1_1_I_3),
    PagePrototypeVideo.from_scene(Func_1_1_P_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_1_P_1_q, Func_1_1_P_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_1_P_1_a),
    PagePrototypeVideo.from_scene(Func_1_1_P_1_b),
    PagePrototypeVideo.from_scene(Func_1_1_P_1_c),
    PagePrototypeVideo.from_scene(Func_1_1_P_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_1_P_2_q, Func_1_1_P_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_1_P_2_a),
    PagePrototypeVideo.from_scene(Func_1_1_P_2_b),
    PagePrototypeVideo.from_scene(Func_1_1_P_2_c),
    PagePrototypeVideo.from_scene(Func_1_1_P_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_1_P_3_q, Func_1_1_P_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_1_P_3_a),
    PagePrototypeVideo.from_scene(Func_1_1_P_3_b),
    PagePrototypeVideo.from_scene(Func_1_1_P_3_c),
    PagePrototypeVideo.from_scene(Func_1_1_P_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_1_P_4_q, Func_1_1_P_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_1_P_4_a),
    PagePrototypeVideo.from_scene(Func_1_1_P_4_b),
    PagePrototypeVideo.from_scene(Func_1_1_P_4_c),
    PagePrototypeVideo.from_scene(Func_1_1_P_5_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_1_P_5_q, Func_1_1_P_5_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_1_P_5_a),
    PagePrototypeVideo.from_scene(Func_1_1_P_5_b),
    PagePrototypeVideo.from_scene(Func_1_1_P_5_c),
    PagePrototypeVideo.from_scene(Func_1_1_P_6_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_1_P_6_q, Func_1_1_P_6_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_1_P_6_a),
    PagePrototypeVideo.from_scene(Func_1_1_P_6_b),
    PagePrototypeVideo.from_scene(Func_1_1_P_6_c),
    PagePrototypeVideo.from_scene(Func_1_1_P_7_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_1_P_7_q, Func_1_1_P_7_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_1_P_7_a),
    PagePrototypeVideo.from_scene(Func_1_1_P_7_b),
    PagePrototypeVideo.from_scene(Func_1_1_P_7_c),
    PagePrototypeVideo.from_scene(Func_1_1_P_8_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_1_1_P_8_q, Func_1_1_P_8_q.__name__),
    PagePrototypeVideo.from_scene(Func_1_1_P_8_a),
    PagePrototypeVideo.from_scene(Func_1_1_P_8_b),
    PagePrototypeVideo.from_scene(Func_1_1_P_8_c)
]


scenes/Func/Func_1: Intro Functions/Func_1_1.py
Sophia-Edu-Labs/sophia-math
# 2_1: Linear Functions Intro, Graph to Term

# Import necessary libraries and modules
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import *
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition


#####################################
#####################################
TASK_Func_2_1_I_1_q = SophiaTaskDefinition(
    answerOptions = ["The red function", "The blue function", "The green function"],
    correctAnswerIndex = 2,
    questionText = "Which function describes the fill level over time?"
)
class Func_2_1_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Load and position images
        lemonade = ImageMobject(assets_folder / "img" / "lemonade.png")
        lemonade = lemonade.scale(3.5/lemonade.get_width()).move_to([-5.2, 1, 0])

        # Create the coordinate system
        cords = self.add_cords([0, 30, 6], [0, 180, 30], x_ticks=[6, 12, 18, 24], y_ticks=[60, 120, 180]).shift(DOWN)
        plane = cords[0]

        # Add title to the scene
        self.add_title("Linear Functions")

        # Create and plot piecewise linear function
        func1 = lambda x: x**2/5
        func_2 = lambda x: 180/(30**0.5) * x**0.5
        func3 = lambda x: 6 * x

        func1_plotted = plane.plot(func1, color=RED)
        Func_2_plotted = plane.plot(func_2, color=BLUE)
        func3_plotted = plane.plot(func3, color=GREEN)

        # Initialize a cursor
        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])

        # Action Sequence
        with self.voiceover(
                text="""
                We're now going to learn about a specific type of functions: - Linear Functions.
                <break time="1s"/>
                Let's start with an example. Suppose we want to enjoy <bookmark mark="lemonade"/> a cold sweet drink.
                We go to the drink dispenser and pour at a steady rate.
                This means that the glass is filled at a constant speed. <bookmark mark="cords"/>
                <break time="1s"/>
                If we plot time on  <bookmark mark="xaxis"/>the x-axis and the fill amount on <bookmark mark="yaxis"/>the y-axis ,
                then we get a function that assigns the fill amount to each point in time.
                <break time="1s"/>
                What does this function look like if the filling speed is constant?
                <break time="1s"/>
                Does it look like the red function? <bookmark mark="red"/>
                <break time="1s"/>
                Or does it look like the blue function? <bookmark mark="blue"/>
                <break time="1s"/>
                Or does it look like the green function? <bookmark mark="green"/>
                """
        ) as tracker:

            self.wait_until_bookmark("lemonade")
            self.add_shift_sound(1.5)
            self.play(lemonade.animate.shift(5*RIGHT))

            self.wait_until_bookmark("cords")
            self.add_shift_sound(1.5)
            self.play(Write(cords), Write(cursor), lemonade.animate.shift(5*RIGHT))

            self.wait_until_bookmark("xaxis")
            cursor.idle = False
            self.play(CursorMarkAxis(cursor, plane, "x"), run_time=1)

            self.wait_until_bookmark("yaxis")
            self.play(CursorMarkAxis(cursor, plane, "y"), run_time=1)
            self.wait(1)
            self.play(CursorMoveResize(cursor, xo, yo, 0.2, 0.2), run_time=.4)
            cursor.idle = True

            self.wait_until_bookmark("red")
            cursor.idle=False
            self.add(cursor.copy()._start_fading(2).add_updater(lambda c: c.move_to(func1_plotted.get_end())))
            self.add_pencil_sound(1)
            self.play(Write(func1_plotted), run_time=1)

            self.wait_until_bookmark("blue")
            self.add(cursor.copy()._start_fading(2).add_updater(lambda c: c.move_to(Func_2_plotted.get_end())))
            self.add_pencil_sound(1)
            self.play(Write(Func_2_plotted), run_time=1)

            self.wait_until_bookmark("green")
            self.add(cursor.copy()._start_fading(2).add_updater(lambda c: c.move_to(func3_plotted.get_end())))
            self.add_pencil_sound(1)
            self.play(Write(func3_plotted), run_time=1)
            cursor.idle=True

        # Wait for 4 seconds at the end of animation
        self.wait(4)

class Func_2_1_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create the coordinate system
        cords = self.add_cords([0, 30, 6], [0, 180, 30], x_ticks=[6, 12, 18, 24], y_ticks=[60, 120, 180]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        # Add title to the scene
        self.add_title("Linear Functions")

        # Create and plot piecewise linear function
        func = lambda x: 6 * x
        func_plotted = plane.plot(func, color=GREEN)

        # Create and plot piecewise linear function
        funcR = lambda x: x**2/5
        funcB = lambda x: 180/(30**0.5) * x**0.5

        funcR_plotted = plane.plot(funcR, color=RED)
        funcB_plotted = plane.plot(funcB, color=BLUE)

        # Initialize a cursor
        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, idle=False)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not correct - It's actually the <bookmark mark="green"/> green function.
                But why does it have to be the green function?
                Let's consider the time period between <bookmark mark="sec12"/> second twelve and second <bookmark mark="sec18"/> eighteen.
                The <bookmark mark="dashed"/> dashed lines show us how much is in the glass at each of the two time points.
                And the red line on the x-axis tells us the time between the two points. We can move the red line <bookmark mark="triangle"/>
                upwards to create a <bookmark mark="slopeTriangle"/> so-called slope triangle.
                The right, vertical side of the slope triangle indicates how much the function has changed, and the bottom,
                horizontal side indicates how much time has elapsed.
                Since we are pouring the drink uniformly, the filling rate is constant.
                When we construct a slope triangle and consider the same time between two points, that is, the width is the same,
                then the height, which is the fill amount, must also be the same. <bookmark mark="moreTriangles"/>
                As we can see, this works for the green function.

                However, if we look at <bookmark mark="moreFunctions"/> the red and blue functions, we see that this does not work.
                If we draw a slope triangle <bookmark mark="redTriangle"/> on the red function and move it, we can see that the slope is not constant.
                This means that the filling rate is not constant.
                The same applies to the blue function. <bookmark mark="blueTriangle"/>, if we construct a slope triangle there,
                and then move it, we can see that the slope is not constant there either.
                
                <bookmark mark="end"/> This means: Only the green function can be the correct solution.
                """
        ) as tracker:

            self.wait_until_bookmark("green")
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda c: c.move_to(func_plotted.get_end())))
            self.play(Write(func_plotted))

            self.wait_until_bookmark("sec12")
            cursor.idle = False
            x12, y12, _ = plane.x_axis.n2p(12)
            self.play(CursorMoveResize(cursor, x12, y12, 0.2, 0.2))

            self.wait_until_bookmark("sec18")
            x15, y15, _ = plane.x_axis.n2p(15)
            self.play(CursorMoveResize(cursor, x15, y15, 2*(x15-x12), 0.1))

            self.wait_until_bookmark("dashed")
            x18, y18, _ = plane.x_axis.n2p(18)
            d1 = DashedLine(start=[x12, y12, 0], end=[x12, plane.y_axis.n2p(func(12))[1], 0], color=BLACK)
            d2 = DashedLine(start=[x18, y18, 0], end=[x18, plane.y_axis.n2p(func(18))[1], 0], color=BLACK)
            self.play(Write(d1), Write(d2))
            circ1 = Circle(radius=0.1, stroke_width=2, color=BLACK).move_to([x12, plane.y_axis.n2p(func(12))[1], 0])
            circ2 = Circle(radius=0.1, stroke_width=2, color=BLACK).move_to([x18, plane.y_axis.n2p(func(18))[1], 0])
            self.play(Write(circ1), Write(circ2))

            self.wait_until_bookmark("triangle")
            self.play(CursorMoveResize(cursor, x15, plane.y_axis.n2p(func(12))[1], 2*(x15-x12), 0.1))

            self.wait_until_bookmark("slopeTriangle")
            tri = Polygon([x12, plane.y_axis.n2p(func(12))[1], 0], [x18, plane.y_axis.n2p(func(12))[1], 0], [x18, plane.y_axis.n2p(func(18))[1], 0], color=GREEN)
            self.play(Write(tri), Unwrite(d1), Unwrite(d2), Unwrite(circ1), Unwrite(circ2), CursorMoveResize(cursor, xo, yo, 0.2, 0.2))
            cursor.idle = True

            self.wait_until_bookmark("moreTriangles")
            unit = plane.c2p(18, func(18)) - plane.c2p(12, func(12))
            tri2, tri3 = tri.copy().shift(unit), tri.copy().shift(-1*unit)
            self.play(Write(tri2), Write(tri3))

            self.wait_until_bookmark("moreFunctions")
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda c: c.move_to(funcR_plotted.get_end())))
            self.add(cursor.copy()._start_fading(2).add_updater(lambda c: c.move_to(funcB_plotted.get_end())))
            self.play(Unwrite(tri), Unwrite(tri2), Unwrite(tri3), Write(funcR_plotted), Write(funcB_plotted))

            self.wait_until_bookmark("redTriangle")
            triRed = Polygon([x12, plane.y_axis.n2p(funcR(12))[1], 0], [x18, plane.y_axis.n2p(funcR(12))[1], 0], [x18, plane.y_axis.n2p(funcR(18))[1], 0], color=RED)
            self.play(Write(triRed))
            unitRed = plane.c2p(18, funcR(18)) - plane.c2p(12, funcR(12))
            triRed2, triRed3 = triRed.copy().shift(unitRed), triRed.copy().shift(-1*unitRed)
            self.play(Write(triRed2), Write(triRed3))

            self.wait_until_bookmark("blueTriangle")
            triBlue = Polygon([x12, plane.y_axis.n2p(funcB(12))[1], 0], [x18, plane.y_axis.n2p(funcB(12))[1], 0], [x18, plane.y_axis.n2p(funcB(18))[1], 0], color=BLUE)
            self.play(Write(triBlue))
            unitBlue = plane.c2p(18, funcB(18)) - plane.c2p(12, funcB(12))
            triBlue2, triBlue3 = triBlue.copy().shift(unitBlue), triBlue.copy().shift(-1*unitBlue)
            self.play(Write(triBlue2), Write(triBlue3))

            self.wait_until_bookmark("end")
            self.play(Unwrite(triRed), Unwrite(triRed2), Unwrite(triRed3), Unwrite(triBlue), Unwrite(triBlue2), Unwrite(triBlue3), Unwrite(funcR_plotted), Unwrite(funcB_plotted))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_2_1_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create the coordinate system
        cords = self.add_cords([0, 30, 6], [0, 180, 30], x_ticks=[6, 12, 18, 24], y_ticks=[60, 120, 180]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        # Add title to the scene
        self.add_title("Linear Functions")

        # Create and plot piecewise linear function
        func = lambda x: 6 * x
        func_plotted = plane.plot(func, color=GREEN)

        # Create and plot piecewise linear function
        funcR = lambda x: x**2/5
        funcB = lambda x: 180/(30**0.5) * x**0.5

        funcR_plotted = plane.plot(funcR, color=RED)
        funcB_plotted = plane.plot(funcB, color=BLUE)

        # Initialize a cursor
        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, idle=False)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not correct - It's actually the <bookmark mark="green"/> green function.
                But why does it have to be the green function?
                Let's consider the time period between <bookmark mark="sec12"/> second twelve and second <bookmark mark="sec18"/> eighteen.
                The <bookmark mark="dashed"/> dashed lines show us how much is in the glass at each of the two time points.
                And the red line on the x-axis tells us the time between the two points. We can move the red line <bookmark mark="triangle"/>
                upwards to create a <bookmark mark="slopeTriangle"/> so-called slope triangle.
                The right, vertical side of the slope triangle indicates how much the function has changed, and the bottom,
                horizontal side indicates how much time has elapsed.
                Since we are pouring the drink uniformly, the filling rate is constant.
                When we construct a slope triangle and consider the same time between two points, that is, the width is the same,
                then the height, which is the fill amount, must also be the same. <bookmark mark="moreTriangles"/>
                As we can see, this works for the green function.

                However, if we look at <bookmark mark="moreFunctions"/> the red and blue functions, we see that this does not work.
                If we draw a slope triangle <bookmark mark="redTriangle"/> on the red function and move it, we can see that the slope is not constant.
                This means that the filling rate is not constant.
                The same applies to the blue function. <bookmark mark="blueTriangle"/>, if we construct a slope triangle there,
                and then move it, we can see that the slope is not constant there either.
                
                <bookmark mark="end"/> This means: Only the green function can be the correct solution.
                """
        ) as tracker:

            self.wait_until_bookmark("green")
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda c: c.move_to(func_plotted.get_end())))
            self.play(Write(func_plotted))

            self.wait_until_bookmark("sec12")
            cursor.idle = False
            x12, y12, _ = plane.x_axis.n2p(12)
            self.play(CursorMoveResize(cursor, x12, y12, 0.2, 0.2))

            self.wait_until_bookmark("sec18")
            x15, y15, _ = plane.x_axis.n2p(15)
            self.play(CursorMoveResize(cursor, x15, y15, 2*(x15-x12), 0.1))

            self.wait_until_bookmark("dashed")
            x18, y18, _ = plane.x_axis.n2p(18)
            d1 = DashedLine(start=[x12, y12, 0], end=[x12, plane.y_axis.n2p(func(12))[1], 0], color=BLACK)
            d2 = DashedLine(start=[x18, y18, 0], end=[x18, plane.y_axis.n2p(func(18))[1], 0], color=BLACK)
            self.play(Write(d1), Write(d2))
            circ1 = Circle(radius=0.1, stroke_width=2, color=BLACK).move_to([x12, plane.y_axis.n2p(func(12))[1], 0])
            circ2 = Circle(radius=0.1, stroke_width=2, color=BLACK).move_to([x18, plane.y_axis.n2p(func(18))[1], 0])
            self.play(Write(circ1), Write(circ2))

            self.wait_until_bookmark("triangle")
            self.play(CursorMoveResize(cursor, x15, plane.y_axis.n2p(func(12))[1], 2*(x15-x12), 0.1))

            self.wait_until_bookmark("slopeTriangle")
            tri = Polygon([x12, plane.y_axis.n2p(func(12))[1], 0], [x18, plane.y_axis.n2p(func(12))[1], 0], [x18, plane.y_axis.n2p(func(18))[1], 0], color=GREEN)
            self.play(Write(tri), Unwrite(d1), Unwrite(d2), Unwrite(circ1), Unwrite(circ2), CursorMoveResize(cursor, xo, yo, 0.2, 0.2))
            cursor.idle = True

            self.wait_until_bookmark("moreTriangles")
            unit = plane.c2p(18, func(18)) - plane.c2p(12, func(12))
            tri2, tri3 = tri.copy().shift(unit), tri.copy().shift(-1*unit)
            self.play(Write(tri2), Write(tri3))

            self.wait_until_bookmark("moreFunctions")
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda c: c.move_to(funcR_plotted.get_end())))
            self.add(cursor.copy()._start_fading(2).add_updater(lambda c: c.move_to(funcB_plotted.get_end())))
            self.play(Unwrite(tri), Unwrite(tri2), Unwrite(tri3), Write(funcR_plotted), Write(funcB_plotted))

            self.wait_until_bookmark("redTriangle")
            triRed = Polygon([x12, plane.y_axis.n2p(funcR(12))[1], 0], [x18, plane.y_axis.n2p(funcR(12))[1], 0], [x18, plane.y_axis.n2p(funcR(18))[1], 0], color=RED)
            self.play(Write(triRed))
            unitRed = plane.c2p(18, funcR(18)) - plane.c2p(12, funcR(12))
            triRed2, triRed3 = triRed.copy().shift(unitRed), triRed.copy().shift(-1*unitRed)
            self.play(Write(triRed2), Write(triRed3))

            self.wait_until_bookmark("blueTriangle")
            triBlue = Polygon([x12, plane.y_axis.n2p(funcB(12))[1], 0], [x18, plane.y_axis.n2p(funcB(12))[1], 0], [x18, plane.y_axis.n2p(funcB(18))[1], 0], color=BLUE)
            self.play(Write(triBlue))
            unitBlue = plane.c2p(18, funcB(18)) - plane.c2p(12, funcB(12))
            triBlue2, triBlue3 = triBlue.copy().shift(unitBlue), triBlue.copy().shift(-1*unitBlue)
            self.play(Write(triBlue2), Write(triBlue3))

            self.wait_until_bookmark("end")
            self.play(Unwrite(triRed), Unwrite(triRed2), Unwrite(triRed3), Unwrite(triBlue), Unwrite(triBlue2), Unwrite(triBlue3), Unwrite(funcR_plotted), Unwrite(funcB_plotted))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)



class Func_2_1_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create the coordinate system
        cords = self.add_cords([0, 30, 6], [0, 180, 30], x_ticks=[6, 12, 18, 24], y_ticks=[60, 120, 180]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        # Add title to the scene
        self.add_title("Linear Functions")

        # Create and plot piecewise linear function
        func = lambda x: 6 * x
        func_plotted = plane.plot(func, color=GREEN)

        # Create and plot piecewise linear function
        funcR = lambda x: x**2/5
        funcB = lambda x: 180/(30**0.5) * x**0.5

        funcR_plotted = plane.plot(funcR, color=RED)
        funcB_plotted = plane.plot(funcB, color=BLUE)

        # Initialize a cursor
        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, idle=False)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                That's correct, well done! - It's the <bookmark mark="green"/> green function.
                But why does it have to be the green function?
                Let's consider the time period between <bookmark mark="sec12"/> second twelve and second <bookmark mark="sec18"/> eighteen.
                The <bookmark mark="dashed"/> dashed lines show us how much is in the glass at each of the two time points.
                And the red line on the x-axis tells us the time between the two points. We can move the red line <bookmark mark="triangle"/>
                upwards to create a <bookmark mark="slopeTriangle"/> so-called slope triangle.
                The right, vertical side of the slope triangle indicates how much the function has changed, and the bottom,
                horizontal side indicates how much time has elapsed.
                Since we are pouring the drink uniformly, the filling rate is constant.
                When we construct a slope triangle and consider the same time between two points, that is, the width is the same,
                then the height, which is the fill amount, must also be the same. <bookmark mark="moreTriangles"/>
                As we can see, this works for the green function.

                However, if we look at <bookmark mark="moreFunctions"/> the red and blue functions, we see that this does not work.
                If we draw a slope triangle <bookmark mark="redTriangle"/> on the red function and move it, we can see that the slope is not constant.
                This means that the filling rate is not constant.
                The same applies to the blue function. <bookmark mark="blueTriangle"/>, if we construct a slope triangle there,
                and then move it, we can see that the slope is not constant there either.
                
                <bookmark mark="end"/> This means: Only the green function can be the correct solution.
                """
        ) as tracker:

            self.wait_until_bookmark("green")
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda c: c.move_to(func_plotted.get_end())))
            self.play(Write(func_plotted))

            self.wait_until_bookmark("sec12")
            cursor.idle = False
            x12, y12, _ = plane.x_axis.n2p(12)
            self.play(CursorMoveResize(cursor, x12, y12, 0.2, 0.2))

            self.wait_until_bookmark("sec18")
            x15, y15, _ = plane.x_axis.n2p(15)
            self.play(CursorMoveResize(cursor, x15, y15, 2*(x15-x12), 0.1))

            self.wait_until_bookmark("dashed")
            x18, y18, _ = plane.x_axis.n2p(18)
            d1 = DashedLine(start=[x12, y12, 0], end=[x12, plane.y_axis.n2p(func(12))[1], 0], color=BLACK)
            d2 = DashedLine(start=[x18, y18, 0], end=[x18, plane.y_axis.n2p(func(18))[1], 0], color=BLACK)
            self.play(Write(d1), Write(d2))
            circ1 = Circle(radius=0.1, stroke_width=2, color=BLACK).move_to([x12, plane.y_axis.n2p(func(12))[1], 0])
            circ2 = Circle(radius=0.1, stroke_width=2, color=BLACK).move_to([x18, plane.y_axis.n2p(func(18))[1], 0])
            self.play(Write(circ1), Write(circ2))

            self.wait_until_bookmark("triangle")
            self.play(CursorMoveResize(cursor, x15, plane.y_axis.n2p(func(12))[1], 2*(x15-x12), 0.1))

            self.wait_until_bookmark("slopeTriangle")
            tri = Polygon([x12, plane.y_axis.n2p(func(12))[1], 0], [x18, plane.y_axis.n2p(func(12))[1], 0], [x18, plane.y_axis.n2p(func(18))[1], 0], color=GREEN)
            self.play(Write(tri), Unwrite(d1), Unwrite(d2), Unwrite(circ1), Unwrite(circ2), CursorMoveResize(cursor, xo, yo, 0.2, 0.2))
            cursor.idle = True

            self.wait_until_bookmark("moreTriangles")
            unit = plane.c2p(18, func(18)) - plane.c2p(12, func(12))
            tri2, tri3 = tri.copy().shift(unit), tri.copy().shift(-1*unit)
            self.play(Write(tri2), Write(tri3))

            self.wait_until_bookmark("moreFunctions")
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda c: c.move_to(funcR_plotted.get_end())))
            self.add(cursor.copy()._start_fading(2).add_updater(lambda c: c.move_to(funcB_plotted.get_end())))
            self.play(Unwrite(tri), Unwrite(tri2), Unwrite(tri3), Write(funcR_plotted), Write(funcB_plotted))

            self.wait_until_bookmark("redTriangle")
            triRed = Polygon([x12, plane.y_axis.n2p(funcR(12))[1], 0], [x18, plane.y_axis.n2p(funcR(12))[1], 0], [x18, plane.y_axis.n2p(funcR(18))[1], 0], color=RED)
            self.play(Write(triRed))
            unitRed = plane.c2p(18, funcR(18)) - plane.c2p(12, funcR(12))
            triRed2, triRed3 = triRed.copy().shift(unitRed), triRed.copy().shift(-1*unitRed)
            self.play(Write(triRed2), Write(triRed3))

            self.wait_until_bookmark("blueTriangle")
            triBlue = Polygon([x12, plane.y_axis.n2p(funcB(12))[1], 0], [x18, plane.y_axis.n2p(funcB(12))[1], 0], [x18, plane.y_axis.n2p(funcB(18))[1], 0], color=BLUE)
            self.play(Write(triBlue))
            unitBlue = plane.c2p(18, funcB(18)) - plane.c2p(12, funcB(12))
            triBlue2, triBlue3 = triBlue.copy().shift(unitBlue), triBlue.copy().shift(-1*unitBlue)
            self.play(Write(triBlue2), Write(triBlue3))

            self.wait_until_bookmark("end")
            self.play(Unwrite(triRed), Unwrite(triRed2), Unwrite(triRed3), Unwrite(triBlue), Unwrite(triBlue2), Unwrite(triBlue3), Unwrite(funcR_plotted), Unwrite(funcB_plotted))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)




#####################################
#####################################
class Func_2_1_I_2(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-3, 3, 1], x_ticks=[-3, -2, -1, 1, 2,3], y_ticks=[-3, -2, -1, 1, 2,3],).shift(DOWN*.2)
        plane = cords[0]

        # Add title to the scene
        self.add_title("Linear Functions")

        # Create and plot piecewise linear function
        func1 = lambda x:  2/3*x + 1
        func_2 = lambda x: -x**+2

        func1_plotted = plane.plot(func1, color=RED)
        Func_2_plotted = plane.plot(func_2, color=BLUE)

        funcTex = MathTex("f(x)=ax+b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=.6)

        # Initialize a cursor
        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])
        self.add(cursor)
        e1 = Tex("1. The slope is constant", color=c1t, font_size=fs3)
        e2 = Tex("2. The graph is a straight line", color=c1t, font_size=fs3)
        e3 = Tex("3. The function has the form\\\\$f(x)=ax+b$", tex_environment="flushright", color=c1t, font_size=fs3)
        explanations = VGroup(e1, e2, e3).arrange(DOWN, buff=.2, aligned_edge=LEFT).next_to(funcTex, DOWN, buff=.6)
        
        # Action Sequence
        with self.voiceover(
                text="""
                Let's formally define: What is a linear function?
                <break time="0.5s"/>
                There are three ways to explain it.
                <bookmark mark="constant"/> First: A linear function is a function with a constant slope.
                We just discussed that. That means, and this is the second way to explain linear 
                functions, <bookmark mark="straight"/> the graph is a straight line.
                <break time="0.5s"/>
                Both of these conditions are met when the function has the form <bookmark mark="term"/>
                f of x equals "a" times "x" plus "b", where we can plug in any number for "a" and "b". That's the third
                way to define linear functions.
                """
        ) as tracker:

            self.play(Write(cords))

            self.wait_until_bookmark("constant")
            self.play(Write(e1), run_time=.3)

            self.wait_until_bookmark("straight")
            self.play(Write(e2), run_time=.3)
            self.play(Write(func1_plotted))

            self.wait_until_bookmark("term")
            self.play(Write(e3), run_time=.3)
            self.play(Write(funcTex))

        # Wait for 4 seconds at the end of animation
        self.wait(4)


#####################################
#####################################
TASK_Func_2_1_I_3_q = SophiaTaskDefinition(
    answerOptions=["The green function", "The purple function", "The orange function"],
    correctAnswerIndex=0,
    questionText="Which of the three is a linear function?"
)

class Func_2_1_I_3_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-3, 3, 1], x_ticks=[-3, -2, -1, 1, 2,3], y_ticks=[-3, -2, -1, 1, 2,3],).shift(DOWN)
        plane = cords[0]

        # Add title to the scene
        self.add_title("Linear Functions")

        # Create and plot piecewise linear function
        func1 = lambda x: 2/3*x + 1
        func_2 = lambda x: -x + 2
        func3 = lambda x: 0.5*x - 1
        func4 = lambda x: -0.5*x + 1 + x**2/5
        func5 = lambda x: -0.5*x**2+2

        func1_plotted = plane.plot(func1, color=RED)
        Func_2_plotted = plane.plot(func_2, color=BLUE)
        func3_plotted = plane.plot(func3, color=GREEN)
        func4_plotted = plane.plot(func4, color=ORANGE)
        func5_plotted = plane.plot(func5, color=PURPLE)

        # Initialize a cursor
        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so the red function was a linear function.
                It has a constant slope, so its graph is a straight line.
                <break time="1s"/>
                <bookmark mark="blue"/> the blue function is also a linear function.
                Because it also has a constant slope, and its graph is also a straight line.
                <break time="1.5s"/>
                Now, consider <bookmark mark="green"/> the green, <bookmark mark="purple"/>the purple,
                and <bookmark mark="orange"/>the orange functions.<break time="1.5s"/>
                Only one of these three functions is a linear function.
                <break time="0.5s"/>
                Which one is it?
                """
        ) as tracker:

            self.play(Write(cords))
            self.add_pencil_sound(1)
            self.play(Write(func1_plotted), run_time=1)

            self.wait_until_bookmark("blue")
            self.add_pencil_sound(1)
            self.play(Write(Func_2_plotted), run_time=1)

            self.wait_until_bookmark("green")
            self.add_pencil_sound(1)
            self.play(Write(func3_plotted), Unwrite(func1_plotted), Unwrite(Func_2_plotted), run_time=1)

            self.wait_until_bookmark("purple")
            self.add_pencil_sound(1)
            self.play(Write(func5_plotted), run_time=1)

            self.wait_until_bookmark("orange")
            self.add_pencil_sound(1)
            self.play(Write(func4_plotted), run_time=1)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)



class Func_2_1_I_3_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()


        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-3, 3, 1], x_ticks=[-3, -2, -1, 1, 2,3], y_ticks=[-3, -2, -1, 1, 2,3],).shift(DOWN)
        plane = cords[0]

        # Add title to the scene
        self.add_title("Linear Functions")

        # Create and plot piecewise linear function
        func3 = lambda x: 0.5*x - 1
        func4 = lambda x: -0.5*x + 1 + x**2/5
        func5 = lambda x: -0.5*x**2+2

        func3_plotted = plane.plot(func3, color=GREEN)
        func4_plotted = plane.plot(func4, color=ORANGE)
        func5_plotted = plane.plot(func5, color=PURPLE)

        # Initialize a cursor
        cursor = AltCursor()

        # Action Sequence
        with self.voiceover(
                text="""
                That's correct: Only <bookmark mark="green"/> the green function is a linear function.
                It has a constant slope, so its graph is a straight line.
                <break time="1s"/>
                The <bookmark mark="purple"/> purple and <bookmark mark="orange"/> orange functions
                are not linear functions because their graphs are not straight lines, and their slopes
                are not constant.
                """
        ) as tracker:

            self.play(Write(cords))

            self.wait_until_bookmark("green")
            self.add_pencil_sound(1)
            self.play(Create(func3_plotted), run_time=1)
            cursor.idle=True

            self.wait_until_bookmark("purple")
            self.add_pencil_sound(1)
            self.play(Create(func5_plotted), run_time=1)

            self.wait_until_bookmark("orange")
            self.add_pencil_sound(1)
            self.play(Create(func4_plotted), run_time=1)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_2_1_I_3_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()


        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-3, 3, 1], x_ticks=[-3, -2, -1, 1, 2,3], y_ticks=[-3, -2, -1, 1, 2,3],).shift(DOWN)
        plane = cords[0]

        # Add title to the scene
        self.add_title("Linear Functions")

        # Create and plot piecewise linear function
        func3 = lambda x: 0.5*x - 1
        func4 = lambda x: -0.5*x + 1 + x**2/5
        func5 = lambda x: -0.5*x**2+2

        func3_plotted = plane.plot(func3, color=GREEN)
        func4_plotted = plane.plot(func4, color=ORANGE)
        func5_plotted = plane.plot(func5, color=PURPLE)

        # Initialize a cursor
        cursor = AltCursor()

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right: Only <bookmark mark="green"/> the green function is a linear function.
                It has a constant slope, so its graph is a straight line.
                <break time="1s"/>
                The <bookmark mark="purple"/> purple and <bookmark mark="orange"/> orange functions
                are not linear functions because their graphs are not straight lines, and their slopes
                are not constant.
                """
        ) as tracker:

            self.play(Write(cords))

            self.wait_until_bookmark("green")
            self.add_pencil_sound(1)
            self.play(Create(func3_plotted), run_time=1)
            cursor.idle=True

            self.wait_until_bookmark("purple")
            self.add_pencil_sound(1)
            self.play(Create(func5_plotted), run_time=1)

            self.wait_until_bookmark("orange")
            self.add_pencil_sound(1)
            self.play(Create(func4_plotted), run_time=1)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_2_1_I_3_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()


        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-3, 3, 1], x_ticks=[-3, -2, -1, 1, 2,3], y_ticks=[-3, -2, -1, 1, 2,3],).shift(DOWN)
        plane = cords[0]

        # Add title to the scene
        self.add_title("Linear Functions")

        # Create and plot piecewise linear function
        func3 = lambda x: 0.5*x - 1
        func4 = lambda x: -0.5*x + 1 + x**2/5
        func5 = lambda x: -0.5*x**2+2

        func3_plotted = plane.plot(func3, color=GREEN)
        func4_plotted = plane.plot(func4, color=ORANGE)
        func5_plotted = plane.plot(func5, color=PURPLE)

        # Initialize a cursor
        cursor = AltCursor()

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right: Only <bookmark mark="green"/> the green function is a linear function.
                It has a constant slope, so its graph is a straight line.
                <break time="1s"/>
                The <bookmark mark="purple"/> purple and <bookmark mark="orange"/> orange functions
                are not linear functions because their graphs are not straight lines, and their slopes
                are not constant.
                """
        ) as tracker:

            self.play(Write(cords))

            self.wait_until_bookmark("green")
            self.add_pencil_sound(1)
            self.play(Create(func3_plotted), run_time=1)
            cursor.idle=True

            self.wait_until_bookmark("purple")
            self.add_pencil_sound(1)
            self.play(Create(func5_plotted), run_time=1)

            self.wait_until_bookmark("orange")
            self.add_pencil_sound(1)
            self.play(Create(func4_plotted), run_time=1)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_2_1_I_4_q = SophiaTaskDefinition(
    answerOptions=["$f(x)=2x^2-4$", "$g(x)=2x-4$", "$h(x)=2/x-4$"],
    correctAnswerIndex=1,
    questionText="Which of the functions is linear?"
)

# Class for creating the animation scene
class Func_2_1_I_4_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        title = self.add_title("Linear Functions")

        # Create and plot piecewise linear function
        func1 = MathTex("f(x)=2x^2-4", color=c1t, font_size=fs1)
        func_2 = MathTex("g(x)=2x-4", color=c1t, font_size=fs1)
        func3 = MathTex("h(x)=2/x-4", color=c1t, font_size=fs1)
        funcs = VGroup(func1, func_2, func3).arrange(DOWN, buff=.6, aligned_edge=LEFT)

        cords = self.add_cords([-3, 3, 1], [-3, 3, 1], x_ticks=[-3, -2, -1, 1, 2,3], y_ticks=[-3, -2, -1, 1, 2,3],).shift(DOWN)
        plane = cords[0]
        func = lambda x: x/2-1
        plot = plane.plot(func, color=BLUE)
        xo,yo,_ = plane.c2p(0,0)

        # Initialize a cursor
        cursor = AltCursor(x=xo, y=yo)
        cursor.add_updater(lambda m, dt: self.bring_to_front(cursor))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                So, now we have seen what a linear function is by looking at the functions graph.
                <break time="0.5s"/>
                But we can <bookmark mark="unplot"/>also recognize whether a function is linear based on its terms.
                Now I will show you three functions. <bookmark mark="note2"/> Which of them is linear?
                <break time="1s"/>
                Is it the <bookmark mark="f"/> function f of x equals two x squared minus four?
                <break time="1s"/>
                Or the <bookmark mark="g"/> function g of x equals two x minus four?
                <break time="1s"/>
                Or the <bookmark mark="h"/> function h of x equals two over x minus four?
                """
        ) as tracker:
            
            self.play(Write(cords))
            x,y,_ = plot.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda c: c.move_to(plot.get_end())))
            self.add_pencil_sound(1)
            cursor.idle=True
            self.play(Create(plot), run_time=1)
            
            self.wait_until_bookmark("unplot")
            self.play(Unwrite(cords), Unwrite(plot), run_time=1)

            self.wait_until_bookmark("f")
            cursor.idle=False
            x, y, _ = func1.get_left() + LEFT * 0.2
            self.play(Write(func1), CursorMoveTo(cursor, x, y), run_time=.5)

            self.wait_until_bookmark("g")
            x, y, _ = func_2.get_left() + LEFT * 0.2
            self.play(Write(func_2), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("h")
            x, y, _ = func3.get_left() + LEFT * 0.2
            self.play(Write(func3), CursorMoveTo(cursor, x, y), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_2_1_I_4_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        title = self.add_title("Linear Functions")

        # Create and plot piecewise linear function
        func1 = MathTex("f(x)=2x^2-4", color=c1t, font_size=fs1)
        func_2 = MathTex("g(x)=2x-4", color=c1t, font_size=fs1)
        func3 = MathTex("h(x)=2/x-4", color=c1t, font_size=fs1)
        self.add(VGroup(func1, func_2, func3).arrange(DOWN, buff=.6, aligned_edge=LEFT))

        # Initialize a cursor
        cursor = AltCursor(idle=True)
        cursor.autoFadeBackground = True
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right.
                <break time="0.5s"/> But which one is linear?
                Let's go through the functions one by one:
                <break time="0.5s"/>
                <bookmark mark="f"/> The function f of x equals two x squared minus four is <bookmark mark="not1"/> not linear
                because the exponent of x is not equal to one.
                Specifically, functions that contain x squared, x cubed, or similar terms are not linear!
                <break time="0.5s"/>
                <bookmark mark="g"/> The function g of x equals two x minus four is <bookmark mark="yes"/> linear!
                It only contains x and simple numbers. It has the structure "a" times x plus b, and in this case, a is two and b is minus four.
                <break time="0.5s"/>
                <bookmark mark="h"/> The function h of x equals two over x minus four is <bookmark mark="not2"/> not linear
                because it involves dividing by x. If there's division by x, the function is not linear!
                """
        ) as tracker:

            self.wait_until_bookmark("f")
            cursor.idle = False
            x, y, _ = func1.get_left() + LEFT * 0.2
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("not1")
            self.play(func1.animate.set_color(RED), run_time=.3)

            self.wait_until_bookmark("g")
            x, y, _ = func_2.get_left() + LEFT * 0.2
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("yes")
            self.play(func_2.animate.set_color(GREEN), run_time=.3)

            self.wait_until_bookmark("h")
            x, y, _ = func3.get_left() + LEFT * 0.2
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("not2")
            self.play(func3.animate.set_color(RED), run_time=.3)

        self.wait(4)



class Func_2_1_I_4_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        title = self.add_title("Linear Functions")

        # Create and plot piecewise linear function
        func1 = MathTex("f(x)=2x^2-4", color=c1t, font_size=fs1)
        func_2 = MathTex("g(x)=2x-4", color=c1t, font_size=fs1)
        func3 = MathTex("h(x)=2/x-4", color=c1t, font_size=fs1)
        self.add(VGroup(func1, func_2, func3).arrange(DOWN, buff=.6, aligned_edge=LEFT))

        # Initialize a cursor
        cursor = AltCursor(idle=True)
        cursor.autoFadeBackground = True
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                That's right, well done.
                <break time="0.5s"/> But which one is linear?
                Let's go through the functions one by one:
                <break time="0.5s"/>
                <bookmark mark="f"/> The function f of x equals two x squared minus four is <bookmark mark="not1"/> not linear
                because the exponent of x is not equal to one.
                Specifically, functions that contain x squared, x cubed, or similar terms are not linear!
                <break time="0.5s"/>
                <bookmark mark="g"/> The function g of x equals two x minus four is <bookmark mark="yes"/> linear!
                It only contains x and simple numbers. It has the structure "a" times x plus b, and in this case, a is two and b is minus four.
                <break time="0.5s"/>
                <bookmark mark="h"/> The function h of x equals two over x minus four is <bookmark mark="not2"/> not linear
                because it involves dividing by x. If there's division by x, the function is not linear!
                """
        ) as tracker:

            self.wait_until_bookmark("f")
            cursor.idle = False
            x, y, _ = func1.get_left() + LEFT * 0.2
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("not1")
            self.play(func1.animate.set_color(RED), run_time=.3)

            self.wait_until_bookmark("g")
            x, y, _ = func_2.get_left() + LEFT * 0.2
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("yes")
            self.play(func_2.animate.set_color(GREEN), run_time=.3)

            self.wait_until_bookmark("h")
            x, y, _ = func3.get_left() + LEFT * 0.2
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("not2")
            self.play(func3.animate.set_color(RED), run_time=.3)

        self.wait(4)
        

class Func_2_1_I_4_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        title = self.add_title("Linear Functions")

        # Create and plot piecewise linear function
        func1 = MathTex("f(x)=2x^2-4", color=c1t, font_size=fs1)
        func_2 = MathTex("g(x)=2x-4", color=c1t, font_size=fs1)
        func3 = MathTex("h(x)=2/x-4", color=c1t, font_size=fs1)
        self.add(VGroup(func1, func_2, func3).arrange(DOWN, buff=.6, aligned_edge=LEFT))

        # Initialize a cursor
        cursor = AltCursor(idle=True)
        cursor.autoFadeBackground = True
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right.
                <break time="0.5s"/> But which one is linear?
                Let's go through the functions one by one:
                <break time="0.5s"/>
                <bookmark mark="f"/> The function f of x equals two x squared minus four is <bookmark mark="not1"/> not linear
                because the exponent of x is not equal to one.
                Specifically, functions that contain x squared, x cubed, or similar terms are not linear!
                <break time="0.5s"/>
                <bookmark mark="g"/> The function g of x equals two x minus four is <bookmark mark="yes"/> linear!
                It only contains x and simple numbers. It has the structure "a" times x plus b, and in this case, a is two and b is minus four.
                <break time="0.5s"/>
                <bookmark mark="h"/> The function h of x equals two over x minus four is <bookmark mark="not2"/> not linear
                because it involves dividing by x. If there's division by x, the function is not linear!
                """
        ) as tracker:

            self.wait_until_bookmark("f")
            cursor.idle = False
            x, y, _ = func1.get_left() + LEFT * 0.2
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("not1")
            self.play(func1.animate.set_color(RED), run_time=.3)

            self.wait_until_bookmark("g")
            x, y, _ = func_2.get_left() + LEFT * 0.2
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("yes")
            self.play(func_2.animate.set_color(GREEN), run_time=.3)

            self.wait_until_bookmark("h")
            x, y, _ = func3.get_left() + LEFT * 0.2
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("not2")
            self.play(func3.animate.set_color(RED), run_time=.3)

        self.wait(4)




#####################################
#####################################
TASK_Func_2_1_I_5_q = SophiaTaskDefinition(
    answerOptions=["The line moves upwards", "The line moves downwards", "The line becomes flatter", "The line becomes steeper"],
    correctAnswerIndex=3,
    questionText="What happens when we choose $a>1$?"
)

class Func_2_1_I_5_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        title = self.add_title("Focus on Function Term")

        # Create the coordinate system
        cords = self.add_cords([-4, 4, 1], [-4, 4, 1], x_ticks=[-4, -2, 0, 2, 4], y_ticks=[-4, -2, 0, 2, 4]).shift(DOWN*.6)
        plane = cords[0]

        # Create and plot piecewise linear function
        func = MathTex("f", "(x)", "=ax+", "b", color=c1t, font_size=fs2).next_to(cords, DOWN).shift(UP * 1.5)
        func_2 = MathTex("f", "(x)", "=", "x", color=c1t, font_size=fs2).next_to(cords, DOWN).shift(UP * 1.5)
        a, b = ValueTracker(1), ValueTracker(0)
        a_decimal = DecimalNumber(1, font_size=fs2, num_decimal_places=1).next_to(func, LEFT, buff=0.5)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value() * x + b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                So, let's take a closer look at the function term of linear functions.
                The <bookmark mark="f"/> general term for linear functions <bookmark mark="tf"/> 
                is f <bookmark mark="tx"/>of x<bookmark mark="tax"/> equals
                "a" times x <bookmark mark="tb"/>plus b.
                <break time="0.5s"/>
                What role does the <bookmark mark="a"/>value of "a" play, and what role does the <bookmark mark="b"/>value of b play?
                To find out, let's consider a specific example,
                <bookmark mark="example"/>namely the <bookmark mark="ef"/>function f <bookmark mark="ex1"/>of x <bookmark mark="ex2"/>equals x,
                which means "a" is equal to 1 and b is 0. The function <bookmark mark="plot"/>looks like this.
                <break time="0.5s"/>
                Now, what happens when we change the value of "a"?<bookmark mark="qmark"/>
                <break time="0.5s"/>
                Specifically, what happens when we substitute a value greater than 1 for "a"?
                """
        ) as tracker:

            self.wait_until_bookmark("f")
            cursor.idle = False
            self.play(Write(func))

            self.wait_until_bookmark("tf")
            x, y, _ = func.submobjects[0].get_center() + DOWN * 0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("tx")
            x, y, _ = func.submobjects[1].get_center() + DOWN * 0.4
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("tax")
            x, y, _ = func.submobjects[2].get_center() + DOWN * 0.4
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("tb")
            x, y, _ = func.submobjects[3].get_center() + DOWN * 0.4 + LEFT * 0.1
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("a")
            x, y, _ = func.submobjects[2].get_center() + DOWN * 0.4
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("b")
            x, y, _ = func.submobjects[3].get_center() + DOWN * 0.4
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("example")
            x, y, _ = func_2.submobjects[0].get_center() + DOWN * 0.4
            self.play(TransformMatchingTex(func, func_2), CursorMoveTo(cursor, x, y))

            self.wait_until_bookmark("ex1")
            x, y, _ = func_2.submobjects[1].get_center() + DOWN * 0.4
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("ex2")
            x, y, _ = func_2.submobjects[3].get_center() + DOWN * 0.4
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("plot")
            x, y, _ = plane.c2p(0, 0)
            self.play(func_2.animate.shift(DOWN * 1.5), Write(cords), CursorMoveTo(cursor, x, y), Write(updated_f),
                      run_time=1)
            cursor.idle = True

            self.wait_until_bookmark("qmark")
            cursor.idle = False
            func_3 = Tex("$f(x)=ax$, $a>1$", color=c1t, font_size=fs2).next_to(cords, DOWN).shift(UP * 1.5)
            self.play(Transform(func_2, func_3), run_time=1)
            self.draw_qmark(cursor, DOWN*2.6, run_time=3)

        # Wait for 4 seconds at the end of animation
        self.wait(4)



class Func_2_1_I_5_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        title = self.add_title("Focus on Function Term")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3, -1, 0, 1, 3], y_ticks=[-4, -2, 0, 2, 4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f", "(x)", "=", "x", color=c1t, font_size=fs2).next_to(cords, DOWN)
        func_2 = MathTex("f", "(x)", "=", "\\,\\,\\,\\,\\,\\,\\,\\,\\,", "\\cdot x", color=c1t, font_size=fs2).next_to(cords, DOWN)
        a, b = ValueTracker(1), ValueTracker(0)
        a_decimal = DecimalNumber(1, font_size=fs2, color=c1t, num_decimal_places=1).next_to(func_2[2], RIGHT, buff=0.1).add_updater(lambda d: d.set_value(a.get_value()))
        self.add(func)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value() * x + b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor()
        cursor.move_to(plane.c2p(0, 0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right.
                We can write the function f of x equals x as <bookmark mark="ftransform"/> f of x equals one times x.
                Let's consider an example, at the point <bookmark mark="x"/>x equals one.
                The value of the function f of x is also <bookmark mark="fx"/>equal to one.
                If we increase the value of "a", let's say to two, <bookmark mark="increaseA"/>the value
                of f of x also increases, and the function becomes steeper.
                This is because we multiply every value of the function by a number greater than one, so they all increase.
                """
        ) as tracker:

            self.wait_until_bookmark("ftransform")
            self.play(TransformMatchingTex(func, func_2), Write(a_decimal), run_time=1)

            self.wait_until_bookmark("x")
            cursor.idle = False
            x,y,_ = plane.c2p(1,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)

            self.wait_until_bookmark("fx")
            x, y, _ = plane.c2p(1, 1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(1, a.get_value() * 1 + b.get_value())))

            self.wait_until_bookmark("increaseA")
            duration = 2
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            self.play(a.animate.set_value(2), run_time=duration)

        # Wait for 4 seconds at the end of animation
        self.wait(4)



class Func_2_1_I_5_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        title = self.add_title("Focus on Function Term")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3, -1, 0, 1, 3], y_ticks=[-4, -2, 0, 2, 4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f", "(x)", "=", "x", color=c1t, font_size=fs2).next_to(cords, DOWN)
        func_2 = MathTex("f", "(x)", "=", "\\,\\,\\,\\,\\,\\,\\,\\,\\,", "\\cdot x", color=c1t, font_size=fs2).next_to(cords, DOWN)
        a, b = ValueTracker(1), ValueTracker(0)
        a_decimal = DecimalNumber(1, font_size=fs2, color=c1t, num_decimal_places=1).next_to(func_2[2], RIGHT, buff=0.1).add_updater(lambda d: d.set_value(a.get_value()))
        self.add(func)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value() * x + b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor()
        cursor.move_to(plane.c2p(0, 0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right.
                We can write the function f of x equals x as <bookmark mark="ftransform"/> f of x equals one times x.
                Let's consider an example, at the point <bookmark mark="x"/>x equals one.
                The value of the function f of x is also <bookmark mark="fx"/>equal to one.
                If we increase the value of "a", let's say to two, <bookmark mark="increaseA"/>the value
                of f of x also increases, and the function becomes steeper.
                This is because we multiply every value of the function by a number greater than one, so they all increase.
                """
        ) as tracker:

            self.wait_until_bookmark("ftransform")
            self.play(TransformMatchingTex(func, func_2), Write(a_decimal), run_time=1)

            self.wait_until_bookmark("x")
            cursor.idle = False
            x,y,_ = plane.c2p(1,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)

            self.wait_until_bookmark("fx")
            x, y, _ = plane.c2p(1, 1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(1, a.get_value() * 1 + b.get_value())))

            self.wait_until_bookmark("increaseA")
            duration = 2
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            self.play(a.animate.set_value(2), run_time=duration)

        # Wait for 4 seconds at the end of animation
        self.wait(4)


class Func_2_1_I_5_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        title = self.add_title("Focus on Function Term")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3, -1, 0, 1, 3], y_ticks=[-4, -2, 0, 2, 4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f", "(x)", "=", "x", color=c1t, font_size=fs2).next_to(cords, DOWN)
        func_2 = MathTex("f", "(x)", "=", "\\,\\,\\,\\,\\,\\,\\,\\,\\,", "\\cdot x", color=c1t, font_size=fs2).next_to(cords, DOWN)
        a, b = ValueTracker(1), ValueTracker(0)
        a_decimal = DecimalNumber(1, font_size=fs2, color=c1t, num_decimal_places=1).next_to(func_2[2], RIGHT, buff=0.1).add_updater(lambda d: d.set_value(a.get_value()))
        self.add(func)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value() * x + b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor()
        cursor.move_to(plane.c2p(0, 0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right.
                We can write the function f of x equals x as <bookmark mark="ftransform"/> f of x equals one times x.
                Let's consider an example, at the point <bookmark mark="x"/>x equals one.
                The value of the function f of x is also <bookmark mark="fx"/>equal to one.
                If we increase the value of "a", let's say to two, <bookmark mark="increaseA"/>the value
                of f of x also increases, and the function becomes steeper.
                This is because we multiply every value of the function by a number greater than one, so they all increase.
                """
        ) as tracker:

            self.wait_until_bookmark("ftransform")
            self.play(TransformMatchingTex(func, func_2), Write(a_decimal), run_time=1)

            self.wait_until_bookmark("x")
            cursor.idle = False
            x,y,_ = plane.c2p(1,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)

            self.wait_until_bookmark("fx")
            x, y, _ = plane.c2p(1, 1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(1, a.get_value() * 1 + b.get_value())))

            self.wait_until_bookmark("increaseA")
            duration = 2
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            self.play(a.animate.set_value(2), run_time=duration)

        # Wait for 4 seconds at the end of animation
        self.wait(4)


class Func_2_1_I_5_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        title = self.add_title("Focus on Function Term")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3, -1, 0, 1, 3], y_ticks=[-4, -2, 0, 2, 4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f", "(x)", "=", "x", color=c1t, font_size=fs2).next_to(cords, DOWN)
        func_2 = MathTex("f", "(x)", "=", "\\,\\,\\,\\,\\,\\,\\,\\,\\,", "\\cdot x", color=c1t, font_size=fs2).next_to(cords, DOWN)
        a, b = ValueTracker(1), ValueTracker(0)
        a_decimal = DecimalNumber(1, font_size=fs2, color=c1t, num_decimal_places=1).next_to(func_2[2], RIGHT, buff=0.1).add_updater(lambda d: d.set_value(a.get_value()))
        self.add(func)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value() * x + b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor()
        cursor.move_to(plane.c2p(0, 0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                That's right, well done!
                We can write the function f of x equals x as <bookmark mark="ftransform"/> f of x equals one times x.
                Let's consider an example, at the point <bookmark mark="x"/>x equals one.
                The value of the function f of x is also <bookmark mark="fx"/>equal to one.
                If we increase the value of "a", let's say to two, <bookmark mark="increaseA"/>the value
                of f of x also increases, and the function becomes steeper.
                This is because we multiply every value of the function by a number greater than one, so they all increase.
                """
        ) as tracker:

            self.wait_until_bookmark("ftransform")
            self.play(TransformMatchingTex(func, func_2), Write(a_decimal), run_time=1)

            self.wait_until_bookmark("x")
            cursor.idle = False
            x,y,_ = plane.c2p(1,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)

            self.wait_until_bookmark("fx")
            x, y, _ = plane.c2p(1, 1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(1, a.get_value() * 1 + b.get_value())))

            self.wait_until_bookmark("increaseA")
            duration = 2
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            self.play(a.animate.set_value(2), run_time=duration)

        # Wait for 4 seconds at the end of animation
        self.wait(4)




#####################################
#####################################
TASK_Func_2_1_I_6_q = SophiaTaskDefinition(
    answerOptions=["The line is shifted upwards", "The line is shifted downwards", "The line becomes flatter", "The line becomes steeper"],
    correctAnswerIndex=0,
    questionText="What happens when we choose $b>0$?"
)

class Func_2_1_I_6_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        title = self.add_title("Focus on Function Term")

        # Create the coordinate system
        cords = self.add_cords([-4, 4, 1], [-4, 4, 1], x_ticks=[-4, -2, 0, 2, 4], y_ticks=[-4, -2, 0, 2, 4])
        plane = cords[0]

        # Create and plot piecewise linear function
        func = MathTex("f", "(x)", "=ax+", "b", color=c1t, font_size=fs2).next_to(cords, DOWN).shift(UP * 1.5)
        func_2 = MathTex("f", "(x)", "=", "x", color=c1t, font_size=fs2).next_to(cords, DOWN).shift(UP * 1.5)
        a, b = ValueTracker(1), ValueTracker(0)
        a_decimal = DecimalNumber(1, font_size=fs2, num_decimal_places=1).next_to(func, LEFT, buff=0.5)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value() * x + b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True

        # Action Sequence
        with self.voiceover(
                text="""
                Let's take another look at the function term of linear functions.
                We're again looking at the general form of linear <bookmark mark="f"/> functions,
                which <bookmark mark="tf"/>is f <bookmark mark="tx"/>of x<bookmark mark="tax"/> equals "a" times x
                <bookmark mark="tb"/>plus b. <break time="0.5s"/>
                As we have seen earlier, the value <bookmark mark="a"/> of "a" determines the slope of the line.
                <break time="0.5s"/><bookmark mark="ahigh"/>
                High values of "a" mean that the line becomes steeper.
                <break time="0.5s"/><bookmark mark="alow"/>
                On the other hand, low values of "a" mean that the line becomes flatter.
                <break time="0.5s"/>
                Now, the only question left is: What role does the value <bookmark mark="b"/> of b play?
                To find out, let's look at our example again,
                that is <bookmark mark="example"/> the function <bookmark mark="ef"/> f of <bookmark mark="ex1"/> x equals <bookmark mark="ex2"/> x,
                So, a is one again, and b is zero again. The function looks like <bookmark mark="plot"/>
                this.
                <break time="0.5s"/>
                Now, what happens if we change the value of b?
                <break time="0.5s"/>
                For example: What happens when we set a value for b that is greater than zero?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            self.play(Write(func))

            self.wait_until_bookmark("tf")
            x, y, _ = func.submobjects[0].get_center() + DOWN * 0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("tx")
            x, y, _ = func.submobjects[1].get_center() + DOWN * 0.4
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("tax")
            x, y, _ = func.submobjects[2].get_center() + DOWN * 0.4
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("tb")
            x, y, _ = func.submobjects[3].get_center() + DOWN * 0.4 + LEFT * 0.1
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("a")
            x, y, _ = func.submobjects[2].get_center() + DOWN * 0.4
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("b")
            x, y, _ = func.submobjects[3].get_center() + DOWN * 0.4
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("example")
            x, y, _ = func_2.submobjects[0].get_center() + DOWN * 0.4
            self.play(TransformMatchingTex(func, func_2), CursorMoveTo(cursor, x, y))

            self.wait_until_bookmark("ex1")
            x, y, _ = func_2.submobjects[1].get_center() + DOWN * 0.4
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("ex2")
            x, y, _ = func_2.submobjects[3].get_center() + DOWN * 0.4
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("plot")
            x, y, _ = plane.c2p(0, 0)
            self.play(func_2.animate.shift(DOWN * 1.5), Write(cords), CursorMoveTo(cursor, x, y), Write(updated_f), run_time=1)
            cursor.idle = True

        # Wait for 4 seconds at the end of animation
        self.wait(4)


class Func_2_1_I_6_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=[["Consider linear function:", "$f(x)=ax+b=x+0$"], ["Increasing $b$", "$\\rightarrow$ Function shifted upwards"], ["Decreasing $b$","$\\rightarrow$ Function shifted downwards"]], buff=0.2, buff_inner=0.05)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Focus on Function Term")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f","(x)","=","x", color=c1t, font_size=fs2).next_to(cords, DOWN)
        a, b = ValueTracker(1), ValueTracker(0)
        a_decimal = DecimalNumber(0, font_size=fs2, color=c1t, include_sign=True, num_decimal_places=1).next_to(func[-1], RIGHT, buff=0.1).add_updater(lambda d: d.set_value(b.get_value()))
        self.add(func)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Hey great, that's correct!
                
                We can write the function f of x equals x as <bookmark mark="ftransform"/> f of x equals x plus zero.
                Now let's consider the point <bookmark mark="x"/> x equals zero as an example.
                The value of the function f of x is also <bookmark mark="fx"/> equals zero at this point.
                <bookmark mark="note01"/> If we increase b, let's say to two, <bookmark mark="increaseB"/> the value of f of x will increase everywhere, and the function will be shifted upwards.
                
                On the other hand, it's similar in reverse: <bookmark mark="note12"/> If we decrease a <bookmark mark="decreaseB"/>, the function will be shifted downwards.
                Here you can see what happens when we set a to minus two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("ftransform")
            note.change_colors([0])
            self.play(Write(a_decimal), run_time=1)

            self.wait_until_bookmark("x")
            x,y,_ = plane.c2p(0,0)
            cursor.idle=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)

            self.wait_until_bookmark("fx")
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(0, a.get_value()*0+b.get_value())))

            self.wait_until_bookmark("note01")
            note.change_colors([0,1])

            self.wait_until_bookmark("increaseB")
            duration = 2
            start = plane.c2p(0,0)
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            self.add(Updown_Arrow(start, color=c3, stroke_width=5, vert=True).add_updater(lambda m: m.put_start_and_end_on(start+0.0000000001*DOWN, [x, cursor.get_y(),0])))
            self.play(b.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("note12")
            note.change_colors([1,2])

            self.wait_until_bookmark("decreaseB")
            duration = 2
            self.add_move_sound("backward", duration=duration, rate_func=smooth)
            self.play(b.animate.set_value(-2), run_time=2)

        # Wait for 4 seconds at the end of animation
        self.wait(4)


class Func_2_1_I_6_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=[["Consider linear function:", "$f(x)=ax+b=x+0$"], ["Increasing $b$", "$\\rightarrow$ Function shifted upwards"], ["Decreasing $b$","$\\rightarrow$ Function shifted downwards"]], buff=0.2, buff_inner=0.05)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Focus on Function Term")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f","(x)","=","x", color=c1t, font_size=fs2).next_to(cords, DOWN)
        a, b = ValueTracker(1), ValueTracker(0)
        a_decimal = DecimalNumber(0, font_size=fs2, color=c1t, include_sign=True, num_decimal_places=1).next_to(func[-1], RIGHT, buff=0.1).add_updater(lambda d: d.set_value(b.get_value()))
        self.add(func)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Oh, too bad, that's unfortunately incorrect.
                
                We can write the function f of x equals x as <bookmark mark="ftransform"/> f of x equals x plus zero.
                Now let's consider the point <bookmark mark="x"/> x equals zero as an example.
                The value of the function f of x is also <bookmark mark="fx"/> equals zero at this point.
                <bookmark mark="note01"/> If we increase b, let's say to two, <bookmark mark="increaseB"/> the value of f of x will increase everywhere, and the function will be shifted upwards.
                
                On the other hand, it's similar in reverse: <bookmark mark="note12"/> If we decrease a <bookmark mark="decreaseB"/>, the function will be shifted downwards.
                Here you can see what happens when we set a to minus two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("ftransform")
            note.change_colors([0])
            self.play(Write(a_decimal), run_time=1)

            self.wait_until_bookmark("x")
            x,y,_ = plane.c2p(0,0)
            cursor.idle=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)

            self.wait_until_bookmark("fx")
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(0, a.get_value()*0+b.get_value())))

            self.wait_until_bookmark("note01")
            note.change_colors([0,1])

            self.wait_until_bookmark("increaseB")
            duration = 2
            start = plane.c2p(0,0)
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            self.add(Updown_Arrow(start, color=c3, stroke_width=5, vert=True).add_updater(lambda m: m.put_start_and_end_on(start+0.0000000001*DOWN, [x, cursor.get_y(),0])))
            self.play(b.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("note12")
            note.change_colors([1,2])

            self.wait_until_bookmark("decreaseB")
            duration = 2
            self.add_move_sound("backward", duration=duration, rate_func=smooth)
            self.play(b.animate.set_value(-2), run_time=2)

        # Wait for 4 seconds at the end of animation
        self.wait(4)

class Func_2_1_I_6_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=[["Consider linear function:", "$f(x)=ax+b=x+0$"], ["Increasing $b$", "$\\rightarrow$ Function shifted upwards"], ["Decreasing $b$","$\\rightarrow$ Function shifted downwards"]], buff=0.2, buff_inner=0.05)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Focus on Function Term")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f","(x)","=","x", color=c1t, font_size=fs2).next_to(cords, DOWN)
        a, b = ValueTracker(1), ValueTracker(0)
        a_decimal = DecimalNumber(0, font_size=fs2, color=c1t, include_sign=True, num_decimal_places=1).next_to(func[-1], RIGHT, buff=0.1).add_updater(lambda d: d.set_value(b.get_value()))
        self.add(func)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Oh, too bad, that's unfortunately incorrect.
                
                We can write the function f of x equals x as <bookmark mark="ftransform"/> f of x equals x plus zero.
                Now let's consider the point <bookmark mark="x"/> x equals zero as an example.
                The value of the function f of x is also <bookmark mark="fx"/> equals zero at this point.
                <bookmark mark="note01"/> If we increase b, let's say to two, <bookmark mark="increaseB"/> the value of f of x will increase everywhere, and the function will be shifted upwards.
                
                On the other hand, it's similar in reverse: <bookmark mark="note12"/> If we decrease a <bookmark mark="decreaseB"/>, the function will be shifted downwards.
                Here you can see what happens when we set a to minus two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("ftransform")
            note.change_colors([0])
            self.play(Write(a_decimal), run_time=1)

            self.wait_until_bookmark("x")
            x,y,_ = plane.c2p(0,0)
            cursor.idle=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)

            self.wait_until_bookmark("fx")
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(0, a.get_value()*0+b.get_value())))

            self.wait_until_bookmark("note01")
            note.change_colors([0,1])

            self.wait_until_bookmark("increaseB")
            duration = 2
            start = plane.c2p(0,0)
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            self.add(Updown_Arrow(start, color=c3, stroke_width=5, vert=True).add_updater(lambda m: m.put_start_and_end_on(start+0.0000000001*DOWN, [x, cursor.get_y(),0])))
            self.play(b.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("note12")
            note.change_colors([1,2])

            self.wait_until_bookmark("decreaseB")
            duration = 2
            self.add_move_sound("backward", duration=duration, rate_func=smooth)
            self.play(b.animate.set_value(-2), run_time=2)

        # Wait for 4 seconds at the end of animation
        self.wait(4)

class Func_2_1_I_6_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=[["Consider linear function:", "$f(x)=ax+b=x+0$"], ["Increasing $b$", "$\\rightarrow$ Function shifted upwards"], ["Decreasing $b$","$\\rightarrow$ Function shifted downwards"]], buff=0.2, buff_inner=0.05)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Focus on Function Term")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f","(x)","=","x", color=c1t, font_size=fs2).next_to(cords, DOWN)
        a, b = ValueTracker(1), ValueTracker(0)
        a_decimal = DecimalNumber(0, font_size=fs2, color=c1t, include_sign=True, num_decimal_places=1).next_to(func[-1], RIGHT, buff=0.1).add_updater(lambda d: d.set_value(b.get_value()))
        self.add(func)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Oh, too bad, that's unfortunately incorrect.
                
                We can write the function f of x equals x as <bookmark mark="ftransform"/> f of x equals x plus zero.
                Now let's consider the point <bookmark mark="x"/> x equals zero as an example.
                The value of the function f of x is also <bookmark mark="fx"/> equals zero at this point.
                <bookmark mark="note01"/> If we increase b, let's say to two, <bookmark mark="increaseB"/> the value of f of x will increase everywhere, and the function will be shifted upwards.
                
                On the other hand, it's similar in reverse: <bookmark mark="note12"/> If we decrease a <bookmark mark="decreaseB"/>, the function will be shifted downwards.
                Here you can see what happens when we set a to minus two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("ftransform")
            note.change_colors([0])
            self.play(Write(a_decimal), run_time=1)

            self.wait_until_bookmark("x")
            x,y,_ = plane.c2p(0,0)
            cursor.idle=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)

            self.wait_until_bookmark("fx")
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(0, a.get_value()*0+b.get_value())))

            self.wait_until_bookmark("note01")
            note.change_colors([0,1])

            self.wait_until_bookmark("increaseB")
            duration = 2
            start = plane.c2p(0,0)
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            self.add(Updown_Arrow(start, color=c3, stroke_width=5, vert=True).add_updater(lambda m: m.put_start_and_end_on(start+0.0000000001*DOWN, [x, cursor.get_y(),0])))
            self.play(b.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("note12")
            note.change_colors([1,2])

            self.wait_until_bookmark("decreaseB")
            duration = 2
            self.add_move_sound("backward", duration=duration, rate_func=smooth)
            self.play(b.animate.set_value(-2), run_time=2)

        # Wait for 4 seconds at the end of animation
        self.wait(4)


class Func_2_1_I_7(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=[["General expression for a linear function:", "$f(x)=ax+b$"], ["$a$ determines the slope", "$a>1$ $\\rightarrow$ Function steeper"], ["$b$ determines the shift","$b>0$ $\\rightarrow$ Shift upwards"]], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Note: Function Term")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs2).next_to(cords, DOWN)
        a, b = ValueTracker(1), ValueTracker(0)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                So, let's review again:
                
                The general expression for a linear function is <bookmark mark="funcTerm"/> f of x equals "a" times x plus b.
                
                The value <bookmark mark="a"/> of a determines the slope here: <bookmark mark="goToOne"/>
                With a high value of a, <bookmark mark="ahigh"/> the function becomes steeper, -
                <bookmark mark="alow"/> with a low value of a, it becomes flatter. <bookmark mark="reset"/>
                
                On the other hand, the value <bookmark mark="b"/> of b determines the shift upwards and downwards. <bookmark mark="goToZero"/>
                With a high value of b <bookmark mark="bhigh"/>, the function is shifted upwards, -
                <bookmark mark="blow"/> with a low value of b, it is shifted downwards.
                """
        ) as tracker:
            
            self.wait_until_bookmark("funcTerm")
            note.change_colors([0])
            self.play(Write(func))

            self.wait_until_bookmark("a")
            note.change_colors([0,1])
            x,y,_ = func[1].get_center()+DOWN*0.4
            cursor.idle=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)

            self.wait_until_bookmark("goToOne")
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(1, a.get_value()*1+b.get_value())))

            self.wait_until_bookmark("ahigh")
            duration = 1
            self.add_scale_sound("up", duration=duration, rate_func=smooth)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(1, a.get_value()*1+b.get_value())))
            self.play(a.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("alow")
            self.add_scale_sound("down", duration=duration, rate_func=smooth)
            self.play(a.animate.set_value(0.5), run_time=duration)

            self.wait_until_bookmark("reset")
            self.play(a.animate.set_value(1), run_time=0.4)

            self.wait_until_bookmark("b")
            note.change_colors([1,2])
            x,y,_ = func[3].get_center()+DOWN*0.4
            cursor.clear_updaters()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)

            self.wait_until_bookmark("goToZero")
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(0, a.get_value()*0+b.get_value())))

            self.wait_until_bookmark("bhigh")
            start = plane.c2p(0,0)
            duration = 1
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            self.add(Updown_Arrow(start, color=c3, stroke_width=5, vert=True).add_updater(lambda m: m.put_start_and_end_on(start+0.0000000001*DOWN, [x, cursor.get_y(),0])))
            self.play(b.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("blow")
            self.add_move_sound("backward", duration=duration, rate_func=smooth)
            self.play(b.animate.set_value(-2), run_time=duration)
            self.wait(2)
            self.play(b.animate.set_value(0), run_time=0.5)
            

        # Wait for 4 seconds at the end of animation
        self.wait(4)


TASK_Func_2_1_I_8_q = SophiaTaskDefinition(
    answerOptions = ["We can directly read $a$: $f(0)=a$", "We can directly read $b$: $f(0)=b$", "We can directly read $a+b$: $f(0)=a+b"],
    correctAnswerIndex = 1,
    questionText = "What happens when we substitute $x=0$ into the function $f(x)=ax+b$?"
)

class Func_2_1_I_8_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=[["General expression for a linear function:", "$f(x)=ax+b$"], ["How do we determine the function term", "when the graph is given?"], "What happens when we substitute $0$?"], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Note: Function Term")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs1).next_to(title, DOWN, buff=1.5)
                
        a, b = ValueTracker(1), ValueTracker(2)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                So, now we know: A linear function always has the form <bookmark mark="f"/> f of x equals "a" times x plus b.
                
                Let's say <bookmark mark="cords"/> we have a function, <bookmark mark="func"/> that looks like this.
                
                How do we determine the term of the function?
                
                <bookmark mark="cursor"/>
                We need to know two values to determine <bookmark mark="cursorA"/> the function: a <bookmark mark="cursorB"/> and b.
                
                So, let's start by figuring out how to find <bookmark mark="circleB"/> b.
                
                There's a simple trick for that. Let's substitute <bookmark mark="plugInZero"/> zero into the function term.
                <bookmark mark="q"/> What happens?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            note.change_colors([0])
            self.play(Write(func))

            self.wait_until_bookmark("cords")
            self.play(Write(cords), func.animate.move_to(cords.get_bottom()+0.5*DOWN), run_time=0.5)

            self.wait_until_bookmark("func")
            self.play(Write(updated_f), run_time=1)
            note.change_colors([0,1])

            self.wait_until_bookmark("cursor")
            self.wait_until_bookmark("cursorA")
            cursor.idle=False
            x,y,_ = func[1].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)

            self.wait_until_bookmark("cursorB")
            x,y,_ = func[3].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)

            self.wait_until_bookmark("circleB")
            x2, y2 = x-0.4, y+0.8
            self.play(CursorMoveToCurved(cursor, x, y2, path_arc=PI), run_time=0.4, rate_func=linear)
            self.play(CursorMoveToCurved(cursor, x, y, path_arc=PI), run_time=0.4, rate_func=linear)

            self.wait_until_bookmark("plugInZero")
            note.change_colors([1,2])
            func0 = MathTex("f(","0",")=","?", color=c1t, font_size=fs1).move_to(func)
            self.play(ReplacementTransform(func, func0), run_time=0.5)
            x,y,_ = func0[1].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("q")
            x,y,_ = func0[3].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

        # Wait for 4 seconds at the end of animation
        self.wait(4)

class Func_2_1_I_8_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=["We substitute $x=0$", "The function value is equal to b: $f(0)=b$", "So, $b=2$"], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Note: Function Term")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs1).move_to(cords.get_bottom()+0.5*DOWN)
        func2 = MathTex("f","(0)","=","a","0","+", "b", "=","b", color=c1t, font_size=fs1).move_to(cords.get_bottom()+0.5*DOWN)
        func2_a = func2[:-1]
        func2_b = func2[-1]
        sol = MathTex("\\rightarrow b=2", color=c1t, font_size=fs1).move_to(cords.get_bottom()+0.5*DOWN)
                
        a, b = ValueTracker(1), ValueTracker(2)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Hmm, unfortunately not. We substitute <bookmark mark="plugInZero"/> zero into the function term and get f
                of zero equals <bookmark mark="a"/> "a" times <bookmark mark="times0"/> zero  <bookmark mark="plusb"/>
                plus b. <bookmark mark="b"/> That is <bookmark mark="eqb"/> equal to b.
                
                Graphically, this means: We can determine b by looking at the value of the function at <bookmark mark="origin"/> x equals zero.
                
                We find this out by looking at where the graph <bookmark mark="yaxis"/> intersects the y-axis.
                
                In this case, it does so at <bookmark mark="f0"/> y equals two.
                
                Therefore, <bookmark mark="beq2"/> b is equal to two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("plugInZero")
            cursor.idle=False
            note.change_colors([0])
            x,y,_ = func2[1].get_center()+DOWN*0.4
            self.play(ReplacementTransform(func, func2_a), run_time=0.5)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("a")
            x,y,_ = func2[3].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("times0")
            x,y,_ = func2[4].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("plusb")
            x,y,_ = func2[6].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("b")
            self.play(Write(func2_b), run_time=0.5)

            self.wait_until_bookmark("eqb")
            note.change_colors([0,1])
            x,y,_ = func2[-1].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("origin")
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("yaxis")
            self.play(CursorMarkAxis(cursor, plane, axis='y'), run_time=0.5)

            self.wait_until_bookmark("f0")
            note.change_colors([1,2])
            x,y,_ = plane.c2p(0,2)
            self.play(CursorMoveResize(cursor, x, y, 0.2, 0.2), run_time=0.4)

            self.wait_until_bookmark("beq2")
            self.play(ReplacementTransform(func2, sol), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_2_1_I_8_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=["We substitute $x=0$", "The function value is equal to b: $f(0)=b$", "So, $b=2$"], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Note: Function Term")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs1).move_to(cords.get_bottom()+0.5*DOWN)
        func2 = MathTex("f","(0)","=","a","0","+", "b", "=","b", color=c1t, font_size=fs1).move_to(cords.get_bottom()+0.5*DOWN)
        func2_a = func2[:-1]
        func2_b = func2[-1]
        sol = MathTex("\\rightarrow b=2", color=c1t, font_size=fs1).move_to(cords.get_bottom()+0.5*DOWN)
                
        a, b = ValueTracker(1), ValueTracker(2)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Exactly right. We substitute <bookmark mark="plugInZero"/> zero into the function term and get f
                of zero equals <bookmark mark="a"/> "a" times <bookmark mark="times0"/> zero  <bookmark mark="plusb"/>
                plus b. <bookmark mark="b"/> That is <bookmark mark="eqb"/> equal to b.
                
                Graphically, this means: We can determine b by looking at the value of the function at <bookmark mark="origin"/> x equals zero.
                
                We find this out by looking at where the graph <bookmark mark="yaxis"/> intersects the y-axis.
                
                In this case, it does so at <bookmark mark="f0"/> y equals two.
                
                Therefore, <bookmark mark="beq2"/> b is equal to two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("plugInZero")
            cursor.idle=False
            note.change_colors([0])
            x,y,_ = func2[1].get_center()+DOWN*0.4
            self.play(ReplacementTransform(func, func2_a), run_time=0.5)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("a")
            x,y,_ = func2[3].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("times0")
            x,y,_ = func2[4].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("plusb")
            x,y,_ = func2[6].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("b")
            self.play(Write(func2_b), run_time=0.5)

            self.wait_until_bookmark("eqb")
            note.change_colors([0,1])
            x,y,_ = func2[-1].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("origin")
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("yaxis")
            self.play(CursorMarkAxis(cursor, plane, axis='y'), run_time=0.5)

            self.wait_until_bookmark("f0")
            note.change_colors([1,2])
            x,y,_ = plane.c2p(0,2)
            self.play(CursorMoveResize(cursor, x, y, 0.2, 0.2), run_time=0.4)

            self.wait_until_bookmark("beq2")
            self.play(ReplacementTransform(func2, sol), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_2_1_I_8_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=["We substitute $x=0$", "The function value is equal to b: $f(0)=b$", "So, $b=2$"], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Note: Function Term")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs1).move_to(cords.get_bottom()+0.5*DOWN)
        func2 = MathTex("f","(0)","=","a","0","+", "b", "=","b", color=c1t, font_size=fs1).move_to(cords.get_bottom()+0.5*DOWN)
        func2_a = func2[:-1]
        func2_b = func2[-1]
        sol = MathTex("\\rightarrow b=2", color=c1t, font_size=fs1).move_to(cords.get_bottom()+0.5*DOWN)
                
        a, b = ValueTracker(1), ValueTracker(2)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Hmm, unfortunately not. We substitute <bookmark mark="plugInZero"/> zero into the function term and get f
                of zero equals <bookmark mark="a"/> "a" times <bookmark mark="times0"/> zero  <bookmark mark="plusb"/>
                plus b. <bookmark mark="b"/> That is <bookmark mark="eqb"/> equal to b.
                
                Graphically, this means: We can determine b by looking at the value of the function at <bookmark mark="origin"/> x equals zero.
                
                We find this out by looking at where the graph <bookmark mark="yaxis"/> intersects the y-axis.
                
                In this case, it does so at <bookmark mark="f0"/> y equals two.
                
                Therefore, <bookmark mark="beq2"/> b is equal to two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("plugInZero")
            cursor.idle=False
            note.change_colors([0])
            x,y,_ = func2[1].get_center()+DOWN*0.4
            self.play(ReplacementTransform(func, func2_a), run_time=0.5)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("a")
            x,y,_ = func2[3].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("times0")
            x,y,_ = func2[4].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("plusb")
            x,y,_ = func2[6].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("b")
            self.play(Write(func2_b), run_time=0.5)

            self.wait_until_bookmark("eqb")
            note.change_colors([0,1])
            x,y,_ = func2[-1].get_center()+DOWN*0.4
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("origin")
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("yaxis")
            self.play(CursorMarkAxis(cursor, plane, axis='y'), run_time=0.5)

            self.wait_until_bookmark("f0")
            note.change_colors([1,2])
            x,y,_ = plane.c2p(0,2)
            self.play(CursorMoveResize(cursor, x, y, 0.2, 0.2), run_time=0.4)

            self.wait_until_bookmark("beq2")
            self.play(ReplacementTransform(func2, sol), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


TASK_Func_2_1_I_9_q = SophiaTaskDefinition(
    answerOptions = ["We can directly read $a$: $f(0)=a$", "We can directly read $b$: $f(0)=b$", "We can directly read $a+b$: $f(0)=a+b"],
    correctAnswerIndex = 1,
    questionText = "What happens when we substitute $x=0$ into the function $f(x)=ax+b$?"
)

class Func_2_1_I_9_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=["Consider the displayed function", ["General expression for a linear function:", "$f(x)=ax+b$"], "What is the value of $b$?"], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Linear Function: Determine b")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5)
        a, b = ValueTracker(1), ValueTracker(2)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Here we now see <bookmark mark="plot"/> another linear function.
                
                <bookmark mark="note2"/>
                If the function is described by <bookmark mark="func"/> f of x equals "a" times x plus b, -
                <bookmark mark="lastNote"/>
                what is the value of b?
                """
        ) as tracker:
            
            self.play(Write(cords), run_time=0.5)

            self.wait_until_bookmark("plot")
            note.change_colors([0])
            self.play(Write(updated_f), run_time=0.5)

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("func")
            self.play(Write(func), run_time=0.5)

            self.wait_until_bookmark("lastNote")
            note.change_colors([1,2])

        # Wait for 4 seconds at the end of animation
        self.wait(4)

class Func_2_1_I_9_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=["We know: $b=f(0)$","$\\rightarrow$ Substitute $x=0$ into the function $f$.", ["We get: $f(0)=2$","$\\rightarrow b=2$"]], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Linear Function: Determine b")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5)
        func_0 = MathTex("f(0)=","a","\\cdot 0+", "b", "=b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5).scale(0.9)
        b_eq = MathTex("f(0)=2","\\rightarrow b=2", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5).next_to(cords, DOWN, buff=0.5)
        self.add(func)
                
        a, b = ValueTracker(1), ValueTracker(2)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,-5.5))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Mhm, not quite.
                
                We know that <bookmark mark="note1"/> the value of b is equal to the value of f at the point <bookmark mark="x0"/> x equals zero.
                
                So we read from the graph, <bookmark mark="note2"/> what the value of the function is at the point x equals zero.
                
                <bookmark mark="note3"/>
                In this case, f of zero equals two <bookmark mark="y0"/>.
                
                Therefore, <bookmark mark="beq"/> b is equal to two.
                """
        ) as tracker:
            
            self.play(Write(cords), run_time=0.5)
            self.play(Write(updated_f), run_time=0.5)

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("x0")
            x,y,_ = plane.c2p(0,0)
            cursor.idle=False
            self.play(TransformMatchingTex(func, func_0))
            self.play(CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.idle=True

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("y0")
            cursor.idle=False
            x,y,_ = plane.c2p(0,2)
            self.play(CursorMoveTo(cursor, x,y),ReplacementTransform(func_0, b_eq[0]),  run_time=1)
            cursor.idle=True

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

            self.wait_until_bookmark("beq")
            self.play(Write(b_eq[1]), run_time=1)

        # Wait for 4 seconds at the end of animation
        self.wait(4)


class Func_2_1_I_9_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=["We know: $b=f(0)$","$\\rightarrow$ Substitute $x=0$ into the function $f$.", ["We get: $f(0)=2$","$\\rightarrow b=2$"]], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Linear Function: Determine b")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5)
        func_0 = MathTex("f(0)=","a","\\cdot 0+", "b", "=b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5).scale(0.9)
        b_eq = MathTex("f(0)=2","\\rightarrow b=2", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5).next_to(cords, DOWN, buff=0.5)
        self.add(func)
                
        a, b = ValueTracker(1), ValueTracker(2)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,-5.5))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, exactly.
                
                We know that <bookmark mark="note1"/> the value of b is equal to the value of f at the point <bookmark mark="x0"/> x equals zero.
                
                So we read from the graph, <bookmark mark="note2"/> what the value of the function is at the point x equals zero.
                
                <bookmark mark="note3"/>
                In this case, f of zero equals two <bookmark mark="y0"/>.
                
                Therefore, <bookmark mark="beq"/> b is equal to two.
                """
        ) as tracker:
            
            self.play(Write(cords), run_time=0.5)
            self.play(Write(updated_f), run_time=0.5)

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("x0")
            x,y,_ = plane.c2p(0,0)
            cursor.idle=False
            self.play(TransformMatchingTex(func, func_0))
            self.play(CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.idle=True

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("y0")
            cursor.idle=False
            x,y,_ = plane.c2p(0,2)
            self.play(CursorMoveTo(cursor, x,y),ReplacementTransform(func_0, b_eq[0]),  run_time=1)
            cursor.idle=True

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

            self.wait_until_bookmark("beq")
            self.play(Write(b_eq[1]), run_time=1)

        # Wait for 4 seconds at the end of animation
        self.wait(4)



class Func_2_1_I_9_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=["We know: $b=f(0)$","$\\rightarrow$ Substitute $x=0$ into the function $f$.", ["We get: $f(0)=2$","$\\rightarrow b=2$"]], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Linear Function: Determine b")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5)
        func_0 = MathTex("f(0)=","a","\\cdot 0+", "b", "=b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5).scale(0.9)
        b_eq = MathTex("f(0)=2","\\rightarrow b=2", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5).next_to(cords, DOWN, buff=0.5)
        self.add(func)
                
        a, b = ValueTracker(1), ValueTracker(2)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,-5.5))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Mhm, not quite.
                
                We know that <bookmark mark="note1"/> the value of b is equal to the value of f at the point <bookmark mark="x0"/> x equals zero.
                
                So we read from the graph, <bookmark mark="note2"/> what the value of the function is at the point x equals zero.
                
                <bookmark mark="note3"/>
                In this case, f of zero equals two <bookmark mark="y0"/>.
                
                Therefore, <bookmark mark="beq"/> b is equal to two.
                """
        ) as tracker:
            
            self.play(Write(cords), run_time=0.5)
            self.play(Write(updated_f), run_time=0.5)

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("x0")
            x,y,_ = plane.c2p(0,0)
            cursor.idle=False
            self.play(TransformMatchingTex(func, func_0))
            self.play(CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.idle=True

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("y0")
            cursor.idle=False
            x,y,_ = plane.c2p(0,2)
            self.play(CursorMoveTo(cursor, x,y),ReplacementTransform(func_0, b_eq[0]),  run_time=1)
            cursor.idle=True

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

            self.wait_until_bookmark("beq")
            self.play(Write(b_eq[1]), run_time=1)

        # Wait for 4 seconds at the end of animation
        self.wait(4)

TASK_Func_2_1_I_10_q = SophiaTaskDefinition(
    answerOptions = ["a: Shift in x-Direction, b: Shift in y-Direction", "a: Shift in y-Direction, b: Shift in x-Direction", "a: Slope of the function, b: Shift in y-Direction", "a: Slope of the function, b: Shift in x-Direction"],
    correctAnswerIndex = 2,
    questionText = "What aspects of the function do $a$ and $b$ describe?"
)

class Func_2_1_I_10_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=[["Given the graph of a function","We want to determine it's term"], "We can find $b$ by plugging in $x=0$", "Remember: What do $a$ and $b$ describe?"], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Role of a and b")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5)
                
        a, b = ValueTracker(1), ValueTracker(0)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        # self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so we wanted <bookmark mark="note1"/> to find out how we determine the term of a function,
                when we are given <bookmark mark="graph"/> the graph of that function.
                And we also know that the term of a linear function f of x has <bookmark mark="funcTerm"/> the structure f of x is equal to "a" times x plus b.
                
                aaaand, <bookmark mark="note2"/> we just learned, how to determine "b": We simply plug in zero for x, and the value of f of zero is equal to the value of b.
                
                Now, how do we obtain "a"?
                
                Before we figure that out: <bookmark mark="note3"/> Let's think back to what "a" and "b" actually describe.
                Do you remember, what aspect of the graph "a" and "b" describe?
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])


            
            self.wait_until_bookmark("graph")
            self.play(Write(updated_f))
            
            self.wait_until_bookmark("funcTerm")
            self.play(Write(func))

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

        # Wait for 4 seconds at the end of animation
        self.wait(4)

class Func_2_1_I_10_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=[["a describes the slope","$a$ large$\\rightarrow$ function steep"], ["$b$ describes shift in y-direction", "$b>0\\rightarrow$ shift upwards"]], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Not quite...")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5)
        self.add(func)
                
        a, b = ValueTracker(1), ValueTracker(0)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Mhmmm, that's not quite right!
                
                <bookmark mark="note1"/>
                "a" describes the slope of the function. <bookmark mark="cursorA"/> Remember: <bookmark mark="aH"/> high values of "a" mean a steep slope, <bookmark mark="aL"/> low values of "a" mean a flat slope. <bookmark mark="a1"/>
                
                "b" describes the shift of the function in y-Direction. Remember: <bookmark mark="bH"/> positive values of "b" lead to an upwards shift, <bookmark mark="bL"/> negative values of "b" lead to a downwards shift. <bookmark mark="b1"/>
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("cursorA")
            x, y, _ = plane.c2p(1, 1)
            cursor.idle=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(1, a.get_value() * 1 + b.get_value())))

            self.wait_until_bookmark("aH")
            duration = 1
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            self.play(a.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("aL")
            duration = 1
            self.add_move_sound("backward", duration=duration, rate_func=smooth)
            self.play(a.animate.set_value(0.5), run_time=duration)

            self.wait_until_bookmark("a1")
            self.play(a.animate.set_value(1), run_time=0.5)
            cursor.clear_updaters()
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(0, a.get_value()*0+b.get_value())))
            note.change_colors([0,1])

            self.wait_until_bookmark("bH")
            duration = 1
            start = plane.c2p(0,0)
            x = start[0]
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            arr = Updown_Arrow(start, color=c3, stroke_width=5, vert=True).add_updater(lambda m: m.put_start_and_end_on(start+0.0000000001*DOWN, [x, cursor.get_y(),0]))
            self.add(arr)
            print(arr.get_center())
            self.play(b.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("bL")
            duration = 1
            self.add_move_sound("backward", duration=duration, rate_func=smooth)
            self.play(b.animate.set_value(-2), run_time=2)

            self.wait_until_bookmark("b1")
            self.play(b.animate.set_value(0), run_time=0.5)

        # Wait for 4 seconds at the end of animation
        self.wait(4)

class Func_2_1_I_10_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=[["a describes the slope","$a$ large$\\rightarrow$ function steep"], ["$b$ describes shift in y-direction", "$b>0\\rightarrow$ shift upwards"]], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Not quite...")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5)
        self.add(func)
                
        a, b = ValueTracker(1), ValueTracker(0)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Mhmmm, that's not quite right!
                
                <bookmark mark="note1"/>
                "a" describes the slope of the function. <bookmark mark="cursorA"/> Remember: <bookmark mark="aH"/> high values of "a" mean a steep slope, <bookmark mark="aL"/> low values of "a" mean a flat slope. <bookmark mark="a1"/>
                
                "b" describes the shift of the function in y-Direction. Remember: <bookmark mark="bH"/> positive values of "b" lead to an upwards shift, <bookmark mark="bL"/> negative values of "b" lead to a downwards shift. <bookmark mark="b1"/>
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("cursorA")
            x, y, _ = plane.c2p(1, 1)
            cursor.idle=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(1, a.get_value() * 1 + b.get_value())))

            self.wait_until_bookmark("aH")
            duration = 1
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            self.play(a.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("aL")
            duration = 1
            self.add_move_sound("backward", duration=duration, rate_func=smooth)
            self.play(a.animate.set_value(0.5), run_time=duration)

            self.wait_until_bookmark("a1")
            self.play(a.animate.set_value(1), run_time=0.5)
            cursor.clear_updaters()
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(0, a.get_value()*0+b.get_value())))
            note.change_colors([0,1])

            self.wait_until_bookmark("bH")
            duration = 1
            start = plane.c2p(0,0)
            x = start[0]
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            arr = Updown_Arrow(start, color=c3, stroke_width=5, vert=True).add_updater(lambda m: m.put_start_and_end_on(start+0.0000000001*DOWN, [x, cursor.get_y(),0]))
            self.add(arr)
            print(arr.get_center())
            self.play(b.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("bL")
            duration = 1
            self.add_move_sound("backward", duration=duration, rate_func=smooth)
            self.play(b.animate.set_value(-2), run_time=2)

            self.wait_until_bookmark("b1")
            self.play(b.animate.set_value(0), run_time=0.5)

        # Wait for 4 seconds at the end of animation
        self.wait(4)


class Func_2_1_I_10_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=[["a describes the slope","$a$ large$\\rightarrow$ function steep"], ["$b$ describes shift in y-direction", "$b>0\\rightarrow$ shift upwards"]], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Correct!")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5)
        self.add(func)
                
        a, b = ValueTracker(1), ValueTracker(0)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Great job, that's exactly right!!!
                
                <bookmark mark="note1"/>
                "a" describes the slope of the function. <bookmark mark="cursorA"/> Remember: <bookmark mark="aH"/> high values of "a" mean a steep slope, <bookmark mark="aL"/> low values of "a" mean a flat slope. <bookmark mark="a1"/>
                
                "b" describes the shift of the function in y-Direction. Remember: <bookmark mark="bH"/> positive values of "b" lead to an upwards shift, <bookmark mark="bL"/> negative values of "b" lead to a downwards shift. <bookmark mark="b1"/>
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("cursorA")
            x, y, _ = plane.c2p(1, 1)
            cursor.idle=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(1, a.get_value() * 1 + b.get_value())))

            self.wait_until_bookmark("aH")
            duration = 1
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            self.play(a.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("aL")
            duration = 1
            self.add_move_sound("backward", duration=duration, rate_func=smooth)
            self.play(a.animate.set_value(0.5), run_time=duration)

            self.wait_until_bookmark("a1")
            self.play(a.animate.set_value(1), run_time=0.5)
            cursor.clear_updaters()
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(0, a.get_value()*0+b.get_value())))
            note.change_colors([0,1])

            self.wait_until_bookmark("bH")
            duration = 1
            start = plane.c2p(0,0)
            x = start[0]
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            arr = Updown_Arrow(start, color=c3, stroke_width=5, vert=True).add_updater(lambda m: m.put_start_and_end_on(start+0.0000000001*DOWN, [x, cursor.get_y(),0]))
            self.add(arr)
            print(arr.get_center())
            self.play(b.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("bL")
            duration = 1
            self.add_move_sound("backward", duration=duration, rate_func=smooth)
            self.play(b.animate.set_value(-2), run_time=2)

            self.wait_until_bookmark("b1")
            self.play(b.animate.set_value(0), run_time=0.5)

        # Wait for 4 seconds at the end of animation
        self.wait(4)


class Func_2_1_I_10_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=[["a describes the slope","$a$ large$\\rightarrow$ function steep"], ["$b$ describes shift in y-direction", "$b>0\\rightarrow$ shift upwards"]], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Not quite...")

        # Create the coordinate system
        cords = self.add_cords([-3, 3, 1], [-4, 4, 1], x_ticks=[-3,-1,0,1,3], y_ticks=[-4,-2,0,2,4],
                               x_labels=[-3,-1,0,1,3], y_labels=[-4,-2,0,2,4])
        plane = cords[0]
        self.add(cords)

        # Create and plot piecewise linear function
        func = MathTex("f(x)=","a","x+", "b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.5)
        self.add(func)
                
        a, b = ValueTracker(1), ValueTracker(0)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        # Sine function that is updated
        updated_f = always_redraw(redraw_f)
        self.add(updated_f)

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to(plane.c2p(0,0))
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Mhmmm, that's not quite right!
                
                <bookmark mark="note1"/>
                "a" describes the slope of the function. <bookmark mark="cursorA"/> Remember: <bookmark mark="aH"/> high values of "a" mean a steep slope, <bookmark mark="aL"/> low values of "a" mean a flat slope. <bookmark mark="a1"/>
                
                "b" describes the shift of the function in y-Direction. Remember: <bookmark mark="bH"/> positive values of "b" lead to an upwards shift, <bookmark mark="bL"/> negative values of "b" lead to a downwards shift. <bookmark mark="b1"/>
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("cursorA")
            x, y, _ = plane.c2p(1, 1)
            cursor.idle=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(1, a.get_value() * 1 + b.get_value())))

            self.wait_until_bookmark("aH")
            duration = 1
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            self.play(a.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("aL")
            duration = 1
            self.add_move_sound("backward", duration=duration, rate_func=smooth)
            self.play(a.animate.set_value(0.5), run_time=duration)

            self.wait_until_bookmark("a1")
            self.play(a.animate.set_value(1), run_time=0.5)
            cursor.clear_updaters()
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.8)
            cursor.add_updater(lambda c: c.move_to(plane.c2p(0, a.get_value()*0+b.get_value())))
            note.change_colors([0,1])

            self.wait_until_bookmark("bH")
            duration = 1
            start = plane.c2p(0,0)
            x = start[0]
            self.add_move_sound("forward", duration=duration, rate_func=smooth)
            arr = Updown_Arrow(start, color=c3, stroke_width=5, vert=True).add_updater(lambda m: m.put_start_and_end_on(start+0.0000000001*DOWN, [x, cursor.get_y(),0]))
            self.add(arr)
            print(arr.get_center())
            self.play(b.animate.set_value(2), run_time=duration)

            self.wait_until_bookmark("bL")
            duration = 1
            self.add_move_sound("backward", duration=duration, rate_func=smooth)
            self.play(b.animate.set_value(-2), run_time=2)

            self.wait_until_bookmark("b1")
            self.play(b.animate.set_value(0), run_time=0.5)

        # Wait for 4 seconds at the end of animation
        self.wait(4)

class Func_2_1_I_11(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=[["We want to determine $a$","$\\rightarrow$We want to find the slope of a function"], "Create slope triangle to find slope"])
        self.add(note)

        # Create the coordinate system
        cords = self.add_cords([-4,4, 1], [-8, 8, 2], x_ticks=[-4,-2,0,2,4], y_ticks=[-8,-4,0,4,8],
                               x_labels=[-4,-2,0,2,4], y_labels=[-8,-4,0,4,8])
        plane = cords[0]

        # Add title to the scene
        self.add_title("Slope of a linear function")

        # Create and plot piecewise linear function
        func = lambda x: 2*x
        func_plotted = plane.plot(func, color=GREEN)

        # Initialize a cursor
        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])
        # self.add(cursor)

        slopeTriangleText = Text("Slope Triangle", color=c1).scale(0.8).next_to(cords, DOWN, buff=0.5)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so we now <bookmark mark="note1"/> want to determine "a" from the graph of a function.
                
                As we just saw, that means we want to determine the slope of the function.
                
                In order to do that, we are revisiting a tool from earlier: <bookmark mark="note2"/> the slope triangle.
                
                <bookmark mark="writeCords"/>
                
                Consider this linear function and look at the line between the <bookmark mark="sec1"/> point x equals 1 and the point <bookmark mark="sec3"/> x equals 3.
                
                Just like earlier, we are drawing <bookmark mark="dashed"/> a vertical line from these points to the graph of the function.
                
                These lines intersect the graph at the values of <bookmark mark="circ1"/> f of one and <bookmark mark="circ2"/> f of three.
                
                We can shift <bookmark mark="triangle"/> the line between the two points up, to the lower of the two function values and connect it to
                the higher of the two values using a vertical line <bookmark mark="slopeTriangle"/> to form a triangle.
                
                This triangle is called <bookmark mark="highlight"/> the slope triangle.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])
            
            self.wait_until_bookmark("writeCords")
            self.play(Write(cords), run_time=0.5)
            self.play(Write(func_plotted), run_time=0.5)
            self.add(cursor)

            self.wait_until_bookmark("sec1")
            cursor.idle = False
            x1, y1, _ = plane.x_axis.n2p(1)
            self.play(CursorMoveResize(cursor, x1, y1, 0.2, 0.2))

            self.wait_until_bookmark("sec3")
            x2, y2, _ = plane.x_axis.n2p(2)
            self.play(CursorMoveResize(cursor, x2, y2, 2*(x2-x1), 0.1))

            self.wait_until_bookmark("dashed")
            x3, y3, _ = plane.x_axis.n2p(3)
            d1 = DashedLine(start=[x1, y1, 0], end=[x1, plane.y_axis.n2p(func(1))[1], 0], color=BLACK)
            d2 = DashedLine(start=[x3, y3, 0], end=[x3, plane.y_axis.n2p(func(3))[1], 0], color=BLACK)
            self.play(Write(d1), Write(d2), run_time=3)

            self.wait_until_bookmark("circ1")
            circ1 = Circle(radius=0.1, stroke_width=2, color=BLACK).move_to([x1, plane.y_axis.n2p(func(1))[1], 0])
            self.play(Write(circ1))
            
            self.wait_until_bookmark("circ2")
            circ2 = Circle(radius=0.1, stroke_width=2, color=BLACK).move_to([x3, plane.y_axis.n2p(func(3))[1], 0])
            self.play(Write(circ2))

            self.wait_until_bookmark("triangle")
            self.play(CursorMoveResize(cursor, x2, plane.y_axis.n2p(func(1))[1], 2*(x2-x1), 0.1), run_time=2.5)

            self.wait_until_bookmark("slopeTriangle")
            tri = Polygon([x1, plane.y_axis.n2p(func(1))[1], 0], [x3, plane.y_axis.n2p(func(1))[1], 0], [x3, plane.y_axis.n2p(func(3))[1], 0], color=GREEN)
            self.play(Write(tri), Unwrite(d1), Unwrite(d2), Unwrite(circ1), Unwrite(circ2), CursorMoveResize(cursor, xo, yo, 0.2, 0.2))
            cursor.idle = True

            self.wait_until_bookmark("highlight")
            self.play(tri.animate(run_time=2.5).set_color(RED), Write(slopeTriangleText))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_2_1_I_12(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=["$1.$Compute width of Triangle", "$2.$Compute height of Triangle", "3. Compute $a$ by dividing height by width"])
        self.add(note)

        # Create the coordinate system
        cords = self.add_cords([-4,4, 2], [-8, 8, 2], x_ticks=[-4,-2,0,4], y_ticks=[-8,-4,0,4,8],
                               x_labels=[-4,-2,0,4], y_labels=[-8,-4,0,4,8])
        plane = cords[0]
        self.add(cords)

        # Add title to the scene
        self.add_title("Slope Triangle")

        # Create and plot piecewise linear function
        func = lambda x: 2*x+1
        func_plotted = plane.plot(func, color=GREEN)
        self.add(func_plotted)

        # Initialize a cursor
        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, idle=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])
        self.add(cursor)

        x1, y1, _ = plane.x_axis.n2p(1)
        x2, y2, _ = plane.x_axis.n2p(2)
        x3, y3, _ = plane.x_axis.n2p(3)
        Left, Right, Top = [x1, plane.y_axis.n2p(func(1))[1], 0], [x3, plane.y_axis.n2p(func(1))[1], 0], [x3, plane.y_axis.n2p(func(3))[1], 0]
        horLine = Line(start = Left, end = Right, color=BLUE)
        vertLine = Line(start = Right, end = Top, color=BLUE)
        width = MathTex("2", color=c1t, font_size=fs3).next_to(horLine, DOWN, buff=0.1)
        height = MathTex("4", color=c1t, font_size=fs3).next_to(vertLine, RIGHT, buff=0.1)
        slopeLine = Line(start = Left, end = Top, color=BLUE)
        tri = Polygon(Left, Right, Top, color=RED)
        self.add(tri)

        d1 = DashedLine(start=[x1, y1, 0], end=Left, color=BLACK)
        d2 = DashedLine(start=[x3, y3, 0], end=Right, color=BLACK)

        shift = plane.x_axis.n2p(0)-plane.x_axis.n2p(3)
        dh1 = DashedLine(start=Right, end=Right+shift, color=BLACK)
        dh2 = DashedLine(start=Top, end=Top+shift, color=BLACK)

        aTerm = MathTex("a=", "{{height}","\\over{width}}","=\\frac42=2", color=BLACK).scale(0.7).next_to(plane, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text="""
                Trust me, it's really important to understand the slope triangle well.
                
                For that reason, let's analyze it step by step.
                
                First, let's look at <bookmark mark="hor"/> the horizontal line.
                -
                As we can see, it describes the width of the triangle.
                
                If we connect the endpoints of that part of the triangle to the x-axis
                <bookmark mark="dashed"/> using vertical lines, we can then read off
                the width of the triangle from the x-axis. In this case,
                <bookmark mark="width"/> the width is 2. <bookmark mark="unDashed"/>
                
                Next, let's look at <bookmark mark="vert"/> the vertical line.
                
                The vertical line describes the height of the triangle.
                
                If we connect the endpoints of that part of the triangle to the y-axis,
                <bookmark mark="dashedh"/> using horizontal lines, we can then read off
                the height of the triangle, similar to how we've read of the width earlier.
                In this example, <bookmark mark="height"/> the height is 4. <bookmark mark="unDashedH"/>
                
                Finally, and most importantly, we want to know what the slope of the triangle is.
                
                The slope is also described by the <bookmark mark="slopeLine"/> third line, which is at an angle.
                """
        ) as tracker:
            
            self.wait_until_bookmark("hor")
            self.play(Write(horLine))

            self.wait_until_bookmark("dashed")
            self.play(Write(d1), Write(d2))
            note.change_colors([0])

            self.wait_until_bookmark("width")
            self.play(Write(width))

            self.wait_until_bookmark("unDashed")
            self.play(Unwrite(d1), Unwrite(d2))

            self.wait_until_bookmark("vert")
            self.play(Write(vertLine), Unwrite(horLine))

            self.wait_until_bookmark("dashedh")
            self.play(Write(dh1), Write(dh2))
            note.change_colors([0,1])

            self.wait_until_bookmark("height")
            self.play(Write(height))

            self.wait_until_bookmark("unDashedH")
            self.play(Unwrite(dh1), Unwrite(dh2), Unwrite(vertLine))

            self.wait_until_bookmark("slopeLine")
            self.play(Write(slopeLine))

        with self.voiceover(
                text="""
                But how do we compute the slope? And by computing the slope, we also mean: how do we <bookmark mark="a"/>
                compute "a"?
                
                We compute the slope by dividing the <bookmark mark="height2"/> height of the triangle
                by the <bookmark mark="width2"/> triangle's width.
                
                In this case, it means dividing <bookmark mark="final"/> 4 by 2, which is 2.
                
                This means, that "a" is also 2.
                
                Great, we just learned how to use the slope triangle to compute the slope of a function:
                
                We compute the height and the width of the triangle, and then obtain the slope by dividing
                the height by the width.
                """
        ) as tracker:

            self.wait_until_bookmark("a")
            self.play(Write(aTerm[0]))

            self.wait_until_bookmark("height2")
            note.change_colors([1,2])
            self.play(Write(aTerm[1]), run_time=0.5)

            self.wait_until_bookmark("width2")
            self.play(Write(aTerm[2]), run_time=0.5)

            self.wait_until_bookmark("final")
            self.play(Write(aTerm[3]))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)






# PROTOTYPES = [
#     PagePrototypeVideo.from_scene(Func_2_1_I_1_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_2_1_I_1_q, Func_2_1_I_1_q.__name__),
#     PagePrototypeVideo.from_scene(Func_2_1_I_1_a),
#     PagePrototypeVideo.from_scene(Func_2_1_I_1_b),
#     PagePrototypeVideo.from_scene(Func_2_1_I_1_c),
#     PagePrototypeVideo.from_scene(Func_2_1_I_2),
#     PagePrototypeVideo.from_scene(Func_2_1_I_3_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_2_1_I_3_q, Func_2_1_I_3_q.__name__),
#     PagePrototypeVideo.from_scene(Func_2_1_I_3_a),
#     PagePrototypeVideo.from_scene(Func_2_1_I_3_b),
#     PagePrototypeVideo.from_scene(Func_2_1_I_3_c),
#     PagePrototypeVideo.from_scene(Func_2_1_I_4_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_2_1_I_3_q, Func_2_1_I_4_q.__name__),
#     PagePrototypeVideo.from_scene(Func_2_1_I_4_a),
#     PagePrototypeVideo.from_scene(Func_2_1_I_4_b),
#     PagePrototypeVideo.from_scene(Func_2_1_I_4_c),
#     PagePrototypeVideo.from_scene(Func_2_1_I_5_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_2_1_I_5_q, Func_2_1_I_5_q.__name__),
#     PagePrototypeVideo.from_scene(Func_2_1_I_5_a),
#     PagePrototypeVideo.from_scene(Func_2_1_I_5_b),
#     PagePrototypeVideo.from_scene(Func_2_1_I_5_c),
#     PagePrototypeVideo.from_scene(Func_2_1_I_5_d),
#     PagePrototypeVideo.from_scene(Func_2_1_I_6_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_2_1_I_6_q, Func_2_1_I_6_q.__name__),
#     PagePrototypeVideo.from_scene(Func_2_1_I_6_a),
#     PagePrototypeVideo.from_scene(Func_2_1_I_6_b),
#     PagePrototypeVideo.from_scene(Func_2_1_I_6_c),
#     PagePrototypeVideo.from_scene(Func_2_1_I_6_d),
#     PagePrototypeVideo.from_scene(Func_2_1_I_7),
#     PagePrototypeVideo.from_scene(Func_2_1_I_8_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_2_1_I_8_q, Func_2_1_I_8_q.__name__),
#     PagePrototypeVideo.from_scene(Func_2_1_I_8_a),
#     PagePrototypeVideo.from_scene(Func_2_1_I_8_b),
#     PagePrototypeVideo.from_scene(Func_2_1_I_8_c),
#     PagePrototypeVideo.from_scene(Func_2_1_I_9_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_2_1_I_9_q, Func_2_1_I_9_q.__name__),
#     PagePrototypeVideo.from_scene(Func_2_1_I_9_a),
#     PagePrototypeVideo.from_scene(Func_2_1_I_9_b),
#     PagePrototypeVideo.from_scene(Func_2_1_I_9_c),
#     PagePrototypeVideo.from_scene(Func_2_1_I_10_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_2_1_I_10_q, Func_2_1_I_10_q.__name__),
#     PagePrototypeVideo.from_scene(Func_2_1_I_10_a),
#     PagePrototypeVideo.from_scene(Func_2_1_I_10_b),
#     PagePrototypeVideo.from_scene(Func_2_1_I_10_c),
#     PagePrototypeVideo.from_scene(Func_2_1_I_10_d),
#     PagePrototypeVideo.from_scene(Func_2_1_I_11),
#     PagePrototypeVideo.from_scene(Func_2_1_I_12),
# ]
scenes/Func/Func_2: Linear Functions/Func2_1.py
Sophia-Edu-Labs/sophia-math
# 2_2: Linear Functions: Term to Graph

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition


TASK_Func_2_2_I_1_q = SophiaTaskDefinition(
    answerOptions=["$f(x)=x$", "$f(x)=10\cdot x$", "$f(x)=10+x$"],
    correctAnswerIndex=2,
    questionText="Which function describes our total expenses?"
)

class Func_2_2_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        lemonade = ImageMobject(assets_folder / "img" / "lemonade.png").scale(0.3).move_to(LEFT*6.7)

        concert = ImageMobject(assets_folder / "img" / "drums.png").scale(0.3).move_to(UP*1.5+LEFT*6.7)

        # Create a notepad with texts
        note = Notepad(texts=[["Which function best describes", "our total expenses?"], "$f(x)=x$", "$f(x)=10\\cdot x$", "$f(x)=10+x$"], buff=0.2, buff_inner=0)
        self.add(note)

        # Add title to the scene
        title = self.add_title("Drawing Functions")

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        self.add(cursor)

        term = Tex("Term", color=c1t, font_size=fs1).next_to(title, DOWN, buff=1)
        to = Tex("$\\downarrow$", color=c1t, font_size=fs1).next_to(term, DOWN, buff=0.5)
        graph = Tex("Graph", color=c1t, font_size=fs1).next_to(to, DOWN, buff=0.5)

        ticket = Tex("$\\rightarrow 10\\$$ Admission", color=c1t, font_size=fs2).next_to(concert, RIGHT, buff=0).shift(RIGHT*5)
        lemPrice = Tex("$\\rightarrow 1\\$$/Lemonade", color=c1t, font_size=fs2).next_to(lemonade, RIGHT, buff=0).shift(RIGHT*5)

        # Action Sequence
        with self.voiceover(
                text="""
                Okay, let's continue and learn something new!
                
                Specifically, we want to learn the following: <bookmark mark="ttg"/> We are given <bookmark mark="term"/> the term of a function, and we want to <bookmark mark="graph"/> draw the corresponding graph.
                We'll start with an example: We are at <bookmark mark="concert"/> a concert and <bookmark mark="lemonade"/> drinking lemonade. We want to know how much money we are spending.
                
                We pay <bookmark mark="ticket"/> ten dollars for admission and then one dollar for <bookmark mark="lemPrice"/> each lemonade.
                <bookmark mark="note"/>
                Which term describes, in dollars, how much we spend if x represents the number of lemonades?
                
                Is it <bookmark mark="t1"/> the term f of x equals one times x?
                
                Or is it <bookmark mark="t2"/> the term f of x equals ten times x?
                
                Or is it <bookmark mark="t3"/> the term f of x equals ten plus x?
                """
        ) as tracker:
            
            self.wait_until_bookmark("ttg")
            self.play(Write(term), Write(to), Write(graph), run_time=0.5)
            cursor.blinking=False

            self.wait_until_bookmark("term")
            x,y,_ = term.get_left()+0.3*LEFT
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("graph")
            x,y,_ = graph.get_left()+0.3*LEFT
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("concert")
            x,y = 0, -1
            self.play(concert.animate(run_time=1).shift(RIGHT*5), CursorMoveTo(cursor, x, y), Unwrite(term), Unwrite(to), Unwrite(graph), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("lemonade")
            self.play(lemonade.animate.shift(RIGHT*5), run_time=1)

            self.wait_until_bookmark("ticket")
            self.play(Write(ticket), run_time=0.5)

            self.wait_until_bookmark("lemPrice")
            self.play(Write(lemPrice), run_time=0.5)

            self.wait_until_bookmark("note")
            note.change_colors([0])
            cursor.blinking=False
            x,y,_ = note.texts[0].get_left()+0.3*LEFT
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("t1")
            x,y,_ = note.texts[1].get_left()+0.3*LEFT
            note.change_colors([0,1])
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("t2")
            x,y,_ = note.texts[2].get_left()+0.3*LEFT
            note.change_colors([1,2])
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("t3")
            x,y,_ = note.texts[3].get_left()+0.3*LEFT
            note.change_colors([2,3])
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_2_2_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=["$10\\$$ Admission", "$1\\$$ Cost per Lemonade", "$\\rightarrow$Total costs are $f(x)=10+x$"])
        self.add(note)

        # Add title to the scene
        title = self.add_title("Drawing Functions")

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        self.add(cursor)

        func = MathTex("f", "(x)", "=", "10", "+", "x", color=c1t, font_size=fs1).next_to(title, DOWN, buff=1.5)
        funcm1, funcm2 = func[-1].copy(), func[-2].copy()

        # Action Sequence
        with self.voiceover(
                text="""
                Unfortunately, that's incorrect.  
                The correct solution is the function <bookmark mark="f"/> f of x equals ten plus x, as this function describes our total expenses.
                
                But how do we arrive at this? And what does it mean?
                It's like this:
                We pay <bookmark mark="firstTen"/> ten dollars for admission, no matter how many lemonades we drink. So, we start with the term <bookmark mark="ff"/> f of <bookmark mark="fx"/> x equals <bookmark mark="ten"/> ten.
                
                <bookmark mark="lemonadeNote"/>
                Since each lemonade costs one dollar, for each lemonade we drink, an additional dollar is added. The variable <bookmark mark="varX"/> x represents the number of lemonades
                we have drunk.
                So, we add <bookmark mark="x"/> x to the function that describes our total expenses.
                
                <bookmark mark="finalNote"/>
                And there you have it, the correct solution, the function <bookmark mark="ff2"/> f of <bookmark mark="fx2"/> x equals <bookmark mark="ten2"/> ten plus <bookmark mark="varX2"/> x.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            self.play(Write(func))

            self.wait_until_bookmark("firstTen")
            cursor.blinking=False
            note.change_colors([0])
            x,y,_ = func[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.4)

            self.wait_until_bookmark("ff")
            x,y,_ = func[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Unwrite(func[-1]), Unwrite(func[-2]), run_time=0.4)

            self.wait_until_bookmark("fx")
            x,y,_ = func[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.2)

            self.wait_until_bookmark("ten")
            x,y,_ = func[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.2)
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("lemonadeNote")
            note.change_colors([0,1])

            self.wait_until_bookmark("varX")
            cursor.blinking=False
            x,y,_ = func[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y),  run_time=0.4)

            self.wait_until_bookmark("x")
            x,y,_ = func[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(funcm1), Write(funcm2), run_time=0.6)
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("finalNote")
            note.change_colors([1,2])

            self.wait_until_bookmark("ff2")
            cursor.blinking=False
            x,y,_ = func[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.2)

            self.wait_until_bookmark("fx2")
            x,y,_ = func[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.2)

            self.wait_until_bookmark("ten2")
            x,y,_ = func[3].get_center()+0.4*DOWN
            funcm1, funcm2 = func[-1].copy(), func[-2].copy()
            self.play(CursorMoveToCurved(cursor,x,y), Unwrite(func[-1]), Unwrite(func[-2]), run_time=0.2)

            self.wait_until_bookmark("varX2")
            x,y,_ = func[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y),  run_time=0.2)
            self.wait(0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of animation
        self.wait(4)

class Func_2_2_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=["$10\\$$ Admission", "$1\\$$ Cost per Lemonade", "$\\rightarrow$Total costs are $f(x)=10+x$"])
        self.add(note)

        # Add title to the scene
        title = self.add_title("Drawing Functions")

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        self.add(cursor)

        func = MathTex("f", "(x)", "=", "10", "+", "x", color=c1t, font_size=fs1).next_to(title, DOWN, buff=1.5)
        funcm1, funcm2 = func[-1].copy(), func[-2].copy()

        # Action Sequence
        with self.voiceover(
                text="""
                Unfortunately, that's incorrect.  
                The correct solution is the function <bookmark mark="f"/> f of x equals ten plus x, as this function describes our total expenses.
                
                But how do we arrive at this? And what does it mean?
                It's like this:
                We pay <bookmark mark="firstTen"/> ten dollars for admission, no matter how many lemonades we drink. So, we start with the term <bookmark mark="ff"/> f of <bookmark mark="fx"/> x equals <bookmark mark="ten"/> ten.
                
                <bookmark mark="lemonadeNote"/>
                Since each lemonade costs one dollar, for each lemonade we drink, an additional dollar is added. The variable <bookmark mark="varX"/> x represents the number of lemonades
                we have drunk.
                So, we add <bookmark mark="x"/> x to the function that describes our total expenses.
                
                <bookmark mark="finalNote"/>
                And there you have it, the correct solution, the function <bookmark mark="ff2"/> f of <bookmark mark="fx2"/> x equals <bookmark mark="ten2"/> ten plus <bookmark mark="varX2"/> x.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            self.play(Write(func))

            self.wait_until_bookmark("firstTen")
            cursor.blinking=False
            note.change_colors([0])
            x,y,_ = func[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.4)

            self.wait_until_bookmark("ff")
            x,y,_ = func[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Unwrite(func[-1]), Unwrite(func[-2]), run_time=0.4)

            self.wait_until_bookmark("fx")
            x,y,_ = func[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.2)

            self.wait_until_bookmark("ten")
            x,y,_ = func[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.2)
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("lemonadeNote")
            note.change_colors([0,1])

            self.wait_until_bookmark("varX")
            cursor.blinking=False
            x,y,_ = func[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y),  run_time=0.4)

            self.wait_until_bookmark("x")
            x,y,_ = func[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(funcm1), Write(funcm2), run_time=0.6)
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("finalNote")
            note.change_colors([1,2])

            self.wait_until_bookmark("ff2")
            cursor.blinking=False
            x,y,_ = func[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.2)

            self.wait_until_bookmark("fx2")
            x,y,_ = func[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.2)

            self.wait_until_bookmark("ten2")
            x,y,_ = func[3].get_center()+0.4*DOWN
            funcm1, funcm2 = func[-1].copy(), func[-2].copy()
            self.play(CursorMoveToCurved(cursor,x,y), Unwrite(func[-1]), Unwrite(func[-2]), run_time=0.2)

            self.wait_until_bookmark("varX2")
            x,y,_ = func[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y),  run_time=0.2)
            self.wait(0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of animation
        self.wait(4)


class Func_2_2_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=["$10\\$$ Admission", "$1\\$$ Cost per Lemonade", "$\\rightarrow$Total costs are $f(x)=10+x$"])
        self.add(note)

        # Add title to the scene
        title = self.add_title("Drawing Functions")

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        self.add(cursor)

        func = MathTex("f", "(x)", "=", "10", "+", "x", color=c1t, font_size=fs1).next_to(title, DOWN, buff=1.5)
        funcm1, funcm2 = func[-1].copy(), func[-2].copy()

        # Action Sequence
        with self.voiceover(
                text="""
                That's correct.  The function <bookmark mark="f"/> f of x equals ten plus x describes our total expenses.
                
                But how do we arrive at this? And what does it mean?
                It's like this:
                We pay <bookmark mark="firstTen"/> ten dollars for admission, no matter how many lemonades we drink. So, we start with the term <bookmark mark="ff"/> f of <bookmark mark="fx"/> x equals <bookmark mark="ten"/> ten.
                
                <bookmark mark="lemonadeNote"/>
                Since each lemonade costs one dollar, for each lemonade we drink, an additional dollar is added. The variable <bookmark mark="varX"/> x represents the number of lemonades
                we have drunk.
                So, we add <bookmark mark="x"/> x to the function that describes our total expenses.
                
                <bookmark mark="finalNote"/>
                And there you have it, the correct solution, the function <bookmark mark="ff2"/> f of <bookmark mark="fx2"/> x equals <bookmark mark="ten2"/> ten plus <bookmark mark="varX2"/> x.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            self.play(Write(func))

            self.wait_until_bookmark("firstTen")
            cursor.blinking=False
            note.change_colors([0])
            x,y,_ = func[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.4)

            self.wait_until_bookmark("ff")
            x,y,_ = func[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Unwrite(func[-1]), Unwrite(func[-2]), run_time=0.4)

            self.wait_until_bookmark("fx")
            x,y,_ = func[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.2)

            self.wait_until_bookmark("ten")
            x,y,_ = func[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.2)
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("lemonadeNote")
            note.change_colors([0,1])

            self.wait_until_bookmark("varX")
            cursor.blinking=False
            x,y,_ = func[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y),  run_time=0.4)

            self.wait_until_bookmark("x")
            x,y,_ = func[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(funcm1), Write(funcm2), run_time=0.6)
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("finalNote")
            note.change_colors([1,2])

            self.wait_until_bookmark("ff2")
            cursor.blinking=False
            x,y,_ = func[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.2)

            self.wait_until_bookmark("fx2")
            x,y,_ = func[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.2)

            self.wait_until_bookmark("ten2")
            x,y,_ = func[3].get_center()+0.4*DOWN
            funcm1, funcm2 = func[-1].copy(), func[-2].copy()
            self.play(CursorMoveToCurved(cursor,x,y), Unwrite(func[-1]), Unwrite(func[-2]), run_time=0.2)

            self.wait_until_bookmark("varX2")
            x,y,_ = func[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y),  run_time=0.2)
            self.wait(0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of animation
        self.wait(4)


###########################################
###########################################
class Func_2_2_I_2(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Create a notepad with texts
        note = Notepad(texts=["We want to determine function graphs", ["$\\rightarrow$ Plug two $x$-values","into the term of the function"], "$\\rightarrow$ Connect the obtained points"])
        self.add(note)

        # Add title to the scene
        title = self.add_title("Drawing Functions")

        # Create the coordinate system
        cords = self.add_cords([0, 20, 5], [0, 30, 5], x_ticks=[0,10,20], y_ticks=[0,10,20,30],
                               x_labels=[0,10,20], y_labels=[0,10,20,30])
        plane = cords[0]

        # Create and plot piecewise linear function

        func_o = MathTex("f", "(x)", "=", "10", "+", "x", color=c1t, font_size=fs1).next_to(title, DOWN, buff=1.5)
        func = MathTex("f", "(x)", "=", "10", "+", "x", color=c1t, font_size=fs1).next_to(cords, DOWN)
        func0 = MathTex("f", "(0)", "=", "10", "+", "0", color=c1t, font_size=fs1).next_to(cords, DOWN)
        func10 = MathTex("f", "(10)", "=", "10", "+", "10", color=c1t, font_size=fs1).next_to(cords, DOWN)
        func_original1 = MathTex("f", "(x)", "=", "10", "+", "x", color=c1t, font_size=fs1).next_to(cords, DOWN)
        func_original2 = MathTex("f", "(x)", "=", "10", "+", "x", color=c1t, font_size=fs1).next_to(cords, DOWN)
        a, b = ValueTracker(1), ValueTracker(10)

        self.add(func_o)

        def redraw_f():
            # Define the sine function
            func = lambda x: a.get_value()*x+b.get_value()
            return plane.plot(func, color=BLUE)

        #sine function that is updated
        updated_f = always_redraw(redraw_f)
        

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.blinking=False

        # Action Sequence
        with self.voiceover(
                text="""
                So now, we have the expression that describes our expenses.
                
                The question now is: <bookmark mark="cords"/> How do we draw the corresponding graph?
                
                We know that the graph is a straight line because our function is linear.
                And to draw a straight line, <bookmark mark="note1"/> we need two points.
                
                For the first point, we always set x to zero. <bookmark mark="x0"/>
                This gives us the value <bookmark mark="ten"/> ten here.
                That's also the intersection point with the upsilon axis...
                Anyway, <bookmark mark="mark1"/> we mark this point.
                
                Next, we set any other value for x.
                Here, for example, we use x equal to <bookmark mark="xten"/> ten because it's easy to calculate.
                By the way, it's always a good idea to use a value that's easy to calculate!
                
                This gives us <bookmark mark="twenty"/> twenty. We also <bookmark mark="mark2"/> mark this point.
                
                So, most of the work is done now. We just need to connect the two points, <bookmark mark="connect"/>
                and the graph is done.
                
                So, in summary: To determine the graph of a linear function, we first set x to zero and
                plot the point. Then we set a different value for x and plot the second point.
                Then we just need to connect the two points, and the graph is done.
                """
        ) as tracker:
            
            self.wait_until_bookmark("cords")
            note.change_colors([0])
            self.play(ReplacementTransform(func_o, func), Write(cords))

            self.wait_until_bookmark("note1")
            note.change_colors([0,1])

            self.wait_until_bookmark("x0")
            self.add(cursor)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("ten")
            x,y,_ = plane.c2p(0,10)
            self.play(CursorMoveTo(cursor,x,y), ReplacementTransform(func, func0), run_time=0.8)

            self.wait_until_bookmark("mark1")
            self.play(Write(Dot(plane.c2p(0,10), color=BLUE)), ReplacementTransform(func0, func_original1), run_time=0.8)

            self.wait_until_bookmark("xten")
            x,y,_ = plane.c2p(10,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.8)

            self.wait_until_bookmark("twenty")
            x,y,_ = plane.c2p(10,20)
            self.play(CursorMoveTo(cursor,x,y), ReplacementTransform(func_original1, func10), run_time=0.8)

            self.wait_until_bookmark("mark2")
            self.play(Write(Dot(plane.c2p(10,20), color=BLUE)))
            x,y,_ = note.texts[-1].get_right()+0.3*RIGHT
            self.play(CursorMoveTo(cursor,x,y), ReplacementTransform(func10, func_original2), run_time=0.8)
            note.change_colors([1,2])

            self.wait_until_bookmark("connect")
            self.play(Write(updated_f), run_time=2)

        # Wait for 4 seconds at the end of animation
        self.wait(4)



###########################################
###########################################
# Pratice Part
###########################################
###########################################
class plotLinearFunctionQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        # Add title to the scene
        title = self.add_title("Drawing Functions")       

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.blinking=False

        # Action Sequence
        
        plane = self.cords[0]
        g1 = plane.plot(self.f1, color=BLUE)
        g2 = plane.plot(self.f2, color=GREEN)
        g3 = plane.plot(self.f3, color=ORANGE)

        # Create a notepad with texts
        note = Notepad(texts=[f"Consider the function ${self.func}$", "What does the graph of this function look like?", "Is it the blue, green, or orange graph?"])
        self.add(note)

        func = MathTex(self.func, color=c1t, font_size=fs1).next_to(title, DOWN, buff=1.5)
        
        with self.voiceover(
                text=f"""
                {self.introText} <bookmark mark="func"/>
                {self.funcText} <bookmark mark="graph"/> 
                {self.qText} 
                
                Is it <bookmark mark="o1"/> the blue graph? 
                Or is it <bookmark mark="o2"/> the green graph? 
                Or is it <bookmark mark="o3"/> the orange graph?
                """
        ) as tracker:
            
            self.wait_until_bookmark("func")
            note.change_colors([0])
            self.play(Write(func))

            self.wait_until_bookmark("graph")
            note.change_colors([0,1])
            self.play(Write(self.cords), func.animate.move_to(self.cords.get_bottom()+0.5*DOWN), run_time=1.5)

            self.wait_until_bookmark("o1")
            note.change_colors([1,2])
            self.play(Write(g1), run_time=1.5)

            self.wait_until_bookmark("o2")
            self.play(Write(g2), run_time=1.5)

            self.wait_until_bookmark("o3")
            self.play(Write(g3), run_time=1.5)
            
        # Wait for 4 seconds at the end of animation
        self.wait(4)

class plotLinearFunctionAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.introText= "Great, that's correct" if self.idx_correct == self.idx_selected else "Unfortunately, that's incorrect."
        self.titleText = "Correct!" if self.idx_correct == self.idx_selected else "Unfortunately Incorrect"
        self.f_correct = self.f1 if self.idx_correct == 0 else self.f2 if self.idx_correct == 1 else self.f3
        self.c_correct = "blue" if self.idx_correct == 0 else "green" if self.idx_correct == 1 else "orange"
        self.color = BLUE if self.idx_correct == 0 else GREEN if self.idx_correct == 1 else ORANGE

        # Add title to the scene
        title = self.add_title(self.titleText)       

        # Initialize a cursor
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.blinking=False

        # Action Sequence
        
        plane = self.cords[0]
        graph = plane.plot(self.f_correct, color=self.color)

        # Create a notepad with texts
        note = Notepad(texts=[f"Consider the function ${self.func}$", "Plug in two x-values", "Connect the points with a straight line"])
        self.add(note)

        func = MathTex(self.func, color=c1t, font_size=fs1).next_to(title, DOWN, buff=1.5)
        
        with self.voiceover(
                text=f"""
                {self.introText} <bookmark mark="func"/>
                The function is {self.funcText}.
                
                To determine the graph, <bookmark mark="note1"/> we need to plug in two x-values. <bookmark mark="cords"/>
                For the first x-value, we use <bookmark mark="x0"/> x equals zero, and we get <bookmark mark="fx0"/> f of Zero equals {get_num(self.f_correct(0))}.
                And for the second value, we plug in <bookmark mark="x"/> x equals {get_num(self.x)}, resulting in <bookmark mark="fx"/> f of {get_num(self.x)} equals {get_num(self.f_correct(self.x))}.
                
                Now, <bookmark mark="graph"/> we connect the two points to obtain the graph of the function, the {self.c_correct} graph.
                """
        ) as tracker:
            
            self.wait_until_bookmark("func")
            note.change_colors([0])
            self.play(Write(func))

            self.wait_until_bookmark("note1")
            note.change_colors([0,1])

            self.wait_until_bookmark("cords")
            self.play(Write(self.cords), func.animate.move_to(self.cords.get_bottom()+0.5*DOWN), run_time=1.5)

            self.wait_until_bookmark("x0")
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("fx0")
            x,y,_ = plane.c2p(0,self.f_correct(0))
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(Dot([x,y,0], color=self.color)), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = plane.c2p(self.x,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("fx")
            x,y,_ = plane.c2p(self.x,self.f_correct(self.x))
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(Dot([x,y,0], color=self.color)), run_time=0.5)

            self.wait_until_bookmark("graph")
            note.change_colors([2,1])
            self.play(Write(graph), run_time=1.5)
            
        # Wait for 4 seconds at the end of animation
        self.wait(4)

###########################################
###########################################
# Concrete Questions
###########################################
###########################################

TASK_Func_2_2_P_1_q = SophiaTaskDefinition(
    answerOptions=["Blue", "Green", "Orange"],
    correctAnswerIndex=0,
    questionText="Which of the graphs matches the function?"
)

class Func_2_2_P_1_q(plotLinearFunctionQuestionScene):
        
    def construct(self):

        self.introText = "Now it's your turn. Consider the function"
        self.funcText = "f of x equals two times x plus one."
        self.func = "f(x)=2x+1"
        self.qText = "I am going to show you three different graphs. Which of them matches the term of the function?"
        self.f1 = lambda x: 2*x+1
        self.f2 = lambda x: 2*x-1
        self.f3 = lambda x: -2*x+1
        self.cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3,0,3], y_ticks=[-6,6])

        super().construct()

class Func_2_2_P_1_a(plotLinearFunctionAnswerScene):
        
    def construct(self):

        self.funcText = "f of x equals two times x plus one."
        self.func = "f(x)=2x+1"
        self.f1 = lambda x: 2*x+1
        self.f2 = lambda x: 2*x-1
        self.f3 = lambda x: -2*x+1
        self.idx_correct = 0
        self.idx_selected = 0
        self.cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3,0,3], y_ticks=[-6,6])
        self.x = 2

        super().construct()

class Func_2_2_P_1_b(plotLinearFunctionAnswerScene):
        
    def construct(self):

        self.funcText = "f of x equals two times x plus one."
        self.func = "f(x)=2x+1"
        self.f1 = lambda x: 2*x+1
        self.f2 = lambda x: 2*x-1
        self.f3 = lambda x: -2*x+1
        self.idx_correct = 0
        self.idx_selected = 1
        self.cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3,0,3], y_ticks=[-6,6])
        self.x = 2

        super().construct()

class Func_2_2_P_1_c(plotLinearFunctionAnswerScene):
        
    def construct(self):

        self.funcText = "f of x equals two times x plus one."
        self.func = "f(x)=2x+1"
        self.f1 = lambda x: 2*x+1
        self.f2 = lambda x: 2*x-1
        self.f3 = lambda x: -2*x+1
        self.idx_correct = 0
        self.idx_selected = 2
        self.cords = self.add_cords([-3, 3, 1], [-6, 6, 2], x_ticks=[-3,0,3], y_ticks=[-6,6])
        self.x = 2

        super().construct()



###########################################
###########################################
TASK_Func_2_2_P_2_q = SophiaTaskDefinition(
    answerOptions=["Blue", "Green", "Orange"],
    correctAnswerIndex=2,
    questionText="Which of the graphs matches the function?"
)
class Func_2_2_P_2_q(plotLinearFunctionQuestionScene):
        
    def construct(self):

        self.introText = "Consider the following function"
        self.funcText = "f of x equals negative three times x plus two."
        self.func = "f(x) = -3x + 2"
        self.qText = "I will now show you three graphs. Which of them corresponds to the function?"
        self.f1 = lambda x: 3*x + 2
        self.f2 = lambda x: 3*x - 2
        self.f3 = lambda x: -3*x + 2
        self.cords = self.add_cords([-4, 4, 1], [-10, 10, 2], x_ticks=[-4, 0, 4], y_ticks=[-8, 8])

        super().construct()

class Func_2_2_P_2_a(plotLinearFunctionAnswerScene):
        
    def construct(self):

        self.funcText = "f of x equals negative three times x plus two."
        self.func = "f(x) = -3x + 2"
        self.f1 = lambda x: 3*x + 2
        self.f2 = lambda x: 3*x - 2
        self.f3 = lambda x: -3*x + 2
        self.idx_correct = 2
        self.idx_selected = 0
        self.cords = self.add_cords([-4, 4, 1], [-10, 10, 2], x_ticks=[-4, 0, 4], y_ticks=[-8, 8])
        self.x = 2

        super().construct()


class Func_2_2_P_2_b(plotLinearFunctionAnswerScene):
        
    def construct(self):

        self.funcText = "f of x equals negative three times x plus two."
        self.func = "f(x) = -3x + 2"
        self.f1 = lambda x: 3*x + 2
        self.f2 = lambda x: 3*x - 2
        self.f3 = lambda x: -3*x + 2
        self.idx_correct = 2
        self.idx_selected = 1
        self.cords = self.add_cords([-4, 4, 1], [-10, 10, 2], x_ticks=[-4, 0, 4], y_ticks=[-8, 8])
        self.x = 2

        super().construct()

class Func_2_2_P_2_c(plotLinearFunctionAnswerScene):
        
    def construct(self):

        self.funcText = "f of x equals negative three times x plus two."
        self.func = "f(x) = -3x + 2"
        self.f1 = lambda x: 3*x + 2
        self.f2 = lambda x: 3*x - 2
        self.f3 = lambda x: -3*x + 2
        self.idx_correct = 2
        self.idx_selected = 2
        self.cords = self.add_cords([-4, 4, 1], [-10, 10, 2], x_ticks=[-4, 0, 4], y_ticks=[-8, 8])
        self.x = 2

        super().construct()


###########################################
###########################################
TASK_Func_2_2_P_3_q = SophiaTaskDefinition(
    answerOptions=["Blue", "Green", "Orange"],
    correctAnswerIndex=1,
    questionText="Which of the graphs matches the function?"
)
class Func_2_2_P_3_q(plotLinearFunctionQuestionScene):
        
    def construct(self):

        self.introText = "Time for another function exercise. Let's examine the following function:"
        self.funcText = "The function f of x is given by four times x plus three."
        self.func = "f(x) = 4x + 3"
        self.qText = "Three graphs will be displayed. Which one matches the function?"
        self.f1 = lambda x: 4*x - 3
        self.f2 = lambda x: 4*x + 3
        self.f3 = lambda x: -4*x - 3
        self.cords = self.add_cords([-2, 2, 1], [-10, 10, 2], x_ticks=[-2, 0, 2], y_ticks=[-10, 10])

        super().construct()

class Func_2_2_P_3_a(plotLinearFunctionAnswerScene):
        
    def construct(self):

        self.funcText = "The function f(x) is given by four times x minus three."
        self.func = "f(x) = 4x - 3"
        self.f1 = lambda x: 4*x - 3
        self.f2 = lambda x: 4*x + 3
        self.f3 = lambda x: -4*x - 3
        self.idx_correct = 1
        self.idx_selected = 1
        self.cords = self.add_cords([-5, 5, 1], [-10, 10, 2], x_ticks=[-5, 0, 5], y_ticks=[-10, 10])
        self.x = 2

        super().construct()

class Func_2_2_P_3_b(plotLinearFunctionAnswerScene):
        
    def construct(self):

        self.funcText = "The function f(x) is given by four times x minus three."
        self.func = "f(x) = 4x - 3"
        self.f1 = lambda x: 4*x - 3
        self.f2 = lambda x: 4*x + 3
        self.f3 = lambda x: -4*x - 3
        self.idx_correct = 1
        self.idx_selected = 1
        self.cords = self.add_cords([-5, 5, 1], [-10, 10, 2], x_ticks=[-5, 0, 5], y_ticks=[-10, 10])
        self.x = 2

        super().construct()


class Func_2_2_P_3_c(plotLinearFunctionAnswerScene):
        
    def construct(self):

        self.funcText = "The function f(x) is given by four times x minus three."
        self.func = "f(x) = 4x - 3"
        self.f1 = lambda x: 4*x - 3
        self.f2 = lambda x: 4*x + 3
        self.f3 = lambda x: -4*x - 3
        self.idx_correct = 1
        self.idx_selected = 2
        self.cords = self.add_cords([-5, 5, 1], [-10, 10, 2], x_ticks=[-5, 0, 5], y_ticks=[-10, 10])
        self.x = 2

        super().construct()



###########################################
###########################################
TASK_Func_2_2_P_4_q = SophiaTaskDefinition(
    answerOptions=["Blue", "Green", "Orange"],
    correctAnswerIndex=1,
    questionText="Which of the graphs matches the function?"
)
class Func_2_2_P_4_q(plotLinearFunctionQuestionScene):
        
    def construct(self):

        self.introText = "Let's delve into another function puzzle. Consider this equation"
        self.funcText = "The function f(x) is defined as five times x plus four."
        self.func = "f(x) = 5x + 4"
        self.qText = "Three graphs will be shown. Which one corresponds to the function?"
        self.f1 = lambda x: 5*x + 4
        self.f2 = lambda x: 5*x - 4
        self.f3 = lambda x: -5*x + 4
        self.cords = self.add_cords([-3, 3, 1], [-15, 15, 5], x_ticks=[-3, 0, 3], y_ticks=[-15, 15])

        super().construct()

class Func_2_2_P_4_a(plotLinearFunctionAnswerScene):
        
    def construct(self):

        self.funcText = "The function f(x) is defined as five times x plus four."
        self.func = "f(x) = 5x + 4"
        self.f1 = lambda x: 5*x + 4
        self.f2 = lambda x: 5*x - 4
        self.f3 = lambda x: -5*x + 4
        self.idx_correct = 0
        self.idx_selected = 0
        self.cords = self.add_cords([-6, 6, 1], [-12, 12, 2], x_ticks=[-6, 0, 6], y_ticks=[-12, 12])
        self.x = 2

        super().construct()

class Func_2_2_P_4_b(plotLinearFunctionAnswerScene):
        
    def construct(self):

        self.funcText = "The function f(x) is defined as five times x plus four."
        self.func = "f(x) = 5x + 4"
        self.f1 = lambda x: 5*x + 4
        self.f2 = lambda x: 5*x - 4
        self.f3 = lambda x: -5*x + 4
        self.idx_correct = 0
        self.idx_selected = 1
        self.cords = self.add_cords([-6, 6, 1], [-12, 12, 2], x_ticks=[-6, 0, 6], y_ticks=[-12, 12])
        self.x = 2

        super().construct()

class Func_2_2_P_4_c(plotLinearFunctionAnswerScene):
        
    def construct(self):

        self.funcText = "The function f(x) is defined as five times x plus four."
        self.func = "f(x) = 5x + 4"
        self.f1 = lambda x: 5*x + 4
        self.f2 = lambda x: 5*x - 4
        self.f3 = lambda x: -5*x + 4
        self.idx_correct = 0
        self.idx_selected = 1
        self.cords = self.add_cords([-6, 6, 1], [-12, 12, 2], x_ticks=[-6, 0, 6], y_ticks=[-12, 12])
        self.x = 2

        super().construct()



PROTOTYPES = [
    PagePrototypeVideo.from_scene(Func_2_2_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_2_2_I_1_q, Func_2_2_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_2_2_I_1_a),
    PagePrototypeVideo.from_scene(Func_2_2_I_1_b),
    PagePrototypeVideo.from_scene(Func_2_2_I_2),
    PagePrototypeVideo.from_scene(Func_2_2_P_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_2_2_P_1_q, Func_2_2_P_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_2_2_P_1_a),
    PagePrototypeVideo.from_scene(Func_2_2_P_1_b),
    PagePrototypeVideo.from_scene(Func_2_2_P_1_c),
    PagePrototypeVideo.from_scene(Func_2_2_P_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_2_2_P_2_q, Func_2_2_P_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_2_2_P_2_a),
    PagePrototypeVideo.from_scene(Func_2_2_P_2_b),
    PagePrototypeVideo.from_scene(Func_2_2_P_2_c),
    PagePrototypeVideo.from_scene(Func_2_2_P_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_2_2_P_3_q, Func_2_2_P_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_2_2_P_3_a),
    PagePrototypeVideo.from_scene(Func_2_2_P_3_b),
    PagePrototypeVideo.from_scene(Func_2_2_P_3_c),
    PagePrototypeVideo.from_scene(Func_2_2_P_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_2_2_P_4_q, Func_2_2_P_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_2_2_P_4_a),
    PagePrototypeVideo.from_scene(Func_2_2_P_4_b),
    PagePrototypeVideo.from_scene(Func_2_2_P_4_c),
]
scenes/Func/Func_2: Linear Functions/Func2_2.py
Sophia-Edu-Labs/sophia-math
# 2_3: Linear Functions: Functions and Linear Equalities

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition


#####################################
#####################################
TASK_Func_2_3_I_1_q = SophiaTaskDefinition(
    answerOptions=["$f(x)=5x+15, \,g(x)=20x$", "$f(x)=15x+15, \,g(x)=20x$","$f(x)=15x+5, \,g(x)=20x$", "$f(x)=15x+15, \,g(x)=20+x$"],
    correctAnswerIndex=2,
    questionText="Which function describes the distances you and your friend have traveled?"
)

class Func_2_3_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Functions and Linear Equations")

        bike = ImageMobject(assets_folder / "img" / "bike.jpg")
        bike = bike.scale(3.2/bike.get_width()).move_to([-5, 1, 0])

        f1 = Tex("Your Friend:", color=c1t, font_size=fs2).next_to(bike, DOWN, buff=0.6).shift(5*RIGHT)
        f2 = BulletedList("$5$km Head start", "$15$km/h speed", buff=0.2, font_size=fs2).set_color(c1t).next_to(f1, DOWN)
        y1 = Tex("You:", color=c1t, font_size=fs2).next_to(f2, DOWN)
        y2 = BulletedList("$20$km/h speed", color=c1t, font_size=fs2).set_color(c1t).next_to(y1, DOWN)
        comparison = VGroup(f1, f2, y1, y2).arrange(DOWN, center=False, aligned_edge=LEFT).shift(0.2*LEFT)
        
        # Action Sequence
        with self.voiceover(
                text="""
                Neww topic! In this chapter, we are looking at linear functions and linear equations,
                and what these two have to do with each other.
                
                And what better way to find out, what the connection is, than to look at a real world example.
                
                This is the scenario: You and your friend are both <bookmark mark="bike"/> cycling to the beach from your house.
                
                <bookmark mark="f1"/>
                Your friend has a <bookmark mark="f2"/> head start of 5 kilometers, and she is cycling <bookmark mark="f3"/> at a speed of 15 kilometers per hour.
                
                <bookmark mark="y1"/>
                You on the other hand are cycling at <bookmark mark="y2"/> a speed of 20 kilometers per hour, but you get no head start.
                
                Question Number one, and this is mainly about functions: What functions f and g describe the distance your friend and you have traveled?
                """
        ) as tracker:
            
            self.wait_until_bookmark("bike")
            self.play(bike.animate.shift(5*RIGHT))

            self.wait_until_bookmark("f1")
            self.play(Write(f1))

            self.wait_until_bookmark("f2")
            self.play(Write(f2[0]))

            self.wait_until_bookmark("f3")
            self.play(Write(f2[1]))

            self.wait_until_bookmark("y1")
            self.play(Write(y1))

            self.wait_until_bookmark("y2")
            self.play(Write(y2[0]))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_2_3_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Not quite right...")

        f1 = Tex("Your Friend:", color=c1t, font_size=fs2).next_to(title, DOWN, buff=0.6)
        f2 = BulletedList("$5$km Head start", "$15$km/h speed", buff=0.2, font_size=fs2).set_color(c1t).next_to(f1, DOWN)
        f3 = MathTex("\\downarrow", color=c1t, font_size=fs2).next_to(f2, DOWN)


        y1 = Tex("You:", color=c1t, font_size=fs2).next_to(title, DOWN)
        y2 = BulletedList("$20$km/h speed", color=c1t, font_size=fs2).set_color(c1t).next_to(y1, DOWN)
        y3 = MathTex("\\downarrow", color=c1t, font_size=fs2).next_to(y2, DOWN)

        # comparison = VGroup(f1, f2, y1, y2).arrange(aligned_edge=LEFT).shift(0.2*LEFT)

        funcFriend = MathTex("f(x)=15x","+5", color=c1t, font_size=fs2).next_to(f3, DOWN)
        funcYou = MathTex("g(x)=20x", color=c1t, font_size=fs2).next_to(y3, DOWN)
        
        # Action Sequence
        with self.voiceover(
                text="""
                Mhmmm, that's not quite right. Let's solve this together.
                
                <bookmark mark="friend"/>
                Your friend cycles at a speed of 15 kilometers per hour, and if x stands for the number of hours cycled,
                we can write her function as <bookmark mark="friendfunc1"/> f of x equals fifteen times x.
                
                And since she also has a head start of 5 kilometers, we have to <bookmark mark="friendfunc2"/> add 5 to the function.
                So the function describing the distance your friend has traveled is f of x equals fifteen times x plus five.
                
                Next, let's look at your function. <bookmark mark="you"/>
                You cycle at a speed of 20 kilometers per hour.
                
                Since you have no head start, your function is simply <bookmark mark="yourfunc"/> g of x equals twenty times x.
                """
        ) as tracker:
            
            self.wait_until_bookmark("friend")
            self.play(Write(f1), Write(f2))
            
            self.wait_until_bookmark("friendfunc1")
            self.play(Write(funcFriend[0]), Write(f3))

            self.wait_until_bookmark("friendfunc2")
            self.play(Write(funcFriend[1]))

            self.wait_until_bookmark("you")
            self.play(Unwrite(f1), Unwrite(f2), Unwrite(f3), Unwrite(funcFriend), run_time=0.5)
            self.play(Write(y1), Write(y2), run_time=1)

            self.wait_until_bookmark("yourfunc")
            self.play(Write(funcYou), Write(y3))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_2_3_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Not quite right...")

        f1 = Tex("Your Friend:", color=c1t, font_size=fs2).next_to(title, DOWN, buff=0.6)
        f2 = BulletedList("$5$km Head start", "$15$km/h speed", buff=0.2, font_size=fs2).set_color(c1t).next_to(f1, DOWN)
        f3 = MathTex("\\downarrow", color=c1t, font_size=fs2).next_to(f2, DOWN)


        y1 = Tex("You:", color=c1t, font_size=fs2).next_to(title, DOWN)
        y2 = BulletedList("$20$km/h speed", color=c1t, font_size=fs2).set_color(c1t).next_to(y1, DOWN)
        y3 = MathTex("\\downarrow", color=c1t, font_size=fs2).next_to(y2, DOWN)

        # comparison = VGroup(f1, f2, y1, y2).arrange(aligned_edge=LEFT).shift(0.2*LEFT)

        funcFriend = MathTex("f(x)=15x","+5", color=c1t, font_size=fs2).next_to(f3, DOWN)
        funcYou = MathTex("g(x)=20x", color=c1t, font_size=fs2).next_to(y3, DOWN)
        
        # Action Sequence
        with self.voiceover(
                text="""
                Mhmmm, that's not quite right. Let's solve this together.
                
                <bookmark mark="friend"/>
                Your friend cycles at a speed of 15 kilometers per hour, and if x stands for the number of hours cycled,
                we can write her function as <bookmark mark="friendfunc1"/> f of x equals fifteen times x.
                
                And since she also has a head start of 5 kilometers, we have to <bookmark mark="friendfunc2"/> add 5 to the function.
                So the function describing the distance your friend has traveled is f of x equals fifteen times x plus five.
                
                Next, let's look at your function. <bookmark mark="you"/>
                You cycle at a speed of 20 kilometers per hour.
                
                Since you have no head start, your function is simply <bookmark mark="yourfunc"/> g of x equals twenty times x.
                """
        ) as tracker:
            
            self.wait_until_bookmark("friend")
            self.play(Write(f1), Write(f2))
            
            self.wait_until_bookmark("friendfunc1")
            self.play(Write(funcFriend[0]), Write(f3))

            self.wait_until_bookmark("friendfunc2")
            self.play(Write(funcFriend[1]))

            self.wait_until_bookmark("you")
            self.play(Unwrite(f1), Unwrite(f2), Unwrite(f3), Unwrite(funcFriend), run_time=0.5)
            self.play(Write(y1), Write(y2), run_time=1)

            self.wait_until_bookmark("yourfunc")
            self.play(Write(funcYou), Write(y3))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_2_3_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Correct!")

        f1 = Tex("Your Friend:", color=c1t, font_size=fs2).next_to(title, DOWN, buff=0.6)
        f2 = BulletedList("$5$km Head start", "$15$km/h speed", buff=0.2, font_size=fs2).set_color(c1t).next_to(f1, DOWN)
        f3 = MathTex("\\downarrow", color=c1t, font_size=fs2).next_to(f2, DOWN)


        y1 = Tex("You:", color=c1t, font_size=fs2).next_to(title, DOWN)
        y2 = BulletedList("$20$km/h speed", color=c1t, font_size=fs2).set_color(c1t).next_to(y1, DOWN)
        y3 = MathTex("\\downarrow", color=c1t, font_size=fs2).next_to(y2, DOWN)

        # comparison = VGroup(f1, f2, y1, y2).arrange(aligned_edge=LEFT).shift(0.2*LEFT)

        funcFriend = MathTex("f(x)=15x","+5", color=c1t, font_size=fs2).next_to(f3, DOWN)
        funcYou = MathTex("g(x)=20x", color=c1t, font_size=fs2).next_to(y3, DOWN)
        
        # Action Sequence
        with self.voiceover(
                text="""
                That's right, good job!
                
                <bookmark mark="friend"/>
                Your friend cycles at a speed of 15 kilometers per hour, and if x stands for the number of hours cycled,
                we can write her function as <bookmark mark="friendfunc1"/> f of x equals fifteen times x.
                
                And since she has a head start of 5 kilometers, we have to <bookmark mark="friendfunc2"/> add 5 to the function.
                So the function describing the distance your friend has traveled is f of x equals fifteen times x plus five.
                
                Next, let's look at your function. <bookmark mark="you"/>
                You cycle at a speed of 20 kilometers per hour.
                
                Since you have no head start, your function is simply <bookmark mark="yourfunc"/> g of x equals twenty times x.
                """
        ) as tracker:
            
            self.wait_until_bookmark("friend")
            self.play(Write(f1), Write(f2))
            
            self.wait_until_bookmark("friendfunc1")
            self.play(Write(funcFriend[0]), Write(f3))

            self.wait_until_bookmark("friendfunc2")
            self.play(Write(funcFriend[1]))

            self.wait_until_bookmark("you")
            self.play(Unwrite(f1), Unwrite(f2), Unwrite(f3), Unwrite(funcFriend), run_time=0.5)
            self.play(Write(y1), Write(y2), run_time=1)

            self.wait_until_bookmark("yourfunc")
            self.play(Write(funcYou), Write(y3))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_2_3_I_1_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Not quite right...")

        f1 = Tex("Your Friend:", color=c1t, font_size=fs2).next_to(title, DOWN, buff=0.6)
        f2 = BulletedList("$5$km Head start", "$15$km/h speed", buff=0.2, font_size=fs2).set_color(c1t).next_to(f1, DOWN)
        f3 = MathTex("\\downarrow", color=c1t, font_size=fs2).next_to(f2, DOWN)


        y1 = Tex("You:", color=c1t, font_size=fs2).next_to(title, DOWN)
        y2 = BulletedList("$20$km/h speed", color=c1t, font_size=fs2).set_color(c1t).next_to(y1, DOWN)
        y3 = MathTex("\\downarrow", color=c1t, font_size=fs2).next_to(y2, DOWN)

        # comparison = VGroup(f1, f2, y1, y2).arrange(aligned_edge=LEFT).shift(0.2*LEFT)

        funcFriend = MathTex("f(x)=15x","+5", color=c1t, font_size=fs2).next_to(f3, DOWN)
        funcYou = MathTex("g(x)=20x", color=c1t, font_size=fs2).next_to(y3, DOWN)
        
        # Action Sequence
        with self.voiceover(
                text="""
                Mhmmm, that's not quite right. Let's solve this together.
                
                <bookmark mark="friend"/>
                Your friend cycles at a speed of 15 kilometers per hour, and if x stands for the number of hours cycled,
                we can write her function as <bookmark mark="friendfunc1"/> f of x equals fifteen times x.
                
                And since she also has a head start of 5 kilometers, we have to <bookmark mark="friendfunc2"/> add 5 to the function.
                So the function describing the distance your friend has traveled is f of x equals fifteen times x plus five.
                
                Next, let's look at your function. <bookmark mark="you"/>
                You cycle at a speed of 20 kilometers per hour.
                
                Since you have no head start, your function is simply <bookmark mark="yourfunc"/> g of x equals twenty times x.
                """
        ) as tracker:
            
            self.wait_until_bookmark("friend")
            self.play(Write(f1), Write(f2))
            
            self.wait_until_bookmark("friendfunc1")
            self.play(Write(funcFriend[0]), Write(f3))

            self.wait_until_bookmark("friendfunc2")
            self.play(Write(funcFriend[1]))

            self.wait_until_bookmark("you")
            self.play(Unwrite(f1), Unwrite(f2), Unwrite(f3), Unwrite(funcFriend), run_time=0.5)
            self.play(Write(y1), Write(y2), run_time=1)

            self.wait_until_bookmark("yourfunc")
            self.play(Write(funcYou), Write(y3))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
class Func_2_3_I_2(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("When will you meet?")

        bikeMeet = ImageMobject(assets_folder / "img" / "cyclistsmeet.png")
        bikeRace = ImageMobject(assets_folder / "img" / "cyclistsrace.png")
        bikeMeet = bikeMeet.scale(3.2/bikeMeet.get_width()).move_to([-5, 0.5, 0])
        bikeRace = bikeRace.scale(3.2/bikeRace.get_width()).move_to([5, -1.5, 0])
        # comparison = VGroup(f1, f2, y1, y2).arrange(aligned_edge=LEFT).shift(0.2*LEFT)

        # funcFriend = MathTex("f(x)=15x","+5", color=c1t, font_size=fs2).next_to(f3, DOWN)
        # funcYou = MathTex("g(x)=20x", color=c1t, font_size=fs2).next_to(y3, DOWN)
        
        Q1 = Text("→ At what point in time", color=RED, font_size=fs3, weight=BOLD).next_to(bikeMeet, DOWN, buff=0.6).shift(RIGHT*5)
        Q2 = Text("will you have traveled", color=RED, font_size=fs3, weight=BOLD).next_to(Q1, DOWN, buff=0.1)
        Q3 = Text("the same distance?", color=RED, font_size=fs3, weight=BOLD).next_to(Q2, DOWN, buff=0.1)        
        Q = VGroup(Q1, Q2, Q3).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(LEFT*0.1)
        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so why are we doing this? And what does it have to do with equations?
                
                Think about this: <bookmark mark="race"/> Since you're both cycling in the same direction, but your friend had a head start,
                you two will meet at some point - because you are cycling faster than her.
                
                But when <bookmark mark="meet"/> will you two meet?
                
                Clearly, you'll meet at the point in time when both of you have traveled the exact same distance.
                <bookmark mark="Q"/>
                
                Think about how we can find that point in time using the two functions we just wrote.
                """
        ) as tracker:
            
            self.wait_until_bookmark("race")
            self.play(bikeRace.animate.shift(5*LEFT))
            
            self.wait_until_bookmark("meet")
            self.play(bikeMeet.animate.shift(5*RIGHT), bikeRace.animate.shift(5*LEFT))

            self.wait_until_bookmark("Q")
            self.play(Write(Q), run_time=0.75)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
class Func_2_3_I_3(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("When will you meet?")

        # comparison = VGroup(f1, f2, y1, y2).arrange(aligned_edge=LEFT).shift(0.2*LEFT)

        funcFriend = MathTex("f(x)=15x","+5", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1)
        textFriend1 = Text("→Describes the distance", color=RED, font_size=fs3, slant=ITALIC).next_to(funcFriend, DOWN, buff=0.2)
        textFriend2 = Text("your friend has traveled", color=RED, font_size=fs3, slant=ITALIC).next_to(textFriend1, DOWN, buff=0.1)
        textFriend = VGroup(textFriend1, textFriend2).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(RIGHT*0.2)

        funcYou = MathTex("g(x)=20x", color=c1t, font_size=fs2).next_to(textFriend, DOWN)
        funcYou = funcYou.shift(LEFT*(funcYou.get_left()[0]-funcFriend.get_left()[0]))
        textYou1 = Text("→Describes the distance", color=RED, font_size=fs3, slant=ITALIC).next_to(funcYou, DOWN, buff=0.2)
        textYou2 = Text("you have traveled", color=RED, font_size=fs3, slant=ITALIC).next_to(textYou1, DOWN, buff=0.1)
        textYou = VGroup(textYou1, textYou2).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(RIGHT*0.2)
        textYou = textYou.shift(LEFT*(textYou.get_left()[0]-textFriend.get_left()[0]))

        funcBoth = MathTex("f(x)=g(x)", color=c1t, font_size=fs2).next_to(textYou, DOWN, buff=1)
        funcBoth = funcBoth.shift(LEFT*(funcBoth.get_left()[0]-funcFriend.get_left()[0]))
        textBoth1 = Text("→Describes the time", color=RED, font_size=fs3, slant=ITALIC).next_to(funcBoth, DOWN, buff=0.2)
        textBoth2 = Text("when you meet", color=RED, font_size=fs3, slant=ITALIC).next_to(textBoth1, DOWN, buff=0.1)
        textBoth = VGroup(textBoth1, textBoth2).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(RIGHT*0.2)
        textBoth = textBoth.shift(LEFT*(textBoth.get_left()[0]-textFriend.get_left()[0]))

        friendBikeWave = ImageMobject(assets_folder / "img" / "friendbikewave.png")
        youBikeWave = ImageMobject(assets_folder / "img" / "youbikewave.png")
        friendBikeWave = friendBikeWave.scale(3.2/friendBikeWave.get_width()).next_to(textFriend, DOWN, buff=0.2).shift(LEFT*5)
        youBikeWave = youBikeWave.scale(3.2/youBikeWave.get_width()).next_to(textYou, DOWN, buff=0.2).shift(LEFT*5)

        # Action Sequence
        with self.voiceover(
                text="""
                Let's think back to what we already know.
                
                The function <bookmark mark="f"/> f of x describes the distance your friend has traveled at time x.
                
                The function <bookmark mark="g"/> g of x on the other hand describes the distance YOU have traveled
                at time x.
                
                <bookmark mark="youLeave"/>
                Since you and your friend meet, when you have traveled the same distance, we can say that
                <bookmark mark="both"/> you meet when f of x is equal to g of x.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            self.play(Write(funcFriend), run_time=0.5)
            self.play(Write(textFriend), friendBikeWave.animate(run_time=1.5).shift(RIGHT*5), run_time=0.5)

            self.wait_until_bookmark("g")
            textFriend.set_color(c3t)
            self.play(friendBikeWave.animate(run_time=0.3).shift(RIGHT*5), Write(funcYou), run_time=0.5)
            self.play(Write(textYou), youBikeWave.animate(run_time=1.5).shift(RIGHT*5), run_time=0.5)

            self.wait_until_bookmark("youLeave")
            self.play(youBikeWave.animate.shift(RIGHT*5))

            self.wait_until_bookmark("both")
            textYou.set_color(c3t)
            self.play(Write(funcBoth), run_time=0.5)
            self.play(Write(textBoth), run_time=0.5)


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
class Func_2_3_I_4(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("When will you meet?")

        # comparison = VGroup(f1, f2, y1, y2).arrange(aligned_edge=LEFT).shift(0.2*LEFT)

        funcFriend = MathTex("f(x)=15x","+5", color=c1t, font_size=fs1).next_to(title, DOWN, buff=0.8)
        funcYou = MathTex("g(x)=20x", color=c1t, font_size=fs1).next_to(funcFriend, DOWN, buff=0.2)
        funcYou = funcYou.shift(LEFT*(funcYou.get_left()[0]-funcFriend.get_left()[0]))

        upShiftBoth = 1.2

        funcBoth = MathTex("f(x)=g(x)", color=c1t, font_size=fs1).next_to(funcYou, DOWN, buff=0.8)
        funcBoth.set_x(0)
        fBA1 = MathTex("\\downarrow", color=c1t, font_size=fs1).next_to(funcBoth, DOWN, buff=0.2).shift(upShiftBoth*UP)
        fB1 = MathTex("15x+5=20x", color=c1t, font_size=fs1).next_to(fBA1, DOWN, buff=0.2)
        fbA2 = MathTex("\\downarrow", color=c1t, font_size=fs1).next_to(fB1, DOWN, buff=0.2)
        fB2 = MathTex("5=5x", color=c1t, font_size=fs1).next_to(fbA2, DOWN, buff=0.2)
        fbA3 = MathTex("\\downarrow", color=c1t, font_size=fs1).next_to(fB2, DOWN, buff=0.2)
        fB3 = MathTex("x=1", color=RED, font_size=fs1).next_to(fbA3, DOWN, buff=0.2)


        # Action Sequence
        with self.voiceover(
                text="""
                Ok, now we know how to find the time when you meet your friend: We just compute
                the value of x where <bookmark mark="both"/> f of x is equal to g of x, because f describes the distance
                your friend has traveled and g describes the distance YOU have traveled.
                
                Remember: f of x is <bookmark mark="f"/> equal to fifteen times x plus five, -
                and g of x is <bookmark mark="g"/> equal to twenty times x.
                
                Now we want to find the value of x where <bookmark mark="calculate"/>
                f of x is equal to g of x.
                
                The first step <bookmark mark="step1a"/> is to <bookmark mark="step1b"/> plug in the terms of f and g.
                We get the equation 15x plus 5 is equal to 20x.
                
                Next, <bookmark mark="step2a"/> we subtract 15x from both sides, which leaves
                us with <bookmark mark="step2b"/> the equation 5 equals 5x.
                
                Finally, <bookmark mark="step3a"/> we divide both sides by 5, which results in
                the final solution, <bookmark mark="step3b"/> that x is equal to 1.
                
                We can now say that you and your friend meet after one hour.
                
                Puh, that was intense. Let's take a deeeeeep breath.
                """
        ) as tracker:
            
            self.wait_until_bookmark("both")
            self.play(Write(funcBoth), run_time=0.5)
            
            self.wait_until_bookmark("f")
            self.play(Write(funcFriend), run_time=0.5)

            self.wait_until_bookmark("g")
            self.play(Write(funcYou), run_time=0.5)

            self.wait_until_bookmark("calculate")
            self.play(funcBoth.animate.shift(UP*upShiftBoth), Unwrite(funcFriend), Unwrite(funcYou), run_time=0.5)

            self.wait_until_bookmark("step1a")
            self.play(Write(fBA1), run_time=0.5)

            self.wait_until_bookmark("step1b")
            self.play(Write(fB1), run_time=0.5)

            self.wait_until_bookmark("step2a")
            self.play(Write(fbA2), run_time=0.5)

            self.wait_until_bookmark("step2b")
            self.play(Write(fB2), run_time=0.5)

            self.wait_until_bookmark("step3a")
            self.play(Write(fbA3), run_time=0.5)

            self.wait_until_bookmark("step3b")
            self.play(Write(fB3), run_time=0.5)

            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)



#####################################
#####################################
class Func_2_3_I_5(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):

        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Functions & Equations")

        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(3.2/qmark.get_width()).move_to([-5, 1, 0])

        function = Text("Functions", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1).shift(LEFT*0.4)
        tf1 = Text("→ Used to describe", color=RED, font_size=fs3, slant=ITALIC).next_to(function, DOWN, buff=0.2)
        tf2 = Text("real world scenarios", color=RED, font_size=fs3, slant=ITALIC).next_to(tf1, DOWN, buff=0.1)
        tf = VGroup(tf1, tf2).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(RIGHT*0.4)

        equation = Text("Equations", color=c1t, font_size=fs2).next_to(tf, DOWN)
        equation = equation.shift(LEFT*(equation.get_left()[0]-function.get_left()[0]))
        te1 = Text("→ Used to find specific", color=RED, font_size=fs3, slant=ITALIC).next_to(equation, DOWN, buff=0.2)
        te2 = Text("value of a variable", color=RED, font_size=fs3, slant=ITALIC).next_to(te1, DOWN, buff=0.1)
        te = VGroup(te1, te2).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(RIGHT*0.2)
        te = te.shift(LEFT*(te.get_left()[0]-tf.get_left()[0]))

        handshake = ImageMobject(assets_folder / "img" / "handshake.png")
        handshake = handshake.scale(1.2/handshake.get_width()).move_to([-5, 1, 0])
        fLeft = Text("Functions", color=c1t, font_size=fs3).next_to(handshake, LEFT, buff=0.1)
        eRight = Text("Equations", color=c1t, font_size=fs3).next_to(handshake, RIGHT, buff=0.1)
        shakeGroup = Group(handshake, fLeft, eRight).scale(0.8).next_to(te, DOWN, buff=0.5)
        ts1 = Text("→ Combine the two to", color=RED, font_size=fs3, slant=ITALIC).next_to(shakeGroup, DOWN, buff=0.2)
        ts2 = Text("compare real world", color=RED, font_size=fs3, slant=ITALIC).next_to(ts1, DOWN, buff=0.1)
        ts3 = Text("scenarios", color=RED, font_size=fs3, slant=ITALIC).next_to(ts2, DOWN, buff=0.1)
        ts = VGroup(ts1, ts2, ts3).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(RIGHT*0.2)
        ts = ts.shift(LEFT*(ts.get_left()[0]-te.get_left()[0]))
        shakeGroup.shift(3*RIGHT)

        # Action Sequence
        with self.voiceover(
                text="""
                So, let's recap <bookmark mark="qmark"/> what we just did, and what it has to do with functions and equations.
                
                <bookmark mark="functions"/> Functions are often used to describe real world scenarios. For example, a function can describe
                the distance you have traveled after some time.
                
                <bookmark mark="equation"/>
                Equations are used to find the value of a variable. For example, an equation can be used to
                determine the point in time at which you have traveled twenty kilometers.
                
                Now, we can <bookmark mark="handshake"/> put these two concepts together to determine at what point in time
                two real world scenarios, that are both described by functions, are equal.
                
                In the example we just looked at, we had two functions, describing the distance you and your friend
                have traveled at any point in time. We then used an equation to determine at what point in time
                you and your friend have traveled the same distance.
                
                We do this, by simply setting the terms of the two functions equal to each other,
                and then solving the equation for the variable, in our case for x.
                """
        ) as tracker:


            self.wait_until_bookmark("qmark")
            self.play(qmark.animate.shift(5*RIGHT), run_time=1)

            self.wait_until_bookmark("functions")
            self.play(qmark.animate.shift(5*RIGHT), run_time=0.4)
            self.play(Write(function), Write(tf))

            self.wait_until_bookmark("equation")
            self.play(Write(equation), Write(te))

            self.wait_until_bookmark("handshake")
            self.play(shakeGroup.animate.shift(3.2*LEFT))
            self.play(Write(ts))

            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_2_3_I_6_q = SophiaTaskDefinition(
    answerOptions=["(1,20)", "(0,5)", "(20,20)", "(1,1)"],
    correctAnswerIndex=0,
    questionText="Where do the functions intersect?"
)

class Func_2_3_I_6_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):

        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Graphical solution")

        cords = self.add_cords([0, 2, 1], [0, 40, 5], x_ticks=[1,2], y_ticks=[10,20,30,40])
        plane = cords[0]

        note = Notepad(texts=["Problem can also be solved graphically", "Consider the plots of $g$ and $f$","Where do the two functions intersect?"])
        self.add(note)

        funcTexf = MathTex("f(x) = 15x + 5", color=c1t, font_size=fs1).next_to(plane, DOWN, buff=0.5)
        funcTexg = MathTex("g(x) = 20x", color=c2t, font_size=fs1).move_to(funcTexf)
        funcTexg = funcTexg.shift(LEFT*(funcTexg.get_left()[0]-funcTexf.get_left()[0]))
        f = lambda x: 15*x + 5
        g = lambda x: 20*x
        plot_f = plane.plot(f, color=BLUE)
        plot_g = plane.plot(g, color=GREEN)

        intersection = plane.c2p(1,20)
        intersectionDot = Dot(intersection, color=RED)

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])

        with self.voiceover(
                text="""
                There is another way we can solve these kinds of problems: <bookmark mark="note1"/> Visually, by using the
                <bookmark mark="cords"/> graph of the functions.
                
                Remember, we want to find the values of x for which two functions are equal.
                
                We can do this by looking at the graph of the two functions, and finding the point at which
                the two functions have the same y-value, so the point at which the two functions meet.
                
                Let's return to our bike example, for the last time, i promise!!!
                
                Remember, the function describing the distance your friend has traveled is given by
                <bookmark mark="f"/> f of x equals fifteen times x plus five,
                and the function describing the distance you have traveled is given by
                <bookmark mark="g"/> g of x equals twenty times x.
                
                Now, let's <bookmark mark="plot"/> plot the two functions. <bookmark mark="note2"/> Where do the two functions intersect?
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("cords")
            self.play(Write(cords))
            self.add(cursor)

            self.wait_until_bookmark("f")
            self.play(Write(funcTexf))

            self.wait_until_bookmark("g")
            self.play(ReplacementTransform(funcTexf, funcTexg))

            self.wait_until_bookmark("plot")
            note.change_colors([0,1])
            self.play(Write(plot_f), Write(plot_g))

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_2_3_I_6_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):

        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Graphical solution")

        cords = self.add_cords([0, 2, 1], [0, 40, 5], x_ticks=[1,2], y_ticks=[10,20,30,40])
        plane = cords[0]

        note = Notepad(texts=[["Follow one of the graphs", "until both intersect"], "Intersection at $(1,20)$","$\\rightarrow$ You meet after $x=1$ hour"])
        self.add(note)

        funcTexf = MathTex("f(x) = 15x + 5", color=c1t, font_size=fs1).next_to(plane, DOWN, buff=0.5)
        funcTexg = MathTex("g(x) = 20x", color=c2t, font_size=fs1).move_to(funcTexf)
        funcTexg = funcTexg.shift(LEFT*(funcTexg.get_left()[0]-funcTexf.get_left()[0]))
        f = lambda x: 15*x + 5
        g = lambda x: 20*x
        plot_f = plane.plot(f, color=BLUE)
        plot_g = plane.plot(g, color=GREEN)

        ix, iy, _ = plane.c2p(1,20)
        # intersectionDot = Dot(intersection, color=RED)

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])

        self.add(cursor, cords, plot_f, plot_g)

        xdown, ydown, _ = plane.c2p(1,0)
        xleft, yleft, _ = plane.c2p(0,20)

        dashed1 = DashedLine([xleft, iy, 0], [ix, iy, 0], color=c2t)
        dashed2 = DashedLine([ix, ydown, 0], [ix, iy, 0], color=c2t)

        with self.voiceover(
                text="""
                Yes! That's correct, very good!
                
                If we <bookmark mark="note1"/> follow one of the graphs <bookmark mark="intersectLoc"/> until it intersects the other graph, we can see that
                the graphs of the two functions intersect at the point 1,20.
                
                <bookmark mark="cursorBack"/>
                The interpretation of that - as we already saw in a previous video - <bookmark mark="note2"/> is that
                you and your friends meet after x equals one hour. The y value - twenty - means that by that time
                you have traveled twenty kilometers, and your friend has traveled twenty kilometers as well.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("intersectLoc")
            cursor.blinking=False
            note.change_colors([0,1])
            self.play(CursorMoveTo(cursor, ix, iy))
            interCirc = Circle(radius=0.2, color=RED).move_to([ix, iy, 0])
            self.play(Write(interCirc), Write(dashed1), Write(dashed2))

            self.wait_until_bookmark("cursorBack")
            self.play(CursorMoveTo(cursor, xo, yo))
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_2_3_I_6_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):

        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Graphical solution")

        cords = self.add_cords([0, 2, 1], [0, 40, 5], x_ticks=[1,2], y_ticks=[10,20,30,40])
        plane = cords[0]

        note = Notepad(texts=[["Follow one of the graphs", "until both intersect"], "Intersection at $(1,20)$","$\\rightarrow$ You meet after $x=1$ hour"])
        self.add(note)

        funcTexf = MathTex("f(x) = 15x + 5", color=c1t, font_size=fs1).next_to(plane, DOWN, buff=0.5)
        funcTexg = MathTex("g(x) = 20x", color=c2t, font_size=fs1).move_to(funcTexf)
        funcTexg = funcTexg.shift(LEFT*(funcTexg.get_left()[0]-funcTexf.get_left()[0]))
        f = lambda x: 15*x + 5
        g = lambda x: 20*x
        plot_f = plane.plot(f, color=BLUE)
        plot_g = plane.plot(g, color=GREEN)

        ix, iy, _ = plane.c2p(1,20)
        # intersectionDot = Dot(intersection, color=RED)

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])

        self.add(cursor, cords, plot_f, plot_g)

        xdown, ydown, _ = plane.c2p(1,0)
        xleft, yleft, _ = plane.c2p(0,20)

        dashed1 = DashedLine([xleft, iy, 0], [ix, iy, 0], color=c2t)
        dashed2 = DashedLine([ix, ydown, 0], [ix, iy, 0], color=c2t)

        with self.voiceover(
                text="""
                Mhm, that's not quite right. I'll show you the correct solution.
                
                If we <bookmark mark="note1"/> follow one of the graphs <bookmark mark="intersectLoc"/> until it intersects the other graph, we can see that
                the graphs of the two functions intersect at the point 1,20.
                
                <bookmark mark="cursorBack"/>
                The interpretation of that - as we already saw in a previous video - <bookmark mark="note2"/> is that
                you and your friends meet after x equals one hour. The y value - twenty - means that by that time
                you have traveled twenty kilometers, and your friend has traveled twenty kilometers as well.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("intersectLoc")
            cursor.blinking=False
            note.change_colors([0,1])
            self.play(CursorMoveTo(cursor, ix, iy))
            interCirc = Circle(radius=0.2, color=RED).move_to([ix, iy, 0])
            self.play(Write(interCirc), Write(dashed1), Write(dashed2))

            self.wait_until_bookmark("cursorBack")
            self.play(CursorMoveTo(cursor, xo, yo))
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)



class Func_2_3_I_6_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):

        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Graphical solution")

        cords = self.add_cords([0, 2, 1], [0, 40, 5], x_ticks=[1,2], y_ticks=[10,20,30,40])
        plane = cords[0]

        note = Notepad(texts=[["Follow one of the graphs", "until both intersect"], "Intersection at $(1,20)$","$\\rightarrow$ You meet after $x=1$ hour"])
        self.add(note)

        funcTexf = MathTex("f(x) = 15x + 5", color=c1t, font_size=fs1).next_to(plane, DOWN, buff=0.5)
        funcTexg = MathTex("g(x) = 20x", color=c2t, font_size=fs1).move_to(funcTexf)
        funcTexg = funcTexg.shift(LEFT*(funcTexg.get_left()[0]-funcTexf.get_left()[0]))
        f = lambda x: 15*x + 5
        g = lambda x: 20*x
        plot_f = plane.plot(f, color=BLUE)
        plot_g = plane.plot(g, color=GREEN)

        ix, iy, _ = plane.c2p(1,20)
        # intersectionDot = Dot(intersection, color=RED)

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])

        self.add(cursor, cords, plot_f, plot_g)

        xdown, ydown, _ = plane.c2p(1,0)
        xleft, yleft, _ = plane.c2p(0,20)

        dashed1 = DashedLine([xleft, iy, 0], [ix, iy, 0], color=c2t)
        dashed2 = DashedLine([ix, ydown, 0], [ix, iy, 0], color=c2t)

        with self.voiceover(
                text="""
                Mhm, that's not quite right. I'll show you the correct solution.
                
                If we <bookmark mark="note1"/> follow one of the graphs <bookmark mark="intersectLoc"/> until it intersects the other graph, we can see that
                the graphs of the two functions intersect at the point 1,20.
                
                <bookmark mark="cursorBack"/>
                The interpretation of that - as we already saw in a previous video - <bookmark mark="note2"/> is that
                you and your friends meet after x equals one hour. The y value - twenty - means that by that time
                you have traveled twenty kilometers, and your friend has traveled twenty kilometers as well.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("intersectLoc")
            cursor.blinking=False
            note.change_colors([0,1])
            self.play(CursorMoveTo(cursor, ix, iy))
            interCirc = Circle(radius=0.2, color=RED).move_to([ix, iy, 0])
            self.play(Write(interCirc), Write(dashed1), Write(dashed2))

            self.wait_until_bookmark("cursorBack")
            self.play(CursorMoveTo(cursor, xo, yo))
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_2_3_I_6_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):

        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Graphical solution")

        cords = self.add_cords([0, 2, 1], [0, 40, 5], x_ticks=[1,2], y_ticks=[10,20,30,40])
        plane = cords[0]

        note = Notepad(texts=[["Follow one of the graphs", "until both intersect"], "Intersection at $(1,20)$","$\\rightarrow$ You meet after $x=1$ hour"])
        self.add(note)

        funcTexf = MathTex("f(x) = 15x + 5", color=c1t, font_size=fs1).next_to(plane, DOWN, buff=0.5)
        funcTexg = MathTex("g(x) = 20x", color=c2t, font_size=fs1).move_to(funcTexf)
        funcTexg = funcTexg.shift(LEFT*(funcTexg.get_left()[0]-funcTexf.get_left()[0]))
        f = lambda x: 15*x + 5
        g = lambda x: 20*x
        plot_f = plane.plot(f, color=BLUE)
        plot_g = plane.plot(g, color=GREEN)

        ix, iy, _ = plane.c2p(1,20)
        # intersectionDot = Dot(intersection, color=RED)

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])

        self.add(cursor, cords, plot_f, plot_g)

        xdown, ydown, _ = plane.c2p(1,0)
        xleft, yleft, _ = plane.c2p(0,20)

        dashed1 = DashedLine([xleft, iy, 0], [ix, iy, 0], color=c2t)
        dashed2 = DashedLine([ix, ydown, 0], [ix, iy, 0], color=c2t)

        with self.voiceover(
                text="""
                Mhm, that's not quite right. I'll show you the correct solution.
                
                If we <bookmark mark="note1"/> follow one of the graphs <bookmark mark="intersectLoc"/> until it intersects the other graph, we can see that
                the graphs of the two functions intersect at the point 1,20.
                
                <bookmark mark="cursorBack"/>
                The interpretation of that - as we already saw in a previous video - <bookmark mark="note2"/> is that
                you and your friends meet after x equals one hour. The y value - twenty - means that by that time
                you have traveled twenty kilometers, and your friend has traveled twenty kilometers as well.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("intersectLoc")
            cursor.blinking=False
            note.change_colors([0,1])
            self.play(CursorMoveTo(cursor, ix, iy))
            interCirc = Circle(radius=0.2, color=RED).move_to([ix, iy, 0])
            self.play(Write(interCirc), Write(dashed1), Write(dashed2))

            self.wait_until_bookmark("cursorBack")
            self.play(CursorMoveTo(cursor, xo, yo))
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
######### Practice Part #############
#####################################
#####################################

class linearFunctionEqualityQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):

        super().construct()
        self.add_mathgrid()

        title = self.add_title("Linear Functions & Equalities")

        fText = f"f of x equals {get_num(self.fParams[0])} times x {get_num(self.fParams[1], negation='minus', pos='plus')}"
        gText = f"g of x equals {get_num(self.gParams[0])} times x {get_num(self.gParams[1], negation='minus', pos='plus')}"
        fTex = f"f(x) = {str(self.fParams[0])}x {get_texNum(self.fParams[1])}"
        gTex = f"g(x) = {str(self.gParams[0])}x {get_texNum(self.gParams[1])}"

        f = MathTex(fTex, color=c1t, font_size=fs1).next_to(title, DOWN, buff=1.5)
        g = MathTex(gTex, color=c2t, font_size=fs1).next_to(f, DOWN, buff=0.2)
        g = g.shift(LEFT*(g.get_left()[0]-f.get_left()[0]))
        handshake = ImageMobject(assets_folder / "img" / "handshake.png")
        handshake = handshake.scale(1.2/handshake.get_width()).move_to([-5, 1, 0])
        fLeft = MathTex("f(x)", color=c1t, font_size=fs1).next_to(handshake, LEFT, buff=0.1)
        gRight = MathTex("g(x)", color=c1t, font_size=fs1).next_to(handshake, RIGHT, buff=0.1)
        equal = MathTex("=", color=c1t, font_size=fs1).next_to(handshake, DOWN, buff=0.1)
        shakeGroup = Group(handshake, fLeft, gRight, equal).scale(0.8).next_to(g, DOWN, buff=1.5).shift(3*RIGHT)

        with self.voiceover(
                text=f"""
                Consider the following two linear functions:
                <bookmark mark="f"/>
                {fText}.
                <bookmark mark="g"/>
                {gText}.
                
                Where do the two functions intersect?
                That is, <bookmark mark="handshake"/> where does f equal g?
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            self.play(Write(f))

            self.wait_until_bookmark("g")
            self.play(Write(g))

            self.wait_until_bookmark("handshake")
            if self.handShake:
                self.play(shakeGroup.animate.shift(LEFT*3))

            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class linearFunctionEqualityAnswerScene(SophiaCursorScene, metaclass=ABCMeta):


    # Main method for constructing the animation
    @abstractmethod
    def construct(self):

        super().construct()
        self.add_mathgrid()

        title = self.add_title("Linear Functions & Equalities")

        upshift = 2

        op1 = ["add", "to"] if self.fParams[1] < 0 else ["subtract", "from"]
        op2 = ["add", "to"] if self.gParams[0] < 0 else ["subtract", "from"]
        plane = self.cords[0]

        fText = f"f of x is equal to {get_num(self.fParams[0])} x {get_num(self.fParams[1], negation='minus', pos='plus')}"
        gText = f"g of x is equal to {get_num(self.gParams[0])} x {get_num(self.gParams[1], negation='minus', pos='plus')}"
        fEqGText = f"{get_num(self.fParams[0])} x {get_num(self.fParams[1], negation='minus', pos='plus')} equals {get_num(self.gParams[0])} x {get_num(self.gParams[1], negation='minus', pos='plus')}"
        fTex = f"f(x) = {str(self.fParams[0])}x {get_texNum(self.fParams[1])}"
        gTex = f"g(x) = {str(self.gParams[0])}x {get_texNum(self.gParams[1])}"
        fEqGTex = f"{str(self.fParams[0])}x {get_texNum(self.fParams[1])}={str(self.gParams[0])}x {get_texNum(self.gParams[1])}"
        f = MathTex(fTex, color=c1t, font_size=fs1).next_to(title, DOWN, buff=1.5)
        g = MathTex(gTex, color=c2t, font_size=fs1).next_to(f, DOWN, buff=0.2)
        fEqG = MathTex("f(x)=g(x)", color=c1t, font_size=fs2).next_to(g, DOWN, buff=0.8)
        downArrow = MathTex("\\downarrow", color=c1t, font_size=fs1).next_to(fEqG, DOWN, buff=0.2)
        fEqGNums = MathTex(fEqGTex, color=c2t, font_size=fs2).next_to(downArrow, DOWN, buff=0.2)
        group1 = Group(fEqG, downArrow, fEqGNums)
        finalG = Group(fEqG, downArrow, fEqGNums)
        prev = Circle(stroke_width=0, fill_opacity=0).move_to(fEqGNums)
        prev = prev.shift(UP*(fEqGNums.get_bottom()[1]-prev.get_bottom()[1])).shift(upshift*UP)

        downArrow2 = MathTex("\\downarrow", color=c1t, font_size=fs1).next_to(prev, DOWN, buff=0.2)
        eqATex = f"{str(self.fParams[0])}x ={str(self.gParams[0])}x {get_texNum(self.gParams[1]-self.fParams[1])}"
        eqAText = f"{get_num(self.fParams[0])} x equals {get_num(self.gParams[0])} x {get_num(self.gParams[1]-self.fParams[1], negation='minus', pos='plus')}"
        eqA = MathTex(eqATex, color=c2t, font_size=fs2).next_to(downArrow2, DOWN, buff=0.2)
        stepA="""<bookmark mark="shiftUp"/><bookmark mark="add"/>"""
        if abs(self.fParams[1])!=0:
            stepA = f"""Next, <bookmark mark="shiftUp"/> we {op1[0]} <bookmark mark="add"/> {abs(self.fParams[1])} {op1[1]} both sides, - and obtain {eqAText}."""
            prev = eqA
            finalG.add(downArrow2, eqA)

        downArrow3 = MathTex("\\downarrow", color=c1t, font_size=fs1).next_to(prev, DOWN, buff=0.2)
        eqBTex = f"{str(self.fParams[0]-self.gParams[0])}x ={self.gParams[1]-self.fParams[1]}"
        eqBText = f"{get_num(self.fParams[0]-self.gParams[0])} x equals {get_num(self.gParams[1]-self.fParams[1], negation='negative')}"
        eqB = MathTex(eqBTex, color=c2t, font_size=fs2).next_to(downArrow3, DOWN, buff=0.2)
        stepB = """<bookmark mark="addx"/>"""
        if abs(self.gParams[0])!=0:
            stepB = f"""Then, we {op2[0]} <bookmark mark="addx"/> {abs(self.gParams[0])} x {op2[1]} both sides, - and obtain {eqBText}."""
            prev = eqB
            finalG.add(downArrow3, eqB)
        
        downArrow4 = MathTex("\\downarrow", color=c1t, font_size=fs1).next_to(prev, DOWN, buff=0.2)
        eqCTex = f"x ={format((self.gParams[1]-self.fParams[1])/(self.fParams[0]-self.gParams[0]), '.2g')}"
        eqCText = f"x equals {get_num((self.gParams[1]-self.fParams[1])/(self.fParams[0]-self.gParams[0]))}"
        eqC = MathTex(eqCTex, color=c2t, font_size=fs2).next_to(downArrow4, DOWN, buff=0.2)
        stepC = """<bookmark mark="final"/>"""
        if (self.fParams[0]-self.gParams[0])!=1:
            stepC = f"""Finally, we divide both sides by {self.fParams[0]-self.gParams[0]} to get <bookmark mark="final"/> {eqCText}."""
            finalG.add(downArrow4, eqC)


        g = g.shift(LEFT*(g.get_left()[0]-f.get_left()[0]))
        handshake = ImageMobject(assets_folder / "img" / "handshake.png")
        handshake = handshake.scale(1.2/handshake.get_width()).move_to([-5, 1, 0])
        fLeft = MathTex("f(x)", color=c1t, font_size=fs1).next_to(handshake, LEFT, buff=0.1)
        gRight = MathTex("g(x)", color=c1t, font_size=fs1).next_to(handshake, RIGHT, buff=0.1)
        equal = MathTex("=", color=c1t, font_size=fs1).next_to(handshake, DOWN, buff=0.1)
        shakeGroup = Group(handshake, fLeft, gRight, equal).scale(0.8).next_to(g, DOWN, buff=1.5).shift(3*RIGHT)

        func_f = lambda x: self.fParams[0]*x+self.fParams[1]
        func_g = lambda x: self.gParams[0]*x+self.gParams[1]
        fGraph = plane.plot(func_f, color=BLUE)
        gGraph = plane.plot(func_g, color=GREEN)

        x_sol = (self.gParams[1]-self.fParams[1])/(self.fParams[0]-self.gParams[0])
        x,y,_ = plane.c2p(x_sol, func_f(x_sol))
        circ = Circle(radius=0.1, color=RED).move_to([x,y,0])

        with self.voiceover(
                text=f"""
                {self.tfIntro}
                Remember: <bookmark mark="f"/>
                {fText} and <bookmark mark="g"/>
                {gText}.
                
                So now, the first thing we do is set <bookmark mark="fEqG"/> f of x equal to g of x.
                
                This gives us <bookmark mark="fEqGNums"/> {fEqGText}.
                
                {stepA}
                
                {stepB}
                
                {stepC}.
                
                We can also verify this, by <bookmark mark="cords"/> plotting the graph of <bookmark mark="plotF"/> f and the graph  <bookmark mark="plotG"/> of g.
                
                Looking at the two graphs, we can <bookmark mark="confirm"/> confirm that the two graphs intersect at the point x equals {get_num(x_sol)}. 
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            self.play(Write(f))

            self.wait_until_bookmark("g")
            self.play(Write(g))
            
            self.wait_until_bookmark("fEqG")
            self.play(Write(fEqG))

            self.wait_until_bookmark("fEqGNums")
            self.play(Write(fEqGNums), Write(downArrow))

            self.wait_until_bookmark("shiftUp")
            if abs(self.fParams[1])!=0:
                self.play(Unwrite(f), Unwrite(g), run_time=0.5)
                self.play(group1.animate.shift(UP*upshift))

            self.wait_until_bookmark("add")
            if abs(self.fParams[1])!=0:
                self.play(Write(downArrow2), Write(eqA))

            self.wait_until_bookmark("addx")
            if abs(self.gParams[0])!=0:
                self.play(Write(downArrow3), Write(eqB))

            self.wait_until_bookmark("final")
            if (self.fParams[0]-self.gParams[0])!=1:
                self.play(Write(downArrow4), Write(eqC))

            self.wait_until_bookmark("cords")
            self.play(finalG.animate(run_time=0.5).shift(RIGHT*5), Write(self.cords))

            self.wait_until_bookmark("plotF")
            self.play(Write(fGraph))

            self.wait_until_bookmark("plotG")
            self.play(Write(gGraph))

            self.wait_until_bookmark("confirm")
            self.play(Write(circ))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################

TASK_Func_2_3_P_1_q = SophiaTaskDefinition(
    answerOptions=["$x=2$", "$x=0$","$x=-2$", "$x=-2.5$"],
    correctAnswerIndex=3,
    questionText="Where do $f(x)$ and $g(x)$ intersect?"
)
class Func_2_3_P_1_q(linearFunctionEqualityQuestionScene):
        
    def construct(self):
        self.fParams = [4, -2]
        self.gParams = [6, 3]
        self.handShake = True
        super().construct()

class Func_2_3_P_1_a(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [4, -2]
        self.gParams = [6, 3]
        self.tfIntro = "Mhm, that's not quite right. Let me show you:"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

class Func_2_3_P_1_b(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [4, -2]
        self.gParams = [6, 3]
        self.tfIntro = "Mhm, that's not quite right. Let me show you:"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

class Func_2_3_P_1_c(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [4, -2]
        self.gParams = [6, 3]
        self.tfIntro = "Mhm, that's not quite right. Let me show you:"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()


class Func_2_3_P_1_d(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [4, -2]
        self.gParams = [6, 3]
        self.tfIntro = "Great job, that's exactly right!"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

#####################################
#####################################$
TASK_Func_2_3_P_2_q = SophiaTaskDefinition(
    answerOptions=["$x=2$", "$x=0$","$x=-2$", "$x=-2.5$"],
    correctAnswerIndex=0,
    questionText="Where do $f(x)$ and $g(x)$ intersect?"
)
class Func_2_3_P_2_q(linearFunctionEqualityQuestionScene):
        
    def construct(self):
        self.fParams = [3, -1]
        self.gParams = [6, -7]
        self.handShake = True
        super().construct()


class Func_2_3_P_2_a(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [3, -1]
        self.gParams = [6, -7]
        self.tfIntro = "Great job, that's exactly right!"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

class Func_2_3_P_2_b(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [3, -1]
        self.gParams = [6, -7]
        self.tfIntro = "Mhm, that's not quite right. Let me show you:"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

class Func_2_3_P_2_c(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [3, -1]
        self.gParams = [6, -7]
        self.tfIntro = "Mhm, that's not quite right. Let me show you:"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()
    
class Func_2_3_P_2_d(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [3, -1]
        self.gParams = [6, -7]
        self.tfIntro = "Mhm, that's not quite right. Let me show you:"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

#####################################
#####################################
TASK_Func_2_3_P_3_q = SophiaTaskDefinition(
    answerOptions=["$x=2/3$", "$x=-1/3$", "$x=8/3$", "$x=5/3$"],
    correctAnswerIndex=2,
    questionText="Where do $f(x)$ and $g(x)$ intersect?"
)
class Func_2_3_P_3_q(linearFunctionEqualityQuestionScene):
        
    def construct(self):
        self.fParams = [2, 3]
        self.gParams = [5, -5]
        self.handShake = True
        super().construct()

class Func_2_3_P_3_a(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [2, 3]
        self.gParams = [5, -5]
        self.tfIntro = "Mhm, that's not quite right. Let me show you:"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

class Func_2_3_P_3_b(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [2, 3]
        self.gParams = [5, -5]
        self.tfIntro = "Mhm, that's not quite right. Let me show you:"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

class Func_2_3_P_3_c(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [2, 3]
        self.gParams = [5, -5]
        self.tfIntro = "Great job, that's exactly right!"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

class Func_2_3_P_3_d(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [2, 3]
        self.gParams = [5, -5]
        self.tfIntro = "Mhm, that's not quite right. Let me show you:"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

#####################################
#####################################
TASK_Func_2_3_P_4_q = SophiaTaskDefinition(
    answerOptions=["$x=0$", "$x=0.25$", "$x=0.5$", "$x=-0.5$"],
    correctAnswerIndex=1,
    questionText="Where do $f(x)$ and $g(x)$ intersect?"
)

class Func_2_3_P_4_q(linearFunctionEqualityQuestionScene):
        
    def construct(self):
        self.fParams = [1, 4]
        self.gParams = [-3, 5]
        self.handShake = True
        super().construct()

class Func_2_3_P_4_a(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [1, 4]
        self.gParams = [-3, 5]
        self.tfIntro = "Mhm, that's not it... I'll explain:"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

class Func_2_3_P_4_b(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [1, 4]
        self.gParams = [-3, 5]
        self.tfIntro = "Great job, that's it!"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

class Func_2_3_P_4_c(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [1, 4]
        self.gParams = [-3, 5]
        self.tfIntro = "Mhm, that's not it... I'll explain:"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

class Func_2_3_P_4_d(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [1, 4]
        self.gParams = [-3, 5]
        self.tfIntro = "Mhm, that's not it... I'll explain:"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

#####################################
#####################################
TASK_Func_2_3_P_5_q = SophiaTaskDefinition(
    answerOptions=["$x=2/3$", "$x=4/3$", "$x=-2/3$", "$x=8/3$"],
    correctAnswerIndex=2,
    questionText="Where do $f(x)$ and $g(x)$ intersect?"
)

class Func_2_3_P_5_q(linearFunctionEqualityQuestionScene):
        
    def construct(self):
        self.fParams = [2, -3]
        self.gParams = [5, -1]
        self.handShake = True
        super().construct()

class Func_2_3_P_5_a(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [2, -3]
        self.gParams = [5, -1]
        self.tfIntro = "No, that's not correct. Let's solve it together"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

class Func_2_3_P_5_b(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [2, -3]
        self.gParams = [5, -1]
        self.tfIntro = "No, that's not correct. Let's solve it together"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

class Func_2_3_P_5_c(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [2, -3]
        self.gParams = [5, -1]
        self.tfIntro = "Great job, you got it right!"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

class Func_2_3_P_5_d(linearFunctionEqualityAnswerScene):
        
    def construct(self):
        self.fParams = [2, -3]
        self.gParams = [5, -1]
        self.tfIntro = "No, that's not correct. Let's solve it together"
        self.cords = self.add_cords([-4, 4, 2], [-24, 24, 6], x_ticks=[-4,-2,2,4], y_ticks=[-24,-12,12,24])
        super().construct()

#####################################
#####################################



#####################################
#####################################
PROTOTYPES = [
    PagePrototypeVideo.from_scene(Func_2_3_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_2_3_I_1_q, Func_2_3_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_2_3_I_1_a),
    PagePrototypeVideo.from_scene(Func_2_3_I_1_b),
    PagePrototypeVideo.from_scene(Func_2_3_I_1_c),
    PagePrototypeVideo.from_scene(Func_2_3_I_1_d),
    PagePrototypeVideo.from_scene(Func_2_3_I_2),
    PagePrototypeVideo.from_scene(Func_2_3_I_3),
    PagePrototypeVideo.from_scene(Func_2_3_I_4),
    PagePrototypeVideo.from_scene(Func_2_3_I_5),
    PagePrototypeVideo.from_scene(Func_2_3_I_6_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_2_3_I_6_q, Func_2_3_I_6_q.__name__),
    PagePrototypeVideo.from_scene(Func_2_3_I_6_a),
    PagePrototypeVideo.from_scene(Func_2_3_I_6_b),
    PagePrototypeVideo.from_scene(Func_2_3_I_6_c),
    PagePrototypeVideo.from_scene(Func_2_3_I_6_d),
    PagePrototypeVideo.from_scene(Func_2_3_P_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_2_3_P_1_q, Func_2_3_P_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_2_3_P_1_a),
    PagePrototypeVideo.from_scene(Func_2_3_P_1_b),
    PagePrototypeVideo.from_scene(Func_2_3_P_1_c),
    PagePrototypeVideo.from_scene(Func_2_3_P_1_d),
    PagePrototypeVideo.from_scene(Func_2_3_P_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_2_3_P_2_q, Func_2_3_P_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_2_3_P_2_a),
    PagePrototypeVideo.from_scene(Func_2_3_P_2_b),
    PagePrototypeVideo.from_scene(Func_2_3_P_2_c),
    PagePrototypeVideo.from_scene(Func_2_3_P_2_d),
    PagePrototypeVideo.from_scene(Func_2_3_P_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_2_3_P_3_q, Func_2_3_P_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_2_3_P_3_a),
    PagePrototypeVideo.from_scene(Func_2_3_P_3_b),
    PagePrototypeVideo.from_scene(Func_2_3_P_3_c),
    PagePrototypeVideo.from_scene(Func_2_3_P_3_d),
    PagePrototypeVideo.from_scene(Func_2_3_P_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_2_3_P_4_q, Func_2_3_P_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_2_3_P_4_a),
    PagePrototypeVideo.from_scene(Func_2_3_P_4_b),
    PagePrototypeVideo.from_scene(Func_2_3_P_4_c),
    PagePrototypeVideo.from_scene(Func_2_3_P_4_d),
    PagePrototypeVideo.from_scene(Func_2_3_P_5_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_2_3_P_5_q, Func_2_3_P_5_q.__name__),
    PagePrototypeVideo.from_scene(Func_2_3_P_5_a),
    PagePrototypeVideo.from_scene(Func_2_3_P_5_b),
    PagePrototypeVideo.from_scene(Func_2_3_P_5_c),
    PagePrototypeVideo.from_scene(Func_2_3_P_5_d),
]
scenes/Func/Func_2: Linear Functions/Func2_3.py
Sophia-Edu-Labs/sophia-math
# 2_3: Linear Functions: Functions and Linear Inequalities

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition


#####################################
#####################################
# TASK_Func_2_3_I_1_q = SophiaTaskDefinition(
#     answerOptions=["$f(x)=5x+15, \,g(x)=20x$", "$f(x)=15x+15, \,g(x)=20x$","$f(x)=15x+5, \,g(x)=20x$", "$f(x)=15x+15, \,g(x)=20+x$"],
#     correctAnswerIndex=2,
#     questionText="Which function describes the distances you and your friend have traveled?"
# )

# class Func_2_3_I_1_q(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()

#         self.add_title("Functions and Linear Equations")

#         bike = ImageMobject(assets_folder / "img" / "bike.jpg")
#         bike = bike.scale(3.2/bike.get_width()).move_to([-5, 1, 0])

#         f1 = Tex("Your Friend:", color=c1t, font_size=fs2).next_to(bike, DOWN, buff=0.6).shift(5*RIGHT)
#         f2 = BulletedList("$5$km Head start", "$15$km/h speed", buff=0.2, font_size=fs2).set_color(c1t).next_to(f1, DOWN)
#         y1 = Tex("You:", color=c1t, font_size=fs2).next_to(f2, DOWN)
#         y2 = BulletedList("$20$km/h speed", color=c1t, font_size=fs2).set_color(c1t).next_to(y1, DOWN)
#         comparison = VGroup(f1, f2, y1, y2).arrange(DOWN, center=False, aligned_edge=LEFT).shift(0.2*LEFT)
        
#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Neww topic! In this chapter, we are looking at linear functions and linear equations,
#                 and what these two have to do with each other.
#                 
#                 And what better way to find out, what the connection is, than to look at a real world example.
#                 
#                 This is the scenario: You and your friend are both <bookmark mark="bike"/> cycling to the beach from your house.
#                 
#                 <bookmark mark="f1"/>
#                 Your friend has a <bookmark mark="f2"/> head start of 5 kilometers, and she is cycling <bookmark mark="f3"/> at a speed of 15 kilometers per hour.
#                 
#                 <bookmark mark="y1"/>
#                 You on the other hand are cycling at <bookmark mark="y2"/> a speed of 20 kilometers per hour, but you get no head start.
#                 
#                 Question Number one, and this is mainly about functions: What functions f and g describe the distance your friend and you have traveled?
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("bike")
#             self.play(bike.animate.shift(5*RIGHT))

#             self.wait_until_bookmark("f1")
#             self.play(Write(f1))

#             self.wait_until_bookmark("f2")
#             self.play(Write(f2[0]))

#             self.wait_until_bookmark("f3")
#             self.play(Write(f2[1]))

#             self.wait_until_bookmark("y1")
#             self.play(Write(y1))

#             self.wait_until_bookmark("y2")
#             self.play(Write(y2[0]))

#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)


# class Func_2_3_I_1_T(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()

#         title = self.add_title("Correct!")

#         f1 = Tex("Your Friend:", color=c1t, font_size=fs2).next_to(title, DOWN, buff=0.6)
#         f2 = BulletedList("$5$km Head start", "$15$km/h speed", buff=0.2, font_size=fs2).set_color(c1t).next_to(f1, DOWN)
#         f3 = MathTex("\\downarrow", color=c1t, font_size=fs2).next_to(f2, DOWN)


#         y1 = Tex("You:", color=c1t, font_size=fs2).next_to(title, DOWN)
#         y2 = BulletedList("$20$km/h speed", color=c1t, font_size=fs2).set_color(c1t).next_to(y1, DOWN)
#         y3 = MathTex("\\downarrow", color=c1t, font_size=fs2).next_to(y2, DOWN)

#         # comparison = VGroup(f1, f2, y1, y2).arrange(aligned_edge=LEFT).shift(0.2*LEFT)

#         funcFriend = MathTex("f(x)=15x","+5", color=c1t, font_size=fs2).next_to(f3, DOWN)
#         funcYou = MathTex("g(x)=20x", color=c1t, font_size=fs2).next_to(y3, DOWN)
        
#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 That's right, good job!
#                 
#                 <bookmark mark="friend"/>
#                 Your friend cycles at a speed of 15 kilometers per hour, and if x stands for the number of hours cycled,
#                 we can write her function as <bookmark mark="friendfunc1"/> f of x equals fifteen times x.
#                 
#                 And since she has a head start of 5 kilometers, we have to <bookmark mark="friendfunc2"/> add 5 to the function.
#                 So the function describing the distance your friend has traveled is f of x equals fifteen times x plus five.
#                 
#                 Next, let's look at your function. <bookmark mark="you"/>
#                 You cycle at a speed of 20 kilometers per hour.
#                 
#                 Since you have no head start, your function is simply <bookmark mark="yourfunc"/> g of x equals twenty times x.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("friend")
#             self.play(Write(f1), Write(f2))
            
#             self.wait_until_bookmark("friendfunc1")
#             self.play(Write(funcFriend[0]), Write(f3))

#             self.wait_until_bookmark("friendfunc2")
#             self.play(Write(funcFriend[1]))

#             self.wait_until_bookmark("you")
#             self.play(Unwrite(f1), Unwrite(f2), Unwrite(f3), Unwrite(funcFriend), run_time=0.5)
#             self.play(Write(y1), Write(y2), run_time=1)

#             self.wait_until_bookmark("yourfunc")
#             self.play(Write(funcYou), Write(y3))

#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)

# class Func_2_3_I_1_F(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()

#         title = self.add_title("Not quite right...")

#         f1 = Tex("Your Friend:", color=c1t, font_size=fs2).next_to(title, DOWN, buff=0.6)
#         f2 = BulletedList("$5$km Head start", "$15$km/h speed", buff=0.2, font_size=fs2).set_color(c1t).next_to(f1, DOWN)
#         f3 = MathTex("\\downarrow", color=c1t, font_size=fs2).next_to(f2, DOWN)


#         y1 = Tex("You:", color=c1t, font_size=fs2).next_to(title, DOWN)
#         y2 = BulletedList("$20$km/h speed", color=c1t, font_size=fs2).set_color(c1t).next_to(y1, DOWN)
#         y3 = MathTex("\\downarrow", color=c1t, font_size=fs2).next_to(y2, DOWN)

#         # comparison = VGroup(f1, f2, y1, y2).arrange(aligned_edge=LEFT).shift(0.2*LEFT)

#         funcFriend = MathTex("f(x)=15x","+5", color=c1t, font_size=fs2).next_to(f3, DOWN)
#         funcYou = MathTex("g(x)=20x", color=c1t, font_size=fs2).next_to(y3, DOWN)
        
#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Mhmmm, that's not quite right. Let's solve this together.
#                 
#                 <bookmark mark="friend"/>
#                 Your friend cycles at a speed of 15 kilometers per hour, and if x stands for the number of hours cycled,
#                 we can write her function as <bookmark mark="friendfunc1"/> f of x equals fifteen times x.
#                 
#                 And since she also has a head start of 5 kilometers, we have to <bookmark mark="friendfunc2"/> add 5 to the function.
#                 So the function describing the distance your friend has traveled is f of x equals fifteen times x plus five.
#                 
#                 Next, let's look at your function. <bookmark mark="you"/>
#                 You cycle at a speed of 20 kilometers per hour.
#                 
#                 Since you have no head start, your function is simply <bookmark mark="yourfunc"/> g of x equals twenty times x.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("friend")
#             self.play(Write(f1), Write(f2))
            
#             self.wait_until_bookmark("friendfunc1")
#             self.play(Write(funcFriend[0]), Write(f3))

#             self.wait_until_bookmark("friendfunc2")
#             self.play(Write(funcFriend[1]))

#             self.wait_until_bookmark("you")
#             self.play(Unwrite(f1), Unwrite(f2), Unwrite(f3), Unwrite(funcFriend), run_time=0.5)
#             self.play(Write(y1), Write(y2), run_time=1)

#             self.wait_until_bookmark("yourfunc")
#             self.play(Write(funcYou), Write(y3))

#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)


# #####################################
# #####################################
# class Func_2_3_I_2(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()

#         title = self.add_title("When will you meet?")

#         bikeMeet = ImageMobject(assets_folder / "img" / "cyclistsmeet.png")
#         bikeRace = ImageMobject(assets_folder / "img" / "cyclistsrace.png")
#         bikeMeet = bikeMeet.scale(3.2/bikeMeet.get_width()).move_to([-5, 0.5, 0])
#         bikeRace = bikeRace.scale(3.2/bikeRace.get_width()).move_to([5, -1.5, 0])
#         # comparison = VGroup(f1, f2, y1, y2).arrange(aligned_edge=LEFT).shift(0.2*LEFT)

#         # funcFriend = MathTex("f(x)=15x","+5", color=c1t, font_size=fs2).next_to(f3, DOWN)
#         # funcYou = MathTex("g(x)=20x", color=c1t, font_size=fs2).next_to(y3, DOWN)
        
#         Q1 = Text("→ At what point in time", color=RED, font_size=fs3, weight=BOLD).next_to(bikeMeet, DOWN, buff=0.6).shift(RIGHT*5)
#         Q2 = Text("will you have traveled", color=RED, font_size=fs3, weight=BOLD).next_to(Q1, DOWN, buff=0.1)
#         Q3 = Text("the same distance?", color=RED, font_size=fs3, weight=BOLD).next_to(Q2, DOWN, buff=0.1)        
#         Q = VGroup(Q1, Q2, Q3).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(LEFT*0.1)
#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Ok, so why are we doing this? And what does it have to do with equations?
#                 
#                 Think about this: <bookmark mark="race"/> Since you're both cycling in the same direction, but your friend had a head start,
#                 you two will meet at some point - because you are cycling faster than her.
#                 
#                 But when <bookmark mark="meet"/> will you two meet?
#                 
#                 Clearly, you'll meet at the point in time when both of you have traveled the exact same distance.
#                 <bookmark mark="Q"/>
#                 
#                 Think about how we can find that point in time using the two functions we just wrote.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("race")
#             self.play(bikeRace.animate.shift(5*LEFT))
            
#             self.wait_until_bookmark("meet")
#             self.play(bikeMeet.animate.shift(5*RIGHT), bikeRace.animate.shift(5*LEFT))

#             self.wait_until_bookmark("Q")
#             self.play(Write(Q), run_time=0.75)

#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)


# #####################################
# #####################################
# class Func_2_3_I_3(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()

#         title = self.add_title("When will you meet?")

#         # comparison = VGroup(f1, f2, y1, y2).arrange(aligned_edge=LEFT).shift(0.2*LEFT)

#         funcFriend = MathTex("f(x)=15x","+5", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1)
#         textFriend1 = Text("→Describes the distance", color=RED, font_size=fs3, slant=ITALIC).next_to(funcFriend, DOWN, buff=0.2)
#         textFriend2 = Text("your friend has traveled", color=RED, font_size=fs3, slant=ITALIC).next_to(textFriend1, DOWN, buff=0.1)
#         textFriend = VGroup(textFriend1, textFriend2).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(RIGHT*0.2)

#         funcYou = MathTex("g(x)=20x", color=c1t, font_size=fs2).next_to(textFriend, DOWN)
#         funcYou = funcYou.shift(LEFT*(funcYou.get_left()[0]-funcFriend.get_left()[0]))
#         textYou1 = Text("→Describes the distance", color=RED, font_size=fs3, slant=ITALIC).next_to(funcYou, DOWN, buff=0.2)
#         textYou2 = Text("you have traveled", color=RED, font_size=fs3, slant=ITALIC).next_to(textYou1, DOWN, buff=0.1)
#         textYou = VGroup(textYou1, textYou2).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(RIGHT*0.2)
#         textYou = textYou.shift(LEFT*(textYou.get_left()[0]-textFriend.get_left()[0]))

#         funcBoth = MathTex("f(x)=g(x)", color=c1t, font_size=fs2).next_to(textYou, DOWN, buff=1)
#         funcBoth = funcBoth.shift(LEFT*(funcBoth.get_left()[0]-funcFriend.get_left()[0]))
#         textBoth1 = Text("→Describes the time", color=RED, font_size=fs3, slant=ITALIC).next_to(funcBoth, DOWN, buff=0.2)
#         textBoth2 = Text("when you meet", color=RED, font_size=fs3, slant=ITALIC).next_to(textBoth1, DOWN, buff=0.1)
#         textBoth = VGroup(textBoth1, textBoth2).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(RIGHT*0.2)
#         textBoth = textBoth.shift(LEFT*(textBoth.get_left()[0]-textFriend.get_left()[0]))

#         friendBikeWave = ImageMobject(assets_folder / "img" / "friendbikewave.png")
#         youBikeWave = ImageMobject(assets_folder / "img" / "youbikewave.png")
#         friendBikeWave = friendBikeWave.scale(3.2/friendBikeWave.get_width()).next_to(textFriend, DOWN, buff=0.2).shift(LEFT*5)
#         youBikeWave = youBikeWave.scale(3.2/youBikeWave.get_width()).next_to(textYou, DOWN, buff=0.2).shift(LEFT*5)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Let's think back to what we already know.
#                 
#                 The function <bookmark mark="f"/> f of x describes the distance your friend has traveled at time x.
#                 
#                 The function <bookmark mark="g"/> g of x on the other hand describes the distance YOU have traveled
#                 at time x.
#                 
#                 <bookmark mark="youLeave"/>
#                 Since you and your friend meet, when you have traveled the same distance, we can say that
#                 <bookmark mark="both"/> you meet when f of x is equal to g of x.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("f")
#             self.play(Write(funcFriend), run_time=0.5)
#             self.play(Write(textFriend), friendBikeWave.animate(run_time=1.5).shift(RIGHT*5), run_time=0.5)

#             self.wait_until_bookmark("g")
#             textFriend.set_color(c3t)
#             self.play(friendBikeWave.animate(run_time=0.3).shift(RIGHT*5), Write(funcYou), run_time=0.5)
#             self.play(Write(textYou), youBikeWave.animate(run_time=1.5).shift(RIGHT*5), run_time=0.5)

#             self.wait_until_bookmark("youLeave")
#             self.play(youBikeWave.animate.shift(RIGHT*5))

#             self.wait_until_bookmark("both")
#             textYou.set_color(c3t)
#             self.play(Write(funcBoth), run_time=0.5)
#             self.play(Write(textBoth), run_time=0.5)


#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)


# #####################################
# #####################################
# class Func_2_3_I_4(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()

#         title = self.add_title("When will you meet?")

#         # comparison = VGroup(f1, f2, y1, y2).arrange(aligned_edge=LEFT).shift(0.2*LEFT)

#         funcFriend = MathTex("f(x)=15x","+5", color=c1t, font_size=fs1).next_to(title, DOWN, buff=0.8)
#         funcYou = MathTex("g(x)=20x", color=c1t, font_size=fs1).next_to(funcFriend, DOWN, buff=0.2)
#         funcYou = funcYou.shift(LEFT*(funcYou.get_left()[0]-funcFriend.get_left()[0]))

#         upShiftBoth = 1.2

#         funcBoth = MathTex("f(x)=g(x)", color=c1t, font_size=fs1).next_to(funcYou, DOWN, buff=0.8)
#         funcBoth.set_x(0)
#         fBA1 = MathTex("\\downarrow", color=c1t, font_size=fs1).next_to(funcBoth, DOWN, buff=0.2).shift(upShiftBoth*UP)
#         fB1 = MathTex("15x+5=20x", color=c1t, font_size=fs1).next_to(fBA1, DOWN, buff=0.2)
#         fbA2 = MathTex("\\downarrow", color=c1t, font_size=fs1).next_to(fB1, DOWN, buff=0.2)
#         fB2 = MathTex("5=5x", color=c1t, font_size=fs1).next_to(fbA2, DOWN, buff=0.2)
#         fbA3 = MathTex("\\downarrow", color=c1t, font_size=fs1).next_to(fB2, DOWN, buff=0.2)
#         fB3 = MathTex("x=1", color=RED, font_size=fs1).next_to(fbA3, DOWN, buff=0.2)


#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Ok, now we know how to find the time when you meet your friend: We just compute
#                 the value of x where <bookmark mark="both"/> f of x is equal to g of x, because f describes the distance
#                 your friend has traveled and g describes the distance YOU have traveled.
#                 
#                 Remember: f of x is <bookmark mark="f"/> equal to fifteen times x plus five, -
#                 and g of x is <bookmark mark="g"/> equal to twenty times x.
#                 
#                 Now we want to find the value of x where <bookmark mark="calculate"/>
#                 f of x is equal to g of x.
#                 
#                 The first step <bookmark mark="step1a"/> is to <bookmark mark="step1b"/> plug in the terms of f and g.
#                 We get the equation 15x plus 5 is equal to 20x.
#                 
#                 Next, <bookmark mark="step2a"/> we subtract 15x from both sides, which leaves
#                 us with <bookmark mark="step2b"/> the equation 5 equals 5x.
#                 
#                 Finally, <bookmark mark="step3a"/> we divide both sides by 5, which results in
#                 the final solution, <bookmark mark="step3b"/> that x is equal to 1.
#                 
#                 We can now say that you and your friend meet after one hour.
#                 
#                 Puh, that was intense. Let's take a deeeeeep breath.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("both")
#             self.play(Write(funcBoth), run_time=0.5)
            
#             self.wait_until_bookmark("f")
#             self.play(Write(funcFriend), run_time=0.5)

#             self.wait_until_bookmark("g")
#             self.play(Write(funcYou), run_time=0.5)

#             self.wait_until_bookmark("calculate")
#             self.play(funcBoth.animate.shift(UP*upShiftBoth), Unwrite(funcFriend), Unwrite(funcYou), run_time=0.5)

#             self.wait_until_bookmark("step1a")
#             self.play(Write(fBA1), run_time=0.5)

#             self.wait_until_bookmark("step1b")
#             self.play(Write(fB1), run_time=0.5)

#             self.wait_until_bookmark("step2a")
#             self.play(Write(fbA2), run_time=0.5)

#             self.wait_until_bookmark("step2b")
#             self.play(Write(fB2), run_time=0.5)

#             self.wait_until_bookmark("step3a")
#             self.play(Write(fbA3), run_time=0.5)

#             self.wait_until_bookmark("step3b")
#             self.play(Write(fB3), run_time=0.5)

            
#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)



# #####################################
# #####################################
# class Func_2_3_I_5(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):

#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()

#         title = self.add_title("Functions & Equations")

#         qmark = ImageMobject(assets_folder / "img" / "qmark.png")
#         qmark = qmark.scale(3.2/qmark.get_width()).move_to([-5, 1, 0])

#         function = Text("Functions", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1).shift(LEFT*0.4)
#         tf1 = Text("→ Used to describe", color=RED, font_size=fs3, slant=ITALIC).next_to(function, DOWN, buff=0.2)
#         tf2 = Text("real world scenarios", color=RED, font_size=fs3, slant=ITALIC).next_to(tf1, DOWN, buff=0.1)
#         tf = VGroup(tf1, tf2).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(RIGHT*0.4)

#         equation = Text("Equations", color=c1t, font_size=fs2).next_to(tf, DOWN)
#         equation = equation.shift(LEFT*(equation.get_left()[0]-function.get_left()[0]))
#         te1 = Text("→ Used to find specific", color=RED, font_size=fs3, slant=ITALIC).next_to(equation, DOWN, buff=0.2)
#         te2 = Text("value of a variable", color=RED, font_size=fs3, slant=ITALIC).next_to(te1, DOWN, buff=0.1)
#         te = VGroup(te1, te2).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(RIGHT*0.2)
#         te = te.shift(LEFT*(te.get_left()[0]-tf.get_left()[0]))

#         handshake = ImageMobject(assets_folder / "img" / "handshake.png")
#         handshake = handshake.scale(1.2/handshake.get_width()).move_to([-5, 1, 0])
#         fLeft = Text("Functions", color=c1t, font_size=fs3).next_to(handshake, LEFT, buff=0.1)
#         eRight = Text("Equations", color=c1t, font_size=fs3).next_to(handshake, RIGHT, buff=0.1)
#         shakeGroup = Group(handshake, fLeft, eRight).scale(0.8).next_to(te, DOWN, buff=0.5)
#         ts1 = Text("→ Combine the two to", color=RED, font_size=fs3, slant=ITALIC).next_to(shakeGroup, DOWN, buff=0.2)
#         ts2 = Text("compare real world", color=RED, font_size=fs3, slant=ITALIC).next_to(ts1, DOWN, buff=0.1)
#         ts3 = Text("scenarios", color=RED, font_size=fs3, slant=ITALIC).next_to(ts2, DOWN, buff=0.1)
#         ts = VGroup(ts1, ts2, ts3).arrange(DOWN, buff=0.1, center=False, aligned_edge=RIGHT).shift(RIGHT*0.2)
#         ts = ts.shift(LEFT*(ts.get_left()[0]-te.get_left()[0]))
#         shakeGroup.shift(3*RIGHT)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 So, let's recap <bookmark mark="qmark"/> what we just did, and what it has to do with functions and equations.
#                 
#                 <bookmark mark="functions"/> Functions are often used to describe real world scenarios. For example, a function can describe
#                 the distance you have traveled after some time.
#                 
#                 <bookmark mark="equation"/>
#                 Equations are used to find the value of a variable. For example, an equation can be used to
#                 determine the point in time at which you have traveled twenty kilometers.
#                 
#                 Now, we can <bookmark mark="handshake"/> put these two concepts together to determine at what point in time
#                 two real world scenarios, that are both described by functions, are equal.
#                 
#                 In the example we just looked at, we had two functions, describing the distance you and your friend
#                 have traveled at any point in time. We then used an equation to determine at what point in time
#                 you and your friend have traveled the same distance.
#                 
#                 We do this, by simply setting the terms of the two functions equal to each other,
#                 and then solving the equation for the variable, in our case for x.
#                 """
#         ) as tracker:


#             self.wait_until_bookmark("qmark")
#             self.play(qmark.animate.shift(5*RIGHT), run_time=1)

#             self.wait_until_bookmark("functions")
#             self.play(qmark.animate.shift(5*RIGHT), run_time=0.4)
#             self.play(Write(function), Write(tf))

#             self.wait_until_bookmark("equation")
#             self.play(Write(equation), Write(te))

#             self.wait_until_bookmark("handshake")
#             self.play(shakeGroup.animate.shift(3.2*LEFT))
#             self.play(Write(ts))

            
#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)


# #####################################
# #####################################
# TASK_Func_2_3_I_6_q = SophiaTaskDefinition(
#     answerOptions=["(1,20)", "(0,5)", "(20,20)", "(1,1)"],
#     correctAnswerIndex=0,
#     questionText="Where do the functions intersect?"
# )

# class Func_2_3_I_6_q(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):

#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()

#         title = self.add_title("Graphical solution")

#         cords = self.add_cords([0, 2, 1], [0, 40, 5], x_ticks=[1,2], y_ticks=[10,20,30,40])
#         plane = cords[0]

#         note = Notepad(texts=["Problem can also be solved graphically", "Consider the plots of $g$ and $f$","Where do the two functions intersect?"])
#         self.add(note)

#         funcTexf = MathTex("f(x) = 15x + 5", color=c1t, font_size=fs1).next_to(plane, DOWN, buff=0.5)
#         funcTexg = MathTex("g(x) = 20x", color=c2t, font_size=fs1).move_to(funcTexf)
#         funcTexg = funcTexg.shift(LEFT*(funcTexg.get_left()[0]-funcTexf.get_left()[0]))
#         f = lambda x: 15*x + 5
#         g = lambda x: 20*x
#         plot_f = plane.plot(f, color=BLUE)
#         plot_g = plane.plot(g, color=GREEN)

#         intersection = plane.c2p(1,20)
#         intersectionDot = Dot(intersection, color=RED)

#         xo, yo, _ = plane.x_axis.n2p(0)
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.move_to([xo, yo, 0])

#         with self.voiceover(
#                 text="""
#                 There is another way we can solve these kinds of problems: <bookmark mark="note1"/> Visually, by using the
#                 <bookmark mark="cords"/> graph of the functions.
#                 
#                 Remember, we want to find the values of x for which two functions are equal.
#                 
#                 We can do this by looking at the graph of the two functions, and finding the point at which
#                 the two functions have the same y-value, so the point at which the two functions meet.
#                 
#                 Let's return to our bike example, for the last time, i promise!!!
#                 
#                 Remember, the function describing the distance your friend has traveled is given by
#                 <bookmark mark="f"/> f of x equals fifteen times x plus five,
#                 and the function describing the distance you have traveled is given by
#                 <bookmark mark="g"/> g of x equals twenty times x.
#                 
#                 Now, let's <bookmark mark="plot"/> plot the two functions. <bookmark mark="note2"/> Where do the two functions intersect?
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("note1")
#             note.change_colors([0])
            
#             self.wait_until_bookmark("cords")
#             self.play(Write(cords))
#             self.add(cursor)

#             self.wait_until_bookmark("f")
#             self.play(Write(funcTexf))

#             self.wait_until_bookmark("g")
#             self.play(ReplacementTransform(funcTexf, funcTexg))

#             self.wait_until_bookmark("plot")
#             note.change_colors([0,1])
#             self.play(Write(plot_f), Write(plot_g))

#             self.wait_until_bookmark("note2")
#             note.change_colors([1,2])
            
#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)

# class Func_2_3_I_6_T(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):

#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()

#         title = self.add_title("Graphical solution")

#         cords = self.add_cords([0, 2, 1], [0, 40, 5], x_ticks=[1,2], y_ticks=[10,20,30,40])
#         plane = cords[0]

#         note = Notepad(texts=[["Follow one of the graphs", "until both intersect"], "Intersection at $(1,20)$","$\\rightarrow$ You meet after $x=1$ hour"])
#         self.add(note)

#         funcTexf = MathTex("f(x) = 15x + 5", color=c1t, font_size=fs1).next_to(plane, DOWN, buff=0.5)
#         funcTexg = MathTex("g(x) = 20x", color=c2t, font_size=fs1).move_to(funcTexf)
#         funcTexg = funcTexg.shift(LEFT*(funcTexg.get_left()[0]-funcTexf.get_left()[0]))
#         f = lambda x: 15*x + 5
#         g = lambda x: 20*x
#         plot_f = plane.plot(f, color=BLUE)
#         plot_g = plane.plot(g, color=GREEN)

#         ix, iy, _ = plane.c2p(1,20)
#         # intersectionDot = Dot(intersection, color=RED)

#         xo, yo, _ = plane.x_axis.n2p(0)
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.move_to([xo, yo, 0])

#         self.add(cursor, cords, plot_f, plot_g)

#         xdown, ydown, _ = plane.c2p(1,0)
#         xleft, yleft, _ = plane.c2p(0,20)

#         dashed1 = DashedLine([xleft, iy, 0], [ix, iy, 0], color=c2t)
#         dashed2 = DashedLine([ix, ydown, 0], [ix, iy, 0], color=c2t)

#         with self.voiceover(
#                 text="""
#                 Yes! That's correct, very good!
#                 
#                 If we <bookmark mark="note1"/> follow one of the graphs <bookmark mark="intersectLoc"/> until it intersects the other graph, we can see that
#                 the graphs of the two functions intersect at the point 1,20.
#                 
#                 <bookmark mark="cursorBack"/>
#                 The interpretation of that - as we already saw in a previous video - <bookmark mark="note2"/> is that
#                 you and your friends meet after x equals one hour. The y value - twenty - means that by that time
#                 you have traveled twenty kilometers, and your friend has traveled twenty kilometers as well.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("note1")
#             note.change_colors([0])
            
#             self.wait_until_bookmark("intersectLoc")
#             cursor.blinking=False
#             note.change_colors([0,1])
#             self.play(CursorMoveTo(cursor, ix, iy))
#             interCirc = Circle(radius=0.2, color=RED).move_to([ix, iy, 0])
#             self.play(Write(interCirc), Write(dashed1), Write(dashed2))

#             self.wait_until_bookmark("cursorBack")
#             self.play(CursorMoveTo(cursor, xo, yo))
#             self.wait(0.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("note2")
#             note.change_colors([1,2])
            
#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)

# class Func_2_3_I_6_F(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):

#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()

#         title = self.add_title("Graphical solution")

#         cords = self.add_cords([0, 2, 1], [0, 40, 5], x_ticks=[1,2], y_ticks=[10,20,30,40])
#         plane = cords[0]

#         note = Notepad(texts=[["Follow one of the graphs", "until both intersect"], "Intersection at $(1,20)$","$\\rightarrow$ You meet after $x=1$ hour"])
#         self.add(note)

#         funcTexf = MathTex("f(x) = 15x + 5", color=c1t, font_size=fs1).next_to(plane, DOWN, buff=0.5)
#         funcTexg = MathTex("g(x) = 20x", color=c2t, font_size=fs1).move_to(funcTexf)
#         funcTexg = funcTexg.shift(LEFT*(funcTexg.get_left()[0]-funcTexf.get_left()[0]))
#         f = lambda x: 15*x + 5
#         g = lambda x: 20*x
#         plot_f = plane.plot(f, color=BLUE)
#         plot_g = plane.plot(g, color=GREEN)

#         ix, iy, _ = plane.c2p(1,20)
#         # intersectionDot = Dot(intersection, color=RED)

#         xo, yo, _ = plane.x_axis.n2p(0)
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.move_to([xo, yo, 0])

#         self.add(cursor, cords, plot_f, plot_g)

#         xdown, ydown, _ = plane.c2p(1,0)
#         xleft, yleft, _ = plane.c2p(0,20)

#         dashed1 = DashedLine([xleft, iy, 0], [ix, iy, 0], color=c2t)
#         dashed2 = DashedLine([ix, ydown, 0], [ix, iy, 0], color=c2t)

#         with self.voiceover(
#                 text="""
#                 Mhm, that's not quite right. I'll show you the correct solution.
#                 
#                 If we <bookmark mark="note1"/> follow one of the graphs <bookmark mark="intersectLoc"/> until it intersects the other graph, we can see that
#                 the graphs of the two functions intersect at the point 1,20.
#                 
#                 <bookmark mark="cursorBack"/>
#                 The interpretation of that - as we already saw in a previous video - <bookmark mark="note2"/> is that
#                 you and your friends meet after x equals one hour. The y value - twenty - means that by that time
#                 you have traveled twenty kilometers, and your friend has traveled twenty kilometers as well.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("note1")
#             note.change_colors([0])
            
#             self.wait_until_bookmark("intersectLoc")
#             cursor.blinking=False
#             note.change_colors([0,1])
#             self.play(CursorMoveTo(cursor, ix, iy))
#             interCirc = Circle(radius=0.2, color=RED).move_to([ix, iy, 0])
#             self.play(Write(interCirc), Write(dashed1), Write(dashed2))

#             self.wait_until_bookmark("cursorBack")
#             self.play(CursorMoveTo(cursor, xo, yo))
#             self.wait(0.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("note2")
#             note.change_colors([1,2])
            
#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)



#####################################
#####################################
#####################################
#####################################
# PROTOTYPES = [
#     PagePrototypeVideo.from_scene(Func_2_3_I_1_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_2_3_I_1_q, Func_2_3_I_1_q.__name__),
# ]
scenes/Func/Func_2: Linear Functions/Func2_4.py
Sophia-Edu-Labs/sophia-math
    # 3_1: Fractional Rational Functions: Intro

# Import necessary libraries and modules
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition



#####################################
#####################################
class Func_3_1_I_1(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Functions")

        # Create a notepad with texts
        note = Notepad(texts=[["Function describes", "Fill level over time"], "$\\rightarrow$Which representation is correct?"])
        self.add(note)

        # Create the coordinate system
        cords = self.add_cords([-4,4, 1], [-3, 3, 1], x_ticks=[-4,-2,2,4],y_ticks=[-3,-2,-1,1,2,3])
        plane = cords[0]
        self.add(cords)

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])
        self.add(cords)

        func = lambda x: x/2
        func_plotted = plane.plot(func, color=RED)

        func_general = MathTex("f(x) = ax + b", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.4)
        func_ex = MathTex("f(x) = 0.5x", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so I'm now assuming you already know what a function is.
                If you don't, go back to the section on functions, and I'll be happy to explain it to you.
                
                Now, the type of functions we've mainly looked at were <bookmark mark="linear"/> linear functions.
                
                They have the form <bookmark mark="funcTerm"/> f of x equals "a" times x plus b, where a and b are constants.
                
                For example, the term of this function is <bookmark mark="thisFunc"/> f of x equals zero point five times x.
                
                We're multiplying "a", in this case zero point five by x, and a is positive, so the function increases when x increases,
                
                and it decreases, when x decreases.
                
                Now take a moment to think about this: What would happen, if instead of multiplying "a" by x, we would divide "a" by x?
                """
        ) as tracker:

            self.wait_until_bookmark("linear")
            self.play(Write(func_plotted))

            self.wait_until_bookmark("funcTerm")
            self.play(Write(func_general))

            self.wait_until_bookmark("thisFunc")
            self.play(ReplacementTransform(func_general, func_ex))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

    
#####################################
#####################################
class Func_3_1_I_2(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Functions")

        # Create a notepad with texts
        note = Notepad(texts=["Consider function $f(x)=\\tfrac1x$", "Plug in several values",["f decreases fast at first", "and then decreases more slowly"]], buff=0.3)
        self.add(note)

        # Create the coordinate system
        cords = self.add_cords([0,4, 1], [0, 4, 1], x_ticks=[1,2,3,4],y_ticks=[1,2,3,4])
        plane = cords[0]

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])

        func = lambda x: 1/x
        func_plotted = plane.plot(func, color=RED, x_range=[1/4, 4, 0.01], use_smoothing=False)

        func_general = MathTex("f(x) = \\tfrac ax", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.4)
        func_ex = MathTex("f(x) = \\tfrac 1x", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text="""
                So, we want to know what a function of the form <bookmark mark="funcA"/> f of x equals "a" divided by x looks like.
                
                As an example, let's look at the function f of x <bookmark mark="note1"/> equals <bookmark mark="funcG"/> one over x.
                
                And, let's start by looking at the positive values only.
                
                To learn more, <bookmark mark="cords"/> let's plug in some values.
                
                If we plug in one, <bookmark mark="plugIn1"/> we get one divided by one, which is one.
                
                If we plug in two, <bookmark mark="plugIn2"/> we get one divided by two, which is one half.
                
                If we plug in four, <bookmark mark="plugIn4"/> we get one divided by four, which is one quarter.
                
                And so on.
                
                Let's also plug in some values that are smaller than one:
                
                If we plug in <bookmark mark="plugInHalf"/> zero point five, we get one divided by zero point five, which is two,
                
                And if we plug in <bookmark mark="plugInQuarter"/> zero point two five, we get one divided by zero point two five, which is four.
                
                Now that we've plugged in some values, let's <bookmark mark="plot"/> connect them on the coordinate system and <bookmark mark="note3"/> see what the function looks like.
                
                As we can see, the function starts <bookmark mark="moveAlongFunc"/> with very high values for low x, and decreases as x gets larger.
                
                At first, it decreases very quickly, but then it decreases slower and slower.
                """
        ) as tracker:

            self.wait_until_bookmark("funcA")
            self.play(Write(func_general))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("funcG")
            self.play(ReplacementTransform(func_general, func_ex))

            self.wait_until_bookmark("cords")
            self.play(Write(cords))
            self.add(cursor)
            note.change_colors([0,1])

            self.wait_until_bookmark("plugIn1")
            cursor.blinking = False
            x,y,_ = plane.c2p(1,1)
            circ1 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circ1))

            self.wait_until_bookmark("plugIn2")
            x,y,_ = plane.c2p(2,0.5)
            circ2 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circ2))

            self.wait_until_bookmark("plugIn4")
            x,y,_ = plane.c2p(4,0.25)
            circ4 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y))
            self.play(Write(circ4))
            cursor.blinking=True

            self.wait_until_bookmark("plugInHalf")
            cursor.blinking=False
            x,y,_ = plane.c2p(0.5,2)
            circHalf = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circHalf))
            
            self.wait_until_bookmark("plugInQuarter")
            x,y,_ = plane.c2p(0.25,4)
            circQuarter = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circQuarter))
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("plot")
            self.play(Write(func_plotted), run_time=2.5)
            self.play(Unwrite(circ1), Unwrite(circ2), Unwrite(circ4), Unwrite(circHalf), Unwrite(circQuarter), run_time=0.5)

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])
            
            self.wait_until_bookmark("moveAlongFunc")
            x,y,_ = plane.c2p(0.25,4)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y),run_time=1)
            self.play(MoveAlongPath(cursor, func_plotted), run_time=9, rate_func=rate_functions.ease_out_sine)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

    
#####################################
#####################################
TASK_Func_3_1_I_3_q = SophiaTaskDefinition(
    answerOptions=["The result is $0$", "The result is $\infty$","The result is undefined", "The result is $1$"],
    correctAnswerIndex=2,
    questionText="What happens if we plug in $x=0$?"
)
class Func_3_1_I_3_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Functions")

        # Create a notepad with texts
        note = Notepad(texts=[["$x$ gets closer to zero","$\\rightarrow f(x)$ increases quickly"], ["$\\rightarrow$ What will happen,","     if we plug in $x=0$"]], buff=0.3)
        self.add(note)

        # Create the coordinate system
        func = lambda x: 1/x
        cordsOld = self.add_cords([0,4, 1], [0, 4, 1], x_ticks=[1,2,3,4],y_ticks=[1,2,3,4])
        planeOld = cordsOld[0]
        func_plotted_Old = planeOld.plot(func, color=RED, x_range=[1/4, 4, 0.01], use_smoothing=False).reverse_points()
        self.add(func_plotted_Old, cordsOld)


        cords = self.add_cords([0,1, 0.2], [0, 10, 2], x_ticks=[0.2*(x+1) for x in range(5)],y_ticks=[2,4,6,8,10], x_labels=[*[np.round(0.2*(x+1),1) for x in range(4)],'1'],)
        plane = cords[0]
        func_plotted = plane.plot(func, color=RED, x_range=[0.001, 1, 0.001], use_smoothing=False).reverse_points()

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])
        self.add(cursor)

        func_ex = MathTex("f(x) = \\tfrac 1x", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=0.4)
        self.add(func_ex)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so <bookmark mark="closerTo0"/> we've seen that <bookmark mark="note1"/> as x gets closer to zero, the values for f of x get larger and larger.
                
                <bookmark mark="cordsAway"/> Now, let's take a closer look at the behavior of f for small values of x.
                
                We've already seen that <bookmark mark="f1"/> f of one is equal to one, that <bookmark mark="f2"/> f of one half is equal
                to 2, and that <bookmark mark="f4"/> f of one quarter is equal to 4.
                
                If we now plug in <bookmark mark="f10"/> f of one tenth, we get 10, and if we plug in <bookmark mark="f20"/> f of one twentieth,
                we get 20.
                
                This doesn't even fit on the screen anymore, but when you <bookmark mark="func"/> connect the points, you can see that the values are still getting larger, and that they're getting
                larger fast.
                
                So we know, that the value of f of x increases, as x gets closer to zero.
                
                Now, <bookmark mark="note2"/> what will happen, if we plug x equals zero into our function?
                """
        ) as tracker:
            
            self.wait_until_bookmark("closerTo0")
            cursor.blinking=False
            x,y,_ = planeOld.c2p(4,1/4)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(MoveAlongPath(cursor, func_plotted_Old), run_time=5)
            cursor.blinking=True

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("cordsAway")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,0)
            self.play(cordsOld.animate(run_time=0.5).shift(RIGHT*5), func_plotted_Old.animate(run_time=0.5).shift(RIGHT*5), Write(cords), CursorMoveTo(cursor,x,y))
            cursor.blinking=True

            self.wait_until_bookmark("f1")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            circ1 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(circ1)

            self.wait_until_bookmark("f2")
            x,y,_ = plane.c2p(0.5,2)
            circHalf = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(circHalf)

            self.wait_until_bookmark("f4")
            x,y,_ = plane.c2p(0.25,4)
            circQuarter = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(circQuarter)

            self.wait_until_bookmark("f10")
            x,y,_ = plane.c2p(0.1,10)
            circTenth = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circTenth))

            self.wait_until_bookmark("f20")
            x,y,_ = plane.c2p(0.05,20)
            circTwentieth = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=2)
            self.play(Write(circTwentieth))

            self.wait_until_bookmark("func")
            self.play(Write(func_plotted))
            self.play(Unwrite(circ1), Unwrite(circHalf), Unwrite(circQuarter), Unwrite(circTenth), Unwrite(circTwentieth))

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_1_I_3_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Watch out!")

        warningsign = ImageMobject(assets_folder / "img" / "warningsign.png").move_to([-5,1,0])
        warningsign = warningsign.scale(3.8/warningsign.get_width())

        # Create a notepad with texts
        note = Notepad(texts=[["Plug in $x=0$", "$\\rightarrow$We get $f(0)=\\frac10$"], ["It's not possible to divide by $0$","$\\rightarrow f(0)$ is undefined"]], buff=0.3)
        self.add(note)



        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        # cursor.move_to([xo, yo, 0])
        # self.add(cursor)

        func = MathTex("f(x) = \\tfrac 1x", color=c1t, font_size=fs1)
        func_0 = MathTex("f(0) = \\tfrac 10", color=c1t, font_size=fs1)
        cross_0 = Cross(color=RED)
        zero = Group(func_0, cross_0)

        f = lambda x: 1/x
        cords = self.add_cords([0,4, 1], [0, 4, 1], x_ticks=[1,2,3,4],y_ticks=[1,2,3,4])
        plane = cords[0]
        func_plotted = plane.plot(f, color=RED, x_range=[1/4, 4, 0.01], use_smoothing=False).reverse_points()

        # Action Sequence
        with self.voiceover(
                text="""
                <bookmark mark="warning"/>
                Careful!!!
                
                Remember, our function is defined as <bookmark mark="func"/> f of x equals one over x.
                If we were to <bookmark mark="note1"/> plug x equals zero into our function, the expression would be
                <bookmark mark="f0"/> f of zero equals one over zero.
                
                But it's <bookmark mark="cross"/> not possible to divide by zero, so the result of one over zero is undefined.
                
                This means, that <bookmark mark="domain"/> we're not allowed to plug x equals zero into our function!
                
                So, just to recap: the function f of x equals one over x is defined for all x except zero.
                
                <bookmark mark="cords"/>
                As the values of x get closer to zero, the values of f of x get bigger and bigger.
                
                But we can't plug x equals zero into our function.
                
                The point x equals zero is also called a singularity.
                """
        ) as tracker:
            
            self.wait_until_bookmark("warning")
            self.play(warningsign.animate.shift(RIGHT*5), run_time=0.4)
            self.wait(0.8)
            self.play(warningsign.animate.shift(RIGHT*5), run_time=0.4)

            self.wait_until_bookmark("func")
            self.play(Write(func))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("f0")
            self.play(ReplacementTransform(func, func_0))

            self.wait_until_bookmark("cross")
            note.change_colors([0,1])
            self.play(Write(cross_0), run_time=4)

            self.wait_until_bookmark("domain")
            self.play(zero.animate.shift(UP*1.5), run_time=0.5)
            warning1 = Tex("Only defined for values", color=c1t, font_size=fs2)
            warning2 = MathTex("x\\neq0", color=c1t, font_size=fs2).next_to(warning1, DOWN, buff=0.1)
            warning = VGroup(warning1, warning2).arrange(DOWN).next_to(zero, DOWN, buff=0.4)
            self.play(Write(warning), run_time=0.8)

            self.wait_until_bookmark("cords")
            anims = [Write(cords), warning1.animate.shift(DOWN*0.55), warning2.animate.shift(DOWN*0.35), zero.animate.shift(5*RIGHT)]
            self.play(*anims, run_time=1)
            self.play(Write(func_plotted, rate_func=rate_functions.ease_out_sine), run_time=9)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_1_I_3_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Watch out!")

        warningsign = ImageMobject(assets_folder / "img" / "warningsign.png").move_to([-5,1,0])
        warningsign = warningsign.scale(3.8/warningsign.get_width())

        # Create a notepad with texts
        note = Notepad(texts=[["Plug in $x=0$", "$\\rightarrow$We get $f(0)=\\frac10$"], ["It's not possible to divide by $0$","$\\rightarrow f(0)$ is undefined"]], buff=0.3)
        self.add(note)



        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        # cursor.move_to([xo, yo, 0])
        # self.add(cursor)

        func = MathTex("f(x) = \\tfrac 1x", color=c1t, font_size=fs1)
        func_0 = MathTex("f(0) = \\tfrac 10", color=c1t, font_size=fs1)
        cross_0 = Cross(color=RED)
        zero = Group(func_0, cross_0)

        f = lambda x: 1/x
        cords = self.add_cords([0,4, 1], [0, 4, 1], x_ticks=[1,2,3,4],y_ticks=[1,2,3,4])
        plane = cords[0]
        func_plotted = plane.plot(f, color=RED, x_range=[1/4, 4, 0.01], use_smoothing=False).reverse_points()

        # Action Sequence
        with self.voiceover(
                text="""
                <bookmark mark="warning"/>
                Careful!!!
                
                Remember, our function is defined as <bookmark mark="func"/> f of x equals one over x.
                If we were to <bookmark mark="note1"/> plug x equals zero into our function, the expression would be
                <bookmark mark="f0"/> f of zero equals one over zero.
                
                But it's <bookmark mark="cross"/> not possible to divide by zero, so the result of one over zero is undefined.
                
                This means, that <bookmark mark="domain"/> we're not allowed to plug x equals zero into our function!
                
                So, just to recap: the function f of x equals one over x is defined for all x except zero.
                
                <bookmark mark="cords"/>
                As the values of x get closer to zero, the values of f of x get bigger and bigger.
                
                But we can't plug x equals zero into our function.
                
                The point x equals zero is also called a singularity.
                """
        ) as tracker:
            
            self.wait_until_bookmark("warning")
            self.play(warningsign.animate.shift(RIGHT*5), run_time=0.4)
            self.wait(0.8)
            self.play(warningsign.animate.shift(RIGHT*5), run_time=0.4)

            self.wait_until_bookmark("func")
            self.play(Write(func))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("f0")
            self.play(ReplacementTransform(func, func_0))

            self.wait_until_bookmark("cross")
            note.change_colors([0,1])
            self.play(Write(cross_0), run_time=4)

            self.wait_until_bookmark("domain")
            self.play(zero.animate.shift(UP*1.5), run_time=0.5)
            warning1 = Tex("Only defined for values", color=c1t, font_size=fs2)
            warning2 = MathTex("x\\neq0", color=c1t, font_size=fs2).next_to(warning1, DOWN, buff=0.1)
            warning = VGroup(warning1, warning2).arrange(DOWN).next_to(zero, DOWN, buff=0.4)
            self.play(Write(warning), run_time=0.8)

            self.wait_until_bookmark("cords")
            anims = [Write(cords), warning1.animate.shift(DOWN*0.55), warning2.animate.shift(DOWN*0.35), zero.animate.shift(5*RIGHT)]
            self.play(*anims, run_time=1)
            self.play(Write(func_plotted, rate_func=rate_functions.ease_out_sine), run_time=9)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_1_I_3_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Watch out!")

        warningsign = ImageMobject(assets_folder / "img" / "warningsign.png").move_to([-5,1,0])
        warningsign = warningsign.scale(3.8/warningsign.get_width())

        # Create a notepad with texts
        note = Notepad(texts=[["Plug in $x=0$", "$\\rightarrow$We get $f(0)=\\frac10$"], ["It's not possible to divide by $0$","$\\rightarrow f(0)$ is undefined"]], buff=0.3)
        self.add(note)



        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        # cursor.move_to([xo, yo, 0])
        # self.add(cursor)

        func = MathTex("f(x) = \\tfrac 1x", color=c1t, font_size=fs1)
        func_0 = MathTex("f(0) = \\tfrac 10", color=c1t, font_size=fs1)
        cross_0 = Cross(color=RED)
        zero = Group(func_0, cross_0)

        f = lambda x: 1/x
        cords = self.add_cords([0,4, 1], [0, 4, 1], x_ticks=[1,2,3,4],y_ticks=[1,2,3,4])
        plane = cords[0]
        func_plotted = plane.plot(f, color=RED, x_range=[1/4, 4, 0.01], use_smoothing=False).reverse_points()

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's right. We have to be
                <bookmark mark="warning"/>
                careful here!
                
                Remember, our function is defined as <bookmark mark="func"/> f of x equals one over x.
                If we were to <bookmark mark="note1"/> plug x equals zero into our function, the expression would be
                <bookmark mark="f0"/> f of zero equals one over zero.
                
                But it's <bookmark mark="cross"/> not possible to divide by zero, so the result of one over zero is undefined.
                
                This means, that <bookmark mark="domain"/> we're not allowed to plug x equals zero into our function!
                
                So, just to recap: the function f of x equals one over x is defined for all x except zero.
                
                <bookmark mark="cords"/>
                As the values of x get closer to zero, the values of f of x get bigger and bigger.
                
                But we can't plug x equals zero into our function.
                
                The point x equals zero is also called a singularity.
                """
        ) as tracker:
            
            self.wait_until_bookmark("warning")
            self.play(warningsign.animate.shift(RIGHT*5), run_time=0.4)
            self.wait(0.8)
            self.play(warningsign.animate.shift(RIGHT*5), run_time=0.4)

            self.wait_until_bookmark("func")
            self.play(Write(func))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("f0")
            self.play(ReplacementTransform(func, func_0))

            self.wait_until_bookmark("cross")
            note.change_colors([0,1])
            self.play(Write(cross_0), run_time=4)

            self.wait_until_bookmark("domain")
            self.play(zero.animate.shift(UP*1.5), run_time=0.5)
            warning1 = Tex("Only defined for values", color=c1t, font_size=fs2)
            warning2 = MathTex("x\\neq0", color=c1t, font_size=fs2).next_to(warning1, DOWN, buff=0.1)
            warning = VGroup(warning1, warning2).arrange(DOWN).next_to(zero, DOWN, buff=0.4)
            self.play(Write(warning), run_time=0.8)

            self.wait_until_bookmark("cords")
            anims = [Write(cords), warning1.animate.shift(DOWN*0.55), warning2.animate.shift(DOWN*0.35), zero.animate.shift(5*RIGHT)]
            self.play(*anims, run_time=1)
            self.play(Write(func_plotted, rate_func=rate_functions.ease_out_sine), run_time=9)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_1_I_3_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Watch out!")

        warningsign = ImageMobject(assets_folder / "img" / "warningsign.png").move_to([-5,1,0])
        warningsign = warningsign.scale(3.8/warningsign.get_width())

        # Create a notepad with texts
        note = Notepad(texts=[["Plug in $x=0$", "$\\rightarrow$We get $f(0)=\\frac10$"], ["It's not possible to divide by $0$","$\\rightarrow f(0)$ is undefined"]], buff=0.3)
        self.add(note)



        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        # cursor.move_to([xo, yo, 0])
        # self.add(cursor)

        func = MathTex("f(x) = \\tfrac 1x", color=c1t, font_size=fs1)
        func_0 = MathTex("f(0) = \\tfrac 10", color=c1t, font_size=fs1)
        cross_0 = Cross(color=RED)
        zero = Group(func_0, cross_0)

        f = lambda x: 1/x
        cords = self.add_cords([0,4, 1], [0, 4, 1], x_ticks=[1,2,3,4],y_ticks=[1,2,3,4])
        plane = cords[0]
        func_plotted = plane.plot(f, color=RED, x_range=[1/4, 4, 0.01], use_smoothing=False).reverse_points()

        # Action Sequence
        with self.voiceover(
                text="""
                <bookmark mark="warning"/>
                Careful!!!
                
                Remember, our function is defined as <bookmark mark="func"/> f of x equals one over x.
                If we were to <bookmark mark="note1"/> plug x equals zero into our function, the expression would be
                <bookmark mark="f0"/> f of zero equals one over zero.
                
                But it's <bookmark mark="cross"/> not possible to divide by zero, so the result of one over zero is undefined.
                
                This means, that <bookmark mark="domain"/> we're not allowed to plug x equals zero into our function!
                
                So, just to recap: the function f of x equals one over x is defined for all x except zero.
                
                <bookmark mark="cords"/>
                As the values of x get closer to zero, the values of f of x get bigger and bigger.
                
                But we can't plug x equals zero into our function.
                
                The point x equals zero is also called a singularity.
                """
        ) as tracker:
            
            self.wait_until_bookmark("warning")
            self.play(warningsign.animate.shift(RIGHT*5), run_time=0.4)
            self.wait(0.8)
            self.play(warningsign.animate.shift(RIGHT*5), run_time=0.4)

            self.wait_until_bookmark("func")
            self.play(Write(func))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("f0")
            self.play(ReplacementTransform(func, func_0))

            self.wait_until_bookmark("cross")
            note.change_colors([0,1])
            self.play(Write(cross_0), run_time=4)

            self.wait_until_bookmark("domain")
            self.play(zero.animate.shift(UP*1.5), run_time=0.5)
            warning1 = Tex("Only defined for values", color=c1t, font_size=fs2)
            warning2 = MathTex("x\\neq0", color=c1t, font_size=fs2).next_to(warning1, DOWN, buff=0.1)
            warning = VGroup(warning1, warning2).arrange(DOWN).next_to(zero, DOWN, buff=0.4)
            self.play(Write(warning), run_time=0.8)

            self.wait_until_bookmark("cords")
            anims = [Write(cords), warning1.animate.shift(DOWN*0.55), warning2.animate.shift(DOWN*0.35), zero.animate.shift(5*RIGHT)]
            self.play(*anims, run_time=1)
            self.play(Write(func_plotted, rate_func=rate_functions.ease_out_sine), run_time=9)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_3_1_I_4_q = SophiaTaskDefinition(
    answerOptions=["$x=0$", "There is no singularity","$x=2$", "$x=-2$"],
    correctAnswerIndex=2,
    questionText="What is the point of the singularity of $g$?"
)
class Func_3_1_I_4_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Singularities")

        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        # cursor.move_to([xo, yo, 0])
        # self.add(cursor)

        f = MathTex("f(x) = \\tfrac 1x", color=c1t, font_size=fs1)
        f0 = MathTex("f(0) = \\tfrac 10", color=c1t, font_size=fs1)
        f_f = f.copy()
        f1 = Tex("Not defined for $x=0$", color=c1t, font_size=fs2)
        f2 = Tex("$\\rightarrow$ Singularity at $x=0$", color=c1t, font_size=fs2)
        f12 = VGroup(f1, f2).arrange(DOWN, aligned_edge=RIGHT, buff=0.2).next_to(f, DOWN, buff=0.2)
        g = MathTex("g(x) = \\tfrac 2{x+2}", color=RED, font_size=fs1).shift(DOWN*0.6)

        # Action Sequence
        with self.voiceover(
                text="""
                Remember, for the <bookmark mark="f"/> function f of x equals one over x, <bookmark mark="f1"/> we're not allowed to plug x equals zero into our function.
                This is because we cannot divide by zero, and if we were to plug <bookmark mark="f0"/> x equals zero into our function, the expression would be one over zero.
                
                We called the point x equals <bookmark mark="f2"/> zero a singularity, because our function is undefined at this point.
                
                Now, <bookmark mark="shift"/> consider the function <bookmark mark="g"/> g of x equals two divided by x+2.
                
                Does it also have a singularity? That means: is there a point x for which the function g is undefined?
                
                And if such a point exists, what is it?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            self.play(Write(f))

            self.wait_until_bookmark("f1")
            self.play(Write(f1))

            self.wait_until_bookmark("f0")
            self.play(ReplacementTransform(f, f0))

            self.wait_until_bookmark("f2")
            self.play(Write(f2), ReplacementTransform(f0, f_f),run_time=0.6)

            self.wait_until_bookmark("shift")
            self.play(f_f.animate.shift(1.5*UP), f12.animate.shift(1.5*UP), run_time=0.6)

            self.wait_until_bookmark("g")
            self.play(Write(g), run_time=0.6)
            

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_1_I_4_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Singularities")

        cursor = AltCursor(blinking=False, stroke_width=0)
        cursor.autoFadeBackground = True
        # cursor.move_to([xo, yo, 0])
        # self.add(cursor)

        
        S1 = Tex("Singularity at $x$", color=c1t, font_size=fs2).next_to(title, DOWN, buff=2)
        S2 = Tex("$\\Leftrightarrow$", color=c1t, font_size=fs2).next_to(S1, DOWN, buff=0.2)
        S3a = Tex("Plugging in $x$ leads to", color=c1t, font_size=fs2)
        S3b = Tex("division by zero", color=c1t, font_size=fs2)
        S3 = VGroup(S3a, S3b).arrange(DOWN, buff=0.1).next_to(S2, DOWN, buff=0.2)
        S = VGroup(S1, S2, S3)

        g = MathTex("g","(x)", "=", "\\tfrac 2{x+2}", color=c1t, font_size=fs1).next_to(title, DOWN, buff=2)

        step1 = MathTex("x+2", "=", "0", color=c1t, font_size=fs1).next_to(g, DOWN, buff=1.5)
        step2 = MathTex("\\Downarrow", color=c1t, font_size=fs1).next_to(step1, DOWN, buff=0.5)
        step3 = MathTex("x", "=", "-2", color=c1t, font_size=fs1).next_to(step2, DOWN, buff=0.5)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right...
                
                There's a <bookmark mark="singularity"/> singularity at x, <bookmark mark="whenever"/> whenever plugging in x would lead to dividing by zero, which as we know is not allowed.
                
                So, <bookmark mark="out"/> looking at <bookmark mark="g"/> g of x equals two over x plus two, we can already suspect, <bookmark mark="cursor"/> that there will be a singularity,
                because <bookmark mark="denom1"/> we're dividing by a sum involving x.
                
                To now find the value of x, where <bookmark mark="c2g"/>  g has a singularity, we must find the value of x for which the denominator is zero.
                
                This means, finding the value for which <bookmark mark="step1"/> x plus two equals zero. Clearly, this value is <bookmark mark="step23"/> x equals negative two.
                
                <bookmark mark="moveUp"/>
                This is how we find out, that g <bookmark mark="final"/> has a singularity at x equals negative two.
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("singularity")
            self.play(Write(S1), run_time=1)

            self.wait_until_bookmark("whenever")
            self.play(Write(S2), Write(S3a), Write(S3b), run_time=1)

            self.wait_until_bookmark("out")
            self.play(S.animate(run_time=0.5).shift(5*RIGHT))

            self.wait_until_bookmark("g")
            self.play(Write(g), run_time=1)

            self.wait_until_bookmark("cursor")
            self.play(Write(cursor))

            self.wait_until_bookmark("denom1")
            cursor.blinking=False
            x,y,_ = g[3].get_bottom()+0.3*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("c2g")
            cursor.blinking=False
            x,y,_ = g[0].get_bottom()+0.3*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("step1")
            cursor.blinking=False
            x,y,_ = step1[0].get_left()+0.4*LEFT
            self.play(Write(step1), CursorMoveTo(cursor,x,y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("step23")
            cursor.blinking=False
            x,y,_ = step3[0].get_left()+0.4*LEFT
            self.play(Write(step2), Write(step3), CursorMoveTo(cursor,x,y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("moveUp")
            self.play(g.animate.shift(UP/2), Unwrite(step1), Unwrite(step2), step3.animate.shift(2.8*UP), run_time=1)

            self.wait_until_bookmark("final")
            center = (g.get_center()+step3.get_center())/2
            explainer = Tex("has a singularity at", color=c1t, font_size=fs2).move_to(center)
            self.play(Write(explainer), run_time=1)
            

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_1_I_4_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Singularities")

        cursor = AltCursor(blinking=False, stroke_width=0)
        cursor.autoFadeBackground = True
        # cursor.move_to([xo, yo, 0])
        # self.add(cursor)

        
        S1 = Tex("Singularity at $x$", color=c1t, font_size=fs2).next_to(title, DOWN, buff=2)
        S2 = Tex("$\\Leftrightarrow$", color=c1t, font_size=fs2).next_to(S1, DOWN, buff=0.2)
        S3a = Tex("Plugging in $x$ leads to", color=c1t, font_size=fs2)
        S3b = Tex("division by zero", color=c1t, font_size=fs2)
        S3 = VGroup(S3a, S3b).arrange(DOWN, buff=0.1).next_to(S2, DOWN, buff=0.2)
        S = VGroup(S1, S2, S3)

        g = MathTex("g","(x)", "=", "\\tfrac 2{x+2}", color=c1t, font_size=fs1).next_to(title, DOWN, buff=2)

        step1 = MathTex("x+2", "=", "0", color=c1t, font_size=fs1).next_to(g, DOWN, buff=1.5)
        step2 = MathTex("\\Downarrow", color=c1t, font_size=fs1).next_to(step1, DOWN, buff=0.5)
        step3 = MathTex("x", "=", "-2", color=c1t, font_size=fs1).next_to(step2, DOWN, buff=0.5)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right...
                
                There's a <bookmark mark="singularity"/> singularity at x, <bookmark mark="whenever"/> whenever plugging in x would lead to dividing by zero, which as we know is not allowed.
                
                So, <bookmark mark="out"/> looking at <bookmark mark="g"/> g of x equals two over x plus two, we can already suspect, <bookmark mark="cursor"/> that there will be a singularity,
                because <bookmark mark="denom1"/> we're dividing by a sum involving x.
                
                To now find the value of x, where <bookmark mark="c2g"/>  g has a singularity, we must find the value of x for which the denominator is zero.
                
                This means, finding the value for which <bookmark mark="step1"/> x plus two equals zero. Clearly, this value is <bookmark mark="step23"/> x equals negative two.
                
                <bookmark mark="moveUp"/>
                This is how we find out, that g <bookmark mark="final"/> has a singularity at x equals negative two.
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("singularity")
            self.play(Write(S1), run_time=1)

            self.wait_until_bookmark("whenever")
            self.play(Write(S2), Write(S3a), Write(S3b), run_time=1)

            self.wait_until_bookmark("out")
            self.play(S.animate(run_time=0.5).shift(5*RIGHT))

            self.wait_until_bookmark("g")
            self.play(Write(g), run_time=1)

            self.wait_until_bookmark("cursor")
            self.play(Write(cursor))

            self.wait_until_bookmark("denom1")
            cursor.blinking=False
            x,y,_ = g[3].get_bottom()+0.3*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("c2g")
            cursor.blinking=False
            x,y,_ = g[0].get_bottom()+0.3*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("step1")
            cursor.blinking=False
            x,y,_ = step1[0].get_left()+0.4*LEFT
            self.play(Write(step1), CursorMoveTo(cursor,x,y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("step23")
            cursor.blinking=False
            x,y,_ = step3[0].get_left()+0.4*LEFT
            self.play(Write(step2), Write(step3), CursorMoveTo(cursor,x,y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("moveUp")
            self.play(g.animate.shift(UP/2), Unwrite(step1), Unwrite(step2), step3.animate.shift(2.8*UP), run_time=1)

            self.wait_until_bookmark("final")
            center = (g.get_center()+step3.get_center())/2
            explainer = Tex("has a singularity at", color=c1t, font_size=fs2).move_to(center)
            self.play(Write(explainer), run_time=1)
            

        # Wait for 4 seconds at the end of the animation
        self.wait(4)



class Func_3_1_I_4_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Singularities")

        cursor = AltCursor(blinking=False, stroke_width=0)
        cursor.autoFadeBackground = True
        # cursor.move_to([xo, yo, 0])
        # self.add(cursor)

        
        S1 = Tex("Singularity at $x$", color=c1t, font_size=fs2).next_to(title, DOWN, buff=2)
        S2 = Tex("$\\Leftrightarrow$", color=c1t, font_size=fs2).next_to(S1, DOWN, buff=0.2)
        S3a = Tex("Plugging in $x$ leads to", color=c1t, font_size=fs2)
        S3b = Tex("division by zero", color=c1t, font_size=fs2)
        S3 = VGroup(S3a, S3b).arrange(DOWN, buff=0.1).next_to(S2, DOWN, buff=0.2)
        S = VGroup(S1, S2, S3)

        g = MathTex("g","(x)", "=", "\\tfrac 2{x+2}", color=c1t, font_size=fs1).next_to(title, DOWN, buff=2)

        step1 = MathTex("x+2", "=", "0", color=c1t, font_size=fs1).next_to(g, DOWN, buff=1.5)
        step2 = MathTex("\\Downarrow", color=c1t, font_size=fs1).next_to(step1, DOWN, buff=0.5)
        step3 = MathTex("x", "=", "-2", color=c1t, font_size=fs1).next_to(step2, DOWN, buff=0.5)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right...
                
                There's a <bookmark mark="singularity"/> singularity at x, <bookmark mark="whenever"/> whenever plugging in x would lead to dividing by zero, which as we know is not allowed.
                
                So, <bookmark mark="out"/> looking at <bookmark mark="g"/> g of x equals two over x plus two, we can already suspect, <bookmark mark="cursor"/> that there will be a singularity,
                because <bookmark mark="denom1"/> we're dividing by a sum involving x.
                
                To now find the value of x, where <bookmark mark="c2g"/>  g has a singularity, we must find the value of x for which the denominator is zero.
                
                This means, finding the value for which <bookmark mark="step1"/> x plus two equals zero. Clearly, this value is <bookmark mark="step23"/> x equals negative two.
                
                <bookmark mark="moveUp"/>
                This is how we find out, that g <bookmark mark="final"/> has a singularity at x equals negative two.
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("singularity")
            self.play(Write(S1), run_time=1)

            self.wait_until_bookmark("whenever")
            self.play(Write(S2), Write(S3a), Write(S3b), run_time=1)

            self.wait_until_bookmark("out")
            self.play(S.animate(run_time=0.5).shift(5*RIGHT))

            self.wait_until_bookmark("g")
            self.play(Write(g), run_time=1)

            self.wait_until_bookmark("cursor")
            self.play(Write(cursor))

            self.wait_until_bookmark("denom1")
            cursor.blinking=False
            x,y,_ = g[3].get_bottom()+0.3*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("c2g")
            cursor.blinking=False
            x,y,_ = g[0].get_bottom()+0.3*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("step1")
            cursor.blinking=False
            x,y,_ = step1[0].get_left()+0.4*LEFT
            self.play(Write(step1), CursorMoveTo(cursor,x,y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("step23")
            cursor.blinking=False
            x,y,_ = step3[0].get_left()+0.4*LEFT
            self.play(Write(step2), Write(step3), CursorMoveTo(cursor,x,y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("moveUp")
            self.play(g.animate.shift(UP/2), Unwrite(step1), Unwrite(step2), step3.animate.shift(2.8*UP), run_time=1)

            self.wait_until_bookmark("final")
            center = (g.get_center()+step3.get_center())/2
            explainer = Tex("has a singularity at", color=c1t, font_size=fs2).move_to(center)
            self.play(Write(explainer), run_time=1)
            

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_1_I_4_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Singularities")

        cursor = AltCursor(blinking=False, stroke_width=0)
        cursor.autoFadeBackground = True
        # cursor.move_to([xo, yo, 0])
        # self.add(cursor)

        
        S1 = Tex("Singularity at $x$", color=c1t, font_size=fs2).next_to(title, DOWN, buff=2)
        S2 = Tex("$\\Leftrightarrow$", color=c1t, font_size=fs2).next_to(S1, DOWN, buff=0.2)
        S3a = Tex("Plugging in $x$ leads to", color=c1t, font_size=fs2)
        S3b = Tex("division by zero", color=c1t, font_size=fs2)
        S3 = VGroup(S3a, S3b).arrange(DOWN, buff=0.1).next_to(S2, DOWN, buff=0.2)
        S = VGroup(S1, S2, S3)

        g = MathTex("g","(x)", "=", "\\tfrac 2{x+2}", color=c1t, font_size=fs1).next_to(title, DOWN, buff=2)

        step1 = MathTex("x+2", "=", "0", color=c1t, font_size=fs1).next_to(g, DOWN, buff=1.5)
        step2 = MathTex("\\Downarrow", color=c1t, font_size=fs1).next_to(step1, DOWN, buff=0.5)
        step3 = MathTex("x", "=", "-2", color=c1t, font_size=fs1).next_to(step2, DOWN, buff=0.5)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, you got it!
                There's a <bookmark mark="singularity"/> singularity at x, <bookmark mark="whenever"/> whenever plugging in x would lead to dividing by zero, which as we know is not allowed.
                
                So, <bookmark mark="out"/> looking at <bookmark mark="g"/> g of x equals two over x plus two, we can already suspect, <bookmark mark="cursor"/> that there will be a singularity,
                because <bookmark mark="denom1"/> we're dividing by a sum involving x.
                
                To now find the value of x, where <bookmark mark="c2g"/>  g has a singularity, we must find the value of x for which the denominator is zero.
                
                This means, finding the value for which <bookmark mark="step1"/> x plus two equals zero. Clearly, this value is <bookmark mark="step23"/> x equals negative two.
                
                <bookmark mark="moveUp"/>
                This is how we find out, that g <bookmark mark="final"/> has a singularity at x equals negative two.
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("singularity")
            self.play(Write(S1), run_time=1)

            self.wait_until_bookmark("whenever")
            self.play(Write(S2), Write(S3a), Write(S3b), run_time=1)

            self.wait_until_bookmark("out")
            self.play(S.animate(run_time=0.5).shift(5*RIGHT))

            self.wait_until_bookmark("g")
            self.play(Write(g), run_time=1)

            self.wait_until_bookmark("cursor")
            self.play(Write(cursor))

            self.wait_until_bookmark("denom1")
            cursor.blinking=False
            x,y,_ = g[3].get_bottom()+0.3*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("c2g")
            cursor.blinking=False
            x,y,_ = g[0].get_bottom()+0.3*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("step1")
            cursor.blinking=False
            x,y,_ = step1[0].get_left()+0.4*LEFT
            self.play(Write(step1), CursorMoveTo(cursor,x,y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("step23")
            cursor.blinking=False
            x,y,_ = step3[0].get_left()+0.4*LEFT
            self.play(Write(step2), Write(step3), CursorMoveTo(cursor,x,y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("moveUp")
            self.play(g.animate.shift(UP/2), Unwrite(step1), Unwrite(step2), step3.animate.shift(2.8*UP), run_time=1)

            self.wait_until_bookmark("final")
            center = (g.get_center()+step3.get_center())/2
            explainer = Tex("has a singularity at", color=c1t, font_size=fs2).move_to(center)
            self.play(Write(explainer), run_time=1)
            

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
class Func_3_1_I_5(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("1/x for large x")

       
        cords = self.add_cords([0,4, 1], [0, 4, 1], x_ticks=[1,2,3,4],y_ticks=[1,2,3,4])
        plane = cords[0]

        newCords = self.add_cords([0,100, 20], [0, 1, 1/4], x_ticks=[20,40,60,80],y_ticks=[0,0.25, 0.5, 0.75,1])
        newPlane = newCords[0]

        cursor = AltCursor(stroke_width=0.0, blinking=False)
        cursor.autoFadeBackground = True
        x,y,_ = plane.c2p(0,0)
        cursor.move_to([x,y,0])

        f = MathTex("f(x) = \\tfrac 1x", color=c1t, font_size=fs1)
        f1 = MathTex("f(1) = 1", color=c1t, font_size=fs1).move_to(1.5*DOWN)
        f2 = MathTex("f(2) = 0.5", color=c1t, font_size=fs1).move_to(f1)
        f10 = MathTex("f(10) = 0.1", color=c1t, font_size=fs1).move_to(f1)
        f50 = MathTex("f(50) = 0.02", color=c1t, font_size=fs1).move_to(f1)
        f100 = MathTex("f(100) = 0.01", color=c1t, font_size=fs1).move_to(f1)
        func = lambda x: 1/x
        f_plotted = plane.plot(func, color=RED, x_range=[1/4, 4, 0.01], use_smoothing=False).reverse_points()
        fNewPlotted = newPlane.plot(func, color=RED, x_range=[1, 100, 0.01], use_smoothing=False)

        circs = VGroup()


        # Action Sequence
        with self.voiceover(
                text="""
                Ok, now let's return to our function <bookmark mark="f"/>f of x equals one over x.
                
                We've already seen  what happens to this function, <bookmark mark="f0"/>when we plug in values that get closer and closer to zero:
                <bookmark mark="f1"/>the function gets larger and larger.
                
                Next, we want to see what happens to the function, if we plug in numbers that are much <bookmark mark="oldCords"/> larger than one.
                
                For this, let's <bookmark mark="newCords"/> look at values of x up to one hundred.
                
                So we've already plugged in the value  <bookmark mark="fOf1"/> f of one, which is one over one, so one.
                
                If we plug in the value two, we get <bookmark mark="fOf2"/> f of two equals one divided by two, which is one half, or zero point five.
                
                Next, let's plug in the value ten. We get <bookmark mark="fOf10"/> f of ten equals one divided by ten,
                which is one tenth, or zero point 1.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            self.play(Write(f), run_time=1)

            self.wait_until_bookmark("f0")
            self.play(f.animate.shift(DOWN*1.5), run_time=1)
            self.play(Write(cords), run_time=1)

            self.wait_until_bookmark("f1")
            self.play(Write(f_plotted), run_time=12, rate_func=rate_functions.ease_out_sine)

            self.wait_until_bookmark("oldCords")
            self.play(cords.animate.shift(5*RIGHT), f_plotted.animate.shift(5*RIGHT), run_time=1)

            self.wait_until_bookmark("newCords")
            self.play(Write(newCords), Write(cursor), run_time=1)

            self.wait_until_bookmark("fOf1")
            x,y,_ = newPlane.c2p(1,1)
            fCopy = f.copy()
            self.play(CursorMoveTo(cursor, x, y), ReplacementTransform(f, f1), run_time=1)
            circ = Circle(radius=0.1, color=RED).move_to(cursor.get_center())
            circs.add(circ)
            self.play(Write(circ), run_time=1)
            # self.play(ReplacementTransform(f1, fCopy), run_time=1)
            f = fCopy

            self.wait_until_bookmark("fOf2")
            x,y,_ = newPlane.c2p(2,0.5)
            self.play(CursorMoveTo(cursor, x, y), ReplacementTransform(f1, f2), run_time=1)
            circ = Circle(radius=0.1, color=RED).move_to(cursor.get_center())
            circs.add(circ)
            self.play(Write(circ), run_time=1)
            # self.play(ReplacementTransform(f2, fCopy), run_time=1)
            # f = fCopy

            self.wait_until_bookmark("fOf10")
            x,y,_ = newPlane.c2p(10,0.1)
            self.play(CursorMoveTo(cursor, x, y), ReplacementTransform(f2, f10), run_time=1)
            circ = Circle(radius=0.1, color=RED).move_to(cursor.get_center())
            circs.add(circ)
            self.play(Write(circ), run_time=1)
            # self.play(ReplacementTransform(f10, fCopy), run_time=1)
            # f = fCopy


        with self.voiceover(
                text="""       
                Ok, now let's plug in the value x equals fifty. If we do that, we get <bookmark mark="fOf50"/>  f of fifty equals one divided by fifty,
                which is one fiftieth, or zero point zero two.
                
                And finally, we'll plug in the value one hundred. We get <bookmark mark="fOf100"/> f of one hundred equals one divided by one hundred,
                which is one hundredth, or zero point zero one.
                <bookmark mark="fEnd"/>
                
                Connecting the dots to see the graph of the function, <bookmark mark="plot"/> we can see that the function gets smaller and smaller,
                as we plug in x-values that get larger.
                """
            ) as tracker:

            self.wait_until_bookmark("fOf50")
            x,y,_ = newPlane.c2p(50,0.02)
            self.play(CursorMoveTo(cursor, x, y), ReplacementTransform(f10, f50), run_time=1)
            circ = Circle(radius=0.1, color=RED).move_to(cursor.get_center())
            circs.add(circ)
            self.play(Write(circ), run_time=1)
            # self.play(ReplacementTransform(f50, fCopy), run_time=1)
            # f = fCopy

            self.wait_until_bookmark("fOf100")
            x,y,_ = newPlane.c2p(100,0.01)
            self.play(CursorMoveTo(cursor, x, y), ReplacementTransform(f50, f100), run_time=1)
            circ = Circle(radius=0.1, color=RED).move_to(cursor.get_center())
            circs.add(circ)
            self.play(Write(circ), run_time=1)
            # self.play(ReplacementTransform(f100, fCopy), run_time=1)
            # f = fCopy

            self.wait_until_bookmark("fEnd")
            x,y,_ = newPlane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), ReplacementTransform(f100, fCopy), run_time=1)
            cursor.blinking=True
        
            self.wait_until_bookmark("plot")
            self.play(Write(fNewPlotted), Unwrite(circs, rate_func=rate_functions.ease_out_sine), run_time=3)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_3_1_I_6_q = SophiaTaskDefinition(
    answerOptions=["Yes, $x=0.000001$", "Yes, $x=0.001$","No", "Yes, $x=0.00000001$"],
    correctAnswerIndex=2,
    questionText="Is there a positive number, that is smaller than the smallest value, that $f(x)$ can reach?"
)
class Func_3_1_I_6_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["$\\frac1x$ is positive for $x>0$", "f(x) gets smaller for large values of $x$", ["Is there a positive number, that is smaller than", "the smallest value $f(x)$ can have?"]], buff=0.28)
        self.add(note)

        self.add_title("1/x for large x")

        cords = self.add_cords([0,100, 20], [0, 1, 1/4], x_ticks=[20,40,60,80],y_ticks=[0,0.25, 0.5, 0.75,1])
        plane = cords[0]

        cursor = AltCursor(stroke_width=0.0, blinking=False)
        cursor.autoFadeBackground = True
        x,y,_ = plane.c2p(0,0)
        cursor.move_to([x,y,0])

        f = MathTex("f(x) = \\tfrac 1x", color=c1t, font_size=fs1)
        func = lambda x: 1/x
        f_plotted = plane.plot(func, color=RED, x_range=[1, 100, 0.01], use_smoothing=False)

        circs = VGroup()


        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so we know, <bookmark mark="note1"/> that for the function <bookmark mark="f"/> f of x equals one divided by x, the values don't get <bookmark mark="cords"/> negative for larger x, because one divided by something positive is always positive.
                
                We've also seen, <bookmark mark="note2"/>that <bookmark mark="plot"/> the function values get closer and closer to zero, as we plug in larger and larger x-values.
                
                Now I have a question for you but it's a bit tricky: <bookmark mark="note3"/>Is there a positive number, that is smaller than the smallest value, that f of x can reach?
                
                I mean, is there a positive number, that is smaller than one divided by 100 and smaller than 1 over 1000 and smaller than 1 over ten thousand and so on?
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("f")
            self.play(Write(f), run_time=1)

            self.wait_until_bookmark("cords")
            self.play(Write(cords), f.animate.shift(DOWN*0.6), run_time=1)

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("plot")
            self.play(Write(f_plotted), run_time=12, rate_func=rate_functions.ease_out_sine)

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_1_I_6_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("$\\tfrac1x$ for large $x$", tex=True)

        cords = self.add_cords([0,100, 20], [0, 1, 1/4], x_ticks=[20,40,60,80],y_ticks=[0,0.25, 0.5, 0.75,1])
        plane = cords[0]

        cursor = AltCursor(stroke_width=0.0, blinking=False)
        cursor.autoFadeBackground = True
        x,y,_ = plane.c2p(0,0)
        cursor.move_to([x,y,0])

        f = MathTex("f(x) = \\tfrac 1x", color=c1t, font_size=fs2)
        t1a = Tex("which is smaller than", color=c1t, font_size=fs3).next_to(f, UP)
        t1b = Tex("There is no positive number $a$,", color=c1t, font_size=fs3).next_to(t1a, UP, buff=0.1)
        t2 = Tex("for large positive x.", color=c1t, font_size=fs3).next_to(f, DOWN)
        t1a = t1a.shift(LEFT*(t1a.get_left()[0]-t1b.get_left()[0]))
        t = VGroup(t1b, t1a, t2)
        t2 = t2.shift(LEFT*(t2.get_left()[0]-t1b.get_left()[0]))
        self.add(f)

        s1 = Tex("1. Choose a tiny number $a$", color=RED, font_size=fs3).next_to(f, UP)
        e1 = Tex("Example: $a=0.001$", color=BLUE, font_size=fs3).next_to(f,DOWN)

        s2 = Tex("2. Write $a$ as a fraction", color=RED, font_size=fs3).next_to(f, UP)
        s2 = s2.shift(LEFT*(s2.get_left()[0]-s1.get_left()[0]))
        e2 = Tex("Our example: $a=\\frac{1}{1000}$", color=BLUE, font_size=fs3).next_to(f,DOWN)

        s3 = Tex("3. Double the denominator", color=RED, font_size=fs3).next_to(f, UP)
        s3 = s3.shift(LEFT*(s3.get_left()[0]-s1.get_left()[0]))
        e3 = MathTex("\\hat a=\\frac{1}{2000}","=f(2000)","<a", color=BLUE, font_size=fs3).next_to(f,DOWN)

        pbc = Tex("Proof by contradiction", color=RED, font_size=fs3).next_to(title, DOWN, buff=0.4)

        func = lambda x: 1/x
        f_plotted = plane.plot(func, color=RED, x_range=[1, 100, 0.01], use_smoothing=False)

        t = t.shift(LEFT*5)

        # Action Sequence
        with self.voiceover(
                text="""
                Nope, that's not right. <bookmark mark="preach"/> There is no positive number that is smaller than the smallest value that f of x equals one over x can obtain.
                
                But why? I'll show you using a method that mathematicians call <bookmark mark="pbc"/>proof by contradiction.
                
                First, <bookmark mark="step1"/> think about a super super tiny positive number, and call that number "a".
                <bookmark mark="e1"/> For example, we could pick the number zero point zero zero one.
                
                Second<bookmark mark="step2"/>, write that number as a fraction.
                In our example,<bookmark mark="e2"/> we would write "a" as one over one hundred.
                
                Third<bookmark mark="step3"/>, take the fraction and double the denominator.
                In our example, <bookmark mark="e3"/>we would get "a" hat equal to one over two hundred.
                
                Now, <bookmark mark="meaning"/>let's think about what this means. <bookmark mark="meaningA"/>
                First, note that f of x is equal to that number, if we plug in the value of the doubled denominator for x
                
                <bookmark mark="meaningB"/>We can also see, that the number is a smaller number than "a".
                
                This means, that no matter which positive number we pick, we can always find a value of x, for which f of x is smaller than that number.
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("preach")
            self.play(t.animate.shift(RIGHT*5))

            self.wait_until_bookmark("pbc")
            self.play(Write(pbc))

            self.wait_until_bookmark("step1")
            self.play(t.animate.shift(RIGHT*5), Write(s1), pbc.animate.set_color(BLACK))

            self.wait_until_bookmark("e1")
            self.play(Write(e1))

            self.wait_until_bookmark("step2")
            self.play(s1.animate.set_color(BLACK), s1.animate.next_to(pbc, DOWN, buff=0.2), e1.animate.shift(5*RIGHT), Write(s2))

            self.wait_until_bookmark("e2")
            self.play(Write(e2))

            self.wait_until_bookmark("step3")
            self.play(s2.animate.set_color(BLACK), s2.animate.next_to(s1, DOWN, buff=0.2), e2.animate.shift(5*RIGHT), Write(s3))

            self.wait_until_bookmark("e3")
            self.play(Write(e3[0]))

            self.wait_until_bookmark("meaning")
            self.play(s3.animate.next_to(s2, DOWN, buff=0.2), s3.animate.set_color(BLACK))

            self.wait_until_bookmark("meaningA")
            self.play(Write(e3[1]))

            self.wait_until_bookmark("meaningB")
            self.play(Write(e3[2]))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_1_I_6_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("$\\tfrac1x$ for large $x$", tex=True)

        cords = self.add_cords([0,100, 20], [0, 1, 1/4], x_ticks=[20,40,60,80],y_ticks=[0,0.25, 0.5, 0.75,1])
        plane = cords[0]

        cursor = AltCursor(stroke_width=0.0, blinking=False)
        cursor.autoFadeBackground = True
        x,y,_ = plane.c2p(0,0)
        cursor.move_to([x,y,0])

        f = MathTex("f(x) = \\tfrac 1x", color=c1t, font_size=fs2)
        t1a = Tex("which is smaller than", color=c1t, font_size=fs3).next_to(f, UP)
        t1b = Tex("There is no positive number $a$,", color=c1t, font_size=fs3).next_to(t1a, UP, buff=0.1)
        t2 = Tex("for large positive x.", color=c1t, font_size=fs3).next_to(f, DOWN)
        t1a = t1a.shift(LEFT*(t1a.get_left()[0]-t1b.get_left()[0]))
        t = VGroup(t1b, t1a, t2)
        t2 = t2.shift(LEFT*(t2.get_left()[0]-t1b.get_left()[0]))
        self.add(f)

        s1 = Tex("1. Choose a tiny number $a$", color=RED, font_size=fs3).next_to(f, UP)
        e1 = Tex("Example: $a=0.001$", color=BLUE, font_size=fs3).next_to(f,DOWN)

        s2 = Tex("2. Write $a$ as a fraction", color=RED, font_size=fs3).next_to(f, UP)
        s2 = s2.shift(LEFT*(s2.get_left()[0]-s1.get_left()[0]))
        e2 = Tex("Our example: $a=\\frac{1}{1000}$", color=BLUE, font_size=fs3).next_to(f,DOWN)

        s3 = Tex("3. Double the denominator", color=RED, font_size=fs3).next_to(f, UP)
        s3 = s3.shift(LEFT*(s3.get_left()[0]-s1.get_left()[0]))
        e3 = MathTex("\\hat a=\\frac{1}{2000}","=f(2000)","<a", color=BLUE, font_size=fs3).next_to(f,DOWN)

        pbc = Tex("Proof by contradiction", color=RED, font_size=fs3).next_to(title, DOWN, buff=0.4)

        func = lambda x: 1/x
        f_plotted = plane.plot(func, color=RED, x_range=[1, 100, 0.01], use_smoothing=False)

        t = t.shift(LEFT*5)

        # Action Sequence
        with self.voiceover(
                text="""
                Nope, that's not right. <bookmark mark="preach"/> There is no positive number that is smaller than the smallest value that f of x equals one over x can obtain.
                
                But why? I'll show you using a method that mathematicians call <bookmark mark="pbc"/>proof by contradiction.
                
                First, <bookmark mark="step1"/> think about a super super tiny positive number, and call that number "a".
                <bookmark mark="e1"/> For example, we could pick the number zero point zero zero one.
                
                Second<bookmark mark="step2"/>, write that number as a fraction.
                In our example,<bookmark mark="e2"/> we would write "a" as one over one hundred.
                
                Third<bookmark mark="step3"/>, take the fraction and double the denominator.
                In our example, <bookmark mark="e3"/>we would get "a" hat equal to one over two hundred.
                
                Now, <bookmark mark="meaning"/>let's think about what this means. <bookmark mark="meaningA"/>
                First, note that f of x is equal to that number, if we plug in the value of the doubled denominator for x
                
                <bookmark mark="meaningB"/>We can also see, that the number is a smaller number than "a".
                
                This means, that no matter which positive number we pick, we can always find a value of x, for which f of x is smaller than that number.
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("preach")
            self.play(t.animate.shift(RIGHT*5))

            self.wait_until_bookmark("pbc")
            self.play(Write(pbc))

            self.wait_until_bookmark("step1")
            self.play(t.animate.shift(RIGHT*5), Write(s1), pbc.animate.set_color(BLACK))

            self.wait_until_bookmark("e1")
            self.play(Write(e1))

            self.wait_until_bookmark("step2")
            self.play(s1.animate.set_color(BLACK), s1.animate.next_to(pbc, DOWN, buff=0.2), e1.animate.shift(5*RIGHT), Write(s2))

            self.wait_until_bookmark("e2")
            self.play(Write(e2))

            self.wait_until_bookmark("step3")
            self.play(s2.animate.set_color(BLACK), s2.animate.next_to(s1, DOWN, buff=0.2), e2.animate.shift(5*RIGHT), Write(s3))

            self.wait_until_bookmark("e3")
            self.play(Write(e3[0]))

            self.wait_until_bookmark("meaning")
            self.play(s3.animate.next_to(s2, DOWN, buff=0.2), s3.animate.set_color(BLACK))

            self.wait_until_bookmark("meaningA")
            self.play(Write(e3[1]))

            self.wait_until_bookmark("meaningB")
            self.play(Write(e3[2]))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_1_I_6_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("$\\tfrac1x$ for large $x$", tex=True)

        cords = self.add_cords([0,100, 20], [0, 1, 1/4], x_ticks=[20,40,60,80],y_ticks=[0,0.25, 0.5, 0.75,1])
        plane = cords[0]

        cursor = AltCursor(stroke_width=0.0, blinking=False)
        cursor.autoFadeBackground = True
        x,y,_ = plane.c2p(0,0)
        cursor.move_to([x,y,0])

        f = MathTex("f(x) = \\tfrac 1x", color=c1t, font_size=fs2)
        t1a = Tex("which is smaller than", color=c1t, font_size=fs3).next_to(f, UP)
        t1b = Tex("There is no positive number $a$,", color=c1t, font_size=fs3).next_to(t1a, UP, buff=0.1)
        t2 = Tex("for large positive x.", color=c1t, font_size=fs3).next_to(f, DOWN)
        t1a = t1a.shift(LEFT*(t1a.get_left()[0]-t1b.get_left()[0]))
        t = VGroup(t1b, t1a, t2)
        t2 = t2.shift(LEFT*(t2.get_left()[0]-t1b.get_left()[0]))
        self.add(f)

        s1 = Tex("1. Choose a tiny number $a$", color=RED, font_size=fs3).next_to(f, UP)
        e1 = Tex("Example: $a=0.001$", color=BLUE, font_size=fs3).next_to(f,DOWN)

        s2 = Tex("2. Write $a$ as a fraction", color=RED, font_size=fs3).next_to(f, UP)
        s2 = s2.shift(LEFT*(s2.get_left()[0]-s1.get_left()[0]))
        e2 = Tex("Our example: $a=\\frac{1}{1000}$", color=BLUE, font_size=fs3).next_to(f,DOWN)

        s3 = Tex("3. Double the denominator", color=RED, font_size=fs3).next_to(f, UP)
        s3 = s3.shift(LEFT*(s3.get_left()[0]-s1.get_left()[0]))
        e3 = MathTex("\\hat a=\\frac{1}{2000}","=f(2000)","<a", color=BLUE, font_size=fs3).next_to(f,DOWN)

        pbc = Tex("Proof by contradiction", color=RED, font_size=fs3).next_to(title, DOWN, buff=0.4)

        func = lambda x: 1/x
        f_plotted = plane.plot(func, color=RED, x_range=[1, 100, 0.01], use_smoothing=False)

        t = t.shift(LEFT*5)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's correct. <bookmark mark="preach"/> There is no positive number that is smaller than the smallest value that f of x equals one over x can obtain.
                
                But why? I'll show you using a method that mathematicians call <bookmark mark="pbc"/>proof by contradiction.
                
                First, <bookmark mark="step1"/> think about a super super tiny positive number, and call that number "a".
                <bookmark mark="e1"/> For example, we could pick the number zero point zero zero one.
                
                Second<bookmark mark="step2"/>, write that number as a fraction.
                In our example,<bookmark mark="e2"/> we would write "a" as one over one hundred.
                
                Third<bookmark mark="step3"/>, take the fraction and double the denominator.
                In our example, <bookmark mark="e3"/>we would get "a" hat equal to one over two hundred.
                
                Now, <bookmark mark="meaning"/>let's think about what this means. <bookmark mark="meaningA"/>
                First, note that f of x is equal to that number, if we plug in the value of the doubled denominator for x
                
                <bookmark mark="meaningB"/>We can also see, that the number is a smaller number than "a".
                
                This means, that no matter which positive number we pick, we can always find a value of x, for which f of x is smaller than that number.
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("preach")
            self.play(t.animate.shift(RIGHT*5))

            self.wait_until_bookmark("pbc")
            self.play(Write(pbc))

            self.wait_until_bookmark("step1")
            self.play(t.animate.shift(RIGHT*5), Write(s1), pbc.animate.set_color(BLACK))

            self.wait_until_bookmark("e1")
            self.play(Write(e1))

            self.wait_until_bookmark("step2")
            self.play(s1.animate.set_color(BLACK), s1.animate.next_to(pbc, DOWN, buff=0.2), e1.animate.shift(5*RIGHT), Write(s2))

            self.wait_until_bookmark("e2")
            self.play(Write(e2))

            self.wait_until_bookmark("step3")
            self.play(s2.animate.set_color(BLACK), s2.animate.next_to(s1, DOWN, buff=0.2), e2.animate.shift(5*RIGHT), Write(s3))

            self.wait_until_bookmark("e3")
            self.play(Write(e3[0]))

            self.wait_until_bookmark("meaning")
            self.play(s3.animate.next_to(s2, DOWN, buff=0.2), s3.animate.set_color(BLACK))

            self.wait_until_bookmark("meaningA")
            self.play(Write(e3[1]))

            self.wait_until_bookmark("meaningB")
            self.play(Write(e3[2]))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_1_I_6_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("$\\tfrac1x$ for large $x$", tex=True)

        cords = self.add_cords([0,100, 20], [0, 1, 1/4], x_ticks=[20,40,60,80],y_ticks=[0,0.25, 0.5, 0.75,1])
        plane = cords[0]

        cursor = AltCursor(stroke_width=0.0, blinking=False)
        cursor.autoFadeBackground = True
        x,y,_ = plane.c2p(0,0)
        cursor.move_to([x,y,0])

        f = MathTex("f(x) = \\tfrac 1x", color=c1t, font_size=fs2)
        t1a = Tex("which is smaller than", color=c1t, font_size=fs3).next_to(f, UP)
        t1b = Tex("There is no positive number $a$,", color=c1t, font_size=fs3).next_to(t1a, UP, buff=0.1)
        t2 = Tex("for large positive x.", color=c1t, font_size=fs3).next_to(f, DOWN)
        t1a = t1a.shift(LEFT*(t1a.get_left()[0]-t1b.get_left()[0]))
        t = VGroup(t1b, t1a, t2)
        t2 = t2.shift(LEFT*(t2.get_left()[0]-t1b.get_left()[0]))
        self.add(f)

        s1 = Tex("1. Choose a tiny number $a$", color=RED, font_size=fs3).next_to(f, UP)
        e1 = Tex("Example: $a=0.001$", color=BLUE, font_size=fs3).next_to(f,DOWN)

        s2 = Tex("2. Write $a$ as a fraction", color=RED, font_size=fs3).next_to(f, UP)
        s2 = s2.shift(LEFT*(s2.get_left()[0]-s1.get_left()[0]))
        e2 = Tex("Our example: $a=\\frac{1}{1000}$", color=BLUE, font_size=fs3).next_to(f,DOWN)

        s3 = Tex("3. Double the denominator", color=RED, font_size=fs3).next_to(f, UP)
        s3 = s3.shift(LEFT*(s3.get_left()[0]-s1.get_left()[0]))
        e3 = MathTex("\\hat a=\\frac{1}{2000}","=f(2000)","<a", color=BLUE, font_size=fs3).next_to(f,DOWN)

        pbc = Tex("Proof by contradiction", color=RED, font_size=fs3).next_to(title, DOWN, buff=0.4)

        func = lambda x: 1/x
        f_plotted = plane.plot(func, color=RED, x_range=[1, 100, 0.01], use_smoothing=False)

        t = t.shift(LEFT*5)

        # Action Sequence
        with self.voiceover(
                text="""
                Nope, that's not right. <bookmark mark="preach"/> There is no positive number that is smaller than the smallest value that f of x equals one over x can obtain.
                
                But why? I'll show you using a method that mathematicians call <bookmark mark="pbc"/>proof by contradiction.
                
                First, <bookmark mark="step1"/> think about a super super tiny positive number, and call that number "a".
                <bookmark mark="e1"/> For example, we could pick the number zero point zero zero one.
                
                Second<bookmark mark="step2"/>, write that number as a fraction.
                In our example,<bookmark mark="e2"/> we would write "a" as one over one hundred.
                
                Third<bookmark mark="step3"/>, take the fraction and double the denominator.
                In our example, <bookmark mark="e3"/>we would get "a" hat equal to one over two hundred.
                
                Now, <bookmark mark="meaning"/>let's think about what this means. <bookmark mark="meaningA"/>
                First, note that f of x is equal to that number, if we plug in the value of the doubled denominator for x
                
                <bookmark mark="meaningB"/>We can also see, that the number is a smaller number than "a".
                
                This means, that no matter which positive number we pick, we can always find a value of x, for which f of x is smaller than that number.
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("preach")
            self.play(t.animate.shift(RIGHT*5))

            self.wait_until_bookmark("pbc")
            self.play(Write(pbc))

            self.wait_until_bookmark("step1")
            self.play(t.animate.shift(RIGHT*5), Write(s1), pbc.animate.set_color(BLACK))

            self.wait_until_bookmark("e1")
            self.play(Write(e1))

            self.wait_until_bookmark("step2")
            self.play(s1.animate.set_color(BLACK), s1.animate.next_to(pbc, DOWN, buff=0.2), e1.animate.shift(5*RIGHT), Write(s2))

            self.wait_until_bookmark("e2")
            self.play(Write(e2))

            self.wait_until_bookmark("step3")
            self.play(s2.animate.set_color(BLACK), s2.animate.next_to(s1, DOWN, buff=0.2), e2.animate.shift(5*RIGHT), Write(s3))

            self.wait_until_bookmark("e3")
            self.play(Write(e3[0]))

            self.wait_until_bookmark("meaning")
            self.play(s3.animate.next_to(s2, DOWN, buff=0.2), s3.animate.set_color(BLACK))

            self.wait_until_bookmark("meaningA")
            self.play(Write(e3[1]))

            self.wait_until_bookmark("meaningB")
            self.play(Write(e3[2]))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
class Func_3_1_I_7(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["$x>0\\Rightarrow f(x)>0$", "Shape of f(x)", "Singularities"], buff=0.28)
        self.add(note)

        title = self.add_title("Rational Functions")

        cords = self.add_cords([0,4, 1], [0, 4, 1], x_ticks=[1,2,3,4],y_ticks=[1,2,3,4])
        plane = cords[0]

        func = lambda x: 1/x
        plotted_right = plane.plot(func, color=RED, x_range=[1, 4, 0.01], use_smoothing=False)
        plotted_left = plane.plot(func, color=RED, x_range=[0.25, 1, 0.01], use_smoothing=False).reverse_points()

        cursor = AltCursor(stroke_width=0.0, blinking=False)
        cursor.autoFadeBackground = True
        x,y,_ = plane.c2p(0,0)
        cursor.move_to([x,y,0])

        f = Tex("$f(x) = \\tfrac 1x$","$>0$", color=c1t, font_size=fs1)
        cond = Tex("for $x\\geq0$", color=c3t, font_size=fs2)
        Group(f,cond).arrange(DOWN, buff=0.05, aligned_edge=LEFT).shift(DOWN*0.4)

        xsmall = Tex("$x$ small", " $\\Rightarrow$ ", "$f(x)$ large", color=RED, font_size=fs2).next_to(title, DOWN, buff=1)
        xlarge = Tex("$x$ large", " $\\Rightarrow$ ", "$f(x)$ small", color=RED, font_size=fs2).next_to(xsmall, DOWN, buff=0.4)
        sL = VGroup(xsmall, xlarge)

        S1 = Tex("Singularity at $x$", color=c1t, font_size=fs2).next_to(title, DOWN, buff=2)
        S2 = Tex("$\\Leftrightarrow$", color=c1t, font_size=fs2).next_to(S1, DOWN, buff=0.2)
        S3a = Tex("Plugging in $x$ leads to", color=c1t, font_size=fs2)
        S3b = Tex("division by zero", color=c1t, font_size=fs2)
        S = VGroup(S1, S2, S3a, S3b).arrange(DOWN, buff=0.2).next_to(title, DOWN, buff=1)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, let's recap what we have learned so far about functions where we divide something by x.
                Again, let's stick to our example <bookmark mark="f"/> f of x equals one over x, and let's
                also <bookmark mark="cond"/> restrict ourselves to numbers that aren't negative.
                
                <bookmark mark="note1"/>
                First, we know that <bookmark mark="fPos"/>f of x is positive for all positive values of x.
                
                <bookmark mark="note2"/>
                Then, we also learned how the function behaves for<bookmark mark="smallLarge"/> very small and very large values of x:
                If x gets very large, we divide one by a very large number, <bookmark mark="xlarge"/>and the result gets very small.
                
                If on the other hand x gets very small, we divide one by a very small number, <bookmark mark="xsmall"/>and the result gets very large.
                
                If we combine these two insights, we can <bookmark mark="cords"/> determine what the graph looks like:
                <bookmark mark="graph"/> Starting from one, the graph gets smaller and smaller, as we move to the right.
                <bookmark mark="left"/> When moving to the left on the other hand, the graph increases rapidly, as we get closer to zero.                
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            self.play(Write(f[0]))

            self.wait_until_bookmark("cond")
            self.play(Write(cond))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("fPos")
            note.change_colors([0,1])
            f[1].set_color(RED)
            self.play(Write(f[1]))

            self.wait_until_bookmark("smallLarge")
            f[1].set_color(c1t)
            self.play(Write(xsmall[0]), Write(xlarge[0]))

            self.wait_until_bookmark("xlarge")
            xsmall[0].set_color(c1t)
            xlarge[0].set_color(c1t)
            self.play(Write(xlarge[1]), Write(xlarge[2]))

            self.wait_until_bookmark("xsmall")
            xlarge[1].set_color(c1t)
            xlarge[2].set_color(c1t)
            self.play(Write(xsmall[1]), Write(xsmall[2]))

            self.wait_until_bookmark("cords")
            xsmall[1].set_color(c1t)
            xsmall[2].set_color(c1t)
            self.play(Write(cords), cond.animate.shift(5*RIGHT), sL.animate.shift(5*RIGHT), Unwrite(f[1]), f[0].animate.shift(0.6*DOWN+f[0].get_center()[0]*LEFT), Write(cursor))

            self.wait_until_bookmark("graph")
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(plotted_right), MoveAlongPath(cursor, plotted_right), run_time=5)

            self.wait_until_bookmark("left")
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(plotted_left), MoveAlongPath(cursor, plotted_left), run_time=5)

        with self.voiceover(text=
            """
                <bookmark mark="note3"/>
                We also learned about <bookmark mark="out"/> singularities: As x gets closer to zero, the value of f of x gets really large.
                But <bookmark mark="sing"/>we can't actually plug in zero, because that would mean dividing by zero, which is not allowed.
                This is why we call <bookmark mark="singDef"/> zero a singularity of the function.
            """
            ) as tracker:

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

            self.wait_until_bookmark("out")
            self.play(Unwrite(cursor), cords.animate.shift(5*RIGHT), sL.animate.shift(5*RIGHT), plotted_left.animate.shift(5*RIGHT), plotted_right.animate.shift(5*RIGHT))

            self.wait_until_bookmark("sing")
            self.play(Write(S3a), Write(S3b))

            self.wait_until_bookmark("singDef")
            self.play(Write(S1), Write(S2))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_3_1_I_8_q = SophiaTaskDefinition(
    answerOptions=["x close to zero -> large negative values,\n x far from zero -> small negative values", 
                   "x close to zero -> large negative values,\n x far from zero -> small positive values", 
                   "x close to zero -> small negative values,\n x far from zero -> large negative values", 
                   "x close to zero -> small negative values,\n x far from zero -> large positive values", ],
    correctAnswerIndex=0,
    questionText="How does f behave for negative values of x?"
)
class Func_3_1_I_8_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Positive x:", "$x$ small $\\Rightarrow f(x)$ large", "$x$ large $\\Rightarrow f(x)$ small"], ["How does $f$ behave for","negative values of $x$?"]], buff=0.28)
        self.add(note)

        title = self.add_title("$\\frac1x$ for negative $x$", tex=True)

        cords = self.add_cords([-4,0, 1], [-4,0, 1], x_ticks=[-1,-2,-3,-4],y_ticks=[-1,-2,-3,-4])
        plane = cords[0]

        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(2/qmark.get_width()).move_to([-5, 1, 0])

        f = Tex("$f(x) = \\tfrac 1x$","$>0$", color=c1t, font_size=fs2).shift(0.2*DOWN)
        cond = Tex("for $x<0$", color=c3t, font_size=fs3)
        Group(f,cond).arrange(DOWN, buff=0.05, aligned_edge=LEFT).shift(DOWN*0.4)

        # Action Sequence
        with self.voiceover(
                text="""
                Now, let's think about <bookmark mark="neg"/> the negative values of x.
                <bookmark mark="note1"/>
                Remember, for positive x the function was very high for small x and got smaller for larger x.
                
                <bookmark mark="cords"/>Now, <bookmark mark="note2"/>how <bookmark mark="Q"/>does f behave for small negative values of x?
                
                And how does it behave for large negative values of x?
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("neg")
            self.play(Write(f[0]), Write(cond))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("cords")
            self.play(Write(cords))

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("Q")
            self.play(qmark.animate.shift(5*RIGHT))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_1_I_8_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("$\\frac1x$ for negative $x$", tex=True)

        # Create a notepad with texts
        note = Notepad(texts=["Consider $f(x)=\\tfrac1x$ for negative x", "Plug in several values",["f(x) close to zero first", "and then decreases rapidly as $x\\rightarrow0$"]], buff=0.3)
        self.add(note)

        # Create the coordinate system
        cords = self.add_cords([-4, 0, 1], [-4, 0, 1], x_ticks=[-1,-2,-3,-4],y_ticks=[-1,-2,-3,-4])
        plane = cords[0]

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])

        func = lambda x: 1/x
        func_plotted = plane.plot(func, color=RED, x_range=[-4, -1/4, 0.01], use_smoothing=False)


        f = Tex("$f(x) = \\tfrac 1x$", color=c1t, font_size=fs2).shift(0.2*DOWN)
        cond = Tex("for $x<0$", color=c3t, font_size=fs3)
        Group(f,cond).arrange(DOWN, buff=0.05, aligned_edge=LEFT).shift(DOWN*0.6)

        # Action Sequence
        with self.voiceover(
                text="""
                Yes, that's correct!
                So, we want to know what the function <bookmark mark="f"/> f of x equals one over x looks like
                for <bookmark mark="cond"/> negative values of x.
                
                Like we did for positive values of x, let's analyze the function by <bookmark mark="cords"/> plugging in some values.
                
                If we plug in negative one, <bookmark mark="plugIn1"/> we get one divided by negative one, which is negative one.
                
                If we plug in negative two, <bookmark mark="plugIn2"/> we get one divided by negative two, which is negative one half.
                
                If we plug in negative four, <bookmark mark="plugIn4"/> we get one divided by negative four, which is negative one quarter.
                
                And so on.
                
                """
        ) as tracker:

            self.wait_until_bookmark("f")
            note.change_colors([0])
            self.play(Write(f))

            self.wait_until_bookmark("cond")
            self.play(Write(cond))

            self.wait_until_bookmark("cords")
            note.change_colors([0,1])
            self.play(Write(cords))
            self.add(cursor)

            self.wait_until_bookmark("plugIn1")
            cursor.blinking = False
            x,y,_ = plane.c2p(-1,-1)
            circ1 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circ1))

            self.wait_until_bookmark("plugIn2")
            x,y,_ = plane.c2p(-2,-0.5)
            circ2 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circ2))

            self.wait_until_bookmark("plugIn4")
            x,y,_ = plane.c2p(-4,-0.25)
            circ4 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y))
            self.play(Write(circ4))
            cursor.blinking=True

        with self.voiceover(
                text="""
                Let's also plug in some values that are larger than negative one:
                
                If we plug in <bookmark mark="plugInHalf"/> negative zero point five, we get one divided by negative zero point five, which is negative two,
                
                And if we plug in <bookmark mark="plugInQuarter"/> negative zero point two five, we get one divided by negative zero point two five, which is negative four.
                
                Now that we've plugged in some values, let's <bookmark mark="plot"/> connect them on the coordinate system and see what the function looks like.
                
                As we can see, <bookmark mark="note"/> the function starts <bookmark mark="moveAlongFunc"/> with values close to zero for low x, and  then decreases as x gets larger.
                
                At first, it decreases very slowly, but then it decreases faster and faster...
                """
        )as tracker:
        
            self.wait_until_bookmark("plugInHalf")
            cursor.blinking=False
            x,y,_ = plane.c2p(-0.5,-2)
            circHalf = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circHalf))
            
            self.wait_until_bookmark("plugInQuarter")
            x,y,_ = plane.c2p(-0.25,-4)
            circQuarter = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circQuarter))
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("plot")
            self.play(Write(func_plotted), run_time=2.5)
            self.play(Unwrite(circ1), Unwrite(circ2), Unwrite(circ4), Unwrite(circHalf), Unwrite(circQuarter), run_time=0.5)

            self.wait_until_bookmark("note")
            note.change_colors([1,2])

            self.wait_until_bookmark("moveAlongFunc")
            x,y,_ = plane.c2p(-4, -1/4)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y),run_time=1)
            self.play(MoveAlongPath(cursor, func_plotted), run_time=12, rate_func=rate_functions.ease_out_sine)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_1_I_8_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("$\\frac1x$ for negative $x$", tex=True)

        # Create a notepad with texts
        note = Notepad(texts=["Consider $f(x)=\\tfrac1x$ for negative x", "Plug in several values",["f(x) close to zero first", "and then decreases rapidly as $x\\rightarrow0$"]], buff=0.3)
        self.add(note)

        # Create the coordinate system
        cords = self.add_cords([-4, 0, 1], [-4, 0, 1], x_ticks=[-1,-2,-3,-4],y_ticks=[-1,-2,-3,-4])
        plane = cords[0]

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])

        func = lambda x: 1/x
        func_plotted = plane.plot(func, color=RED, x_range=[-4, -1/4, 0.01], use_smoothing=False)


        f = Tex("$f(x) = \\tfrac 1x$", color=c1t, font_size=fs2).shift(0.2*DOWN)
        cond = Tex("for $x<0$", color=c3t, font_size=fs3)
        Group(f,cond).arrange(DOWN, buff=0.05, aligned_edge=LEFT).shift(DOWN*0.6)

        # Action Sequence
        with self.voiceover(
                text="""
                Mhm, that's not right!
                So, we want to know what the function <bookmark mark="f"/> f of x equals one over x looks like
                for <bookmark mark="cond"/> negative values of x.
                
                Like we did for positive values of x, let's analyze the function by <bookmark mark="cords"/> plugging in some values.
                
                If we plug in negative one, <bookmark mark="plugIn1"/> we get one divided by negative one, which is negative one.
                
                If we plug in negative two, <bookmark mark="plugIn2"/> we get one divided by negative two, which is negative one half.
                
                If we plug in negative four, <bookmark mark="plugIn4"/> we get one divided by negative four, which is negative one quarter.
                
                And so on.
                
                """
        ) as tracker:

            self.wait_until_bookmark("f")
            note.change_colors([0])
            self.play(Write(f))

            self.wait_until_bookmark("cond")
            self.play(Write(cond))

            self.wait_until_bookmark("cords")
            note.change_colors([0,1])
            self.play(Write(cords))
            self.add(cursor)

            self.wait_until_bookmark("plugIn1")
            cursor.blinking = False
            x,y,_ = plane.c2p(-1,-1)
            circ1 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circ1))

            self.wait_until_bookmark("plugIn2")
            x,y,_ = plane.c2p(-2,-0.5)
            circ2 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circ2))

            self.wait_until_bookmark("plugIn4")
            x,y,_ = plane.c2p(-4,-0.25)
            circ4 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y))
            self.play(Write(circ4))
            cursor.blinking=True

        with self.voiceover(
                text="""
                Let's also plug in some values that are larger than negative one:
                
                If we plug in <bookmark mark="plugInHalf"/> negative zero point five, we get one divided by negative zero point five, which is negative two,
                
                And if we plug in <bookmark mark="plugInQuarter"/> negative zero point two five, we get one divided by negative zero point two five, which is negative four.
                
                Now that we've plugged in some values, let's <bookmark mark="plot"/> connect them on the coordinate system and see what the function looks like.
                
                As we can see, <bookmark mark="note"/> the function starts <bookmark mark="moveAlongFunc"/> with values close to zero for low x, and  then decreases as x gets larger.
                
                At first, it decreases very slowly, but then it decreases faster and faster...
                """
        )as tracker:
        
            self.wait_until_bookmark("plugInHalf")
            cursor.blinking=False
            x,y,_ = plane.c2p(-0.5,-2)
            circHalf = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circHalf))
            
            self.wait_until_bookmark("plugInQuarter")
            x,y,_ = plane.c2p(-0.25,-4)
            circQuarter = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circQuarter))
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("plot")
            self.play(Write(func_plotted), run_time=2.5)
            self.play(Unwrite(circ1), Unwrite(circ2), Unwrite(circ4), Unwrite(circHalf), Unwrite(circQuarter), run_time=0.5)

            self.wait_until_bookmark("note")
            note.change_colors([1,2])

            self.wait_until_bookmark("moveAlongFunc")
            x,y,_ = plane.c2p(-4, -1/4)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y),run_time=1)
            self.play(MoveAlongPath(cursor, func_plotted), run_time=12, rate_func=rate_functions.ease_out_sine)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_1_I_8_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("$\\frac1x$ for negative $x$", tex=True)

        # Create a notepad with texts
        note = Notepad(texts=["Consider $f(x)=\\tfrac1x$ for negative x", "Plug in several values",["f(x) close to zero first", "and then decreases rapidly as $x\\rightarrow0$"]], buff=0.3)
        self.add(note)

        # Create the coordinate system
        cords = self.add_cords([-4, 0, 1], [-4, 0, 1], x_ticks=[-1,-2,-3,-4],y_ticks=[-1,-2,-3,-4])
        plane = cords[0]

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])

        func = lambda x: 1/x
        func_plotted = plane.plot(func, color=RED, x_range=[-4, -1/4, 0.01], use_smoothing=False)


        f = Tex("$f(x) = \\tfrac 1x$", color=c1t, font_size=fs2).shift(0.2*DOWN)
        cond = Tex("for $x<0$", color=c3t, font_size=fs3)
        Group(f,cond).arrange(DOWN, buff=0.05, aligned_edge=LEFT).shift(DOWN*0.6)

        # Action Sequence
        with self.voiceover(
                text="""
                Mhm, that's not right!
                So, we want to know what the function <bookmark mark="f"/> f of x equals one over x looks like
                for <bookmark mark="cond"/> negative values of x.
                
                Like we did for positive values of x, let's analyze the function by <bookmark mark="cords"/> plugging in some values.
                
                If we plug in negative one, <bookmark mark="plugIn1"/> we get one divided by negative one, which is negative one.
                
                If we plug in negative two, <bookmark mark="plugIn2"/> we get one divided by negative two, which is negative one half.
                
                If we plug in negative four, <bookmark mark="plugIn4"/> we get one divided by negative four, which is negative one quarter.
                
                And so on.
                
                """
        ) as tracker:

            self.wait_until_bookmark("f")
            note.change_colors([0])
            self.play(Write(f))

            self.wait_until_bookmark("cond")
            self.play(Write(cond))

            self.wait_until_bookmark("cords")
            note.change_colors([0,1])
            self.play(Write(cords))
            self.add(cursor)

            self.wait_until_bookmark("plugIn1")
            cursor.blinking = False
            x,y,_ = plane.c2p(-1,-1)
            circ1 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circ1))

            self.wait_until_bookmark("plugIn2")
            x,y,_ = plane.c2p(-2,-0.5)
            circ2 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circ2))

            self.wait_until_bookmark("plugIn4")
            x,y,_ = plane.c2p(-4,-0.25)
            circ4 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y))
            self.play(Write(circ4))
            cursor.blinking=True

        with self.voiceover(
                text="""
                Let's also plug in some values that are larger than negative one:
                
                If we plug in <bookmark mark="plugInHalf"/> negative zero point five, we get one divided by negative zero point five, which is negative two,
                
                And if we plug in <bookmark mark="plugInQuarter"/> negative zero point two five, we get one divided by negative zero point two five, which is negative four.
                
                Now that we've plugged in some values, let's <bookmark mark="plot"/> connect them on the coordinate system and see what the function looks like.
                
                As we can see, <bookmark mark="note"/> the function starts <bookmark mark="moveAlongFunc"/> with values close to zero for low x, and  then decreases as x gets larger.
                
                At first, it decreases very slowly, but then it decreases faster and faster...
                """
        )as tracker:
        
            self.wait_until_bookmark("plugInHalf")
            cursor.blinking=False
            x,y,_ = plane.c2p(-0.5,-2)
            circHalf = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circHalf))
            
            self.wait_until_bookmark("plugInQuarter")
            x,y,_ = plane.c2p(-0.25,-4)
            circQuarter = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circQuarter))
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("plot")
            self.play(Write(func_plotted), run_time=2.5)
            self.play(Unwrite(circ1), Unwrite(circ2), Unwrite(circ4), Unwrite(circHalf), Unwrite(circQuarter), run_time=0.5)

            self.wait_until_bookmark("note")
            note.change_colors([1,2])

            self.wait_until_bookmark("moveAlongFunc")
            x,y,_ = plane.c2p(-4, -1/4)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y),run_time=1)
            self.play(MoveAlongPath(cursor, func_plotted), run_time=12, rate_func=rate_functions.ease_out_sine)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_1_I_8_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("$\\frac1x$ for negative $x$", tex=True)

        # Create a notepad with texts
        note = Notepad(texts=["Consider $f(x)=\\tfrac1x$ for negative x", "Plug in several values",["f(x) close to zero first", "and then decreases rapidly as $x\\rightarrow0$"]], buff=0.3)
        self.add(note)

        # Create the coordinate system
        cords = self.add_cords([-4, 0, 1], [-4, 0, 1], x_ticks=[-1,-2,-3,-4],y_ticks=[-1,-2,-3,-4])
        plane = cords[0]

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.move_to([xo, yo, 0])

        func = lambda x: 1/x
        func_plotted = plane.plot(func, color=RED, x_range=[-4, -1/4, 0.01], use_smoothing=False)


        f = Tex("$f(x) = \\tfrac 1x$", color=c1t, font_size=fs2).shift(0.2*DOWN)
        cond = Tex("for $x<0$", color=c3t, font_size=fs3)
        Group(f,cond).arrange(DOWN, buff=0.05, aligned_edge=LEFT).shift(DOWN*0.6)

        # Action Sequence
        with self.voiceover(
                text="""
                Mhm, that's not right!
                So, we want to know what the function <bookmark mark="f"/> f of x equals one over x looks like
                for <bookmark mark="cond"/> negative values of x.
                
                Like we did for positive values of x, let's analyze the function by <bookmark mark="cords"/> plugging in some values.
                
                If we plug in negative one, <bookmark mark="plugIn1"/> we get one divided by negative one, which is negative one.
                
                If we plug in negative two, <bookmark mark="plugIn2"/> we get one divided by negative two, which is negative one half.
                
                If we plug in negative four, <bookmark mark="plugIn4"/> we get one divided by negative four, which is negative one quarter.
                
                And so on.
                
                """
        ) as tracker:

            self.wait_until_bookmark("f")
            note.change_colors([0])
            self.play(Write(f))

            self.wait_until_bookmark("cond")
            self.play(Write(cond))

            self.wait_until_bookmark("cords")
            note.change_colors([0,1])
            self.play(Write(cords))
            self.add(cursor)

            self.wait_until_bookmark("plugIn1")
            cursor.blinking = False
            x,y,_ = plane.c2p(-1,-1)
            circ1 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circ1))

            self.wait_until_bookmark("plugIn2")
            x,y,_ = plane.c2p(-2,-0.5)
            circ2 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circ2))

            self.wait_until_bookmark("plugIn4")
            x,y,_ = plane.c2p(-4,-0.25)
            circ4 = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y))
            self.play(Write(circ4))
            cursor.blinking=True

        with self.voiceover(
                text="""
                Let's also plug in some values that are larger than negative one:
                
                If we plug in <bookmark mark="plugInHalf"/> negative zero point five, we get one divided by negative zero point five, which is negative two,
                
                And if we plug in <bookmark mark="plugInQuarter"/> negative zero point two five, we get one divided by negative zero point two five, which is negative four.
                
                Now that we've plugged in some values, let's <bookmark mark="plot"/> connect them on the coordinate system and see what the function looks like.
                
                As we can see, <bookmark mark="note"/> the function starts <bookmark mark="moveAlongFunc"/> with values close to zero for low x, and  then decreases as x gets larger.
                
                At first, it decreases very slowly, but then it decreases faster and faster...
                """
        )as tracker:
        
            self.wait_until_bookmark("plugInHalf")
            cursor.blinking=False
            x,y,_ = plane.c2p(-0.5,-2)
            circHalf = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circHalf))
            
            self.wait_until_bookmark("plugInQuarter")
            x,y,_ = plane.c2p(-0.25,-4)
            circQuarter = Circle(radius=0.1, color=RED).move_to([x,y,0])
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(circQuarter))
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("plot")
            self.play(Write(func_plotted), run_time=2.5)
            self.play(Unwrite(circ1), Unwrite(circ2), Unwrite(circ4), Unwrite(circHalf), Unwrite(circQuarter), run_time=0.5)

            self.wait_until_bookmark("note")
            note.change_colors([1,2])

            self.wait_until_bookmark("moveAlongFunc")
            x,y,_ = plane.c2p(-4, -1/4)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y),run_time=1)
            self.play(MoveAlongPath(cursor, func_plotted), run_time=12, rate_func=rate_functions.ease_out_sine)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
class Func_3_1_I_9(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Consider our function $f(x)=\\tfrac1x$", "for positive and negative $x$"], ["Function forms two rounded edges","around x- and y-axis"]], buff=0.28)
        self.add(note)

        title = self.add_title("Rational Functions")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]
        x_ax = plane.x_axis.copy().set_color(RED)
        y_ax = plane.y_axis.copy().set_color(RED)

        func = lambda x: 1/x
        plotted_right = plane.plot(func, color=BLUE, x_range=[0.25, 4, 0.01], use_smoothing=False).reverse_points()
        plotted_left = plane.plot(func, color=BLUE, x_range=[-4, -0.25, 0.01], use_smoothing=False)

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        f = MathTex("f(x)=\\tfrac{1}{x}", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)


        # Action Sequence
        with self.voiceover(
                text="""
                Well, now that we've analyzed the function <bookmark mark="f"/> f of x equals one over x for positive and for negative
                values of x, let's now get a good look <bookmark mark="cords"/> at the function itself.
                
                Let's first look at negative values of x<bookmark mark="fNeg"/>.
                
                So as we just saw, for large negative values of x, the function is slightly below zero, <bookmark mark="moveNeg"/>but as
                the values of x get closer and closer to zero, the function values decrease very quickly.
                
                Now, let's turn to positive x values.<bookmark mark="fPos"/>
                
                <bookmark mark="xLarge"/>For large values of x, the function values
                are very small but positive. <bookmark mark="movePos"/>As the x values get closer to zero on the other hand,
                the function values seem to explode, getting larger and larger very fast.
                
                Now, this is what the entire function f of x equals one over x looks like.
                
                <bookmark mark="note"/>
                See how the function is structured around a cross
                formed by the <bookmark mark="x"/> x axis and the <bookmark mark="y"/> y axis?
                
                It seems to consist of two rounded corners, one on the <bookmark mark="tR"/> top right of that cross,
                and one on the <bookmark mark="bL"/> bottom left of that cross.
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            note.change_colors([0])
            self.play(Write(f))
            
            self.wait_until_bookmark("cords")
            self.play(Write(cords))
            self.add(cursor)
            
            self.wait_until_bookmark("fNeg")
            x,y,_ = plane.c2p(-4, -0.25)
            cursor.blinking=False
            self.play(Write(plotted_left))
            self.play(CursorMoveTo(cursor,x,y))
            cursor.blinking=True

            self.wait_until_bookmark("moveNeg")
            cursor.blinking=False
            self.play(MoveAlongPath(cursor, plotted_left), run_time=6, rate_func=rate_functions.ease_out_sine)
            cursor.blinking=True
            
            self.wait_until_bookmark("fPos")
            x,y,_ = plane.c2p(4, 0.25)
            self.play(Write(plotted_right))

            self.wait_until_bookmark("xLarge")
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y))
            cursor.blinking=True

            self.wait_until_bookmark("movePos")
            cursor.blinking=False
            self.play(MoveAlongPath(cursor, plotted_right), run_time=8, rate_func=rate_functions.ease_out_sine)
            self.wait(0.2)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("note")
            note.change_colors([0,1])

            self.wait_until_bookmark("x")
            self.play(Write(x_ax), run_time=0.7)

            self.wait_until_bookmark("y")
            self.play(Write(y_ax), run_time=0.7)

            self.wait_until_bookmark("tR")
            x,y,_ = plane.c2p(2,2)
            cursor.blinking=False
            self.play(CursorMoveResize(cursor,x,y, 1.2, 1.2), run_time=0.5)

            self.wait_until_bookmark("bL")
            x,y,_ = plane.c2p(-2,-2)
            self.play(CursorMoveResize(cursor,x,y, 1.2, 1.2), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
PROTOTYPES = [
    PagePrototypeVideo.from_scene(Func_3_1_I_1),
    PagePrototypeVideo.from_scene(Func_3_1_I_2),
    PagePrototypeVideo.from_scene(Func_3_1_I_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_3_1_I_3_q, Func_3_1_I_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_3_1_I_3_a),
    PagePrototypeVideo.from_scene(Func_3_1_I_3_b),
    PagePrototypeVideo.from_scene(Func_3_1_I_3_c),
    PagePrototypeVideo.from_scene(Func_3_1_I_3_d),
    PagePrototypeVideo.from_scene(Func_3_1_I_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_3_1_I_4_q, Func_3_1_I_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_3_1_I_4_a),
    PagePrototypeVideo.from_scene(Func_3_1_I_4_b),
    PagePrototypeVideo.from_scene(Func_3_1_I_4_c),
    PagePrototypeVideo.from_scene(Func_3_1_I_4_d),
    PagePrototypeVideo.from_scene(Func_3_1_I_5),
    PagePrototypeVideo.from_scene(Func_3_1_I_6_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_3_1_I_6_q, Func_3_1_I_6_q.__name__),
    PagePrototypeVideo.from_scene(Func_3_1_I_6_a),
    PagePrototypeVideo.from_scene(Func_3_1_I_6_b),
    PagePrototypeVideo.from_scene(Func_3_1_I_6_c),
    PagePrototypeVideo.from_scene(Func_3_1_I_6_d),
    PagePrototypeVideo.from_scene(Func_3_1_I_7),
    PagePrototypeVideo.from_scene(Func_3_1_I_8_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_3_1_I_8_q, Func_3_1_I_8_q.__name__),
    PagePrototypeVideo.from_scene(Func_3_1_I_8_a),
    PagePrototypeVideo.from_scene(Func_3_1_I_8_b),
    PagePrototypeVideo.from_scene(Func_3_1_I_8_c),
    PagePrototypeVideo.from_scene(Func_3_1_I_8_d),
    PagePrototypeVideo.from_scene(Func_3_1_I_9),
]
scenes/Func/Func_3: Rational Functions I/Func3_1.py
Sophia-Edu-Labs/sophia-math
# 3_2: Fractional Rational Functions: Asymptotes

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition

#####################################
#####################################
#### Instruction Part ###############
#####################################
#####################################



#####################################
#####################################
class Func_3_2_I_1(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["$x$ very large positive","$\\Rightarrow f(x)$ approaches x-axis from above"], ["$x$ very large negative","$\\Rightarrow f(x)$ approaches x-axis from below"], "$\\Rightarrow$ $x$ Axis is a \"horizontal Asymptote\""], buff=0.28)
        self.add(note)

        title = self.add_title("Asymptotes")

        cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]
        x_ax = plane.x_axis.copy().set_color(RED)
        y_ax = plane.y_axis.copy().set_color(RED)

        func = lambda x: 1/x
        plotted_right = plane.plot(func, color=BLUE, x_range=[0.25, 8, 0.01], use_smoothing=False)
        plotted_left = plane.plot(func, color=BLUE, x_range=[-8, -0.25, 0.01], use_smoothing=False).reverse_points()

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        f = MathTex("f(x)=\\tfrac{1}{x}", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)


        # Action Sequence
        with self.voiceover(
                text="""
                Ok now, I have a new concept for you. Asymptotes.
                
                Again, our favorite function <bookmark mark="f"/> f of x equals one over x.
                
                <bookmark mark="pos"/>
                When analyzing this function, we can see that for large positive values of x, the function values are very small but positive.
                They get closer and closer to zero, but never reach zero.
                
                <bookmark mark="neg"/>
                For large negative values of x, the function values are very small but negative. Again, as the values of x get more and more negative,
                the function values get closer and closer to zero from below, but never reach zero.
                
                If you look at the graph, it looks like it is <bookmark mark="hug"/>hugging the x-axis.
                
                But we're doing Mathematics here, so we need to find a complicated sounding word to describe this.
                
                So, we say that the <bookmark mark="note"/>"x"-axis is an Asymptote of the function f of x.
                
                To be precise, the "x"-axis is a horizontal Asymptote of our function f.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            self.play(Write(f), Write(cords), Write(plotted_left), Write(plotted_right), Write(cursor))

            self.wait_until_bookmark("pos")
            note.change_colors([0])
            x,y,_ = plane.c2p(8,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=5)
            cursor.blinking=True

            self.wait_until_bookmark("neg")
            note.change_colors([0,1])
            x,y,_ = plane.c2p(-8,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, xo, yo), run_time=0.5)
            self.play(CursorMoveTo(cursor, x, y), run_time=5)
            cursor.blinking=True

            self.wait_until_bookmark("hug")
            cursor.blinking=False
            self.play(CursorMarkAxis(cursor, plane), run_time=0.8)

            self.wait_until_bookmark("note")
            note.change_colors([1,2])

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
# TASK_Func_3_2_I_2_q = SophiaTaskDefinition(
#     answerOptions=["The orange line", "The green Line", "The purple line"],
#     correctAnswerIndex=0,
#     questionText="Which of the lines describes the horizontal asymptote of the function?",
# )
# class Func_3_2_I_2_q(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()

#         note = Notepad(texts=[["$x$ very large positive","$\\Rightarrow f(x)$ approaches x-axis from above"], ["$x$ very large negative","$\\Rightarrow f(x)$ approaches x-axis from below"], "$\\Rightarrow$ $x$ Axis is a \"horizontal Asymptote\""], buff=0.28)
#         self.add(note)

#         title = self.add_title("Asymptotes")

#         cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
#         plane = cords[0]
#         x_ax = plane.x_axis.copy().set_color(RED)
#         y_ax = plane.y_axis.copy().set_color(RED)

#         func = lambda x: 1/x+2
#         plotted_right = plane.plot(func, color=BLUE, x_range=[0.5, 8, 0.01], use_smoothing=False)
#         plotted_left = plane.plot(func, color=BLUE, x_range=[-8, -1/6, 0.01], use_smoothing=False).reverse_points()

#         xo, yo, _ = plane.x_axis.n2p(0)
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
#         cursor.add_updater(lambda m: self.bring_to_front(cursor))

#         LineOrange = Line(plane.c2p(-8,0), plane.c2p(8,0), color=ORANGE)
#         LineGreen = Line(plane.c2p(-8,2), plane.c2p(8,2), color=GREEN)
#         LinePurple = Line(plane.c2p(0,-4), plane.c2p(0,4), color=PURPLE)


#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Here's a question for you and to be fair, you cannot really know this, but try to make a guess: <bookmark mark="cords"/>
#                 
#                 Look at the <bookmark mark="f"/> function that is shown on this graph.
#                 
#                 Which of the following three lines describes the horizontal Asymptote of this function?
#                 
#                 <bookmark mark="OrangeLine"/>
#                 Is it the orange line?
#                 
#                 <bookmark mark="GreenLine"/>
#                 Is it the green line?
#                 
#                 <bookmark mark="PurpleLine"/>
#                 Or is it the purple line?
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("cords")
#             self.play(Write(cords), Write(cursor))

#             self.wait_until_bookmark("f")
#             self.play(Write(plotted_left), Write(plotted_right))

#             self.wait_until_bookmark("OrangeLine")
#             self.play(Write(LineOrange))

#             self.wait_until_bookmark("GreenLine")
#             self.play(Write(LineGreen))

#             self.wait_until_bookmark("PurpleLine")
#             self.play(Write(LinePurple))
                    
#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)


#####################################
#####################################
TASK_Func_3_2_I_2_q = SophiaTaskDefinition(
    answerOptions=["The orange line", "The green Line", "The purple line"],
    correctAnswerIndex=1,
    questionText="Which of the lines describes the horizontal asymptote of the function?",
)
class Func_3_2_I_2_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["$x$ very large positive","$\\Rightarrow f(x)$ approaches x-axis from above"], ["$x$ very large negative","$\\Rightarrow f(x)$ approaches x-axis from below"], "$\\Rightarrow$ $x$ Axis is a \"horizontal Asymptote\""], buff=0.28)
        self.add(note)

        title = self.add_title("Asymptotes")

        cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]
        x_ax = plane.x_axis.copy().set_color(RED)
        y_ax = plane.y_axis.copy().set_color(RED)

        func = lambda x: 1/x+2
        plotted_right = plane.plot(func, color=BLUE, x_range=[0.5, 8, 0.01], use_smoothing=False)
        plotted_left = plane.plot(func, color=BLUE, x_range=[-8, -1/6, 0.01], use_smoothing=False).reverse_points()

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        LineOrange = Line(plane.c2p(-8,0), plane.c2p(8,0), color=ORANGE)
        LineGreen = Line(plane.c2p(-8,2), plane.c2p(8,2), color=GREEN)
        LinePurple = Line(plane.c2p(0,-4), plane.c2p(0,4), color=PURPLE)


        # Action Sequence
        with self.voiceover(
                text="""
                Here's a question for you and to be fair, you can't really know this, but try to make a guess: <bookmark mark="cords"/>
                
                Look at the <bookmark mark="f"/> function that is shown on this graph.
                
                Which of the following three lines describes the horizontal Asymptote of this function?
                
                <bookmark mark="OrangeLine"/>
                Is it the orange line?
                
                <bookmark mark="GreenLine"/>
                Is it the green line?
                
                <bookmark mark="PurpleLine"/>
                Or is it the purple line?
                """
        ) as tracker:
            
            self.wait_until_bookmark("cords")
            self.play(Write(cords), Write(cursor))

            self.wait_until_bookmark("f")
            self.play(Write(plotted_left), Write(plotted_right))

            self.wait_until_bookmark("OrangeLine")
            self.play(Write(LineOrange))

            self.wait_until_bookmark("GreenLine")
            self.play(Write(LineGreen))

            self.wait_until_bookmark("PurpleLine")
            self.play(Write(LinePurple))
                    
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_2_I_2_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Orange Line crosses function","$\\Rightarrow$ not an asymptote"], ["Purple Line is vertical","$\\Rightarrow$ not a horizontal asymptote"], "$\\Rightarrow$ Green Line is the horizontal Asymptote"], buff=0.28)
        self.add(note)

        title = self.add_title("Asymptotes")

        cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]
        x_ax = plane.x_axis.copy().set_color(RED)
        y_ax = plane.y_axis.copy().set_color(RED)

        func = lambda x: 1/x+2
        plotted_right = plane.plot(func, color=BLUE, x_range=[0.5, 8, 0.01], use_smoothing=False)
        plotted_left = plane.plot(func, color=BLUE, x_range=[-8, -1/6, 0.01], use_smoothing=False).reverse_points()

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        LineOrange = Line(plane.c2p(-8,0), plane.c2p(8,0), color=ORANGE)
        LineGreen = Line(plane.c2p(-8,2), plane.c2p(8,2), color=GREEN)
        LinePurple = Line(plane.c2p(0,-4), plane.c2p(0,4), color=PURPLE)


        # Action Sequence
        with self.voiceover(
                text="""
                Mhm, that's not right. I admit, it was a bit tricky, so no worries!
                <bookmark mark="cords"/>
                
                So now, why is it indeed the green line that describes the vertical asymptote?
                When we look at the <bookmark mark="f"/>function, we can see that there are two lines that
                the function "hugs", so there are two lines that the function gets really close to, but never reaches:
                One is <bookmark mark="GreenLine"/>the green line,
                and the other one is <bookmark mark="PurpleLine"/>the purple line.
                
                That's also <bookmark mark="note1"/>the reason it can't be the<bookmark mark="OrangeLine"/> orange line: Because the function
                crosses that line.
                
                So now we know, that it has to be <bookmark mark="noOrange"/> either the green line or the purple line
                that describes the horizontal asymptote.
                
                But how do we know which one it is? Easy: <bookmark mark="note2"/>The purple line is a vertical line, and the green line is a horizontal line.
                Since we're looking for a horizontal asymptote, it <bookmark mark="solution"/> has to be the green line.
                """
        ) as tracker:
            
            self.wait_until_bookmark("cords")
            self.play(Write(cords), Write(cursor))

            self.wait_until_bookmark("f")
            self.play(Write(plotted_left), Write(plotted_right))

            self.wait_until_bookmark("GreenLine")
            self.play(Write(LineGreen))

            self.wait_until_bookmark("PurpleLine")
            self.play(Write(LinePurple))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("OrangeLine")
            self.play(Write(LineOrange))

            self.wait_until_bookmark("noOrange")
            self.play(FadeOut(LineOrange))

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("solution")
            note.change_colors([1,2])
            self.play(FadeOut(LinePurple), LineGreen.animate.set_stroke_width(10), run_time=1)
            self.play(FadeOut(LinePurple), LineGreen.animate.set_stroke_width(4), run_time=1)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

        
        

class Func_3_2_I_2_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Orange Line crosses function","$\\Rightarrow$ not an asymptote"], ["Purple Line is vertical","$\\Rightarrow$ not a horizontal asymptote"], "$\\Rightarrow$ Green Line is the horizontal Asymptote"], buff=0.28)
        self.add(note)

        title = self.add_title("Asymptotes")

        cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]
        x_ax = plane.x_axis.copy().set_color(RED)
        y_ax = plane.y_axis.copy().set_color(RED)

        func = lambda x: 1/x+2
        plotted_right = plane.plot(func, color=BLUE, x_range=[0.5, 8, 0.01], use_smoothing=False)
        plotted_left = plane.plot(func, color=BLUE, x_range=[-8, -1/6, 0.01], use_smoothing=False).reverse_points()

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        LineOrange = Line(plane.c2p(-8,0), plane.c2p(8,0), color=ORANGE)
        LineGreen = Line(plane.c2p(-8,2), plane.c2p(8,2), color=GREEN)
        LinePurple = Line(plane.c2p(0,-4), plane.c2p(0,4), color=PURPLE)


        # Action Sequence
        with self.voiceover(
                text="""
                Wow, that's correct. I admit, it was a bit tricky, so great job for getting it right!
                <bookmark mark="cords"/>
                
                So now, why is it indeed the green line that describes the vertical asymptote?
                When we look at the <bookmark mark="f"/>function, we can see that there are two lines that
                the function "hugs", so there are two lines that the function gets really close to, but never reaches:
                One is <bookmark mark="GreenLine"/>the green line,
                and the other one is <bookmark mark="PurpleLine"/>the purple line.
                
                That's also <bookmark mark="note1"/>the reason it can't be the<bookmark mark="OrangeLine"/> orange line: Because the function
                crosses that line.
                
                So now we know, that it has to be <bookmark mark="noOrange"/> either the green line or the purple line
                that describes the horizontal asymptote.
                
                But how do we know which one it is? Easy: <bookmark mark="note2"/>The purple line is a vertical line, and the green line is a horizontal line.
                Since we're looking for a horizontal asymptote, it <bookmark mark="solution"/> has to be the green line.
                """
        ) as tracker:
            
            self.wait_until_bookmark("cords")
            self.play(Write(cords), Write(cursor))

            self.wait_until_bookmark("f")
            self.play(Write(plotted_left), Write(plotted_right))

            self.wait_until_bookmark("GreenLine")
            self.play(Write(LineGreen))

            self.wait_until_bookmark("PurpleLine")
            self.play(Write(LinePurple))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("OrangeLine")
            self.play(Write(LineOrange))

            self.wait_until_bookmark("noOrange")
            self.play(FadeOut(LineOrange))

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("solution")
            note.change_colors([1,2])
            self.play(FadeOut(LinePurple), LineGreen.animate.set_stroke_width(10), run_time=1)
            self.play(FadeOut(LinePurple), LineGreen.animate.set_stroke_width(4), run_time=1)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_2_I_2_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Orange Line crosses function","$\\Rightarrow$ not an asymptote"], ["Purple Line is vertical","$\\Rightarrow$ not a horizontal asymptote"], "$\\Rightarrow$ Green Line is the horizontal Asymptote"], buff=0.28)
        self.add(note)

        title = self.add_title("Asymptotes")

        cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]
        x_ax = plane.x_axis.copy().set_color(RED)
        y_ax = plane.y_axis.copy().set_color(RED)

        func = lambda x: 1/x+2
        plotted_right = plane.plot(func, color=BLUE, x_range=[0.5, 8, 0.01], use_smoothing=False)
        plotted_left = plane.plot(func, color=BLUE, x_range=[-8, -1/6, 0.01], use_smoothing=False).reverse_points()

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        LineOrange = Line(plane.c2p(-8,0), plane.c2p(8,0), color=ORANGE)
        LineGreen = Line(plane.c2p(-8,2), plane.c2p(8,2), color=GREEN)
        LinePurple = Line(plane.c2p(0,-4), plane.c2p(0,4), color=PURPLE)


        # Action Sequence
        with self.voiceover(
                text="""
                Mhm, that's not right. I admit, it was a bit tricky, so no worries!
                <bookmark mark="cords"/>
                
                So now, why is it indeed the green line that describes the vertical asymptote?
                When we look at the <bookmark mark="f"/>function, we can see that there are two lines that
                the function "hugs", so there are two lines that the function gets really close to, but never reaches:
                One is <bookmark mark="GreenLine"/>the green line,
                and the other one is <bookmark mark="PurpleLine"/>the purple line.
                
                That's also <bookmark mark="note1"/>the reason it can't be the<bookmark mark="OrangeLine"/> orange line: Because the function
                crosses that line.
                
                So now we know, that it has to be <bookmark mark="noOrange"/> either the green line or the purple line
                that describes the horizontal asymptote.
                
                But how do we know which one it is? Easy: <bookmark mark="note2"/>The purple line is a vertical line, and the green line is a horizontal line.
                Since we're looking for a horizontal asymptote, it <bookmark mark="solution"/> has to be the green line.
                """
        ) as tracker:
            
            self.wait_until_bookmark("cords")
            self.play(Write(cords), Write(cursor))

            self.wait_until_bookmark("f")
            self.play(Write(plotted_left), Write(plotted_right))

            self.wait_until_bookmark("GreenLine")
            self.play(Write(LineGreen))

            self.wait_until_bookmark("PurpleLine")
            self.play(Write(LinePurple))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("OrangeLine")
            self.play(Write(LineOrange))

            self.wait_until_bookmark("noOrange")
            self.play(FadeOut(LineOrange))

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("solution")
            note.change_colors([1,2])
            self.play(FadeOut(LinePurple), LineGreen.animate.set_stroke_width(10), run_time=1)
            self.play(FadeOut(LinePurple), LineGreen.animate.set_stroke_width(4), run_time=1)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
class Func_3_2_I_3(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Asymptote of a function f:","A line that the function gets","arbitrarily close to,","but never reaches"]], buff=0.28)
        self.add(note)

        title = self.add_title("Asymptotes")

        cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]
        x_ax = plane.x_axis.copy().set_color(RED)
        y_ax = plane.y_axis.copy().set_color(RED)

        func = lambda x: 1/x+2
        plotted_right = plane.plot(func, color=BLUE, x_range=[0.5, 8, 0.01], use_smoothing=False)
        plotted_left = plane.plot(func, color=BLUE, x_range=[-8, -1/6, 0.01], use_smoothing=False).reverse_points()

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        LineGreen = Line(plane.c2p(-8,2), plane.c2p(8,2), color=GREEN)
        LinePurple = Line(plane.c2p(0,-4), plane.c2p(0,4), color=PURPLE)


        # Action Sequence
        with self.voiceover(
                text="""
                Ok, now let's define what an asymptote actually is. Listen up:
                
                An asymptote of <bookmark mark="cords"/>a function f, is a line that the function gets arbitrarily close to, but never reaches.
                
                We are considering two types of asymptotes: <bookmark mark="horizontal"/> Horizontal asymptotes, and<bookmark mark="vertical"/> vertical asymptotes.
                
                A horizontal asymptote is simply an asymptote that is parallel to <bookmark mark="x"/>the x-axis, so a horizontal line that
                the function gets arbitrarily close to, but never reaches.
                
                <bookmark mark="cursorReset"/>
                In this example, the green line is a horizontal asymptote.
                
                A vertical asymptote on the other hand, is an asymptote that is parallel to <bookmark mark="y"/>the y-axis, so a vertical line that
                the function gets arbitrarily close to, but never reaches. <bookmark mark="fin"/>
                
                In this example, the purple line is a vertical asymptote.
                """
        ) as tracker:
            
            self.wait_until_bookmark("cords")
            self.play(Write(cords), Write(cursor), Write(plotted_left), Write(plotted_right))

            self.wait_until_bookmark("horizontal")
            self.play(Write(LineGreen))

            self.wait_until_bookmark("vertical")
            self.play(Write(LinePurple))

            self.wait_until_bookmark("x")
            cursor.blinking=False
            self.play(CursorMarkAxis(cursor, plane))

            self.wait_until_bookmark("cursorReset")
            self.play(CursorMoveResize(cursor, xo, yo, 0.2, 0.2))
            cursor.blinking=True

            self.wait_until_bookmark("y")
            cursor.blinking=False
            self.play(CursorMarkAxis(cursor, plane, axis='y'))

            self.wait_until_bookmark("fin")
            self.play(CursorMoveResize(cursor, xo, yo, 0.2, 0.2))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)



#####################################
#####################################
#### Practice Part ##################
#####################################
#####################################



#####################################
#####################################
### Question Templates ##############
#####################################
#####################################

class horizontalAsymptoteQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["Consider the function shown here", "Is the green line a horizontal asymptote?", "Is the purple line a horizontal asymptote?"], buff=0.28)
        self.add(note)

        title = self.add_title("Asymptotes")

        cords = self.cords
        plane = cords[0]
        xmin, xmax, _ = plane.get_x_range()

        plots = VGroup(*[plane.plot(self.funcs[i], color=BLUE, x_range=self.funcRanges[i], use_smoothing=False) for i in range(len(self.funcs))])

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        LineGreen = Line(plane.c2p(xmin,self.yGreen), plane.c2p(xmax,self.yGreen), color=GREEN)
        LinePurple = Line(plane.c2p(xmin,self.yPurple), plane.c2p(xmax,self.yPurple), color=PURPLE)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.introText}
                <bookmark mark="note1"/>Consider the function <bookmark mark="cords"/> f that belongs to the graph,
                which is <bookmark mark="f"/>shown here.
                
                <bookmark mark="note2"/>Is the <bookmark mark="green"/>green line a horizontal asymptote of the function?
                
                <bookmark mark="note3"/>And what about the purple line, is the <bookmark mark="purple"/>purple line a horizontal asymptote of the function?
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("cords")
            self.play(Write(cords), Write(cursor))

            self.wait_until_bookmark("f")
            self.play(Write(plots))

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("green")
            self.play(Write(LineGreen))

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

            self.wait_until_bookmark("purple")
            self.play(Write(LinePurple))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class horizontalAsymptoteAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Asymptote of a function f:","A line that the function gets","arbitrarily close to,","but never reaches"]], buff=0.28)
        self.add(note)

        title = self.add_title("Asymptotes")

        cords = self.cords
        plane = cords[0]
        xmin, xmax, _ = plane.get_x_range()

        plots = VGroup(*[plane.plot(self.funcs[i], color=BLUE, x_range=self.funcRanges[i], use_smoothing=False) for i in range(len(self.funcs))])

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        LineGreen = Line(plane.c2p(xmin,self.yGreen), plane.c2p(xmax,self.yGreen), color=GREEN)
        LinePurple = Line(plane.c2p(xmin,self.yPurple), plane.c2p(xmax,self.yPurple), color=PURPLE)



        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.introText}
                An asymptote of a function f, is a line that the function gets arbitrarily close to, but never reaches.
                
                This means the <bookmark mark="green"/>green line is {self.greenText}
                
                It also implies that the <bookmark mark="purple"/>purple line {self.purpleText}
                """
        ) as tracker:
            
            self.play(Write(cords), Write(cursor), Write(plots))

            self.wait_until_bookmark("green")
            self.play(Write(LineGreen))

            self.wait_until_bookmark("purple")
            self.play(Write(LinePurple))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
class verticalAsymptoteQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["Consider the function shown here", "Is the green line a vertical asymptote?", "Is the purple line a vertical asymptote?"], buff=0.28)
        self.add(note)

        title = self.add_title("Asymptotes")

        cords = self.cords
        plane = cords[0]
        ymin, ymax, _ = plane.get_y_range()

        plots = VGroup(*[plane.plot(self.funcs[i], color=BLUE, x_range=self.funcRanges[i], use_smoothing=False) for i in range(len(self.funcs))])

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        LineGreen = Line(plane.c2p(self.xGreen, ymin), plane.c2p(self.xGreen, ymax), color=GREEN)
        LinePurple = Line(plane.c2p(self.xPurple, ymin), plane.c2p(self.xPurple, ymax), color=PURPLE)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.introText}
                <bookmark mark="note1"/>Consider the function <bookmark mark="cords"/> f that belongs to the graph,
                which is <bookmark mark="f"/>shown here.
                
                <bookmark mark="note2"/>Is the <bookmark mark="green"/>green line a vertical asymptote of the function?
                
                <bookmark mark="note3"/>And what about the purple line, is the <bookmark mark="purple"/>purple line a vertical asymptote of the function?
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("cords")
            self.play(Write(cords), Write(cursor))

            self.wait_until_bookmark("f")
            self.play(Write(plots))

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("green")
            self.play(Write(LineGreen))

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

            self.wait_until_bookmark("purple")
            self.play(Write(LinePurple))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class verticalAsymptoteAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Asymptote of a function f:","A line that the function gets","arbitrarily close to,","but never reaches"]], buff=0.28)
        self.add(note)

        title = self.add_title("Asymptotes")

        cords = self.cords
        plane = cords[0]
        ymin, ymax, _ = plane.get_y_range()

        plots = VGroup(*[plane.plot(self.funcs[i], color=BLUE, x_range=self.funcRanges[i], use_smoothing=False) for i in range(len(self.funcs))])

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        LineGreen = Line(plane.c2p(self.xGreen, ymin), plane.c2p(self.xGreen, ymax), color=GREEN)
        LinePurple = Line(plane.c2p(self.xPurple, ymin), plane.c2p(self.xPurple, ymax), color=PURPLE)



        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.introText}
                An asymptote of a function f, is a line that the function gets arbitrarily close to, but never reaches.
                
                This means the <bookmark mark="green"/>green line is {self.greenText}
                
                It also implies that the <bookmark mark="purple"/>purple line {self.purpleText}
                """
        ) as tracker:
            
            self.play(Write(cords), Write(cursor), Write(plots))

            self.wait_until_bookmark("green")
            self.play(Write(LineGreen))

            self.wait_until_bookmark("purple")
            self.play(Write(LinePurple))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
### Actual Questions ################
#####################################
#####################################

#####################################
#####################################
TASK_Func_3_2_P_1_q = SophiaTaskDefinition(
    answerOptions=["The Purple line", "The green Line", "Both lines", "neither of the lines"],
    correctAnswerIndex=1,
    questionText="Which of the lines describes a horizontal asymptote of the function?",
)
class Func_3_2_P_1_q(horizontalAsymptoteQuestionScene):

    def construct(self):

        self.introText = "Let's practice!"
        self.funcs = [lambda x: 1/x+2, lambda x: 1/x+2]
        self.funcRanges = [[0.5, 8, 0.01], [-8, -1/6, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.yGreen = 2
        self.yPurple = -2

        super().construct()

class Func_3_2_P_1_a(horizontalAsymptoteAnswerScene):

    def construct(self):

        self.introText = "Nope, not quite right! Remember the definition of an Asymptote:"
        self.funcs = [lambda x: 1/x+2, lambda x: 1/x+2]
        self.funcRanges = [[0.5, 8, 0.01], [-8, -1/6, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.yGreen = 2
        self.yPurple = -2
        self.greenText = "an asymptote of the function, because the function gets arbitrarily close to it, but never reaches it."
        self.purpleText = "is not an asymptote of the function, because the function crosses it."

        super().construct()

class Func_3_2_P_1_b(horizontalAsymptoteAnswerScene):

    def construct(self):

        self.introText = "Nope, not quite right! Remember the definition of an Asymptote:"
        self.funcs = [lambda x: 1/x+2, lambda x: 1/x+2]
        self.funcRanges = [[0.5, 8, 0.01], [-8, -1/6, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.yGreen = 2
        self.yPurple = -2
        self.greenText = "an asymptote of the function, because the function gets arbitrarily close to it, but never reaches it."
        self.purpleText = "is not an asymptote of the function, because the function crosses it."

        super().construct()

class Func_3_2_P_1_c(horizontalAsymptoteAnswerScene):

    def construct(self):

        self.introText = "Yep, you got it! Remember the definition of an Asymptote:"
        self.funcs = [lambda x: 1/x+2, lambda x: 1/x+2]
        self.funcRanges = [[0.5, 8, 0.01], [-8, -1/6, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.yGreen = 2
        self.yPurple = -2
        self.greenText = "an asymptote of the function, because the function gets arbitrarily close to it, but never reaches it."
        self.purpleText = "is not an asymptote of the function, because the function crosses it."

        super().construct()

class Func_3_2_P_1_d(horizontalAsymptoteAnswerScene):

    def construct(self):

        self.introText = "Nope, not quite right! Remember the definition of an Asymptote:"
        self.funcs = [lambda x: 1/x+2, lambda x: 1/x+2]
        self.funcRanges = [[0.5, 8, 0.01], [-8, -1/6, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.yGreen = 2
        self.yPurple = -2
        self.greenText = "an asymptote of the function, because the function gets arbitrarily close to it, but never reaches it."
        self.purpleText = "is not an asymptote of the function, because the function crosses it."

        super().construct()

#####################################
#####################################
TASK_Func_3_2_P_2_q = SophiaTaskDefinition(
    answerOptions=["The purple line", "The green Line", "Both lines", "neither of the lines"],
    correctAnswerIndex=0,
    questionText="Which of the lines describes a horizontal asymptote of the function?",
)
class Func_3_2_P_2_q(verticalAsymptoteQuestionScene):

    def construct(self):

        self.introText = "Let's look at vertical asymptotes now."
        self.funcs = [lambda x: 1/x+2, lambda x: 1/x+2]
        self.funcRanges = [[0.5, 8, 0.01], [-8, -1/6, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.xGreen = 2
        self.xPurple = 0

        super().construct()

class Func_3_2_P_2_a(verticalAsymptoteAnswerScene):

    def construct(self):

        self.introText = "Yep, that is correct! Excellent! Remember the definition of an Asymptote:"
        self.funcs = [lambda x: 1/x+2, lambda x: 1/x+2]
        self.funcRanges = [[0.5, 8, 0.01], [-8, -1/6, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.xGreen = 0
        self.xPurple = -2
        self.greenText = "an asymptote of the function, because the function gets arbitrarily close to it, but never reaches it."
        self.purpleText = "is not an asymptote of the function, because the function crosses it."


        super().construct()

class Func_3_2_P_2_b(verticalAsymptoteAnswerScene):

    def construct(self):

        self.introText = "Nope, not quite right! Remember the definition of an Asymptote:"
        self.funcs = [lambda x: 1/x+2, lambda x: 1/x+2]
        self.funcRanges = [[0.5, 8, 0.01], [-8, -1/6, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.xGreen = 0
        self.xPurple = -2
        self.greenText = "an asymptote of the function, because the function gets arbitrarily close to it, but never reaches it."
        self.purpleText = "is not an asymptote of the function, because the function crosses it."

        super().construct()

class Func_3_2_P_2_c(verticalAsymptoteAnswerScene):

    def construct(self):

        self.introText = "Nope, not quite right! Remember the definition of an Asymptote:"
        self.funcs = [lambda x: 1/x+2, lambda x: 1/x+2]
        self.funcRanges = [[0.5, 8, 0.01], [-8, -1/6, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.xGreen = 0
        self.xPurple = -2
        self.greenText = "an asymptote of the function, because the function gets arbitrarily close to it, but never reaches it."
        self.purpleText = "is not an asymptote of the function, because the function crosses it."

        super().construct()

class Func_3_2_P_2_d(verticalAsymptoteAnswerScene):

    def construct(self):

        self.introText = "Nope, not quite right! Remember the definition of an Asymptote:"
        self.funcs = [lambda x: 1/x+2, lambda x: 1/x+2]
        self.funcRanges = [[0.5, 8, 0.01], [-8, -1/6, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.xGreen = 0
        self.xPurple = -2
        self.greenText = "an asymptote of the function, because the function gets arbitrarily close to it, but never reaches it."
        self.purpleText = "is not an asymptote of the function, because the function crosses it."

        super().construct()


#####################################
#####################################

TASK_Func_3_2_P_3_q = SophiaTaskDefinition(
    answerOptions=["The purple line", "The green Line", "Both lines", "neither of the lines"],
    correctAnswerIndex=2,
    questionText="Which of the lines describes a horizontal asymptote of the function?",
)
class Func_3_2_P_3_q(verticalAsymptoteQuestionScene):

    def construct(self):

        self.introText = "Let's look at vertical asymptotes once more."
        self.funcs = 3*[lambda x: 1/((x-1)*(x+1))+1]
        self.funcRanges = [[-8, -1.1547, 0.01], [-0.89442, 0.89442, 0.01], [1.1547, 8, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.xGreen = 1
        self.xPurple = -1

        super().construct()

class Func_3_2_P_3_a(verticalAsymptoteAnswerScene):

    def construct(self):

        self.introText = "That's not correct. Remember: We defined asymptotes like this:"
        self.funcs = 3*[lambda x: 1/((x-1)*(x+1))+1]
        self.funcRanges = [[-8, -1.1547, 0.01], [-0.89442, 0.89442, 0.01], [1.1547, 8, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.xGreen = 1
        self.xPurple = -1
        self.greenText = "an asymptote of the function, because the function gets arbitrarily close to it, but never reaches it."
        self.purpleText = "is also an asymptote of the function, again because the function gets arbitrarily close to it, but never reaches it."

        super().construct()

class Func_3_2_P_3_b(verticalAsymptoteAnswerScene):

    def construct(self):

        self.introText = "That's not correct. Remember: We defined asymptotes like this:"
        self.funcs = 3*[lambda x: 1/((x-1)*(x+1))+1]
        self.funcRanges = [[-8, -1.1547, 0.01], [-0.89442, 0.89442, 0.01], [1.1547, 8, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.xGreen = 1
        self.xPurple = -1
        self.greenText = "an asymptote of the function, because the function gets arbitrarily close to it, but never reaches it."
        self.purpleText = "is also an asymptote of the function, again because the function gets arbitrarily close to it, but never reaches it."

        super().construct()

class Func_3_2_P_3_c(verticalAsymptoteAnswerScene):

    def construct(self):

        self.introText = "Yep, that is correct! Excellent! Remember the definition of an Asymptote:"
        self.funcs = 3*[lambda x: 1/((x-1)*(x+1))+1]
        self.funcRanges = [[-8, -1.1547, 0.01], [-0.89442, 0.89442, 0.01], [1.1547, 8, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.xGreen = 1
        self.xPurple = -1
        self.greenText = "an asymptote of the function, because the function gets arbitrarily close to it, but never reaches it."
        self.purpleText = "is also an asymptote of the function, again because the function gets arbitrarily close to it, but never reaches it."


        super().construct()

class Func_3_2_P_3_d(verticalAsymptoteAnswerScene):

    def construct(self):

        self.introText = "That's not correct. Remember: We defined asymptotes like this:"
        self.funcs = 3*[lambda x: 1/((x-1)*(x+1))+1]
        self.funcRanges = [[-8, -1.1547, 0.01], [-0.89442, 0.89442, 0.01], [1.1547, 8, 0.01]]
        self.cords = self.add_cords([-8,8, 2], [-4, 4, 1], x_ticks=[4*i-8 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        self.xGreen = 1
        self.xPurple = -1
        self.greenText = "an asymptote of the function, because the function gets arbitrarily close to it, but never reaches it."
        self.purpleText = "is also an asymptote of the function, again because the function gets arbitrarily close to it, but never reaches it."

        super().construct()


PROTOTYPES = [
    PagePrototypeVideo.from_scene(Func_3_2_I_1),
    PagePrototypeVideo.from_scene(Func_3_2_I_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_3_2_I_2_q, Func_3_2_I_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_3_2_I_2_a),
    PagePrototypeVideo.from_scene(Func_3_2_I_2_b),
    PagePrototypeVideo.from_scene(Func_3_2_I_2_c),
    PagePrototypeVideo.from_scene(Func_3_2_I_3),
    PagePrototypeVideo.from_scene(Func_3_2_P_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_3_2_P_1_q, Func_3_2_P_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_3_2_P_1_a),
    PagePrototypeVideo.from_scene(Func_3_2_P_1_b),
    PagePrototypeVideo.from_scene(Func_3_2_P_1_c),
    PagePrototypeVideo.from_scene(Func_3_2_P_1_d),
    PagePrototypeVideo.from_scene(Func_3_2_P_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_3_2_P_2_q, Func_3_2_P_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_3_2_P_2_a),
    PagePrototypeVideo.from_scene(Func_3_2_P_2_b),
    PagePrototypeVideo.from_scene(Func_3_2_P_2_c),
    PagePrototypeVideo.from_scene(Func_3_2_P_2_d),
    PagePrototypeVideo.from_scene(Func_3_2_P_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_3_2_P_3_q, Func_3_2_P_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_3_2_P_3_a),
    PagePrototypeVideo.from_scene(Func_3_2_P_3_b),
    PagePrototypeVideo.from_scene(Func_3_2_P_3_c),
    PagePrototypeVideo.from_scene(Func_3_2_P_3_d),
]
scenes/Func/Func_3: Rational Functions I/Func3_2.py
Sophia-Edu-Labs/sophia-math
# 3_3: Fractional Rational Functions: Shifting and Scaling

# Import necessary libraries and modules
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition

#####################################
#####################################
#### Instruction Part ###############
#####################################
#####################################


#This function takes an interval [a,b] and returns a lower and an upper bound c and d,
#such that f is between min and max in that range. This is achieved through sampling.
def get_valid_xrange(a,b,min,max,f):
    x = np.linspace(a,b,1000)
    y = f(x)
    valid_x = x[(y > min) & (y < max)]
    return [valid_x.min(), valid_x.max()]


#####################################
#####################################
class Func_3_3_I_1(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Asymptotes are lines that a function","gets arbitrarily close to but never touches."], ["Singularities are points where", "the function is  undefined,"], ["A hyperbola is the curve describing the", "graph of a fractional rational function."]], buff=0.25, buff_inner=0.05)
        self.add(note)

        title = self.add_title("Fractional rational functions")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        f = MathTex("f(x)=\\tfrac{a}{x+b}+c", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)

        # Action Sequence
        with self.voiceover(
                text="""
                Before we start diving into a new topic, let's review some of the vocabulary related to
                <bookmark mark="cords"/>fractional rational functions. We've already covered what an <bookmark mark="note1"/>asymptote is:
                Asymptotes are lines that a function gets arbitrarily close to but never touches.
                
                There are vertical asymptotes, like the <bookmark mark="x"/>x-axis in this example,
                and there are horizontal asymptotes, like the <bookmark mark="y"/>y-axis in this example.
                
                <bookmark mark="singularities1"/>
                Then there are singularities, that is points where the function is not defined,
                because the denominator would be zero. In our example, the singularity is at <bookmark mark="singularities2"/>x equals zero.
                
                <bookmark mark="note2"/>
                Now, a new term: Hyperbola.
                
                A hyperbola is the graph of a fractional rational function. Hyperbolas are easily recognizable,
                because they have two branches, one on each side of the asymptotes.
                
                So in our example, the hyperbola is the graph consisting of <bookmark mark="leftCurve"/>the left curve 
                and <bookmark mark="rightCurve"/>the right curve.
                """
        ) as tracker:
            
            self.wait_until_bookmark("cords")
            self.play(Write(cords), Write(plotted_right), Write(plotted_left), Write(cursor))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("x")
            cursor.blinking=False
            self.play(CursorMarkAxis(cursor, plane))

            self.wait_until_bookmark("y")
            self.play(CursorMarkAxis(cursor, plane, axis="y"))

            self.wait_until_bookmark("singularities1")
            note.change_colors([0,1])
            self.play(CursorMoveResize(cursor, xo, yo, 0.2, 0.2))
            cursor.blinking=True

            self.wait_until_bookmark("singularities2")
            cursor.blinking=False
            self.play(CursorMarkAxis(cursor, plane, axis="y"), run_time=0.5)
            self.wait(1)
            self.play(CursorMoveResize(cursor, xo, yo, 0.2, 0.2))
            cursor.blinking=True

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])

            self.wait_until_bookmark("leftCurve")
            x,y,_ = plane.c2p(-1,-1)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("rightCurve")
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.wait(0.5)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_3_3_I_2_q = SophiaTaskDefinition(
    answerOptions=["It is stretched in y-Direction", "It is shifted in x-Direction", "It is squashed in y-Direction",  "It is shifted in y-Direction"],
    correctAnswerIndex=2,
    questionText="How does the graph change when it is multiplied with $a<1$?",
)
class Func_3_3_I_2_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["Consider function $f(x)=\\tfrac{1}{x}$", ["Scale the function by multilpying", "with factor $a\\rightarrow f(x)=\\tfrac a x$"], "How does the graph change when $a<1$?"], buff=0.25, buff_inner=0.05)
        self.add(note)

        title = self.add_title("Scaling the function")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        f0 = MathTex("f(x)=\\tfrac1x", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        f1 = MathTex("f(x)=\\tfrac ax", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        f = MathTex("f(x)=\\tfrac{a}{x+b}+c", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)

        # Action Sequence
        with self.voiceover(
                text="""
                Look at <bookmark mark="graph"/> this graph.
                
                It's a hyperbola, and it shows the graph of the function <bookmark mark="f0"/>f of x equals one over x.
                
                Let's now explore how we can transform this function.
                <bookmark mark="note1"/>
                One thing we can do, is scale the function. If we multiply the function by a, we can write <bookmark mark="f1"/>f of x equals a over x.
                Then we are scaling the function by a factor of a.
                <bookmark mark="note2"/>
                But what does this change? Let's say that <bookmark mark="aLessOne"/>a is smaller than one. What happens to the function?

                """
        ) as tracker:
            
            self.wait_until_bookmark("graph")
            note.change_colors([0])
            self.play(Write(cords), Write(plotted_right), Write(plotted_left), Write(cursor))
            
            self.wait_until_bookmark("f0")
            self.play(Write(f0))

            self.wait_until_bookmark("note1")
            note.change_colors([0,1])

            self.wait_until_bookmark("f1")
            self.play(ReplacementTransform(f0, f1))

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_2_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["$a<1$", ["$\\rightarrow$ we multiply each","value by something$<1$"], "The graph is squashed in y-Direction"], buff=0.25, buff_inner=0.05)
        self.add(note)

        title = self.add_title("Scaling the function")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        f0 = MathTex("f(x)=\\tfrac1x", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        f1 = MathTex("f(x)=\\tfrac ax", ",\\,a=", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        a_tex = DecimalNumber(1, num_decimal_places=2, color=c1t).scale(0.8).next_to(f1, RIGHT, buff=0.1).shift(0.05*UP).add_updater(lambda m: m.set_value(a.get_value()))

        self.add(cords, plotted_right, plotted_left, cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it.
                
                So we're going from the function <bookmark mark="f1"/> f of x equals one over x to the function
                <bookmark mark="f2"/> f of x equals a over x, <bookmark mark="note1"/> where a is smaller than one.
                
                Since a is smaller than one, this we're means <bookmark mark="note2"/>multiplying one over x by a value that is smaller than one.
                
                That in turn, means that we're multiplying each value of the function by <bookmark mark="decimalNumber"/>something than one.
                <bookmark mark="note3"/>So we're kind of squashing the function in the y-direction.
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("f1")
            self.play(Write(f0))

            self.wait_until_bookmark("f2")
            self.play(ReplacementTransform(f0, f1[0]))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("decimalNumber")
            x,y,_ = plane.c2p(1,1)
            cursor.blinking=False
            self.play(Write(a_tex), Write(f1[1]), CursorMoveTo(cursor, x, y))
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, a.get_value())))
            self.play(a.animate.set_value(0.1), run_time=10)

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_2_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["$a<1$", ["$\\rightarrow$ we multiply each","value by something$<1$"], "The graph is squashed in y-Direction"], buff=0.25, buff_inner=0.05)
        self.add(note)

        title = self.add_title("Scaling the function")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        f0 = MathTex("f(x)=\\tfrac1x", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        f1 = MathTex("f(x)=\\tfrac ax", ",\\,a=", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        a_tex = DecimalNumber(1, num_decimal_places=2, color=c1t).scale(0.8).next_to(f1, RIGHT, buff=0.1).shift(0.05*UP).add_updater(lambda m: m.set_value(a.get_value()))

        self.add(cords, plotted_right, plotted_left, cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it.
                
                So we're going from the function <bookmark mark="f1"/> f of x equals one over x to the function
                <bookmark mark="f2"/> f of x equals a over x, <bookmark mark="note1"/> where a is smaller than one.
                
                Since a is smaller than one, this we're means <bookmark mark="note2"/>multiplying one over x by a value that is smaller than one.
                
                That in turn, means that we're multiplying each value of the function by <bookmark mark="decimalNumber"/>something than one.
                <bookmark mark="note3"/>So we're kind of squashing the function in the y-direction.
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("f1")
            self.play(Write(f0))

            self.wait_until_bookmark("f2")
            self.play(ReplacementTransform(f0, f1[0]))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("decimalNumber")
            x,y,_ = plane.c2p(1,1)
            cursor.blinking=False
            self.play(Write(a_tex), Write(f1[1]), CursorMoveTo(cursor, x, y))
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, a.get_value())))
            self.play(a.animate.set_value(0.1), run_time=10)

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_2_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["$a<1$", ["$\\rightarrow$ we multiply each","value by something$<1$"], "The graph is squashed in y-Direction"], buff=0.25, buff_inner=0.05)
        self.add(note)

        title = self.add_title("Scaling the function")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        f0 = MathTex("f(x)=\\tfrac1x", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        f1 = MathTex("f(x)=\\tfrac ax", ",\\,a=", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        a_tex = DecimalNumber(1, num_decimal_places=2, color=c1t).scale(0.8).next_to(f1, RIGHT, buff=0.1).shift(0.05*UP).add_updater(lambda m: m.set_value(a.get_value()))

        self.add(cords, plotted_right, plotted_left, cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                You got it! Nice!
                
                So we're going from the function <bookmark mark="f1"/> f of x equals one over x to the function
                <bookmark mark="f2"/> f of x equals a over x, <bookmark mark="note1"/> where a is smaller than one.
                
                Since a is smaller than one, this we're means <bookmark mark="note2"/>multiplying one over x by a value that is smaller than one.
                
                That in turn, means that we're multiplying each value of the function by <bookmark mark="decimalNumber"/>something than one.
                <bookmark mark="note3"/>So we're kind of squashing the function in the y-direction.
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("f1")
            self.play(Write(f0))

            self.wait_until_bookmark("f2")
            self.play(ReplacementTransform(f0, f1[0]))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("decimalNumber")
            x,y,_ = plane.c2p(1,1)
            cursor.blinking=False
            self.play(Write(a_tex), Write(f1[1]), CursorMoveTo(cursor, x, y))
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, a.get_value())))
            self.play(a.animate.set_value(0.1), run_time=10)

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_2_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["$a<1$", ["$\\rightarrow$ we multiply each","value by something$<1$"], "The graph is squashed in y-Direction"], buff=0.25, buff_inner=0.05)
        self.add(note)

        title = self.add_title("Scaling the function")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        f0 = MathTex("f(x)=\\tfrac1x", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        f1 = MathTex("f(x)=\\tfrac ax", ",\\,a=", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        a_tex = DecimalNumber(1, num_decimal_places=2, color=c1t).scale(0.8).next_to(f1, RIGHT, buff=0.1).shift(0.05*UP).add_updater(lambda m: m.set_value(a.get_value()))

        self.add(cords, plotted_right, plotted_left, cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it.
                
                So we're going from the function <bookmark mark="f1"/> f of x equals one over x to the function
                <bookmark mark="f2"/> f of x equals a over x, <bookmark mark="note1"/> where a is smaller than one.
                
                Since a is smaller than one, this we're means <bookmark mark="note2"/>multiplying one over x by a value that is smaller than one.
                
                That in turn, means that we're multiplying each value of the function by <bookmark mark="decimalNumber"/>something than one.
                <bookmark mark="note3"/>So we're kind of squashing the function in the y-direction.
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("f1")
            self.play(Write(f0))

            self.wait_until_bookmark("f2")
            self.play(ReplacementTransform(f0, f1[0]))

            self.wait_until_bookmark("note1")
            note.change_colors([0])

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("decimalNumber")
            x,y,_ = plane.c2p(1,1)
            cursor.blinking=False
            self.play(Write(a_tex), Write(f1[1]), CursorMoveTo(cursor, x, y))
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, a.get_value())))
            self.play(a.animate.set_value(0.1), run_time=10)

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_3_3_I_3_q = SophiaTaskDefinition(
    answerOptions=["It is stretched in y-Direction", "It is squashed in y-Direction", "It is shifted in x-Direction", "It is flipped around the x-axis"],
    correctAnswerIndex=3,
    questionText="How does the graph change when it is multiplied with $a<0$?",
)
class Func_3_3_I_3_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["Consider $f(x)=\\tfrac ax$", ["$a<1\\Rightarrow$ f is squashed","$a>1\\Rightarrow$ f is stretched"], "What happens for $a=-1$?"], buff=0.25, buff_inner=0.05)
        self.add(note)

        title = self.add_title("Fractional rational functions")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        f1 = MathTex("f(x)=\\tfrac ax", ",\\,a=", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        a_tex = DecimalNumber(1, num_decimal_places=1, color=c1t).scale(0.8).next_to(f1, RIGHT, buff=0.1).shift(0.05*UP).add_updater(lambda m: m.set_value(a.get_value()))
        a_tex_neg1 = MathTex("-1", color=c1t).scale(0.8).next_to(f1, RIGHT, buff=0.1).shift(0.05*UP)
        self.add(cords, plotted_right, plotted_left, cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so we're looking at <bookmark mark="f"/> f of x equals a over x and we can see <bookmark mark="moveCursor"/>
                that for <bookmark mark="smallA1"/>small a, the function is squashed in the y-direction.
                
                For <bookmark mark="largeA1"/>large values of a on the other hand, the function is stretched in the y-direction.
                
                This makes intuitive sense: We multiply with large values, so the function gets stretched,
                because both positive and negative values get larger.
                
                If we multiply with <bookmark mark="smallA2"/>small values, the function gets squashed, because both positive and negative
                values get smaller.
                
                <bookmark mark="resetA"/>Now, those were all positive values.
                What happens, if we plug in something negative for "a"? For example, what will happen if we set <bookmark mark="neg1"/>"a" to minus one?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            note.change_colors([0])
            self.play(Write(f1), Write(a_tex))

            self.wait_until_bookmark("moveCursor")
            x,y,_ = plane.c2p(1,1)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y))

            self.wait_until_bookmark("smallA1")
            note.change_colors([0,1])
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, a.get_value())))
            self.play(a.animate.set_value(0.1), run_time=5, rate_func=linear)

            self.wait_until_bookmark("largeA1")
            self.play(a.animate.set_value(3), run_time=5, rate_func=linear)

            self.wait_until_bookmark("smallA2")
            self.play(a.animate.set_value(0.1), run_time=2, rate_func=linear)

            self.wait_until_bookmark("resetA")
            note.change_colors([1,2])
            self.play(a.animate.set_value(1), run_time=1, rate_func=linear)
            cursor.clear_updaters()

            self.wait_until_bookmark("neg1")
            a_tex.clear_updaters()
            self.play(ReplacementTransform(a_tex, a_tex_neg1))


        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_3_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["Take any point on the graph of $f$", ["We multiply $f$ by $-1$","$\\Rightarrow$ point is flipped"], "$\\Rightarrow$ entire graph is flipped"], buff=0.25, buff_inner=0.05)
        self.add(note)

        title = self.add_title("Flipping the function")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        a1n1 = MathTex("f(x)=\\tfrac1x", "\\rightarrow", "f(x)=\\tfrac{-1}x", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)

        f1 = MathTex("f(x)=\\tfrac ax", ",\\,a=", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        a_tex = DecimalNumber(1, num_decimal_places=1, color=c1t).scale(0.8).next_to(f1, RIGHT, buff=0.1).shift(0.05*UP).add_updater(lambda m: m.set_value(a.get_value()))
        self.add(cords, plotted_right, plotted_left, cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it.
                <bookmark mark="note1"/>
                Take any point on the function, for example the point <bookmark mark="oneOne"/>1 1.
                Now if we go from <bookmark mark="a1"/>"a" equals one to <bookmark mark="a2"/>a equals negative one,
                <bookmark mark="note2"/>
                that's the same as multiplying the function by minus one.
                This means, that <bookmark mark="func1"/>each value of the function gets multiplied by negative one, <bookmark mark="func2"/> so the function gets flipped
                across the x-axis.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("oneOne")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y))

            self.wait_until_bookmark("a1")
            self.play(Write(a1n1[0]), run_time=0.5)

            self.wait_until_bookmark("a2")
            self.play(Write(a1n1[1]), Write(a1n1[2]), run_time=0.5)

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("func1")
            self.play(ReplacementTransform(a1n1, f1), Write(a_tex))

            self.wait_until_bookmark("func2")
            note.change_colors([1,2])
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, a.get_value())))
            self.play(a.animate.set_value(-1), run_time=3)
            self.wait(0.5)
            self.play(CursorMoveTo(cursor, xo, yo), run_time=0.5)
            cursor.blinking=True
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_3_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["Take any point on the graph of $f$", ["We multiply $f$ by $-1$","$\\Rightarrow$ point is flipped"], "$\\Rightarrow$ entire graph is flipped"], buff=0.25, buff_inner=0.05)
        self.add(note)

        title = self.add_title("Flipping the function")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        a1n1 = MathTex("f(x)=\\tfrac1x", "\\rightarrow", "f(x)=\\tfrac{-1}x", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)

        f1 = MathTex("f(x)=\\tfrac ax", ",\\,a=", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        a_tex = DecimalNumber(1, num_decimal_places=1, color=c1t).scale(0.8).next_to(f1, RIGHT, buff=0.1).shift(0.05*UP).add_updater(lambda m: m.set_value(a.get_value()))
        self.add(cords, plotted_right, plotted_left, cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it.
                <bookmark mark="note1"/>
                Take any point on the function, for example the point <bookmark mark="oneOne"/>1 1.
                Now if we go from <bookmark mark="a1"/>"a" equals one to <bookmark mark="a2"/>a equals negative one,
                <bookmark mark="note2"/>
                that's the same as multiplying the function by minus one.
                This means, that <bookmark mark="func1"/>each value of the function gets multiplied by negative one, <bookmark mark="func2"/> so the function gets flipped
                across the x-axis.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("oneOne")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y))

            self.wait_until_bookmark("a1")
            self.play(Write(a1n1[0]), run_time=0.5)

            self.wait_until_bookmark("a2")
            self.play(Write(a1n1[1]), Write(a1n1[2]), run_time=0.5)

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("func1")
            self.play(ReplacementTransform(a1n1, f1), Write(a_tex))

            self.wait_until_bookmark("func2")
            note.change_colors([1,2])
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, a.get_value())))
            self.play(a.animate.set_value(-1), run_time=3)
            self.wait(0.5)
            self.play(CursorMoveTo(cursor, xo, yo), run_time=0.5)
            cursor.blinking=True
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_3_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["Take any point on the graph of $f$", ["We multiply $f$ by $-1$","$\\Rightarrow$ point is flipped"], "$\\Rightarrow$ entire graph is flipped"], buff=0.25, buff_inner=0.05)
        self.add(note)

        title = self.add_title("Flipping the function")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        a1n1 = MathTex("f(x)=\\tfrac1x", "\\rightarrow", "f(x)=\\tfrac{-1}x", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)

        f1 = MathTex("f(x)=\\tfrac ax", ",\\,a=", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        a_tex = DecimalNumber(1, num_decimal_places=1, color=c1t).scale(0.8).next_to(f1, RIGHT, buff=0.1).shift(0.05*UP).add_updater(lambda m: m.set_value(a.get_value()))
        self.add(cords, plotted_right, plotted_left, cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it.
                <bookmark mark="note1"/>
                Take any point on the function, for example the point <bookmark mark="oneOne"/>1 1.
                Now if we go from <bookmark mark="a1"/>"a" equals one to <bookmark mark="a2"/>a equals negative one,
                <bookmark mark="note2"/>
                that's the same as multiplying the function by minus one.
                This means, that <bookmark mark="func1"/>each value of the function gets multiplied by negative one, <bookmark mark="func2"/> so the function gets flipped
                across the x-axis.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("oneOne")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y))

            self.wait_until_bookmark("a1")
            self.play(Write(a1n1[0]), run_time=0.5)

            self.wait_until_bookmark("a2")
            self.play(Write(a1n1[1]), Write(a1n1[2]), run_time=0.5)

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("func1")
            self.play(ReplacementTransform(a1n1, f1), Write(a_tex))

            self.wait_until_bookmark("func2")
            note.change_colors([1,2])
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, a.get_value())))
            self.play(a.animate.set_value(-1), run_time=3)
            self.wait(0.5)
            self.play(CursorMoveTo(cursor, xo, yo), run_time=0.5)
            cursor.blinking=True
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_3_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["Take any point on the graph of $f$", ["We multiply $f$ by $-1$","$\\Rightarrow$ point is flipped"], "$\\Rightarrow$ entire graph is flipped"], buff=0.25, buff_inner=0.05)
        self.add(note)

        title = self.add_title("Flipping the function")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        a1n1 = MathTex("f(x)=\\tfrac1x", "\\rightarrow", "f(x)=\\tfrac{-1}x", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)

        f1 = MathTex("f(x)=\\tfrac ax", ",\\,a=", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        a_tex = DecimalNumber(1, num_decimal_places=1, color=c1t).scale(0.8).next_to(f1, RIGHT, buff=0.1).shift(0.05*UP).add_updater(lambda m: m.set_value(a.get_value()))
        self.add(cords, plotted_right, plotted_left, cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Yes, that's right. Nice!
                <bookmark mark="note1"/>
                Take any point on the function, for example the point <bookmark mark="oneOne"/>1 1.
                Now if we go from <bookmark mark="a1"/>"a" equals one to <bookmark mark="a2"/>a equals negative one,
                <bookmark mark="note2"/>
                that's the same as multiplying the function by minus one.
                This means, that <bookmark mark="func1"/>each value of the function gets multiplied by negative one, <bookmark mark="func2"/> so the function gets flipped
                across the x-axis.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("oneOne")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y))

            self.wait_until_bookmark("a1")
            self.play(Write(a1n1[0]), run_time=0.5)

            self.wait_until_bookmark("a2")
            self.play(Write(a1n1[1]), Write(a1n1[2]), run_time=0.5)

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("func1")
            self.play(ReplacementTransform(a1n1, f1), Write(a_tex))

            self.wait_until_bookmark("func2")
            note.change_colors([1,2])
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, a.get_value())))
            self.play(a.animate.set_value(-1), run_time=3)
            self.wait(0.5)
            self.play(CursorMoveTo(cursor, xo, yo), run_time=0.5)
            cursor.blinking=True
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)



#####################################
#####################################
class Func_3_3_I_4(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["Modify $f$ by varying $a$:","increase $a\\rightarrow f$ is stretched","decrease $a\\rightarrow f$ is squashed","$a$ negative $\\rightarrow f$ is flipped"], buff=0.1, buff_inner=0)
        self.add(note)

        title = self.add_title("Scaling the function")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        a1n1 = MathTex("f(x)=\\tfrac1x", "\\rightarrow", "f(x)=\\tfrac{-1}x", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)

        f1 = MathTex("f(x)=\\tfrac ax", ",\\,a=", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        a_tex = DecimalNumber(1, num_decimal_places=1, color=c1t).scale(0.8).next_to(f1, RIGHT, buff=0.1).shift(0.05*UP).add_updater(lambda m: m.set_value(a.get_value()))
        self.add(cords, plotted_right, plotted_left, cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so now we've seen <bookmark mark="note1"/>what we can do to the function <bookmark mark="f"/>f of x equals a over x, when we vary the parameter <bookmark mark="a"/> "a":
                <bookmark mark="note2"/>If we <bookmark mark="increase"/> increase "a", the function gets stretched in the y-direction.
                <bookmark mark="note3"/>If we <bookmark mark="decrease"/> decrease "a", the function gets squashed in the y-direction.
                <bookmark mark="note4"/>And if we <bookmark mark="negate"/> make "a" negative, the function gets flipped across the x-axis.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("f")
            self.play(Write(f1[0]))

            self.wait_until_bookmark("a")
            self.play(Write(f1[1]), Write(a_tex))
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, a.get_value())))

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("increase")
            self.play(a.animate.set_value(3), rate_func=linear)

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

            self.wait_until_bookmark("decrease")
            self.play(a.animate.set_value(0.1), rate_func=linear)

            self.wait_until_bookmark("note4")
            note.change_colors([2,3])

            self.wait_until_bookmark("negate")
            self.play(a.animate.set_value(-1), rate_func=linear)

        self.wait(4)

#####################################
#####################################
TASK_Func_3_3_I_5_q = SophiaTaskDefinition(
    answerOptions=["$f(x)=\\tfrac{a+1}x$", "$f(x)=\\tfrac{a-1}x$", "$f(x)=\\tfrac ax+1$", "$f(x)=\\tfrac ax-1$"],
    correctAnswerIndex=2,
    questionText="How do we modify the graph $f(x)=\\tfrac ax$ to shift it up by $1$?",
)

class Func_3_3_I_5_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Function can be squashed, stretched,","or flipped by varying the factor $a$"],"Next: Shifting the function in y-direction", ["How do we modify $f$,","to shift it up by $1$?"]], buff=0.2, buff_inner=0)
        note.change_colors([0])
        self.add(note)

        title = self.add_title("Shifting the function up")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))


        f1 = MathTex("f(x)=\\tfrac ax", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        self.add(cords, plotted_right, plotted_left, cursor)

        self.add(f1)

        # Action Sequence
        with self.voiceover(
                text="""
                Now that we know <bookmark mark="resolve"/> how to squash, stretch and flip the function,
                let us do something new: <bookmark mark="note1"/>Shift the function in y-direction.
                That means either <bookmark mark="cursorBack"/> moving the function <bookmark mark="up"/> up,
                or it means moving the function <bookmark mark="down"/> down.
                <bookmark mark="note2"/>Now tell me: <bookmark mark="back"/> How do we modify the term f of x equals a over x,
                so that the function gets <bookmark mark="upOne"/>shifted up by one?
                """
        ) as tracker:

            self.wait_until_bookmark("note1")
            note.change_colors([0,1])
        
            self.wait_until_bookmark("cursorBack")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))

            self.wait_until_bookmark("up")
            self.play(c.animate.set_value(2), run_time=0.5)

            self.wait_until_bookmark("down")
            self.play(c.animate.set_value(-2), run_time=0.5)

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])

            self.wait_until_bookmark("back")
            self.play(c.animate.set_value(0), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("upOne")
            cursor.blinking=False
            self.play(c.animate.set_value(1))


            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_5_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["We want to shift function up by one", "$\\Rightarrow$ shift every point up by one", ["Add $1$ to function", "$\\Rightarrow f(x)=\\tfrac ax+1$"]], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting the function up")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))


        f1 = MathTex("f","(x)", "=", "\\tfrac ax", "+", "1", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor, f1[0], f1[1], f1[2], f1[3])

        # Action Sequence
        with self.voiceover(
                text="""
                No, not quite.
                <bookmark mark="note1"/>
                If we want to shift the function up by one,<bookmark mark="cursor"/> every point on the function needs to be <bookmark mark="upOne"/> shifted up by one.
                We shift an individual point up by one by simply adding one,<bookmark mark="note2"/> so to shift the entire function up,
                we need to add one to each value of the function. So the new function will be <bookmark mark="funcNew"/> f of <bookmark mark="x"/> x equals
                <bookmark mark="a"/>a over x <bookmark mark="plusOne"/>plus one. By adding one in the end here, we add one to each value of the function.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("cursor")
            note.change_colors([0,1])
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("upOne")
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(1), run_time=2)
            cursor.clear_updaters()

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])

            self.wait_until_bookmark("funcNew")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1[1]), f1.animate.shift(fShift[0]*RIGHT), CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("a")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("plusOne")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_5_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["We want to shift function up by one", "$\\Rightarrow$ shift every point up by one", ["Add $1$ to function", "$\\Rightarrow f(x)=\\tfrac ax+1$"]], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting the function up")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))


        f1 = MathTex("f","(x)", "=", "\\tfrac ax", "+", "1", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor, f1[0], f1[1], f1[2], f1[3])

        # Action Sequence
        with self.voiceover(
                text="""
                No, not quite.
                <bookmark mark="note1"/>
                If we want to shift the function up by one,<bookmark mark="cursor"/> every point on the function needs to be <bookmark mark="upOne"/> shifted up by one.
                We shift an individual point up by one by simply adding one,<bookmark mark="note2"/> so to shift the entire function up,
                we need to add one to each value of the function. So the new function will be <bookmark mark="funcNew"/> f of <bookmark mark="x"/> x equals
                <bookmark mark="a"/>a over x <bookmark mark="plusOne"/>plus one. By adding one in the end here, we add one to each value of the function.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("cursor")
            note.change_colors([0,1])
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("upOne")
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(1), run_time=2)
            cursor.clear_updaters()

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])

            self.wait_until_bookmark("funcNew")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1[1]), f1.animate.shift(fShift[0]*RIGHT), CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("a")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("plusOne")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_3_I_5_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["We want to shift function up by one", "$\\Rightarrow$ shift every point up by one", ["Add $1$ to function", "$\\Rightarrow f(x)=\\tfrac ax+1$"]], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting the function up")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))


        f1 = MathTex("f","(x)", "=", "\\tfrac ax", "+", "1", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor, f1[0], f1[1], f1[2], f1[3])

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's right.
                <bookmark mark="note1"/>
                If we want to shift the function up by one,<bookmark mark="cursor"/> every point on the function needs to be <bookmark mark="upOne"/> shifted up by one.
                We shift an individual point up by one by simply adding one,<bookmark mark="note2"/> so to shift the entire function up,
                we need to add one to each value of the function. So the new function will be <bookmark mark="funcNew"/> f of <bookmark mark="x"/> x equals
                <bookmark mark="a"/>a over x <bookmark mark="plusOne"/>plus one. By adding one in the end here, we add one to each value of the function.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("cursor")
            note.change_colors([0,1])
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("upOne")
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(1), run_time=2)
            cursor.clear_updaters()

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])

            self.wait_until_bookmark("funcNew")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1[1]), f1.animate.shift(fShift[0]*RIGHT), CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("a")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("plusOne")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_5_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["We want to shift function up by one", "$\\Rightarrow$ shift every point up by one", ["Add $1$ to function", "$\\Rightarrow f(x)=\\tfrac ax+1$"]], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting the function up")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))


        f1 = MathTex("f","(x)", "=", "\\tfrac ax", "+", "1", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor, f1[0], f1[1], f1[2], f1[3])

        # Action Sequence
        with self.voiceover(
                text="""
                No, not quite.
                <bookmark mark="note1"/>
                If we want to shift the function up by one,<bookmark mark="cursor"/> every point on the function needs to be <bookmark mark="upOne"/> shifted up by one.
                We shift an individual point up by one by simply adding one,<bookmark mark="note2"/> so to shift the entire function up,
                we need to add one to each value of the function. So the new function will be <bookmark mark="funcNew"/> f of <bookmark mark="x"/> x equals
                <bookmark mark="a"/>a over x <bookmark mark="plusOne"/>plus one. By adding one in the end here, we add one to each value of the function.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("cursor")
            note.change_colors([0,1])
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("upOne")
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(1), run_time=2)
            cursor.clear_updaters()

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])

            self.wait_until_bookmark("funcNew")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1[1]), f1.animate.shift(fShift[0]*RIGHT), CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("a")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("plusOne")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
TASK_Func_3_3_I_6_q = SophiaTaskDefinition(
    answerOptions=["$f(x)=\\tfrac{2a}x$", "$f(x)=\\tfrac{a-2}x$", "$f(x)=\\tfrac a{2x}$", "$f(x)=\\tfrac ax-2$"],
    correctAnswerIndex=3,
    questionText="How do we modify the graph $f(x)=\\tfrac ax$ to shift it down by $2$?",
)

class Func_3_3_I_6_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["Consider the function $f(x)=\\tfrac ax$", "We want to shift it down by $2$", "How does the term of the function change?"], buff=0.2, buff_inner=0)
        note.change_colors([0])
        self.add(note)

        title = self.add_title("Shifting the function down")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))


        f1 = MathTex("f", "(x)", "=", "\\tfrac ax", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        self.add(cords, plotted_right, plotted_left, cursor)

        self.add(f1)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, back with our favorite <bookmark mark="f"/>function f <bookmark mark="x"/>of x equals <bookmark mark="ax"/>
                a over x. <bookmark mark="note1"/> Now let us shift the function <bookmark mark="db2"/> down by two.
                <bookmark mark="note2"/>So tell me: <bookmark mark="back"/> How do we modify the term f of x equals a over x,
                to <bookmark mark="downTwo"/>shift the function down by two?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("ax")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("note1")
            note.change_colors([0,1])
            x,y,_ = plane.c2p(1,1)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("db2")
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(-2), run_time=1.5)
            self.wait(1)
            self.play(c.animate.set_value(0), run_time=.5)
            cursor.blinking = True

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])

            self.wait_until_bookmark("downTwo")
            cursor.blinking=False
            self.play(c.animate.set_value(-2))


            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_3_I_6_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["We want to shift function down by two", "$\\Rightarrow$ shift every point down by two", ["Subtract $1$ from function", "$\\Rightarrow f(x)=\\tfrac ax-2$"]], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting the function down")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))


        f1 = MathTex("f","(x)", "=", "\\tfrac ax", "-", "2", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor, f1[0], f1[1], f1[2], f1[3])

        # Action Sequence
        with self.voiceover(
                text="""
                No, not quite.
                <bookmark mark="note1"/>
                If we want to shift the function down by two,<bookmark mark="cursor"/> every point on the function needs to be <bookmark mark="upOne"/> shifted down by two.
                We shift an individual point down by two by simply subtracting two,<bookmark mark="note2"/> so to shift the entire function down,
                we need to subtract two from each value of the function. So the new function will be <bookmark mark="funcNew"/> f of <bookmark mark="x"/> x equals
                <bookmark mark="a"/>a over x <bookmark mark="plusOne"/>minus two. By subtracting two in the end here, we subtract two from each value of the function.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("cursor")
            note.change_colors([0,1])
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("upOne")
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(1), run_time=2)
            cursor.clear_updaters()

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])

            self.wait_until_bookmark("funcNew")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1[1]), f1.animate.shift(fShift[0]*RIGHT), CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("a")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("plusOne")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_6_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["We want to shift function down by two", "$\\Rightarrow$ shift every point down by two", ["Subtract $1$ from function", "$\\Rightarrow f(x)=\\tfrac ax-2$"]], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting the function down")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))


        f1 = MathTex("f","(x)", "=", "\\tfrac ax", "-", "2", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor, f1[0], f1[1], f1[2], f1[3])

        # Action Sequence
        with self.voiceover(
                text="""
                No, not quite.
                <bookmark mark="note1"/>
                If we want to shift the function down by two,<bookmark mark="cursor"/> every point on the function needs to be <bookmark mark="upOne"/> shifted down by two.
                We shift an individual point down by two by simply subtracting two,<bookmark mark="note2"/> so to shift the entire function down,
                we need to subtract two from each value of the function. So the new function will be <bookmark mark="funcNew"/> f of <bookmark mark="x"/> x equals
                <bookmark mark="a"/>a over x <bookmark mark="plusOne"/>minus two. By subtracting two in the end here, we subtract two from each value of the function.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("cursor")
            note.change_colors([0,1])
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("upOne")
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(1), run_time=2)
            cursor.clear_updaters()

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])

            self.wait_until_bookmark("funcNew")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1[1]), f1.animate.shift(fShift[0]*RIGHT), CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("a")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("plusOne")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_6_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["We want to shift function down by two", "$\\Rightarrow$ shift every point down by two", ["Subtract $1$ from function", "$\\Rightarrow f(x)=\\tfrac ax-2$"]], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting the function down")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))


        f1 = MathTex("f","(x)", "=", "\\tfrac ax", "-", "2", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor, f1[0], f1[1], f1[2], f1[3])

        # Action Sequence
        with self.voiceover(
                text="""
                No, not quite.
                <bookmark mark="note1"/>
                If we want to shift the function down by two,<bookmark mark="cursor"/> every point on the function needs to be <bookmark mark="upOne"/> shifted down by two.
                We shift an individual point down by two by simply subtracting two,<bookmark mark="note2"/> so to shift the entire function down,
                we need to subtract two from each value of the function. So the new function will be <bookmark mark="funcNew"/> f of <bookmark mark="x"/> x equals
                <bookmark mark="a"/>a over x <bookmark mark="plusOne"/>minus two. By subtracting two in the end here, we subtract two from each value of the function.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("cursor")
            note.change_colors([0,1])
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("upOne")
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(1), run_time=2)
            cursor.clear_updaters()

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])

            self.wait_until_bookmark("funcNew")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1[1]), f1.animate.shift(fShift[0]*RIGHT), CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("a")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("plusOne")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_6_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["We want to shift function down by two", "$\\Rightarrow$ shift every point down by two", ["Subtract $1$ from function", "$\\Rightarrow f(x)=\\tfrac ax-2$"]], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting the function down")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))


        f1 = MathTex("f","(x)", "=", "\\tfrac ax", "-", "2", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor, f1[0], f1[1], f1[2], f1[3])

        # Action Sequence
        with self.voiceover(
                text="""
                Yes, that's it.
                <bookmark mark="note1"/>
                If we want to shift the function down by two,<bookmark mark="cursor"/> every point on the function needs to be <bookmark mark="upOne"/> shifted down by two.
                We shift an individual point down by two by simply subtracting two,<bookmark mark="note2"/> so to shift the entire function down,
                we need to subtract two from each value of the function. So the new function will be <bookmark mark="funcNew"/> f of <bookmark mark="x"/> x equals
                <bookmark mark="a"/>a over x <bookmark mark="plusOne"/>minus two. By subtracting two in the end here, we subtract two from each value of the function.
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            
            self.wait_until_bookmark("cursor")
            note.change_colors([0,1])
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("upOne")
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(1), run_time=2)
            cursor.clear_updaters()

            self.wait_until_bookmark("note2")
            note.change_colors([1,2])

            self.wait_until_bookmark("funcNew")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1[1]), f1.animate.shift(fShift[0]*RIGHT), CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("a")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("plusOne")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
class Func_3_3_I_7(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["We're shifting hyperbolas along the y-axis", "Formalization as $f(x)=\\tfrac a x+c$", "$c>0\\Rightarrow$ shift up", "$c<0\\Rightarrow$ shift down",], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting hyperbolas")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))


        f1 = MathTex("f","(x)", "=", "\\tfrac ax", "+", "c", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor, f1[0], f1[1], f1[2], f1[3])

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so let's formalize this a bit. <bookmark mark="note1"/>
                What we've been doing now is shifting the <bookmark mark="up1"/>hyperbola up and<bookmark mark="down1"/> down, so we shifted the function
                along <bookmark mark="y"/>the y-axis.
                <bookmark mark="backInPos"/>
                To shift it <bookmark mark="up2"/>up, we added a constant to the function, so that every point on the function was shifted up by that constant.
                And to shift it <bookmark mark="down2"/> down on the other hand, we subtracted a constant from the function, so that every point on the function
                was shifted down by that constant. <bookmark mark="note2"/> In general, we can now write the function as <bookmark mark="func"/> f of
                <bookmark mark="x"/> x equals <bookmark mark="ax"/> a over x plus <bookmark mark="c"/> c. Here, c is the constant that we add to the function.
                <bookmark mark="notePos"/>If c is positive, we <bookmark mark="resetCursorFinal"/>shift the function up, <bookmark mark="noteNeg"/>and if c is
                <bookmark mark="cNeg"/>negative, we shift the function down.<bookmark mark="resetC"/>
                """
        ) as tracker:
            
            self.wait_until_bookmark("note1")
            note.change_colors([0])
            x,y,_ = plane.c2p(1,1)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))

            self.wait_until_bookmark("up1")
            self.play(c.animate.set_value(2), run_time=0.6)

            self.wait_until_bookmark("down1")
            self.play(c.animate.set_value(-2), run_time=0.5)
            self.wait(0.4)
            self.play(c.animate.set_value(0), run_time=0.5)
            cursor.clear_updaters()

            self.wait_until_bookmark("y")
            self.play(CursorMarkAxis(cursor, plane, axis='y'), run_time=0.5)

            self.wait_until_bookmark("backInPos")
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveResize(cursor, x, y, 0.2, 0.2), run_time=0.5)
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))

            self.wait_until_bookmark("up2")
            self.play(c.animate.set_value(2), run_time=0.5)
            cursor.clear_updaters()
            cursor._setup_blinking()
            cursor.blinking=True

            self.wait_until_bookmark("down2")
            cursor.blinking=False
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(-2), run_time=0.5)
            cursor.clear_updaters()
            cursor._setup_blinking()
            cursor.blinking=True

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])
            x,y,_ = plane.c2p(0,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), c.animate.set_value(0), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("func")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(f1[4]), Write(f1[5]), f1.animate.shift(fShift[0]*RIGHT), CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("ax")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("c")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("notePos")
            note.change_colors([1,2])

            self.wait_until_bookmark("resetCursorFinal")
            x,y,_ = plane.c2p(1,1)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(2))

            self.wait_until_bookmark("noteNeg")
            note.change_colors([2,3])

            self.wait_until_bookmark("cNeg")
            self.play(c.animate.set_value(-2))

            self.wait_until_bookmark("resetC")
            cursor.clear_updaters()
            x,y,_ = plane.c2p(0,0)
            self.play(c.animate.set_value(0), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor._setup_blinking()
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_3_3_I_8_q = SophiaTaskDefinition(
    answerOptions=["At $y=0$", "At $y=2$", "At $y=4$", "At $y=-4$"],
    correctAnswerIndex=1,
    questionText="Where is the horizontal asymptote of the shifted function?",
)
class Func_3_3_I_8_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=["We're shifting hyperbolas up or down", "Shifted function: $f(x)=\\tfrac 1 x+2$", ["Where is the horizontal asymptote", "of the shifted function"],], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting hyperbolas")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))


        f1 = MathTex("f","(x)", "=", "\\tfrac1x", "+", "2", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, now let's say, <bookmark mark="setupCursor"/>we're shifting the <bookmark mark="up"/> function up <bookmark mark="down"/>or down.
                But if we do that, what happens to the horizontal asymptotes?
                So to make this more specific, let's take the example <bookmark mark="func"/> f of x equals one over x. <bookmark mark="note2"/>
                And let's shift it <bookmark mark="upByTwo"/>up by two, so the shifted function is <bookmark mark="funcNew"/> f of <bookmark mark="x"/>x equals <bookmark mark="one"/>one over x plus <bookmark mark="two"/>two.
                <bookmark mark="noteLast"/>Where is the horizontal asymptote of the shifted function?
                """
        ) as tracker:
            
            self.wait_until_bookmark("setupCursor")
            note.change_colors([0])
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("up")
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(2), run_time=0.5)

            self.wait_until_bookmark("down")
            self.play(c.animate.set_value(-2), run_time=0.5)
            self.wait(.5)
            self.play(c.animate.set_value(0), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("func")
            self.play(Write(f1[0]), Write(f1[1]), Write(f1[2]), Write(f1[3]), run_time=0.5)

            self.wait_until_bookmark("note2")
            note.change_colors([0,1])

            self.wait_until_bookmark("upByTwo")
            cursor.blinking=False
            self.play(c.animate.set_value(2), run_time=0.5)

            self.wait_until_bookmark("funcNew")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            cursor.clear_updaters()
            cursor._setup_blinking()
            self.play(Write(f1[4]), Write(f1[5]), f1.animate.shift(fShift[0]*RIGHT), CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("one")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("two")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("noteLast")
            note.change_colors([1,2])


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_3_I_8_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Asymptote: Line that function approaches,","but never reaches"], ["Function is shifted up by two", "$\\Rightarrow$ Asymptote is shifted up by two"], "Asymptote at $y=2$"], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting hyperbolas")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        y_unit = (plane.c2p(0,1)-plane.c2p(0,0))

        aT1 = Line(plane.c2p(-4,0), plane.c2p(4,0), color=GREEN)



        f1 = MathTex("f","(x)", "=", "\\tfrac1x", "+", "2", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor, f1[0], f1[1], f1[2], f1[3])

        # Action Sequence
        with self.voiceover(
                text="""
                No, not quite...
                First, let us remind ourselves of the definition of an asymptote.
                <bookmark mark="asymptote"/>An asymptote is a line that the function approaches, but never reaches.
                We know that the asymptote of the original function is the <bookmark mark="as0"/>horizontal line at y equals zero.
                Now, let's look at the shifted function. <bookmark mark="note1"/>The shifted function <bookmark mark="func"/>is the function
                <bookmark mark="f"/>f of <bookmark mark="x"/> x equals <bookmark mark="oneOverX"/>one over x <bookmark mark="plusTwo"/>plus two, so it's <bookmark mark="shiftUp"/> the original function
                shifted up by two. <bookmark mark="note3"/>This means that the asymptote of the shifted function is <bookmark mark="cursorBack"/> the asymptote of
                the original function shifted up by two. This means, that the horizontal asymptote is at y equals two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("asymptote")
            note.change_colors([0])

            self.wait_until_bookmark("as0")
            self.play(Write(aT1))

            self.wait_until_bookmark("note1")
            note.change_colors([0,1])

            self.wait_until_bookmark("func")
            cursor.blinking=False
            self.play(Write(f1[4]), Write(f1[5]), run_time=0.5)

            self.wait_until_bookmark("f")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("oneOverX")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("plusTwo")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("shiftUp")
            x,y,_ = plane.c2p(1,1)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(2))
            cursor.clear_updaters()
            cursor._setup_blinking()
            cursor.blinking=True

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

            self.wait_until_bookmark("cursorBack")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.add_updater(lambda m: cursor.move_to(aT1.get_center()))
            self.play(aT1.animate.shift(2*y_unit))
            cursor.clear_updaters()
            cursor._setup_blinking()
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_3_I_8_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Asymptote: Line that function approaches,","but never reaches"], ["Function is shifted up by two", "$\\Rightarrow$ Asymptote is shifted up by two"], "Asymptote at $y=2$"], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting hyperbolas")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        y_unit = (plane.c2p(0,1)-plane.c2p(0,0))

        aT1 = Line(plane.c2p(-4,0), plane.c2p(4,0), color=GREEN)



        f1 = MathTex("f","(x)", "=", "\\tfrac1x", "+", "2", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor, f1[0], f1[1], f1[2], f1[3])

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's it!
                First, let us remind ourselves of the definition of an asymptote.
                <bookmark mark="asymptote"/>An asymptote is a line that the function approaches, but never reaches.
                We know that the asymptote of the original function is the <bookmark mark="as0"/>horizontal line at y equals zero.
                Now, let's look at the shifted function. <bookmark mark="note1"/>The shifted function <bookmark mark="func"/>is the function
                <bookmark mark="f"/>f of <bookmark mark="x"/> x equals <bookmark mark="oneOverX"/>one over x <bookmark mark="plusTwo"/>plus two, so it's <bookmark mark="shiftUp"/> the original function
                shifted up by two. <bookmark mark="note3"/>This means that the asymptote of the shifted function is <bookmark mark="cursorBack"/> the asymptote of
                the original function shifted up by two. This means, that the horizontal asymptote is at y equals two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("asymptote")
            note.change_colors([0])

            self.wait_until_bookmark("as0")
            self.play(Write(aT1))

            self.wait_until_bookmark("note1")
            note.change_colors([0,1])

            self.wait_until_bookmark("func")
            cursor.blinking=False
            self.play(Write(f1[4]), Write(f1[5]), run_time=0.5)

            self.wait_until_bookmark("f")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("oneOverX")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("plusTwo")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("shiftUp")
            x,y,_ = plane.c2p(1,1)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(2))
            cursor.clear_updaters()
            cursor._setup_blinking()
            cursor.blinking=True

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

            self.wait_until_bookmark("cursorBack")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.add_updater(lambda m: cursor.move_to(aT1.get_center()))
            self.play(aT1.animate.shift(2*y_unit))
            cursor.clear_updaters()
            cursor._setup_blinking()
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_3_3_I_8_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Asymptote: Line that function approaches,","but never reaches"], ["Function is shifted up by two", "$\\Rightarrow$ Asymptote is shifted up by two"], "Asymptote at $y=2$"], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting hyperbolas")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        y_unit = (plane.c2p(0,1)-plane.c2p(0,0))

        aT1 = Line(plane.c2p(-4,0), plane.c2p(4,0), color=GREEN)



        f1 = MathTex("f","(x)", "=", "\\tfrac1x", "+", "2", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor, f1[0], f1[1], f1[2], f1[3])

        # Action Sequence
        with self.voiceover(
                text="""
                No, not quite...
                First, let us remind ourselves of the definition of an asymptote.
                <bookmark mark="asymptote"/>An asymptote is a line that the function approaches, but never reaches.
                We know that the asymptote of the original function is the <bookmark mark="as0"/>horizontal line at y equals zero.
                Now, let's look at the shifted function. <bookmark mark="note1"/>The shifted function <bookmark mark="func"/>is the function
                <bookmark mark="f"/>f of <bookmark mark="x"/> x equals <bookmark mark="oneOverX"/>one over x <bookmark mark="plusTwo"/>plus two, so it's <bookmark mark="shiftUp"/> the original function
                shifted up by two. <bookmark mark="note3"/>This means that the asymptote of the shifted function is <bookmark mark="cursorBack"/> the asymptote of
                the original function shifted up by two. This means, that the horizontal asymptote is at y equals two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("asymptote")
            note.change_colors([0])

            self.wait_until_bookmark("as0")
            self.play(Write(aT1))

            self.wait_until_bookmark("note1")
            note.change_colors([0,1])

            self.wait_until_bookmark("func")
            cursor.blinking=False
            self.play(Write(f1[4]), Write(f1[5]), run_time=0.5)

            self.wait_until_bookmark("f")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("oneOverX")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("plusTwo")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("shiftUp")
            x,y,_ = plane.c2p(1,1)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(2))
            cursor.clear_updaters()
            cursor._setup_blinking()
            cursor.blinking=True

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

            self.wait_until_bookmark("cursorBack")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.add_updater(lambda m: cursor.move_to(aT1.get_center()))
            self.play(aT1.animate.shift(2*y_unit))
            cursor.clear_updaters()
            cursor._setup_blinking()
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_3_I_8_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        note = Notepad(texts=[["Asymptote: Line that function approaches,","but never reaches"], ["Function is shifted up by two", "$\\Rightarrow$ Asymptote is shifted up by two"], "Asymptote at $y=2$"], buff=0.2, buff_inner=0.1)
        self.add(note)

        title = self.add_title("Shifting hyperbolas")

        cords = self.add_cords([-4,4, 1], [-4, 4, 1], x_ticks=[2*i-4 for i in range(5)],y_ticks=[2*i-4 for i in range(5)])
        plane = cords[0]

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)

        func = lambda x: a.get_value()/(x+b.get_value())+c.get_value()

        #sine function that is updated
        plotted_right = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-4,-b.get_value(), -4,4,func), 0.01], use_smoothing=False))
        plotted_left = always_redraw(lambda: plane.plot(func, color=BLUE, x_range=[*get_valid_xrange(-b.get_value(),4, -4,4,func), 0.01], use_smoothing=False).reverse_points())

        xo, yo, _ = plane.x_axis.n2p(0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=xo, y=yo)
        cursor.add_updater(lambda m: self.bring_to_front(cursor))

        y_unit = (plane.c2p(0,1)-plane.c2p(0,0))

        aT1 = Line(plane.c2p(-4,0), plane.c2p(4,0), color=GREEN)



        f1 = MathTex("f","(x)", "=", "\\tfrac1x", "+", "2", color=c1t).scale(0.8).next_to(cords, DOWN, buff=0.5)
        fShift = f1[2].get_center()
        f1 = f1.shift(fShift[0]*LEFT)
        self.add(cords, plotted_right, plotted_left, cursor, f1[0], f1[1], f1[2], f1[3])

        # Action Sequence
        with self.voiceover(
                text="""
                No, not quite...
                First, let us remind ourselves of the definition of an asymptote.
                <bookmark mark="asymptote"/>An asymptote is a line that the function approaches, but never reaches.
                We know that the asymptote of the original function is the <bookmark mark="as0"/>horizontal line at y equals zero.
                Now, let's look at the shifted function. <bookmark mark="note1"/>The shifted function <bookmark mark="func"/>is the function
                <bookmark mark="f"/>f of <bookmark mark="x"/> x equals <bookmark mark="oneOverX"/>one over x <bookmark mark="plusTwo"/>plus two, so it's <bookmark mark="shiftUp"/> the original function
                shifted up by two. <bookmark mark="note3"/>This means that the asymptote of the shifted function is <bookmark mark="cursorBack"/> the asymptote of
                the original function shifted up by two. This means, that the horizontal asymptote is at y equals two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("asymptote")
            note.change_colors([0])

            self.wait_until_bookmark("as0")
            self.play(Write(aT1))

            self.wait_until_bookmark("note1")
            note.change_colors([0,1])

            self.wait_until_bookmark("func")
            cursor.blinking=False
            self.play(Write(f1[4]), Write(f1[5]), run_time=0.5)

            self.wait_until_bookmark("f")
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("oneOverX")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("plusTwo")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("shiftUp")
            x,y,_ = plane.c2p(1,1)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.add_updater(lambda m: cursor.move_to(plane.c2p(1, 1+c.get_value())))
            self.play(c.animate.set_value(2))
            cursor.clear_updaters()
            cursor._setup_blinking()
            cursor.blinking=True

            self.wait_until_bookmark("note3")
            note.change_colors([1,2])

            self.wait_until_bookmark("cursorBack")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.add_updater(lambda m: cursor.move_to(aT1.get_center()))
            self.play(aT1.animate.shift(2*y_unit))
            cursor.clear_updaters()
            cursor._setup_blinking()
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
#### Practice Part ##################
#####################################
#####################################



#####################################
#####################################
### Question Templates ##############
#####################################
#####################################

#####################################
#####################################
### Actual Questions ################
#####################################
#####################################

PROTOTYPES = [
    PagePrototypeVideo.from_scene(Func_3_3_I_1),
    PagePrototypeVideo.from_scene(Func_3_3_I_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_3_3_I_2_q, Func_3_3_I_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_3_3_I_2_a),
    PagePrototypeVideo.from_scene(Func_3_3_I_2_b),
    PagePrototypeVideo.from_scene(Func_3_3_I_2_c),
    PagePrototypeVideo.from_scene(Func_3_3_I_2_d),
    PagePrototypeVideo.from_scene(Func_3_3_I_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_3_3_I_3_q, Func_3_3_I_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_3_3_I_3_a),
    PagePrototypeVideo.from_scene(Func_3_3_I_3_b),
    PagePrototypeVideo.from_scene(Func_3_3_I_3_c),
    PagePrototypeVideo.from_scene(Func_3_3_I_3_d),
    PagePrototypeVideo.from_scene(Func_3_3_I_4),
    PagePrototypeVideo.from_scene(Func_3_3_I_5_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_3_3_I_5_q, Func_3_3_I_5_q.__name__),
    PagePrototypeVideo.from_scene(Func_3_3_I_5_a),
    PagePrototypeVideo.from_scene(Func_3_3_I_5_b),
    PagePrototypeVideo.from_scene(Func_3_3_I_5_c),
    PagePrototypeVideo.from_scene(Func_3_3_I_5_d),
    PagePrototypeVideo.from_scene(Func_3_3_I_6_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_3_3_I_6_q, Func_3_3_I_6_q.__name__),
    PagePrototypeVideo.from_scene(Func_3_3_I_6_a),
    PagePrototypeVideo.from_scene(Func_3_3_I_6_b),
    PagePrototypeVideo.from_scene(Func_3_3_I_6_c),
    PagePrototypeVideo.from_scene(Func_3_3_I_6_d),
    PagePrototypeVideo.from_scene(Func_3_3_I_7),
    PagePrototypeVideo.from_scene(Func_3_3_I_8_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_3_3_I_8_q, Func_3_3_I_8_q.__name__),
    PagePrototypeVideo.from_scene(Func_3_3_I_8_a),
    PagePrototypeVideo.from_scene(Func_3_3_I_8_b),
    PagePrototypeVideo.from_scene(Func_3_3_I_8_c),
    PagePrototypeVideo.from_scene(Func_3_3_I_8_d),
]
scenes/Func/Func_3: Rational Functions I/Func3_3.py
Sophia-Edu-Labs/sophia-math
# 4_1: Quadratic Functions: Intro, Term
# To-Do Here: add practice part, add recognizing non-standard squared fct. termsb

# Import necessary libraries and modules
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition



#####################################
#####################################
TASK_Func_4_1_I_1_q = SophiaTaskDefinition(
    answerOptions = ["$f(x) = x^2 - 1$", "$g(x) = 0.5x^2 - x - 1$", "$h(x) = x^3 - x^2 + 1$"],
    correctAnswerIndex = 2,
    questionText = "Which is not a quadratic function?"
)

class Func_4_1_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Quadratic Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        func_general = MathTex("f(x) = ax^2 + bx +c", color=c1t, font_size=fs1).shift(UP)

        func1 = MathTex("f(x) = x^2 - 1", color=c1t, font_size=fs2)
        func2 = MathTex("g(x) = 0.5x^2 - x - 1", color=c1t, font_size=fs2)
        func3 = MathTex("h(x)", " = x^3 - x^2 + 1", color=c1t, font_size=fs2)
        funcs = VGroup(func1, func2, func3).arrange(DOWN, buff=0.5, aligned_edge=LEFT)
        start_point = func3[0].get_center()+0.4*DOWN
        b = Bubble(["One of these", "is not a quadratic function!"], width=4, height=1.2, start_point = start_point, center=[0,-2.6,0], loc="t1")
        

        # Action Sequence
        with self.voiceover(
                text="""
                So apparently, we're now supposed to learn about quadratic functions.
                In order to do that, I think it doesn't hurt to find out, what exactly a quadratic function is.
                So, let's start by looking at three examples.
                The first example is <bookmark mark="f"/>f of x equals x squared minus one.
                The second example is <bookmark mark="g"/>g of x equals 0.5 times x squared minus x minus one.
                And the third example is <bookmark mark="h"/>h of x equals x cubed minus x squared plus one.
                Out of these three examples, 
                two are quadratic functions, <bookmark mark="moveCursor"/>and <bookmark mark="bubble"/> one is not a quadratic function. Which one is it?
                """
        ) as tracker:

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = func1[0].get_left()+0.2*LEFT
            self.play(Write(func1), CursorMoveTo(cursor, x, y))
            cursor.blinking=True

            self.wait_until_bookmark("g")
            cursor.blinking=False
            x,y,_ = func2[0].get_left()+0.2*LEFT
            self.play(Write(func2), CursorMoveTo(cursor, x, y))
            cursor.blinking=True
            
            self.wait_until_bookmark("h")
            cursor.blinking=False
            x,y,_ = func3[0].get_left()+0.2*LEFT
            self.play(Write(func3), CursorMoveTo(cursor, x, y))
            cursor.blinking=True

            self.wait_until_bookmark("moveCursor")
            x,y,_ = start_point
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("bubble")
            cursor.add_updater(lambda m: m.move_to(b.get_end()))
            self.add_bubble_sound(1.5)
            self.play(Create(b), Create(b.text))
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_1_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Quadratic Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        allowed = VGroup(MathTex("x^2", color=GREEN), MathTex("x", color=GREEN), MathTex("1", color=GREEN)).arrange(RIGHT, buff=0.2).next_to(title, DOWN, buff=0.5)

        func_general = MathTex("f(x) = ax^2 + bx +c", color=c1t, font_size=fs1).shift(UP)

        func1 = MathTex("f(x) = x^2 - 1", color=c1t, font_size=fs2)
        func2 = MathTex("g(x) = 0.5x^2 - x - 1", color=c1t, font_size=fs2)
        func3 = MathTex("h(x)", " =" ,"x^3","- x^2 + 1", color=c1t, font_size=fs2)
        funcs = VGroup(func1, func2, func3).arrange(DOWN, buff=0.5, aligned_edge=LEFT)
        start_point = func3[2].get_center()+0.4*DOWN
        b = Bubble(["h is not a quadratic function", "because it contains $x^3$"], width=4, height=1.2, start_point = start_point, center=[0,-2.6,0], loc="t1")
        
        funcWrong = MathTex("f(x) = x^2 - 1", color=c1t, font_size=fs2)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not correct. <bookmark mark="funcWrong"/> f of x equals x squared minus one is indeed a quadratic function,
                because it only contains a quadratic term and a constant. <bookmark mark="funcWrong2"/>
                So a quadratic function is only allowed to have an <bookmark mark="a1"/>x squared term, an <bookmark mark="a2"/>x term and a <bookmark mark="a3"/>constant term.
                That means, that <bookmark mark="f"/>f of x equals x squared minus one is a quadratic function, because it has an x squared term and a constant term.
                Likewise, <bookmark mark="g"/>g of  x is also a quadratic function, because it has an x squared term, an x term and a constant term.
                Finally, <bookmark mark="h"/>h is not a quadratic function, <bookmark mark="xcubed"/> because it has an x cubed term. <bookmark mark="bubble"/>
                """
        ) as tracker:
            
            self.wait_until_bookmark("funcWrong")
            cursor.blinking=False
            x,y,_ = funcWrong[0].get_left()+0.2*LEFT
            self.play(Write(funcWrong), CursorMoveTo(cursor, x, y))
            cursor.blinking=True

            self.wait_until_bookmark("funcWrong2")
            self.play(Unwrite(funcWrong))

            self.wait_until_bookmark("a1")
            cursor.blinking=False
            x,y,_ = allowed[0].get_center()+0.5*DOWN+0.1*LEFT
            self.play(CursorMoveTo(cursor, x,y ), Write(allowed[0]), run_time=0.5)

            self.wait_until_bookmark("a2")
            x,y,_ = allowed[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), Write(allowed[1]), run_time=0.5)

            self.wait_until_bookmark("a3")
            x,y,_ = allowed[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), Write(allowed[2]), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = func1[0].get_left()+0.2*LEFT
            self.play(Write(func1), CursorMoveTo(cursor, x, y))
            cursor.blinking=True

            self.wait_until_bookmark("g")
            cursor.blinking=False
            x,y,_ = func2[0].get_left()+0.2*LEFT
            self.play(Write(func2), CursorMoveTo(cursor, x, y))
            cursor.blinking=True
            
            self.wait_until_bookmark("h")
            cursor.blinking=False
            x,y,_ = func3[0].get_left()+0.2*LEFT
            self.play(Write(func3), CursorMoveTo(cursor, x, y))
            cursor.blinking=True

            self.wait_until_bookmark("xcubed")
            cursor.blinking=False
            x,y,_ = start_point
            self.play(CursorMoveTo(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("bubble")    
            self.add_bubble_sound(1.5)
            cursor.add_updater(lambda m: m.move_to(b.get_end()))
            self.play(Create(b), Create(b.text))
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_1_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Quadratic Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        allowed = VGroup(MathTex("x^2", color=GREEN), MathTex("x", color=GREEN), MathTex("1", color=GREEN)).arrange(RIGHT, buff=0.2).next_to(title, DOWN, buff=0.5)

        func_general = MathTex("f(x) = ax^2 + bx +c", color=c1t, font_size=fs1).shift(UP)

        func1 = MathTex("f(x) = x^2 - 1", color=c1t, font_size=fs2)
        func2 = MathTex("g(x) = 0.5x^2 - x - 1", color=c1t, font_size=fs2)
        func3 = MathTex("h(x)", " =" ,"x^3","- x^2 + 1", color=c1t, font_size=fs2)
        funcs = VGroup(func1, func2, func3).arrange(DOWN, buff=0.5, aligned_edge=LEFT)
        start_point = func3[2].get_center()+0.4*DOWN
        b = Bubble(["h is not a quadratic function", "because it contains $x^3$"], width=4, height=1.2, start_point = start_point, center=[0,-2.6,0], loc="t1")
        
        funcWrong = MathTex("g(x) = 0.5x^2 - x - 1", color=c1t, font_size=fs2)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not correct. <bookmark mark="funcWrong"/> g of x equals zero point five x squared minus x minus one is indeed a quadratic function,
                because it only contains a quadratic term, an x term and a constant term.<bookmark mark="funcWrong2"/>
                So a quadratic function is only allowed to have an <bookmark mark="a1"/>x squared term, an <bookmark mark="a2"/>x term and a <bookmark mark="a3"/>constant term.
                That means, that <bookmark mark="f"/>f of x equals x squared minus one is a quadratic function, because it has an x squared term and a constant term.
                Likewise, <bookmark mark="g"/>g of  x is also a quadratic function, because it has an x squared term, an x term and a constant term.
                Finally, <bookmark mark="h"/>h is not a quadratic function, <bookmark mark="xcubed"/> because it has an x cubed term. <bookmark mark="bubble"/>
                """
        ) as tracker:
            
            self.wait_until_bookmark("funcWrong")
            cursor.blinking=False
            x,y,_ = funcWrong[0].get_left()+0.2*LEFT
            self.play(Write(funcWrong), CursorMoveTo(cursor, x, y))
            cursor.blinking=True

            self.wait_until_bookmark("funcWrong2")
            self.play(Unwrite(funcWrong))

            self.wait_until_bookmark("a1")
            cursor.blinking=False
            x,y,_ = allowed[0].get_center()+0.5*DOWN+0.1*LEFT
            self.play(CursorMoveTo(cursor, x,y ), Write(allowed[0]), run_time=0.5)

            self.wait_until_bookmark("a2")
            x,y,_ = allowed[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), Write(allowed[1]), run_time=0.5)

            self.wait_until_bookmark("a3")
            x,y,_ = allowed[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), Write(allowed[2]), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = func1[0].get_left()+0.2*LEFT
            self.play(Write(func1), CursorMoveTo(cursor, x, y))
            cursor.blinking=True

            self.wait_until_bookmark("g")
            cursor.blinking=False
            x,y,_ = func2[0].get_left()+0.2*LEFT
            self.play(Write(func2), CursorMoveTo(cursor, x, y))
            cursor.blinking=True
            
            self.wait_until_bookmark("h")
            cursor.blinking=False
            x,y,_ = func3[0].get_left()+0.2*LEFT
            self.play(Write(func3), CursorMoveTo(cursor, x, y))
            cursor.blinking=True

            self.wait_until_bookmark("xcubed")
            cursor.blinking=False
            x,y,_ = start_point
            self.play(CursorMoveTo(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("bubble")    
            self.add_bubble_sound(1.5)
            cursor.add_updater(lambda m: m.move_to(b.get_end()))
            self.play(Create(b), Create(b.text))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_1_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Quadratic Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        allowed = MathTex("x^2", "\\,\\,\\,\\,\\,x", "\\,\\,\\,\\,\\,c", color=GREEN).scale(1.4).next_to(title, DOWN, buff=0.5)


        func1 = MathTex("f(x) = x^2 - 1", color=c1t, font_size=fs2)
        func2 = MathTex("g(x) = 0.5x^2 - x - 1", color=c1t, font_size=fs2)
        func3 = MathTex("h(x)", " =" ,"x^3","- x^2 + 1", color=c1t, font_size=fs2)
        funcs = VGroup(func1, func2, func3).arrange(DOWN, buff=0.5, aligned_edge=LEFT)
        start_point = func3[2].get_center()+0.4*DOWN
        b = Bubble(["h is not a quadratic function", "because it contains $x^3$"], width=4, height=1.2, start_point = start_point, center=[0,-2.6,0], loc="t1")
        
        funcWrong = MathTex("h(x)", " =" ,"x^3","- x^2 + 1", color=c1t, font_size=fs2)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's right. <bookmark mark="funcWrong"/> h of x equals x cubed minus x squared plus one is not a quadratic function,
                because it contains x cubed.<bookmark mark="funcWrong2"/>
                So a quadratic function is only allowed to have an <bookmark mark="a1"/>x squared term, an <bookmark mark="a2"/>x term and a <bookmark mark="a3"/>constant term.
                That means, that <bookmark mark="f"/>f of x equals x squared minus one is a quadratic function, because it has an x squared term and a constant term.
                Likewise, <bookmark mark="g"/>g of  x is also a quadratic function, because it has an x squared term, an x term and a constant term.
                Finally, <bookmark mark="h"/>h is not a quadratic function, <bookmark mark="xcubed"/> because it has an x cubed term. <bookmark mark="bubble"/>
                """
        ) as tracker:
            
            self.wait_until_bookmark("funcWrong")
            cursor.blinking=False
            x,y,_ = funcWrong[0].get_left()+0.2*LEFT
            self.play(Write(funcWrong), CursorMoveTo(cursor, x, y))
            cursor.blinking=True

            self.wait_until_bookmark("funcWrong2")
            self.play(Unwrite(funcWrong))

            self.wait_until_bookmark("a1")
            cursor.blinking=False
            x,y,_ = allowed[0].get_center()+0.5*DOWN+0.1*LEFT
            self.play(CursorMoveTo(cursor, x,y ), Write(allowed[0]), run_time=0.5)

            self.wait_until_bookmark("a2")
            x,y,_ = allowed[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), Write(allowed[1]), run_time=0.5)

            self.wait_until_bookmark("a3")
            x,y,_ = allowed[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), Write(allowed[2]), run_time=0.5)
            cursor.blinking=True
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = func1[0].get_left()+0.2*LEFT
            self.play(Write(func1), CursorMoveTo(cursor, x, y))
            cursor.blinking=True

            self.wait_until_bookmark("g")
            cursor.blinking=False
            x,y,_ = func2[0].get_left()+0.2*LEFT
            self.play(Write(func2), CursorMoveTo(cursor, x, y))
            cursor.blinking=True
            
            self.wait_until_bookmark("h")
            cursor.blinking=False
            x,y,_ = func3[0].get_left()+0.2*LEFT
            self.play(Write(func3), CursorMoveTo(cursor, x, y))
            cursor.blinking=True

            self.wait_until_bookmark("xcubed")
            cursor.blinking=False
            x,y,_ = start_point
            self.play(CursorMoveTo(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("bubble")    
            self.add_bubble_sound(1.5)
            cursor.add_updater(lambda m: m.move_to(b.get_end()))
            self.play(Create(b), Create(b.text))
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_4_1_I_2_q = SophiaTaskDefinition(
    answerOptions = ["The blue graph", "The purple graph", "The green graph"],
    correctAnswerIndex = 1,
    questionText = "Which of the graphs does not correspond to a quadratic function?"
)
class Func_4_1_I_2_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Quadratic Graphs")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*1.4)
        plane = cords[0]

        f1 = lambda x: 2*x**2
        f2= lambda x: 0.5*x**3
        f3 = lambda x: -2*x**2

        g1 = plane.plot(f1, color=BLUE, x_range=[-2**0.5,2**0.5, 0.001])
        g2 = plane.plot(f2, color=PURPLE)
        g3 = plane.plot(f3, color=GREEN, x_range=[-2**0.5,2**0.5, 0.001])

        tQ = Tex("Two graphs are quadratic", color=GREEN, font_size=fs2).next_to(cords, DOWN, buff=1)
        fQ = Tex("One is not", color=RED, font_size=fs2).next_to(tQ, DOWN, buff=0.2)
        

        # Action Sequence
        with self.voiceover(
                text="""
                I really like graphs, so now let's look at the graphs of quadratic functions.
                Again, I have prepared three examples of <bookmark mark="cords"/> graphs.
                And again, <bookmark mark="two"/>two of them are graphs of quadratic functions, and <bookmark mark="one"/>one is not a graph of a quadratic function.
                Which one is not a graph of a quadratic function?
                Is it <bookmark mark="blue"/>the blue graph?
                Is it <bookmark mark="purple"/>the purple graph?
                Or is it <bookmark mark="green"/>the green graph?
                """
        ) as tracker:
            
            self.wait_until_bookmark("cords")
            self.play(Create(cords))

            self.wait_until_bookmark("two")
            self.play(Write(tQ))

            self.wait_until_bookmark("one")
            self.play(Write(fQ))

            self.wait_until_bookmark("blue")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g1.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(g1), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("purple")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g2.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(g2), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("green")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g3.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(g3), run_time=0.8)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_1_I_2_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Quadratic Graphs")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*1.4)
        plane = cords[0]
        self.add(cords)

        f1 = lambda x: 2*x**2
        f2= lambda x: 0.5*x**3
        f3 = lambda x: -2*x**2

        g1 = plane.plot(f1, color=BLUE, x_range=[-2**0.5,2**0.5, 0.001])
        g2 = plane.plot(f2, color=PURPLE)
        g3 = plane.plot(f3, color=GREEN, x_range=[-2**0.5,2**0.5, 0.001])

        start_point = g2.get_start()+0.2*DOWN
        b = Bubble(["ends point in opposite directions", "$\\Rightarrow$ purple graph not quadratic"], width=4, height=1.2, start_point = start_point, center=[0,-2.6,0], loc="t1")
        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                Quadratic graphs are always shaped like a U or an upside down U.
                This means, that the <bookmark mark="blue"/>blue graph is a quadratic graph, because it is shaped like a U.
                The <bookmark mark="purple"/>purple graph is not a quadratic graph, because it's not shaped like a U.
                And the <bookmark mark="green"/>green graph is a quadratic graph again, because it is shaped like a U.
                <bookmark mark="Unwrite"/>Another good way of recognizing that the purple graph is not a quadratic graph,
                is by checking where the two ends are pointing. The right end <bookmark mark="right"/>of the purple graph
                is pointing up, while the left end <bookmark mark="left"/> is pointing down.
                Since the <bookmark mark="bubble"/>two ends are pointing in different directions, the purple graph is not a quadratic graph.
                """
        ) as tracker:
            
            self.wait_until_bookmark("blue")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g1.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(g1), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("purple")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g2.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(g2), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("green")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g3.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(g3), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("Unwrite")
            self.play(Unwrite(g1), Unwrite(g3))

            self.wait_until_bookmark("right")
            cursor.blinking=False
            x,y,_ = g2.get_end()
            self.play(CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("left")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("bubble")
            cursor.blinking=False
            x,y,_ = g2.get_start()+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_bubble_sound(1.5)
            cursor.add_updater(lambda m: m.move_to(b.get_end()))
            self.play(Create(b), Create(b.text))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_1_I_2_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Quadratic Graphs")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*1.4)
        plane = cords[0]
        self.add(cords)

        f1 = lambda x: 2*x**2
        f2= lambda x: 0.5*x**3
        f3 = lambda x: -2*x**2

        g1 = plane.plot(f1, color=BLUE, x_range=[-2**0.5,2**0.5, 0.001])
        g2 = plane.plot(f2, color=PURPLE)
        g3 = plane.plot(f3, color=GREEN, x_range=[-2**0.5,2**0.5, 0.001])

        start_point = g2.get_start()+0.2*DOWN
        b = Bubble(["ends point in opposite directions", "$\\Rightarrow$ purple graph not quadratic"], width=4, height=1.2, start_point = start_point, center=[0,-2.6,0], loc="t1")
        

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, you got it.
                Quadratic graphs are always shaped like a U or an upside down U.
                This means, that the <bookmark mark="blue"/>blue graph is a quadratic graph, because it is shaped like a U.
                The <bookmark mark="purple"/>purple graph is not a quadratic graph, because it's not shaped like a U.
                And the <bookmark mark="green"/>green graph is a quadratic graph again, because it is shaped like a U.
                <bookmark mark="Unwrite"/>Another good way of recognizing that the purple graph is not a quadratic graph,
                is by checking where the two ends are pointing. The right end <bookmark mark="right"/>of the purple graph
                is pointing up, while the left end <bookmark mark="left"/> is pointing down.
                Since the <bookmark mark="bubble"/>two ends are pointing in different directions, the purple graph is not a quadratic graph.
                """
        ) as tracker:
            
            self.wait_until_bookmark("blue")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g1.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(g1), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("purple")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g2.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(g2), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("green")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g3.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(g3), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("Unwrite")
            self.play(Unwrite(g1), Unwrite(g3))

            self.wait_until_bookmark("right")
            cursor.blinking=False
            x,y,_ = g2.get_end()
            self.play(CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("left")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("bubble")
            cursor.blinking=False
            x,y,_ = g2.get_start()+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_bubble_sound(1.5)
            cursor.add_updater(lambda m: m.move_to(b.get_end()))
            self.play(Create(b), Create(b.text))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_1_I_2_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Quadratic Graphs")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*1.4)
        plane = cords[0]
        self.add(cords)

        f1 = lambda x: 2*x**2
        f2= lambda x: 0.5*x**3
        f3 = lambda x: -2*x**2

        g1 = plane.plot(f1, color=BLUE, x_range=[-2**0.5,2**0.5, 0.001])
        g2 = plane.plot(f2, color=PURPLE)
        g3 = plane.plot(f3, color=GREEN, x_range=[-2**0.5,2**0.5, 0.001])

        start_point = g2.get_start()+0.2*DOWN
        b = Bubble(["ends point in opposite directions", "$\\Rightarrow$ purple graph not quadratic"], width=4, height=1.2, start_point = start_point, center=[0,-2.6,0], loc="t1")
        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                Quadratic graphs are always shaped like a U or an upside down U.
                This means, that the <bookmark mark="blue"/>blue graph is a quadratic graph, because it is shaped like a U.
                The <bookmark mark="purple"/>purple graph is not a quadratic graph, because it's not shaped like a U.
                And the <bookmark mark="green"/>green graph is a quadratic graph again, because it is shaped like a U.
                <bookmark mark="Unwrite"/>Another good way of recognizing that the purple graph is not a quadratic graph,
                is by checking where the two ends are pointing. The right end <bookmark mark="right"/>of the purple graph
                is pointing up, while the left end <bookmark mark="left"/> is pointing down.
                Since the <bookmark mark="bubble"/>two ends are pointing in different directions, the purple graph is not a quadratic graph.
                """
        ) as tracker:
            
            self.wait_until_bookmark("blue")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g1.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(g1), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("purple")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g2.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(g2), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("green")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g3.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(g3), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("Unwrite")
            self.play(Unwrite(g1), Unwrite(g3))

            self.wait_until_bookmark("right")
            cursor.blinking=False
            x,y,_ = g2.get_end()
            self.play(CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("left")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("bubble")
            cursor.blinking=False
            x,y,_ = g2.get_start()+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_bubble_sound(1.5)
            cursor.add_updater(lambda m: m.move_to(b.get_end()))
            self.play(Create(b), Create(b.text))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
class Func_4_1_I_3(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()


        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        title = self.add_title("Quadratic Functions")

        func_general = MathTex("f","(x)", "=", "ax^2", "+bx+","c", color=c1t, font_size=fs2).next_to(title, DOWN, buff=0.5)
        aNotZero = MathTex("a", "\\neq", "0", color=c1t, font_size=fs2).next_to(func_general, DOWN, buff=0.2)

        f = MathTex("f","(x)", "=", "x^2", "-1", color=c1t, font_size=fs2).next_to(aNotZero, DOWN, buff=1)
        f[3].set_color(BLUE)
        f[4].set_color(PURPLE)
        fExplained = MathTex("\\Rightarrow", "\\, a=1,","\\,b=0,", "\\, c=-1", color=c1t, font_size=fs2).next_to(f, DOWN, buff=0.2)
        fExplained[1].set_color(BLUE)
        fExplained[3].set_color(PURPLE)
        g = MathTex("g","(x)", "=", "0.5x^3", "-2x", color=c1t, font_size=fs2).next_to(fExplained, DOWN, buff=0.5)

        startpoint = g[3].get_center()+0.4*DOWN
        b = Bubble(["$\\Rightarrow$ not quadratic", "because of $x^3$"], width=3, height=1, start_point = startpoint, center=[0,-2.4,0], loc="t1")
        

        # Action Sequence
        with self.voiceover(
                text="""
                Now, let's formally define quadratic functions.
                A quadratic function is a function of the form <bookmark mark="func_general"/> f of <bookmark mark="x"/>x equals <bookmark mark="ax"/>a
                x squared plus <bookmark mark="bx"/>b x plus <bookmark mark="c"/>c.
                We call <bookmark mark="aa"/>a, <bookmark mark="bb"/>b and <bookmark mark="cc"/>c the coefficients of the quadratic function.
                They can be any real numbers, the only restriction is that a <bookmark mark="aNot0"/> cannot be zero.
                So, for example, <bookmark mark="f"/> f of x equals x squared minus one is a quadratic function with<bookmark mark="fExplained"/>
                a equals one, <bookmark mark="eb"/>b equals zero and <bookmark mark="ec"/>c equals minus one.
                A counterexample, so an example that is not a quadratic function is <bookmark mark="g"/> g of x equals 0.5 x cubed minus two x.
                g is <bookmark mark="gnot"/>not a quadratic function, because it contains an <bookmark mark="cube"/>x cubed term.
                <bookmark mark="bubble"/>This is not allowed for quadratic functions.
                """
        ) as tracker:
            
            self.wait_until_bookmark("func_general")
            cursor.blinking=False
            x,y,_ = func_general[0].get_center()+0.4*DOWN
            self.play(Write(func_general), CursorMoveTo(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = func_general[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("ax")
            x,y,_ = func_general[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("bx")
            x,y,_ = func_general[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("c")
            x,y,_ = func_general[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("aa")
            cursor.blinking=False
            c2 = cursor.copy()._start_fading(1)
            self.play(c2.animate.move_to(func_general[3].get_center()+0.4*DOWN), run_time=0.3)

            self.wait_until_bookmark("bb")
            c3 = cursor.copy()._start_fading(1)
            self.play(c3.animate.move_to(func_general[4].get_center()+0.4*DOWN), run_time=0.3)

            self.wait_until_bookmark("cc")
            c4 = cursor.copy()._start_fading(2)
            self.play(c4.animate.scale(3))
            cursor.blinking=True

            self.wait_until_bookmark("aNot0")
            cursor.blinking=False
            x,y,_ = aNotZero.get_center()+0.4*DOWN
            self.play(Write(aNotZero), CursorMoveTo(cursor, x,y ), run_time=0.8)
            cursor

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f[0].get_center()+0.4*LEFT
            self.play(Write(f), CursorMoveTo(cursor, x,y ), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("fExplained")
            cursor.blinking=False
            x,y,_ = fExplained[1].get_center()+0.4*DOWN
            self.play(Write(fExplained), CursorMoveTo(cursor, x,y ), run_time=1)
            
            self.wait_until_bookmark("eb")
            x,y,_ = fExplained[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("ec")
            x,y,_ = fExplained[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("g")
            cursor.blinking=False
            x,y,_ = g[0].get_center()+0.4*LEFT
            self.play(Write(g), CursorMoveTo(cursor, x,y ), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("gnot")
            self.play(g.animate.set_color(RED))

            self.wait_until_bookmark("cube")
            cursor.blinking=False
            x,y,_ = g[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("bubble")
            cursor.blinking=False
            x,y,_ = startpoint
            self.add_bubble_sound(1.5)
            cursor.add_updater(lambda m: m.move_to(b.get_end()))
            self.play(Create(b), Create(b.text))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
class Func_4_1_I_4(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Parabolas")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*1.4)
        plane = cords[0]
        self.add(cords)

        f1 = lambda x: -2*x**2+4
        f2= lambda x: x**2-x-4
        f3 = lambda x: -2*x**2

        g1 = plane.plot(f1, color=BLUE, x_range=[-1.8,1.8, 0.001])
        g2 = plane.plot(f2, color=PURPLE)
        g3 = plane.plot(f3, color=GREEN, x_range=[-2**0.5,2**0.5, 0.001])

        tQ = Tex("Two graphs are quadratic", color=GREEN, font_size=fs2).next_to(cords, DOWN, buff=1)
        fQ = Tex("One is not", color=RED, font_size=fs2).next_to(tQ, DOWN, buff=0.2)
        

        # Action Sequence
        with self.voiceover(
                text="""
                The graph of a quadratic function is called a parabola.
                Parabolas always have the <bookmark mark="plot"/>shape of a curve, like in our example a curve that looks like an upside down U.
                They can also have the shape of a slightly tilted U, like the <bookmark mark="purple"/> purple graph.
                The point where the parabola turns is called the vertex.
                The vertex of the <bookmark mark="blueVertex"/> blue graph is at the top of the parabola.
                It is called a <bookmark mark="max"/> maximum, because the function value is the highest at this point.
                The vertex<bookmark mark="purpleVertex"/> of the purple graph is at the bottom of the parabola.
                It is called a <bookmark mark="min"/> minimum, because the function value is the lowest at this point.
                """
        ) as tracker:
            
            self.wait_until_bookmark("plot")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g1.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            cursor.blinking=True
            self.play(Create(g1), run_time=0.8)

            self.wait_until_bookmark("purple")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g2.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            cursor.blinking=True
            self.play(Create(g2), run_time=0.8)

            self.wait_until_bookmark("blueVertex")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,4)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("max")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,4)+0.2*UP
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            bMax = Bubble(["This vertex", "is a maximum"], width=2.2, height=0.8, start_point = plane.c2p(0,4)+0.2*UP, center=[-0.6,2.4,0], loc="b2")
            self.add_bubble_sound(1.5)
            bUpdater = lambda m: m.move_to(bMax.get_end())
            cursor.add_updater(bUpdater)
            self.play(Create(bMax), Create(bMax.text))
            cursor.remove_updater(bUpdater)
            cursor.blinking=True

            self.wait_until_bookmark("purpleVertex")
            cursor.blinking=False
            x,y,_ = plane.c2p(0.5,-4.25)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("min")
            cursor.blinking=False
            x,y,_ = plane.c2p(0.5,-4.25)+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            bMin = Bubble(["This vertex", "is a minimum"], width=2.2, height=0.8, start_point = plane.c2p(0.5,-4.25)+0.2*DOWN, center=[0.6,-2.6,0], loc="t2")
            self.add_bubble_sound(1.5)
            cursor.add_updater(lambda m: m.move_to(bMin.get_end()))
            self.play(Create(bMin), Create(bMin.text))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
class Func_4_1_I_5(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Unit Parabola")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-2, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-2,2,4]).shift(DOWN)
        plane = cords[0]

        f1 = lambda x: x**2
        
        posLine = Line(plane.c2p(2.5,0), plane.c2p(2.5,4), color=GREEN, stroke_width=6)
        posTex = MathTex("\\geq0", color=GREEN, font_size=fs3).next_to(posLine, RIGHT, buff=0.1)

        symLine = Line(plane.c2p(0,-2), plane.c2p(0,4), color=PURPLE, stroke_width=6)
        symTex = MathTex("f(-x)","=", "f(x)", color=BLUE, font_size=fs2).next_to(symLine, UP, buff=0.4)

        g1 = plane.plot(f1, color=BLUE)

        startpoint = plane.c2p(-0.5,-0.5)
        b = Bubble(["Unit Parabola:", "Vertex at the origin"], width=3, height=1, start_point = startpoint, center=[0,-1.7,0], loc="t1")
        
        funcTerm = MathTex("f","(x)", "=", "x^2", color=c1t, font_size=fs2).next_to(b, DOWN, buff=0.5)

        # Action Sequence
        with self.voiceover(
                text="""
                Now for a special kind of parabola, the <bookmark mark="cords"/>unit parabola.
                The <bookmark mark="unit"/>unit parabola is the parabola that is created by the function <bookmark mark="funcTerm"/>
                f of <bookmark mark="x"/>x equals <bookmark mark="xsquared"/>x squared.
                It allows us to study the properties of parabolas and helps us
                recognize other quadratic functions.
                The unit parabola is <bookmark mark="origin"/> shaped like a U and has <bookmark mark="vertexBubble"/> its vertex at the origin.
                The unit parabola has two special properties.
                First, it is <bookmark mark="posLine"/> always above or on the x-axis. This means,
                that <bookmark mark="geq0"/>the function value is always greater or equal to zero.
                Second, it is <bookmark mark="symLine"/> symmetric to the y-axis. This means, that the function value
                at <bookmark mark="symTex"/> minus x is the same as the <bookmark mark="sym2"/>function value at x.
                """
        ) as tracker:
            
            self.wait_until_bookmark("cords")
            self.play(Create(cords), run_time=1)

            self.wait_until_bookmark("unit")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_pencil_sound(0.8)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g1.get_end()))._start_fading(1))
            self.play(Create(g1), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("funcTerm")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm), CursorMoveTo(cursor, x,y ), run_time=0.4)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("xsquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("origin")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("vertexBubble")
            cursor.blinking=False
            x,y,_ = startpoint
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_bubble_sound(1.5)
            bUpdater = lambda m: m.move_to(b.get_end())
            cursor.add_updater(bUpdater)
            self.play(Create(b), Create(b.text))
            cursor.remove_updater(bUpdater)
            cursor.blinking=True

            self.wait_until_bookmark("posLine")
            cursor.blinking=False
            x,y,_ = posLine.get_bottom()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(posLine.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(posLine), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("geq0")
            cursor.blinking=False
            x,y,_ = posTex.get_center()+0.4*DOWN
            self.play(Write(posTex), CursorMoveTo(cursor, x,y ), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("symLine")
            cursor.blinking=False
            x,y,_ = symLine.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(symLine.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(symLine), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("symTex")
            cursor.blinking=False
            x,y,_ = symTex[0].get_center()+0.4*DOWN
            self.play(Write(symTex), CursorMoveTo(cursor, x,y ), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("sym2")
            cursor.blinking=False
            x,y,_ = symTex[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)
            cursor.blinking=True
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
class Func_4_1_I_5(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Unit Parabola")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-2, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-2,2,4]).shift(DOWN)
        plane = cords[0]

        f1 = lambda x: x**2
        
        posLine = Line(plane.c2p(2.5,0), plane.c2p(2.5,4), color=GREEN, stroke_width=6)
        posTex = MathTex("\\geq0", color=GREEN, font_size=fs3).next_to(posLine, RIGHT, buff=0.1)

        symLine = Line(plane.c2p(0,-2), plane.c2p(0,4), color=PURPLE, stroke_width=6)
        symTex = MathTex("f(-x)","=", "f(x)", color=BLUE, font_size=fs2).next_to(symLine, UP, buff=0.4)

        g1 = plane.plot(f1, color=BLUE)

        startpoint = plane.c2p(-0.5,-0.5)
        b = Bubble(["Unit Parabola:", "Vertex at the origin"], width=3, height=1, start_point = startpoint, center=[0,-1.7,0], loc="t1")
        
        funcTerm = MathTex("f","(x)", "=", "x^2", color=c1t, font_size=fs2).next_to(b, DOWN, buff=0.5)

        # Action Sequence
        with self.voiceover(
                text="""
                Now for a special kind of parabola, the <bookmark mark="cords"/>unit parabola.
                The <bookmark mark="unit"/>unit parabola is the parabola that is created by the function <bookmark mark="funcTerm"/>
                f of <bookmark mark="x"/>x equals <bookmark mark="xsquared"/>x squared.
                It allows us to study the properties of parabolas and helps us
                recognize other quadratic functions.
                The unit parabola is <bookmark mark="origin"/> shaped like a U and has <bookmark mark="vertexBubble"/> its vertex at the origin.
                The unit parabola has two special properties.
                First, it is <bookmark mark="posLine"/> always above or on the x-axis. This means,
                that <bookmark mark="geq0"/>the function value is always greater or equal to zero.
                Second, it is <bookmark mark="symLine"/> symmetric to the y-axis. This means, that the function value
                at <bookmark mark="symTex"/> minus x is the same as the <bookmark mark="sym2"/>function value at x.
                """
        ) as tracker:
            
            self.wait_until_bookmark("cords")
            self.play(Create(cords), run_time=1)

            self.wait_until_bookmark("unit")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_pencil_sound(0.8)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g1.get_end()))._start_fading(1))
            self.play(Create(g1), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("funcTerm")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm), CursorMoveTo(cursor, x,y ), run_time=0.4)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("xsquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("origin")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("vertexBubble")
            cursor.blinking=False
            x,y,_ = startpoint
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_bubble_sound(1.5)
            bUpdater = lambda m: m.move_to(b.get_end())
            cursor.add_updater(bUpdater)
            self.play(Create(b), Create(b.text))
            cursor.remove_updater(bUpdater)
            cursor.blinking=True

            self.wait_until_bookmark("posLine")
            cursor.blinking=False
            x,y,_ = posLine.get_bottom()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(posLine.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(posLine), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("geq0")
            cursor.blinking=False
            x,y,_ = posTex.get_center()+0.4*DOWN
            self.play(Write(posTex), CursorMoveTo(cursor, x,y ), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("symLine")
            cursor.blinking=False
            x,y,_ = symLine.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(symLine.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(symLine), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("symTex")
            cursor.blinking=False
            x,y,_ = symTex[0].get_center()+0.4*DOWN
            self.play(Write(symTex), CursorMoveTo(cursor, x,y ), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("sym2")
            cursor.blinking=False
            x,y,_ = symTex[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)
            cursor.blinking=True
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
TASK_Func_4_1_I_6_q = SophiaTaskDefinition(
    answerOptions = ["The graph moves up", "The graph moves down", "The graph gets flatter", "The graph gets steeper"],
    correctAnswerIndex = 3,
    questionText = "What happens, if we increase the value of $a$?"
)
class Func_4_1_I_6_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Function Term")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)
        f1 = lambda x: a.get_value()*x**2+b.get_value()*x+c.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[-2/a.get_value(), 2/a.get_value(), 0.001]))
        funcTerm = MathTex("f","(x)", "=", "ax^2", "+bx", "+c", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.5)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, let's go back to the term of quadratic functions.
                As we've seen before, the term of a quadratic function has the form <bookmark mark="term"/>f of
                <bookmark mark="x"/>x equals <bookmark mark="xsquared"/>a x squared plus <bookmark mark="bx"/>b x plus <bookmark mark="c"/>c.
                But what do the <bookmark mark="aa"/>parameters a, <bookmark mark="bb"/>b and <bookmark mark="cc"/>c mean for the <bookmark mark='graph' />graph of the function?
                Let's start with the parameter <bookmark mark="aaa"/>a, what happens if we<bookmark mark="increaseA"/> increase a?
                """
        ) as tracker:
            
            self.wait_until_bookmark("term")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm), CursorMoveTo(cursor, x,y ), run_time=0.4)
            
            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("xsquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("bx")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("c")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("aa")
            cursor.blinking=False
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("bb")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.2)

            self.wait_until_bookmark("cc")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.2)

            self.wait_until_bookmark("graph")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().add_updater(lambda m: m.move_to(g1.get_end()))._start_fading(1))
            self.add_pencil_sound(0.8)
            self.play(Create(g1), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("aaa")
            cursor.blinking=False
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("increaseA")
            cursor.blinking=False
            cc = cursor.copy()._start_fading(1)
            self.play(cc.animate.scale(3))
            cursor.blinking=True
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_1_I_6_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Function Term")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)
        f1 = lambda x: a.get_value()*x**2+b.get_value()*x+c.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[max(-2,-2**(1/a.get_value())), min(2,2**(1/a.get_value())), 0.001]))
        self.add(g1)
        funcTerm = MathTex("f","(x)", "=", "\\,a\\,","x^2", "+bx", "+c", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.5)
        aIncreased = Tex("Large a", "$\\,\\,\\Rightarrow\\,\\,$", "steep graph", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=1)
        aDecreased = Tex("Small a", "$\\,\\,\\Rightarrow\\,\\,$", "flat graph", color=c1t, font_size=fs3).next_to(aIncreased, DOWN, buff=0.2)
        self.add(funcTerm)
        aTracked = DecimalNumber(1, color=c1t, num_decimal_places=1).move_to(funcTerm[3]).add_updater(lambda m: m.set_value(a.get_value())).shift(0.08*LEFT)
        aTracked.scale(2*funcTerm[3].get_width()/aTracked.get_width())
        aTracked.shift((funcTerm[3].get_bottom()[1]-aTracked.get_bottom()[1])*UP)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right.
                Note that in the term of the function, the parameter <bookmark mark="a"/>a is multiplied with x squared. Let's see what that implies.
                We'll start with <bookmark mark="a1"/> the value of a equals 1 and <bookmark mark="a2"/> slowly start
                increasing it. As you can see, the graph gets steeper and steeper.
                So, if we increase the value of a, the graph <bookmark mark="a4"/> gets steeper. If we <bookmark mark="decreaseA"/> decrease a on the other hand,
                the graph gets flatter. So quick summary: <bookmark mark="largeA"/>large a, steep graph, <bookmark mark="smallA"/>small a, flat graph.
                """
        ) as tracker:
            
            self.wait_until_bookmark("a")
            cursor.blinking=False
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y ), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("a1")
            self.play(Unwrite(funcTerm[3]), Write(aTracked), run_time=1)

            self.wait_until_bookmark("a2")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            funcDater = lambda m: m.move_to(plane.c2p(1,f1(1)))
            cursor.add_updater(funcDater)
            self.play(a.animate.set_value(3), run_time=4)
            cursor.blinking=True

            self.wait_until_bookmark("decreaseA")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(a.animate(run_time=6).set_value(0.2), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("largeA")
            cursor.blinking=False
            cursor.remove_updater(funcDater)
            x,y,_ = aIncreased.get_left()+0.2*LEFT
            self.play(CursorMoveTo(cursor, x, y), a.animate.set_value(1), run_time=0.3)
            self.play(Write(aIncreased), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("smallA")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(Write(aDecreased), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_1_I_6_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Function Term")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)
        f1 = lambda x: a.get_value()*x**2+b.get_value()*x+c.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[max(-2,-2**(1/a.get_value())), min(2,2**(1/a.get_value())), 0.001]))
        self.add(g1)
        funcTerm = MathTex("f","(x)", "=", "\\,a\\,","x^2", "+bx", "+c", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.5)
        aIncreased = Tex("Large a", "$\\,\\,\\Rightarrow\\,\\,$", "steep graph", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=1)
        aDecreased = Tex("Small a", "$\\,\\,\\Rightarrow\\,\\,$", "flat graph", color=c1t, font_size=fs3).next_to(aIncreased, DOWN, buff=0.2)
        self.add(funcTerm)
        aTracked = DecimalNumber(1, color=c1t, num_decimal_places=1).move_to(funcTerm[3]).add_updater(lambda m: m.set_value(a.get_value())).shift(0.08*LEFT)
        aTracked.scale(2*funcTerm[3].get_width()/aTracked.get_width())
        aTracked.shift((funcTerm[3].get_bottom()[1]-aTracked.get_bottom()[1])*UP)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right.
                Note that in the term of the function, the parameter <bookmark mark="a"/>a is multiplied with x squared. Let's see what that implies.
                We'll start with <bookmark mark="a1"/> the value of a equals 1 and <bookmark mark="a2"/> slowly start
                increasing it. As you can see, the graph gets steeper and steeper.
                So, if we increase the value of a, the graph <bookmark mark="a4"/> gets steeper. If we <bookmark mark="decreaseA"/> decrease a on the other hand,
                the graph gets flatter. So quick summary: <bookmark mark="largeA"/>large a, steep graph, <bookmark mark="smallA"/>small a, flat graph.
                """
        ) as tracker:
            
            self.wait_until_bookmark("a")
            cursor.blinking=False
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y ), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("a1")
            self.play(Unwrite(funcTerm[3]), Write(aTracked), run_time=1)

            self.wait_until_bookmark("a2")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            funcDater = lambda m: m.move_to(plane.c2p(1,f1(1)))
            cursor.add_updater(funcDater)
            self.play(a.animate.set_value(3), run_time=4)
            cursor.blinking=True

            self.wait_until_bookmark("decreaseA")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(a.animate(run_time=6).set_value(0.2), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("largeA")
            cursor.blinking=False
            cursor.remove_updater(funcDater)
            x,y,_ = aIncreased.get_left()+0.2*LEFT
            self.play(CursorMoveTo(cursor, x, y), a.animate.set_value(1), run_time=0.3)
            self.play(Write(aIncreased), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("smallA")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(Write(aDecreased), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_1_I_6_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Function Term")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)
        f1 = lambda x: a.get_value()*x**2+b.get_value()*x+c.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[max(-2,-2**(1/a.get_value())), min(2,2**(1/a.get_value())), 0.001]))
        self.add(g1)
        funcTerm = MathTex("f","(x)", "=", "\\,a\\,","x^2", "+bx", "+c", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.5)
        aIncreased = Tex("Large a", "$\\,\\,\\Rightarrow\\,\\,$", "steep graph", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=1)
        aDecreased = Tex("Small a", "$\\,\\,\\Rightarrow\\,\\,$", "flat graph", color=c1t, font_size=fs3).next_to(aIncreased, DOWN, buff=0.2)
        self.add(funcTerm)
        aTracked = DecimalNumber(1, color=c1t, num_decimal_places=1).move_to(funcTerm[3]).add_updater(lambda m: m.set_value(a.get_value())).shift(0.08*LEFT)
        aTracked.scale(2*funcTerm[3].get_width()/aTracked.get_width())
        aTracked.shift((funcTerm[3].get_bottom()[1]-aTracked.get_bottom()[1])*UP)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right.
                Note that in the term of the function, the parameter <bookmark mark="a"/>a is multiplied with x squared. Let's see what that implies.
                We'll start with <bookmark mark="a1"/> the value of a equals 1 and <bookmark mark="a2"/> slowly start
                increasing it. As you can see, the graph gets steeper and steeper.
                So, if we increase the value of a, the graph <bookmark mark="a4"/> gets steeper. If we <bookmark mark="decreaseA"/> decrease a on the other hand,
                the graph gets flatter. So quick summary: <bookmark mark="largeA"/>large a, steep graph, <bookmark mark="smallA"/>small a, flat graph.
                """
        ) as tracker:
            
            self.wait_until_bookmark("a")
            cursor.blinking=False
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y ), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("a1")
            self.play(Unwrite(funcTerm[3]), Write(aTracked), run_time=1)

            self.wait_until_bookmark("a2")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            funcDater = lambda m: m.move_to(plane.c2p(1,f1(1)))
            cursor.add_updater(funcDater)
            self.play(a.animate.set_value(3), run_time=4)
            cursor.blinking=True

            self.wait_until_bookmark("decreaseA")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(a.animate(run_time=6).set_value(0.2), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("largeA")
            cursor.blinking=False
            cursor.remove_updater(funcDater)
            x,y,_ = aIncreased.get_left()+0.2*LEFT
            self.play(CursorMoveTo(cursor, x, y), a.animate.set_value(1), run_time=0.3)
            self.play(Write(aIncreased), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("smallA")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(Write(aDecreased), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_1_I_6_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Function Term")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)
        f1 = lambda x: a.get_value()*x**2+b.get_value()*x+c.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[max(-2,-2**(1/a.get_value())), min(2,2**(1/a.get_value())), 0.001]))
        self.add(g1)
        funcTerm = MathTex("f","(x)", "=", "\\,a\\,","x^2", "+bx", "+c", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.5)
        aIncreased = Tex("Large a", "$\\,\\,\\Rightarrow\\,\\,$", "steep graph", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=1)
        aDecreased = Tex("Small a", "$\\,\\,\\Rightarrow\\,\\,$", "flat graph", color=c1t, font_size=fs3).next_to(aIncreased, DOWN, buff=0.2)
        self.add(funcTerm)
        aTracked = DecimalNumber(1, color=c1t, num_decimal_places=1).move_to(funcTerm[3]).add_updater(lambda m: m.set_value(a.get_value())).shift(0.08*LEFT)
        aTracked.scale(2*funcTerm[3].get_width()/aTracked.get_width())
        aTracked.shift((funcTerm[3].get_bottom()[1]-aTracked.get_bottom()[1])*UP)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's it.
                Note that in the term of the function, the parameter <bookmark mark="a"/>a is multiplied with x squared. Let's see what that implies.
                We'll start with <bookmark mark="a1"/> the value of a equals 1 and <bookmark mark="a2"/> slowly start
                increasing it. As you can see, the graph gets steeper and steeper.
                So, if we increase the value of a, the graph <bookmark mark="a4"/> gets steeper. If we <bookmark mark="decreaseA"/> decrease a on the other hand,
                the graph gets flatter. So quick summary: <bookmark mark="largeA"/>large a, steep graph, <bookmark mark="smallA"/>small a, flat graph.
                """
        ) as tracker:
            
            self.wait_until_bookmark("a")
            cursor.blinking=False
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y ), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("a1")
            self.play(Unwrite(funcTerm[3]), Write(aTracked), run_time=1)

            self.wait_until_bookmark("a2")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            funcDater = lambda m: m.move_to(plane.c2p(1,f1(1)))
            cursor.add_updater(funcDater)
            self.play(a.animate.set_value(3), run_time=4)
            cursor.blinking=True

            self.wait_until_bookmark("decreaseA")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(a.animate(run_time=6).set_value(0.2), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("largeA")
            cursor.blinking=False
            cursor.remove_updater(funcDater)
            x,y,_ = aIncreased.get_left()+0.2*LEFT
            self.play(CursorMoveTo(cursor, x, y), a.animate.set_value(1), run_time=0.3)
            self.play(Write(aIncreased), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("smallA")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(Write(aDecreased), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_4_1_I_7_q = SophiaTaskDefinition(
    answerOptions = ["The graph gets tilted left", "The graph gets tilted right", "The graph is shifted up", "The graph is shifted down"],
    correctAnswerIndex = 0,
    questionText = "What happens, if we increase the value of $b$?"
)
class Func_4_1_I_7_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Function Term")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)
        f1 = lambda x: a.get_value()*x**2+b.get_value()*x+c.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[-2/a.get_value(), 2/a.get_value(), 0.001]))
        funcTerm = MathTex("f","(x)", "=", "ax^2", "+bx", "+c", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.5)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so we're still looking at a <bookmark mark="plot"/> quadratic function with the form <bookmark mark="term"/>f of
                <bookmark mark="x"/>x equals <bookmark mark="xsquared"/>"a" x squared plus <bookmark mark="bx"/>b x plus <bookmark mark="c"/>c.
                Now, let's analyze the parameter <bookmark mark="bbb"/>b. What happens to the graph, if we<bookmark mark="increaseB"/> increase b?
                How will it change?
                """
        ) as tracker:
            
            self.wait_until_bookmark("plot")
            x,y,_ = g1.get_start()
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x,y ), run_time=0.4)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g1))
            
            self.wait_until_bookmark("term")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm), CursorMoveTo(cursor, x,y ), run_time=0.4)
            
            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("xsquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("bx")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)

            self.wait_until_bookmark("c")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("bbb")
            cursor.blinking=False
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("increaseB")
            cursor.blinking=False
            cc = cursor.copy()._start_fading(1)
            self.play(cc.animate.scale(3))
            cursor.blinking=True
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_1_I_7_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Function Term")
        
        #Create the coordinate system
        cords = self.add_cords([-3,3, 1], [-10, 10, 4], x_ticks=[-3,-1,1,3],y_ticks=[-8,-4,4,8]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)
        f1 = lambda x: a.get_value()*x**2+b.get_value()*x+c.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE))
        self.add(g1)
        funcTerm = MathTex("f","(x)", "=", "a","x^2", "\\,\\,+b\\,\\,", "x+c", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.5)
        aIncreased = Tex("$b>0$", "$\\,\\,\\Rightarrow\\,\\,$", "graph is tilted left", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=1)
        aDecreased = Tex("$b<0$", "$\\,\\,\\Rightarrow\\,\\,$", "graph is tilted right", color=c1t, font_size=fs3).next_to(aIncreased, DOWN, buff=0.2)
        self.add(funcTerm)
        aTracked = DecimalNumber(0, color=c1t, num_decimal_places=1, include_sign=True).move_to(funcTerm[5]).add_updater(lambda m: m.set_value(b.get_value())).shift(0.08*LEFT)
        aTracked.scale(4*funcTerm[3].get_width()/aTracked.get_width())
        aTracked.shift((funcTerm[3].get_bottom()[1]-aTracked.get_bottom()[1])*UP)

        # Action Sequence
        with self.voiceover(
                text="""
                That's correct, nicely done!
                We can see that in the term of the function, the parameter <bookmark mark="b"/>b is multiplied with x. Let's look at the effects it has on the graph.
                We'll start with <bookmark mark="b1"/> the value of b equals 0 and <bookmark mark="b2"/> slowly start
                increasing it. As you can see, the graph gets higher on the right, and lower on the left.
                So, if we increase the value of b, the graph gets tilted to the left. If we <bookmark mark="decreaseB"/> decrease b on the other hand,
                so that it's negative, the graph gets tilted to the right. So quick summary: <bookmark mark="posB"/>positive b, graph is tilted left,
                <bookmark mark="negB"/>negative b, graph is tilted right.
                """
        ) as tracker:
            
            self.wait_until_bookmark("b")
            cursor.blinking=False
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y ), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            self.play(Unwrite(funcTerm[5]), Write(aTracked), run_time=1)

            self.wait_until_bookmark("b2")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            funcDater = lambda m: m.move_to(plane.c2p(1,f1(1)))
            cursor.add_updater(funcDater)
            self.play(b.animate.set_value(2), run_time=4)
            cursor.blinking=True

            self.wait_until_bookmark("decreaseB")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(b.animate(run_time=6).set_value(-2), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("posB")
            cursor.blinking=False
            cursor.remove_updater(funcDater)
            x,y,_ = aIncreased.get_left()+0.2*LEFT
            self.play(CursorMoveTo(cursor, x, y), b.animate.set_value(0), run_time=0.3)
            self.play(Write(aIncreased), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("negB")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(Write(aDecreased), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_1_I_7_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Function Term")
        
        #Create the coordinate system
        cords = self.add_cords([-3,3, 1], [-10, 10, 4], x_ticks=[-3,-1,1,3],y_ticks=[-8,-4,4,8]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)
        f1 = lambda x: a.get_value()*x**2+b.get_value()*x+c.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE))
        self.add(g1)
        funcTerm = MathTex("f","(x)", "=", "a","x^2", "\\,\\,+b\\,\\,", "x+c", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.5)
        aIncreased = Tex("$b>0$", "$\\,\\,\\Rightarrow\\,\\,$", "graph is tilted left", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=1)
        aDecreased = Tex("$b<0$", "$\\,\\,\\Rightarrow\\,\\,$", "graph is tilted right", color=c1t, font_size=fs3).next_to(aIncreased, DOWN, buff=0.2)
        self.add(funcTerm)
        aTracked = DecimalNumber(0, color=c1t, num_decimal_places=1, include_sign=True).move_to(funcTerm[5]).add_updater(lambda m: m.set_value(b.get_value())).shift(0.08*LEFT)
        aTracked.scale(4*funcTerm[3].get_width()/aTracked.get_width())
        aTracked.shift((funcTerm[3].get_bottom()[1]-aTracked.get_bottom()[1])*UP)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right.
                We can see that in the term of the function, the parameter <bookmark mark="b"/>b is multiplied with x. Let's look at the effects it has on the graph.
                We'll start with <bookmark mark="b1"/> the value of b equals 0 and <bookmark mark="b2"/> slowly start
                increasing it. As you can see, the graph gets higher on the right, and lower on the left.
                So, if we increase the value of b, the graph gets tilted to the left. If we <bookmark mark="decreaseB"/> decrease b on the other hand,
                so that it's negative, the graph gets tilted to the right. So quick summary: <bookmark mark="posB"/>positive b, graph is tilted left,
                <bookmark mark="negB"/>negative b, graph is tilted right.
                """
        ) as tracker:
            
            self.wait_until_bookmark("b")
            cursor.blinking=False
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y ), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            self.play(Unwrite(funcTerm[5]), Write(aTracked), run_time=1)

            self.wait_until_bookmark("b2")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            funcDater = lambda m: m.move_to(plane.c2p(1,f1(1)))
            cursor.add_updater(funcDater)
            self.play(b.animate.set_value(2), run_time=4)
            cursor.blinking=True

            self.wait_until_bookmark("decreaseB")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(b.animate(run_time=6).set_value(-2), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("posB")
            cursor.blinking=False
            cursor.remove_updater(funcDater)
            x,y,_ = aIncreased.get_left()+0.2*LEFT
            self.play(CursorMoveTo(cursor, x, y), b.animate.set_value(0), run_time=0.3)
            self.play(Write(aIncreased), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("negB")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(Write(aDecreased), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_1_I_7_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Function Term")
        
        #Create the coordinate system
        cords = self.add_cords([-3,3, 1], [-10, 10, 4], x_ticks=[-3,-1,1,3],y_ticks=[-8,-4,4,8]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)
        f1 = lambda x: a.get_value()*x**2+b.get_value()*x+c.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE))
        self.add(g1)
        funcTerm = MathTex("f","(x)", "=", "a","x^2", "\\,\\,+b\\,\\,", "x+c", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.5)
        aIncreased = Tex("$b>0$", "$\\,\\,\\Rightarrow\\,\\,$", "graph is tilted left", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=1)
        aDecreased = Tex("$b<0$", "$\\,\\,\\Rightarrow\\,\\,$", "graph is tilted right", color=c1t, font_size=fs3).next_to(aIncreased, DOWN, buff=0.2)
        self.add(funcTerm)
        aTracked = DecimalNumber(0, color=c1t, num_decimal_places=1, include_sign=True).move_to(funcTerm[5]).add_updater(lambda m: m.set_value(b.get_value())).shift(0.08*LEFT)
        aTracked.scale(4*funcTerm[3].get_width()/aTracked.get_width())
        aTracked.shift((funcTerm[3].get_bottom()[1]-aTracked.get_bottom()[1])*UP)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right.
                We can see that in the term of the function, the parameter <bookmark mark="b"/>b is multiplied with x. Let's look at the effects it has on the graph.
                We'll start with <bookmark mark="b1"/> the value of b equals 0 and <bookmark mark="b2"/> slowly start
                increasing it. As you can see, the graph gets higher on the right, and lower on the left.
                So, if we increase the value of b, the graph gets tilted to the left. If we <bookmark mark="decreaseB"/> decrease b on the other hand,
                so that it's negative, the graph gets tilted to the right. So quick summary: <bookmark mark="posB"/>positive b, graph is tilted left,
                <bookmark mark="negB"/>negative b, graph is tilted right.
                """
        ) as tracker:
            
            self.wait_until_bookmark("b")
            cursor.blinking=False
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y ), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            self.play(Unwrite(funcTerm[5]), Write(aTracked), run_time=1)

            self.wait_until_bookmark("b2")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            funcDater = lambda m: m.move_to(plane.c2p(1,f1(1)))
            cursor.add_updater(funcDater)
            self.play(b.animate.set_value(2), run_time=4)
            cursor.blinking=True

            self.wait_until_bookmark("decreaseB")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(b.animate(run_time=6).set_value(-2), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("posB")
            cursor.blinking=False
            cursor.remove_updater(funcDater)
            x,y,_ = aIncreased.get_left()+0.2*LEFT
            self.play(CursorMoveTo(cursor, x, y), b.animate.set_value(0), run_time=0.3)
            self.play(Write(aIncreased), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("negB")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(Write(aDecreased), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_1_I_7_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Function Term")
        
        #Create the coordinate system
        cords = self.add_cords([-3,3, 1], [-10, 10, 4], x_ticks=[-3,-1,1,3],y_ticks=[-8,-4,4,8]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)
        f1 = lambda x: a.get_value()*x**2+b.get_value()*x+c.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE))
        self.add(g1)
        funcTerm = MathTex("f","(x)", "=", "a","x^2", "\\,\\,+b\\,\\,", "x+c", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.5)
        aIncreased = Tex("$b>0$", "$\\,\\,\\Rightarrow\\,\\,$", "graph is tilted left", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=1)
        aDecreased = Tex("$b<0$", "$\\,\\,\\Rightarrow\\,\\,$", "graph is tilted right", color=c1t, font_size=fs3).next_to(aIncreased, DOWN, buff=0.2)
        self.add(funcTerm)
        aTracked = DecimalNumber(0, color=c1t, num_decimal_places=1, include_sign=True).move_to(funcTerm[5]).add_updater(lambda m: m.set_value(b.get_value())).shift(0.08*LEFT)
        aTracked.scale(4*funcTerm[3].get_width()/aTracked.get_width())
        aTracked.shift((funcTerm[3].get_bottom()[1]-aTracked.get_bottom()[1])*UP)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right.
                We can see that in the term of the function, the parameter <bookmark mark="b"/>b is multiplied with x. Let's look at the effects it has on the graph.
                We'll start with <bookmark mark="b1"/> the value of b equals 0 and <bookmark mark="b2"/> slowly start
                increasing it. As you can see, the graph gets higher on the right, and lower on the left.
                So, if we increase the value of b, the graph gets tilted to the left. If we <bookmark mark="decreaseB"/> decrease b on the other hand,
                so that it's negative, the graph gets tilted to the right. So quick summary: <bookmark mark="posB"/>positive b, graph is tilted left,
                <bookmark mark="negB"/>negative b, graph is tilted right.
                """
        ) as tracker:
            
            self.wait_until_bookmark("b")
            cursor.blinking=False
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y ), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            self.play(Unwrite(funcTerm[5]), Write(aTracked), run_time=1)

            self.wait_until_bookmark("b2")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            funcDater = lambda m: m.move_to(plane.c2p(1,f1(1)))
            cursor.add_updater(funcDater)
            self.play(b.animate.set_value(2), run_time=4)
            cursor.blinking=True

            self.wait_until_bookmark("decreaseB")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(b.animate(run_time=6).set_value(-2), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("posB")
            cursor.blinking=False
            cursor.remove_updater(funcDater)
            x,y,_ = aIncreased.get_left()+0.2*LEFT
            self.play(CursorMoveTo(cursor, x, y), b.animate.set_value(0), run_time=0.3)
            self.play(Write(aIncreased), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("negB")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(Write(aDecreased), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_4_1_I_8_q = SophiaTaskDefinition(
    answerOptions = ["The graph is shifted down", "The graph is shifted up", "The graph is flipped along the x-axis", "The graph is flipped along the x-axis"],
    correctAnswerIndex = 0,
    questionText = "What happens, if we increase the value of $c$?"
)
class Func_4_1_I_8_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Function Term")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)
        f1 = lambda x: a.get_value()*x**2+b.get_value()*x+c.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[-2/a.get_value(), 2/a.get_value(), 0.001]))
        funcTerm = MathTex("f","(x)", "=", "ax^2", "+bx", "+","c", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.5)

        # Action Sequence
        with self.voiceover(
                text="""
                Now we're almost done analyzing the <bookmark mark="plot"/>quadratic function with the form <bookmark mark="term"/>f of
                <bookmark mark="x"/>x equals <bookmark mark="xsquared"/>"a" x squared plus <bookmark mark="bx"/>b x plus <bookmark mark="c"/>c.
                The last parameter, we still need to analyze is <bookmark mark="ccc"/>c. What happens to the graph, if we<bookmark mark="increaseC"/> increase c?
                How will it change?
                """
        ) as tracker:
            
            self.wait_until_bookmark("plot")
            x,y,_ = g1.get_start()
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x,y ), run_time=0.4)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g1))
            
            self.wait_until_bookmark("term")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm), CursorMoveTo(cursor, x,y ), run_time=0.4)
            
            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.2)

            self.wait_until_bookmark("xsquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.2)

            self.wait_until_bookmark("bx")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.2)

            self.wait_until_bookmark("c")
            x,y,_ = funcTerm[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y ), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("increaseC")
            cursor.blinking=False
            cc = cursor.copy()._start_fading(1)
            self.play(cc.animate.scale(3))
            cursor.blinking=True
            
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_1_I_8_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Function Term")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b, c = ValueTracker(1), ValueTracker(0), ValueTracker(0)
        f1 = lambda x: a.get_value()*x**2+b.get_value()*x+c.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE))
        self.add(g1)
        funcTerm = MathTex("f","(x)", "=", "a","x^2", "+bx", "\\,\\,+c", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.5)
        aIncreased = Tex("$c>0$", "$\\,\\,\\Rightarrow\\,\\,$", "graph is shifted up", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=1)
        aDecreased = Tex("$c<0$", "$\\,\\,\\Rightarrow\\,\\,$", "graph is shifted down", color=c1t, font_size=fs3).next_to(aIncreased, DOWN, buff=0.2)
        self.add(funcTerm)
        aTracked = DecimalNumber(0, color=c1t, num_decimal_places=1, include_sign=True).move_to(funcTerm[-1]).add_updater(lambda m: m.set_value(c.get_value())).shift(0.08*LEFT)
        aTracked.scale(1.4*funcTerm[-1].get_width()/aTracked.get_width())
        aTracked.shift((funcTerm[-1].get_bottom()[1]-aTracked.get_bottom()[1])*UP)

        # Action Sequence
        with self.voiceover(
                text="""
                That's correct, nicely done!
                We can see that in the term of the function, the parameter <bookmark mark="c"/>c is added to the function. Let's look at the effects it has on the graph.
                We'll start with <bookmark mark="c1"/> the value of c equals 0 and <bookmark mark="c2"/> increase it. As you can see, the graph moves up.
                So, if we increase the value of c, the graph is shifted up. If we <bookmark mark="decreaseC"/> decrease c on the other hand,
                so that it's negative, the graph is shifted down. So quick summary: <bookmark mark="posC"/>positive c, graph is shifted up,
                <bookmark mark="negC"/>negative c, graph is shifted down.
                """
        ) as tracker:
            
            self.wait_until_bookmark("c")
            cursor.blinking=False
            x,y,_ = funcTerm[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y ), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("c1")
            self.play(Unwrite(funcTerm[-1]), Write(aTracked), run_time=1)

            self.wait_until_bookmark("c2")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            funcDater = lambda m: m.move_to(plane.c2p(0,f1(0)))
            cursor.add_updater(funcDater)
            self.play(c.animate.set_value(2), run_time=4)
            cursor.blinking=True

            self.wait_until_bookmark("decreaseC")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(c.animate(run_time=6).set_value(-2), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("posC")
            cursor.blinking=False
            cursor.remove_updater(funcDater)
            x,y,_ = aIncreased.get_left()+0.2*LEFT
            self.play(CursorMoveTo(cursor, x, y), c.animate.set_value(0), run_time=0.3)
            self.play(Write(aIncreased), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("negC")
            cursor.blinking=False
            x,y,_ = aDecreased.get_left()+0.2*LEFT
            self.play(Write(aDecreased), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
###### Practice Part ################
#####################################
#####################################

#####################################
#####################################
#### General Functions ##############
#####################################
#####################################

PROTOTYPES = [
    PagePrototypeVideo.from_scene(Func_4_1_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_1_I_1_q, Func_4_1_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_1_I_1_a),
    PagePrototypeVideo.from_scene(Func_4_1_I_1_b),
    PagePrototypeVideo.from_scene(Func_4_1_I_1_c),
    PagePrototypeVideo.from_scene(Func_4_1_I_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_1_I_2_q, Func_4_1_I_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_1_I_2_a),
    PagePrototypeVideo.from_scene(Func_4_1_I_2_b),
    PagePrototypeVideo.from_scene(Func_4_1_I_2_c),
    PagePrototypeVideo.from_scene(Func_4_1_I_3),
    PagePrototypeVideo.from_scene(Func_4_1_I_4),
    PagePrototypeVideo.from_scene(Func_4_1_I_5),
    PagePrototypeVideo.from_scene(Func_4_1_I_6_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_1_I_6_q, Func_4_1_I_6_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_1_I_6_a),
    PagePrototypeVideo.from_scene(Func_4_1_I_6_b),
    PagePrototypeVideo.from_scene(Func_4_1_I_6_c),
    PagePrototypeVideo.from_scene(Func_4_1_I_6_d),
    PagePrototypeVideo.from_scene(Func_4_1_I_7_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_1_I_7_q, Func_4_1_I_7_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_1_I_7_a),
    PagePrototypeVideo.from_scene(Func_4_1_I_7_b),
    PagePrototypeVideo.from_scene(Func_4_1_I_7_c),
    PagePrototypeVideo.from_scene(Func_4_1_I_7_d),
    PagePrototypeVideo.from_scene(Func_4_1_I_8_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_1_I_8_q, Func_4_1_I_8_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_1_I_8_a),

]
scenes/Func/Func_4: Quadratic Functions/Func_4_1.py
Sophia-Edu-Labs/sophia-math
# 4_2: Quadratic Functions: Shifting

# Import necessary libraries and modules
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition



#####################################
#####################################
TASK_Func_4_2_I_1_q = SophiaTaskDefinition(
    answerOptions = ["$f(x) = x^2 +c,\, c<0$", "$f(x) = x^2 +c,\, c>0$", "$f(x) = (x+c)^2,\, c>0$", "$f(x) = (x+c)^2,\, c<0$"],
    correctAnswerIndex = 1,
    questionText = "How do we shift the unit parabola up?"
)

class Func_4_2_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b = ValueTracker(0), ValueTracker(0)
        f1 = lambda x: (x-a.get_value())**2+b.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[-2+a.get_value(),2+a.get_value(),0.001]))
        funcTerm = MathTex("f","(x)", "=","x^2", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        

        # Action Sequence
        with self.voiceover(
                text="""
                Like all other functions<bookmark mark="f"/>, quadratic functions can be modified in various ways, for example:
                <bookmark mark="origin"/>They can be shifted <bookmark mark="up"/> up, they can be shifted
                <bookmark mark="down"/>down, they can <bookmark mark="reset"/> be shifted <bookmark mark="left"/>left, and they
                can be shifted <bookmark mark="right"/>right.
                Now let's take the <bookmark mark="unit"/>unit parabola <bookmark mark="f2"/>f of <bookmark mark="x"/>x equals
                <bookmark mark="xSquared"/>x squared as an example. <bookmark mark="origin2"/>How do we shift it
                <bookmark mark="up2"/> up? What does the term of the function look like, after we shifted it up?
                """
        ) as tracker:

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("origin")
            x,y,_ = plane.c2p(0,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=False

            self.wait_until_bookmark("up")
            cursor.blinking=False
            uLR = lambda m: m.move_to(g1.get_bottom())
            cursor.add_updater(uLR)
            self.play(b.animate.set_value(2), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("down")
            cursor.blinking=False
            self.play(b.animate.set_value(-2), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("reset")
            cursor.blinking=False
            self.play(b.animate.set_value(0), run_time=0.5)
            cursor.remove_updater(uLR)
            cursor.blinking=True


            self.wait_until_bookmark("left")
            cursor.blinking=False
            uUD = lambda m: m.move_to(plane.c2p(a.get_value(),0))
            cursor.add_updater(uUD)
            self.play(a.animate.set_value(-1), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("right")
            cursor.blinking=False
            self.play(a.animate.set_value(1), run_time=0.5)
            cursor.blinking=True
            self.wait(1.5)
            cursor.blinking=False
            self.play(a.animate.set_value(0), run_time=0.5)
            cursor.remove_updater(uUD)
            cursor.blinking=True

            self.wait_until_bookmark("unit")
            self.play(Write(funcTerm), run_time=0.5)

            self.wait_until_bookmark("f2")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("origin2")
            x,y,_ = plane.c2p(0,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=False

            self.wait_until_bookmark("up2")
            cursor.blinking=False
            uLR = lambda m: m.move_to(g1.get_bottom())
            cursor.add_updater(uLR)
            self.play(b.animate.set_value(2), run_time=0.5)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_2_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b = ValueTracker(0), ValueTracker(0)
        f1 = lambda x: (x-a.get_value())**2+b.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[-2+a.get_value(),2+a.get_value(),0.001]))
        self.add(g1)
        funcTerm = MathTex("f","(x)", "=","x^2", "+", "c,", "\\,\\,c>0" , color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right!
                To shift the <bookmark mark="up"/>function up, we need every value to be higher by the same amount, so we add
                a positive constant c to the function term. The term of the shifted function is therefore <bookmark mark="f"/>f of
                <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared plus <bookmark mark="c"/>c, where <bookmark mark="cGeq0"/>
                c is greater than zero.
                """
        ) as tracker:

            self.wait_until_bookmark("up")
            cursor.blinking=False
            uLR = lambda m: m.move_to(g1.get_bottom())
            cursor.add_updater(uLR)
            self.play(b.animate.set_value(2), run_time=0.5)
            cursor.remove_updater(uLR)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("c")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("cGeq0")
            x,y,_ = funcTerm[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_2_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b = ValueTracker(0), ValueTracker(0)
        f1 = lambda x: (x-a.get_value())**2+b.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[-2+a.get_value(),2+a.get_value(),0.001]))
        self.add(g1)
        funcTerm = MathTex("f","(x)", "=","x^2", "+", "c,", "\\,\\,c>0" , color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        

        # Action Sequence
        with self.voiceover(
                text="""
                Exactly right!
                To shift the <bookmark mark="up"/>function up, we need every value to be higher by the same amount, so we add
                a positive constant c to the function term. The term of the shifted function is therefore <bookmark mark="f"/>f of
                <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared plus <bookmark mark="c"/>c, where <bookmark mark="cGeq0"/>
                c is greater than zero.
                """
        ) as tracker:

            self.wait_until_bookmark("up")
            cursor.blinking=False
            uLR = lambda m: m.move_to(g1.get_bottom())
            cursor.add_updater(uLR)
            self.play(b.animate.set_value(2), run_time=0.5)
            cursor.remove_updater(uLR)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("c")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("cGeq0")
            x,y,_ = funcTerm[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_2_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b = ValueTracker(0), ValueTracker(0)
        f1 = lambda x: (x-a.get_value())**2+b.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[-2+a.get_value(),2+a.get_value(),0.001]))
        self.add(g1)
        funcTerm = MathTex("f","(x)", "=","x^2", "+", "c,", "\\,\\,c>0" , color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right!
                To shift the <bookmark mark="up"/>function up, we need every value to be higher by the same amount, so we add
                a positive constant c to the function term. The term of the shifted function is therefore <bookmark mark="f"/>f of
                <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared plus <bookmark mark="c"/>c, where <bookmark mark="cGeq0"/>
                c is greater than zero.
                """
        ) as tracker:

            self.wait_until_bookmark("up")
            cursor.blinking=False
            uLR = lambda m: m.move_to(g1.get_bottom())
            cursor.add_updater(uLR)
            self.play(b.animate.set_value(2), run_time=0.5)
            cursor.remove_updater(uLR)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("c")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("cGeq0")
            x,y,_ = funcTerm[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_2_I_1_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b = ValueTracker(0), ValueTracker(0)
        f1 = lambda x: (x-a.get_value())**2+b.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[-2+a.get_value(),2+a.get_value(),0.001]))
        self.add(g1)
        funcTerm = MathTex("f","(x)", "=","x^2", "+", "c,", "\\,\\,c>0" , color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right!
                To shift the <bookmark mark="up"/>function up, we need every value to be higher by the same amount, so we add
                a positive constant c to the function term. The term of the shifted function is therefore <bookmark mark="f"/>f of
                <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared plus <bookmark mark="c"/>c, where <bookmark mark="cGeq0"/>
                c is greater than zero.
                """
        ) as tracker:

            self.wait_until_bookmark("up")
            cursor.blinking=False
            uLR = lambda m: m.move_to(g1.get_bottom())
            cursor.add_updater(uLR)
            self.play(b.animate.set_value(2), run_time=0.5)
            cursor.remove_updater(uLR)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("c")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("cGeq0")
            x,y,_ = funcTerm[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_4_2_I_2_q = SophiaTaskDefinition(
    answerOptions = ["$f(x) = x^2+2x+3$","$f(x) = x^2-6x-3$", "$f(x) = x^2+2x-3$","$f(x) = x^2-2x-3$"],
    correctAnswerIndex = 3,
    questionText = "What is the term of the shifted function?"
)

class Func_4_2_I_2_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-6, 6, 2], x_ticks=[-2,-1,1,2],y_ticks=[-6,-4,-2,2,4,6]).shift(DOWN*0.6)
        plane = cords[0]

        #Create the coordinate system
        unitCords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        unitPlane = unitCords[0]
        self.add(unitCords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b = ValueTracker(0), ValueTracker(0)
        f1 = lambda x: x**2-2*x+b.get_value()
        unitFunc = lambda x: x**2+a.get_value()
        unitG = always_redraw(lambda: unitPlane.plot(unitFunc, color=BLUE))
        self.add(unitG)
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE))
        funcTerm = MathTex("f","(x)", "=","x^2", "-2x", "+1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so knowing that to <bookmark mark="unitUP"/>shift the unit parabola up by two, we need to add two to the function term, let's now try to shift
                a slightly more <bookmark mark="graph"/>complex quadratic function down: What is the term of the function <bookmark mark="f"/>f of <bookmark mark="x"/>x
                equals <bookmark mark="xSquared"/>x squared minus <bookmark mark="2x"/>2x plus <bookmark mark="1"/>1, after we <bookmark mark="cursor"/>shift
                the graph <bookmark mark="down"/> down by four?
                """
        ) as tracker:
            
            self.wait_until_bookmark("unitUP")
            cursor.blinking=False
            unitUpdater = lambda m: m.move_to(unitPlane.c2p(0,unitFunc(0)))
            cursor.add_updater(unitUpdater)
            self.play(a.animate.set_value(2), run_time=0.5)
            cursor.blinking=True
            cursor.remove_updater(unitUpdater)
            
            self.wait_until_bookmark("graph")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), Write(cords), Unwrite(unitCords), Unwrite(unitCords), Unwrite(unitG), run_time=0.5)
            self.add_pencil_sound(0.8)
            gUpdater = lambda m: m.move_to(g1.get_end())
            self.add(cursor.copy()._start_fading(2).add_updater(gUpdater))
            self.play(Create(g1), run_time=0.8)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("2x")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("1")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("cursor")
            cursor.blinking=False
            uLR = lambda m: m.move_to(plane.c2p(1,f1(1)))
            cursor.add_updater(uLR)
            cursor.blinking=True

            self.wait_until_bookmark("down")
            cursor.blinking=False
            self.play(b.animate.set_value(-4), run_time=0.5)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_2_I_2_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-6, 6, 2], x_ticks=[-2,-1,1,2],y_ticks=[-6,-4,-2,2,4,6]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(1,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b = ValueTracker(0), ValueTracker(0)
        f1 = lambda x: x**2-2*x+1+b.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[-2+a.get_value(),2+a.get_value(),0.001]))
        self.add(g1)
        funcTerm_old = MathTex("f","(x)", "=","x^2", "-2x", "+1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        arrow = Tex("Subtract $4\\,\\Downarrow$", font_size=fs2, color=c1t).next_to(funcTerm_old, DOWN, buff=0.3)
        funcTerm = MathTex("f","(x)", "=","x^2", "-2x", "-3", color=c1t, font_size=fs2).next_to(arrow, DOWN, buff=0.3)
        self.add(funcTerm_old)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                We saw that to shift a function up, we add a positive constant to the entire function term.
                So to shift the function<bookmark mark="down"/> down, we need to add a negative constant to the entire function term.
                Since we want to shift the function down by four, we subtract four from the function term.
                This means, the function <bookmark mark="fOld"/>f of <bookmark mark="xOld"/>x equals <bookmark mark="xSquaredOld"/>x
                squared minus <bookmark mark="2xOld"/>two x plus <bookmark mark="oneOldOld"/>one  turns into  <bookmark mark="f"/>
                f of <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared minus <bookmark mark="2x"/>2x minus
                <bookmark mark="3"/>3. As you can see, the <bookmark mark="plusOne"/>plus one from the original term turned into a
                <bookmark mark="minusThree"/>minus three.
                """
        ) as tracker:
            
            self.wait_until_bookmark("down")
            cursor.blinking=False
            uLR = lambda m: m.move_to(plane.c2p(1, f1(1)))
            cursor.add_updater(uLR)
            self.play(b.animate.set_value(-4), run_time=0.5)
            cursor.remove_updater(uLR)
            cursor.blinking=True

            self.wait_until_bookmark("fOld")
            cursor.blinking=False
            x,y,_ = funcTerm_old[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm_old), run_time=0.3)

            self.wait_until_bookmark("xOld")
            x,y,_ = funcTerm_old[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquaredOld")
            x,y,_ = funcTerm_old[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("2xOld")
            x,y,_ = funcTerm_old[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("oneOldOld")
            x,y,_ = funcTerm_old[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), Write(arrow), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("2x")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("3")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("plusOne")
            x,y,_ = funcTerm_old[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusThree")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_2_I_2_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-6, 6, 2], x_ticks=[-2,-1,1,2],y_ticks=[-6,-4,-2,2,4,6]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(1,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b = ValueTracker(0), ValueTracker(0)
        f1 = lambda x: x**2-2*x+1+b.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[-2+a.get_value(),2+a.get_value(),0.001]))
        self.add(g1)
        funcTerm_old = MathTex("f","(x)", "=","x^2", "-2x", "+1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        arrow = Tex("Subtract $4\\,\\Downarrow$", font_size=fs2, color=c1t).next_to(funcTerm_old, DOWN, buff=0.3)
        funcTerm = MathTex("f","(x)", "=","x^2", "-2x", "-3", color=c1t, font_size=fs2).next_to(arrow, DOWN, buff=0.3)
        self.add(funcTerm_old)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                We saw that to shift a function up, we add a positive constant to the entire function term.
                So to shift the function<bookmark mark="down"/> down, we need to add a negative constant to the entire function term.
                Since we want to shift the function down by four, we subtract four from the function term.
                This means, the function <bookmark mark="fOld"/>f of <bookmark mark="xOld"/>x equals <bookmark mark="xSquaredOld"/>x
                squared minus <bookmark mark="2xOld"/>two x plus <bookmark mark="oneOldOld"/>one  turns into  <bookmark mark="f"/>
                f of <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared minus <bookmark mark="2x"/>2x minus
                <bookmark mark="3"/>3. As you can see, the <bookmark mark="plusOne"/>plus one from the original term turned into a
                <bookmark mark="minusThree"/>minus three.
                """
        ) as tracker:
            
            self.wait_until_bookmark("down")
            cursor.blinking=False
            uLR = lambda m: m.move_to(plane.c2p(1, f1(1)))
            cursor.add_updater(uLR)
            self.play(b.animate.set_value(-4), run_time=0.5)
            cursor.remove_updater(uLR)
            cursor.blinking=True

            self.wait_until_bookmark("fOld")
            cursor.blinking=False
            x,y,_ = funcTerm_old[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm_old), run_time=0.3)

            self.wait_until_bookmark("xOld")
            x,y,_ = funcTerm_old[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquaredOld")
            x,y,_ = funcTerm_old[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("2xOld")
            x,y,_ = funcTerm_old[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("oneOldOld")
            x,y,_ = funcTerm_old[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), Write(arrow), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("2x")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("3")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("plusOne")
            x,y,_ = funcTerm_old[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusThree")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_2_I_2_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-6, 6, 2], x_ticks=[-2,-1,1,2],y_ticks=[-6,-4,-2,2,4,6]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(1,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b = ValueTracker(0), ValueTracker(0)
        f1 = lambda x: x**2-2*x+1+b.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[-2+a.get_value(),2+a.get_value(),0.001]))
        self.add(g1)
        funcTerm_old = MathTex("f","(x)", "=","x^2", "-2x", "+1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        arrow = Tex("Subtract $4\\,\\Downarrow$", font_size=fs2, color=c1t).next_to(funcTerm_old, DOWN, buff=0.3)
        funcTerm = MathTex("f","(x)", "=","x^2", "-2x", "-3", color=c1t, font_size=fs2).next_to(arrow, DOWN, buff=0.3)
        self.add(funcTerm_old)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                We saw that to shift a function up, we add a positive constant to the entire function term.
                So to shift the function<bookmark mark="down"/> down, we need to add a negative constant to the entire function term.
                Since we want to shift the function down by four, we subtract four from the function term.
                This means, the function <bookmark mark="fOld"/>f of <bookmark mark="xOld"/>x equals <bookmark mark="xSquaredOld"/>x
                squared minus <bookmark mark="2xOld"/>two x plus <bookmark mark="oneOldOld"/>one  turns into  <bookmark mark="f"/>
                f of <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared minus <bookmark mark="2x"/>2x minus
                <bookmark mark="3"/>3. As you can see, the <bookmark mark="plusOne"/>plus one from the original term turned into a
                <bookmark mark="minusThree"/>minus three.
                """
        ) as tracker:
            
            self.wait_until_bookmark("down")
            cursor.blinking=False
            uLR = lambda m: m.move_to(plane.c2p(1, f1(1)))
            cursor.add_updater(uLR)
            self.play(b.animate.set_value(-4), run_time=0.5)
            cursor.remove_updater(uLR)
            cursor.blinking=True

            self.wait_until_bookmark("fOld")
            cursor.blinking=False
            x,y,_ = funcTerm_old[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm_old), run_time=0.3)

            self.wait_until_bookmark("xOld")
            x,y,_ = funcTerm_old[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquaredOld")
            x,y,_ = funcTerm_old[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("2xOld")
            x,y,_ = funcTerm_old[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("oneOldOld")
            x,y,_ = funcTerm_old[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), Write(arrow), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("2x")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("3")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("plusOne")
            x,y,_ = funcTerm_old[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusThree")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_2_I_2_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-6, 6, 2], x_ticks=[-2,-1,1,2],y_ticks=[-6,-4,-2,2,4,6]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(1,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b = ValueTracker(0), ValueTracker(0)
        f1 = lambda x: x**2-2*x+1+b.get_value()
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[-2+a.get_value(),2+a.get_value(),0.001]))
        self.add(g1)
        funcTerm_old = MathTex("f","(x)", "=","x^2", "-2x", "+1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        arrow = Tex("Subtract $4\\,\\Downarrow$", font_size=fs2, color=c1t).next_to(funcTerm_old, DOWN, buff=0.3)
        funcTerm = MathTex("f","(x)", "=","x^2", "-2x", "-3", color=c1t, font_size=fs2).next_to(arrow, DOWN, buff=0.3)
        self.add(funcTerm_old)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's it. Good work!
                We saw that to shift a function up, we add a positive constant to the entire function term.
                So to shift the function<bookmark mark="down"/> down, we need to add a negative constant to the entire function term.
                Since we want to shift the function down by four, we subtract four from the function term.
                This means, the function <bookmark mark="fOld"/>f of <bookmark mark="xOld"/>x equals <bookmark mark="xSquaredOld"/>x
                squared minus <bookmark mark="2xOld"/>two x plus <bookmark mark="oneOldOld"/>one  turns into  <bookmark mark="f"/>
                f of <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared minus <bookmark mark="2x"/>2x minus
                <bookmark mark="3"/>3. As you can see, the <bookmark mark="plusOne"/>plus one from the original term turned into a
                <bookmark mark="minusThree"/>minus three.
                """
        ) as tracker:
            
            self.wait_until_bookmark("down")
            cursor.blinking=False
            uLR = lambda m: m.move_to(plane.c2p(1, f1(1)))
            cursor.add_updater(uLR)
            self.play(b.animate.set_value(-4), run_time=0.5)
            cursor.remove_updater(uLR)
            cursor.blinking=True

            self.wait_until_bookmark("fOld")
            cursor.blinking=False
            x,y,_ = funcTerm_old[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm_old), run_time=0.3)

            self.wait_until_bookmark("xOld")
            x,y,_ = funcTerm_old[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquaredOld")
            x,y,_ = funcTerm_old[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("2xOld")
            x,y,_ = funcTerm_old[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("oneOldOld")
            x,y,_ = funcTerm_old[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), Write(arrow), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("2x")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("3")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("plusOne")
            x,y,_ = funcTerm_old[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusThree")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################

######################
# The voiceover seems to be broken (the timing is off)
# IDK Why
class Func_4_2_I_3(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting sideways")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        unitFunc = lambda x: x**2
        unitG = plane.plot(unitFunc, color=BLUE)
        funcTerm = MathTex("f","(x)", "=","x^2", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)

        l02 = Line(plane.c2p(0,0), plane.c2p(2,0), color=PURPLE)
        l13 = Line(plane.c2p(1,1), plane.c2p(3,1), color=PURPLE)
        arrow1Updater = lambda m: m.move_to(l02.get_end())
        arrow2Updater = lambda m: m.move_to(l13.get_end())
    
        xUnit = plane.c2p(1,0)-plane.c2p(0,0)
        t1 = MathTex("f(2)", "\\,\\Rightarrow\\,", "f(0)", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1).next_to(cords, DOWN, buff=0.5)
        t2 = MathTex("2", "\\,\\Rightarrow\\,", "0", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1).next_to(t1, DOWN, buff=0.2)
        t1[1].set_color(PURPLE)
        t2[1].set_color(PURPLE)
        t3 = (VGroup(Tex("Shift right", font_size=fs2, color=c1t), MathTex("\\Downarrow", font_size=fs2, color=PURPLE), Tex("subtract from $x$", font_size=fs2, color=c1t)).arrange(DOWN, buff=.1)).next_to(t2, DOWN, buff=0.6)

        # Action Sequence
        with self.voiceover(
                text="""
                Shifting <bookmark mark="parabola"/>parabolas up and down is not too difficult. <bookmark mark="origin"/>
                Shifting them <bookmark mark="sideWays"/> sideways however is a bit harder. But worry not! Together,
                we'll learn it in no time. Before we start with an example, let's build a bit of intuition using our
                favorite function <bookmark mark="f"/>f of <bookmark mark="x"/>x equals
                <bookmark mark="xSquared"/>x squared. Now we want to shift the function <bookmark mark="origin2"/>to
                the side, say <bookmark mark="twoRight"/>by two units to the right. That means, that every point on
                the parabola is shifted two points to the right. So the point <bookmark mark="f0"/>f of zero is shifted
                to the point <bookmark mark="f2"/>f of two. The point <bookmark mark="f1"/>f of one is shifted to the point
                <bookmark mark="f3"/>f of three and so on.
                So we see, that the value <bookmark mark="t10"/> f of two after the shift is what used to be the point
                <bookmark mark="t11"/>f of zero before the shift. So we can say, that the value <bookmark mark="t20"/>
                x equals two after the shift is what used to be the value <bookmark mark="t21"/>x equals zero before the
                shift. To achieve this, we need to <bookmark mark="t3"/> subtract two from the x value. So we can say, that the function
                is shifted two units to the right, if we subtract two from the x value...
                """
        ) as tracker:
            
            self.wait_until_bookmark("parabola")
            cursor.blinking=False
            x,y,_ = unitG.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(unitG.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(unitG))
            cursor.blinking=True

            self.wait_until_bookmark("origin")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sideWays")
            cursor.blinking=False
            shiftUpdater = lambda m: m.set_x(unitG.get_center()[0])
            cursor.add_updater(shiftUpdater)
            self.play(unitG.animate.shift(LEFT*2*xUnit), run_time=1.5)
            self.play(unitG.animate.shift(RIGHT*4*xUnit), run_time=1.5)
            self.play(unitG.animate.shift(LEFT*2*xUnit), run_time=0.5)
            cursor.remove_updater(shiftUpdater)
            cursor.blinking=True
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("origin2")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("twoRight")
            cursor.blinking=False
            x,y,_ = plane.c2p(2,0)
            cursor.add_updater(shiftUpdater)
            self.add(unitG.copy().set_color(GREY))
            self.play(unitG.animate.shift(RIGHT*2*xUnit), run_time=1.5)
            cursor.remove_updater(shiftUpdater)
            cursor.blinking=True

            self.wait_until_bookmark("f0")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("f2")
            self.add(cursor.copy()._start_fading(2).add_updater(arrow1Updater))
            self.play(Create(l02))
            cursor.blinking=True

            self.wait_until_bookmark("f1")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("f3")
            self.add(cursor.copy()._start_fading(2).add_updater(arrow2Updater))
            self.play(Create(l13))
            cursor.blinking=True

            self.wait_until_bookmark("t10")
            cursor.blinking=False
            x,y,_ = t1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(t1), Unwrite(funcTerm), run_time=0.3)

            self.wait_until_bookmark("t11")
            x,y,_ = t1[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("t20")
            cursor.blinking=False
            x,y,_ = t2[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(t2), run_time=0.3)

            self.wait_until_bookmark("t21")
            x,y,_ = t2[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("t3")
            cursor.blinking=False
            x,y,_ = t3[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(t3), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_4_2_I_4_q = SophiaTaskDefinition(
    answerOptions = ["$f(x)=(x-2)^2-2$", "$f(x)=x^2-4$", "$f(x)=(x+2)^2-2$", "$f(x)=x^2$"],
    correctAnswerIndex = 2,
    questionText = "What is the term of the shfited function?"
)
class Func_4_2_I_4_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting sideways")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f = lambda x: x**2-2
        g = plane.plot(f, color=BLUE)
        funcTerm = MathTex("f","(x)", "=","x^2", "-2", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        xUnit = plane.c2p(1,0)-plane.c2p(0,0)
        self.add(g)

        # Action Sequence
        with self.voiceover(
                text="""
                Now we want to shift the function <bookmark mark="f"/>f of <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared minus <bookmark mark="minusTwo"/>two
                to <bookmark mark="shift"/>the left by two. What is the term of the shifted function?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            
            self.wait_until_bookmark("minusTwo")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("shift")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,-2)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            shiftUpdater = lambda m: m.set_x(g.get_center()[0])
            cursor.add_updater(shiftUpdater)
            self.add(g.copy().set_color(GREY))
            self.play(g.animate.shift(LEFT*2*xUnit), run_time=1.5)
            cursor.remove_updater(shiftUpdater)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_2_I_4_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting sideways")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f = lambda x: x**2-2
        g = plane.plot(f, color=BLUE)
        funcTerm = MathTex("f","(x)", "=","x^2", "-2", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        xUnit = plane.c2p(1,0)-plane.c2p(0,0)
        self.add(g)

        l02 = Line(plane.c2p(-2,-2), plane.c2p(0,-2), color=PURPLE)

        t1 = MathTex("f(-2)", "\\,\\Rightarrow\\,", "f(0)", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1).next_to(cords, DOWN, buff=0.5)
        t2 = MathTex("-2", "\\,\\Rightarrow\\,", "0", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1).next_to(t1, DOWN, buff=0.2)
        t1[1].set_color(PURPLE)
        t2[1].set_color(PURPLE)
        t3 = Tex("Shift left$\\Rightarrow$ add $2$ to $x$", font_size=fs2, color=c1t).next_to(t2, DOWN, buff=0.4)
        funcTermShifted = MathTex("f","(x)", "=","(x","+2)^2", "-2", color=c1t, font_size=fs2).next_to(t3, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text="""
                No. So we're starting with <bookmark mark="f"/>f of <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared minus <bookmark mark="minusTwo"/>two. 
                To shift it to <bookmark mark="shift"/>the left by two, we need the new function for <bookmark mark="lNeg2"/>f of <bookmark mark="explain1"/>negative two to have the same value as the old function 
                <bookmark mark="l0"/>for f of zero. So basically, we need the new function to turn the value<bookmark mark="explainTwo"/> negative two into the value zero, before applying the new function,
                so before squaring x, <bookmark mark="explain3"/>we need to add two. This means, that the shifted function is <bookmark mark="fNew"/>f of <bookmark mark="xNew"/>x equals open bracket
                <bookmark mark="xSquaredNew"/>x plus <bookmark mark="twoNew"/>two close bracket squared, <bookmark mark="minusTwoNew"/>minus two. See how instead of squaring two, we now square x plus two?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            
            self.wait_until_bookmark("minusTwo")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("shift")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,-2)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            shiftUpdater = lambda m: m.set_x(g.get_center()[0])
            cursor.add_updater(shiftUpdater)
            self.add(g.copy().set_color(GREY))
            self.play(g.animate.shift(LEFT*2*xUnit), run_time=1.5)
            cursor.remove_updater(shiftUpdater)
            cursor.blinking=True

            self.wait_until_bookmark("lNeg2")
            cursor.blinking=False
            self.play(ApplyWave(cursor, amplitude=0.4, direction=UP))
            cursor.blinking = True

            self.wait_until_bookmark("explain1")
            self.play(Write(t1), Unwrite(funcTerm))
            
            self.wait_until_bookmark("l0")
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(l02.get_end())))
            self.play(Create(l02))

            self.wait_until_bookmark("explainTwo")
            self.play(Write(t2))

            self.wait_until_bookmark("explain3")
            self.play(Write(t3))

            self.wait_until_bookmark("fNew")
            cursor.blinking=False
            x,y,_ = funcTermShifted[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTermShifted), run_time=0.3)

            self.wait_until_bookmark("xNew")
            x,y,_ = funcTermShifted[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquaredNew")
            x,y,_ = funcTermShifted[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("twoNew")
            x,y,_ = funcTermShifted[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusTwoNew")
            x,y,_ = funcTermShifted[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True



        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_2_I_4_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting sideways")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f = lambda x: x**2-2
        g = plane.plot(f, color=BLUE)
        funcTerm = MathTex("f","(x)", "=","x^2", "-2", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        xUnit = plane.c2p(1,0)-plane.c2p(0,0)
        self.add(g)

        l02 = Line(plane.c2p(-2,-2), plane.c2p(0,-2), color=PURPLE)

        t1 = MathTex("f(-2)", "\\,\\Rightarrow\\,", "f(0)", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1).next_to(cords, DOWN, buff=0.5)
        t2 = MathTex("-2", "\\,\\Rightarrow\\,", "0", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1).next_to(t1, DOWN, buff=0.2)
        t1[1].set_color(PURPLE)
        t2[1].set_color(PURPLE)
        t3 = Tex("Shift left$\\Rightarrow$ add $2$ to $x$", font_size=fs2, color=c1t).next_to(t2, DOWN, buff=0.4)
        funcTermShifted = MathTex("f","(x)", "=","(x","+2)^2", "-2", color=c1t, font_size=fs2).next_to(t3, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                No. So we're starting with <bookmark mark="f"/>f of <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared minus <bookmark mark="minusTwo"/>two. 
                To shift it to <bookmark mark="shift"/>the left by two, we need the new function for <bookmark mark="lNeg2"/>f of <bookmark mark="explain1"/>negative two to have the same value as the old function 
                <bookmark mark="l0"/>for f of zero. So basically, we need the new function to turn the value<bookmark mark="explainTwo"/> negative two into the value zero, before applying the new function,
                so before squaring x, <bookmark mark="explain3"/>we need to add two. This means, that the shifted function is <bookmark mark="fNew"/>f of <bookmark mark="xNew"/>x equals open bracket
                <bookmark mark="xSquaredNew"/>x plus <bookmark mark="twoNew"/>two close bracket squared, <bookmark mark="minusTwoNew"/>minus two. See how instead of squaring two, we now square x plus two?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            
            self.wait_until_bookmark("minusTwo")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("shift")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,-2)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            shiftUpdater = lambda m: m.set_x(g.get_center()[0])
            cursor.add_updater(shiftUpdater)
            self.add(g.copy().set_color(GREY))
            self.play(g.animate.shift(LEFT*2*xUnit), run_time=1.5)
            cursor.remove_updater(shiftUpdater)
            cursor.blinking=True

            self.wait_until_bookmark("lNeg2")
            cursor.blinking=False
            self.play(ApplyWave(cursor, amplitude=0.4, direction=UP))
            cursor.blinking = True

            self.wait_until_bookmark("explain1")
            self.play(Write(t1), Unwrite(funcTerm))
            
            self.wait_until_bookmark("l0")
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(l02.get_end())))
            self.play(Create(l02))

            self.wait_until_bookmark("explainTwo")
            self.play(Write(t2))

            self.wait_until_bookmark("explain3")
            self.play(Write(t3))

            self.wait_until_bookmark("fNew")
            cursor.blinking=False
            x,y,_ = funcTermShifted[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTermShifted), run_time=0.3)

            self.wait_until_bookmark("xNew")
            x,y,_ = funcTermShifted[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquaredNew")
            x,y,_ = funcTermShifted[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("twoNew")
            x,y,_ = funcTermShifted[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusTwoNew")
            x,y,_ = funcTermShifted[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True



        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_2_I_4_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting sideways")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f = lambda x: x**2-2
        g = plane.plot(f, color=BLUE)
        funcTerm = MathTex("f","(x)", "=","x^2", "-2", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        xUnit = plane.c2p(1,0)-plane.c2p(0,0)
        self.add(g)

        l02 = Line(plane.c2p(-2,-2), plane.c2p(0,-2), color=PURPLE)

        t1 = MathTex("f(-2)", "\\,\\Rightarrow\\,", "f(0)", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1).next_to(cords, DOWN, buff=0.5)
        t2 = MathTex("-2", "\\,\\Rightarrow\\,", "0", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1).next_to(t1, DOWN, buff=0.2)
        t1[1].set_color(PURPLE)
        t2[1].set_color(PURPLE)
        t3 = Tex("Shift left$\\Rightarrow$ add $2$ to $x$", font_size=fs2, color=c1t).next_to(t2, DOWN, buff=0.4)
        funcTermShifted = MathTex("f","(x)", "=","(x","+2)^2", "-2", color=c1t, font_size=fs2).next_to(t3, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                Yes, you got it right! So we're starting with <bookmark mark="f"/>f of <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared minus <bookmark mark="minusTwo"/>two. 
                To shift it to <bookmark mark="shift"/>the left by two, we need the new function for <bookmark mark="lNeg2"/>f of <bookmark mark="explain1"/>negative two to have the same value as the old function 
                <bookmark mark="l0"/>for f of zero. So basically, we need the new function to turn the value<bookmark mark="explainTwo"/> negative two into the value zero, before applying the new function,
                so before squaring x, <bookmark mark="explain3"/>we need to add two. This means, that the shifted function is <bookmark mark="fNew"/>f of <bookmark mark="xNew"/>x equals open bracket
                <bookmark mark="xSquaredNew"/>x plus <bookmark mark="twoNew"/>two close bracket squared, <bookmark mark="minusTwoNew"/>minus two. See how instead of squaring two, we now square x plus two?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            
            self.wait_until_bookmark("minusTwo")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("shift")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,-2)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            shiftUpdater = lambda m: m.set_x(g.get_center()[0])
            cursor.add_updater(shiftUpdater)
            self.add(g.copy().set_color(GREY))
            self.play(g.animate.shift(LEFT*2*xUnit), run_time=1.5)
            cursor.remove_updater(shiftUpdater)
            cursor.blinking=True

            self.wait_until_bookmark("lNeg2")
            cursor.blinking=False
            self.play(ApplyWave(cursor, amplitude=0.4, direction=UP))
            cursor.blinking = True

            self.wait_until_bookmark("explain1")
            self.play(Write(t1), Unwrite(funcTerm))
            
            self.wait_until_bookmark("l0")
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(l02.get_end())))
            self.play(Create(l02))

            self.wait_until_bookmark("explainTwo")
            self.play(Write(t2))

            self.wait_until_bookmark("explain3")
            self.play(Write(t3))

            self.wait_until_bookmark("fNew")
            cursor.blinking=False
            x,y,_ = funcTermShifted[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTermShifted), run_time=0.3)

            self.wait_until_bookmark("xNew")
            x,y,_ = funcTermShifted[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquaredNew")
            x,y,_ = funcTermShifted[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("twoNew")
            x,y,_ = funcTermShifted[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusTwoNew")
            x,y,_ = funcTermShifted[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True



        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_2_I_4_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting sideways")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f = lambda x: x**2-2
        g = plane.plot(f, color=BLUE)
        funcTerm = MathTex("f","(x)", "=","x^2", "-2", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        xUnit = plane.c2p(1,0)-plane.c2p(0,0)
        self.add(g)

        l02 = Line(plane.c2p(-2,-2), plane.c2p(0,-2), color=PURPLE)

        t1 = MathTex("f(-2)", "\\,\\Rightarrow\\,", "f(0)", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1).next_to(cords, DOWN, buff=0.5)
        t2 = MathTex("-2", "\\,\\Rightarrow\\,", "0", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1).next_to(t1, DOWN, buff=0.2)
        t1[1].set_color(PURPLE)
        t2[1].set_color(PURPLE)
        t3 = Tex("Shift left$\\Rightarrow$ add $2$ to $x$", font_size=fs2, color=c1t).next_to(t2, DOWN, buff=0.4)
        funcTermShifted = MathTex("f","(x)", "=","(x","+2)^2", "-2", color=c1t, font_size=fs2).next_to(t3, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                No. So we're starting with <bookmark mark="f"/>f of <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared minus <bookmark mark="minusTwo"/>two. 
                To shift it to <bookmark mark="shift"/>the left by two, we need the new function for <bookmark mark="lNeg2"/>f of <bookmark mark="explain1"/>negative two to have the same value as the old function 
                <bookmark mark="l0"/>for f of zero. So basically, we need the new function to turn the value<bookmark mark="explainTwo"/> negative two into the value zero, before applying the new function,
                so before squaring x, <bookmark mark="explain3"/>we need to add two. This means, that the shifted function is <bookmark mark="fNew"/>f of <bookmark mark="xNew"/>x equals open bracket
                <bookmark mark="xSquaredNew"/>x plus <bookmark mark="twoNew"/>two close bracket squared, <bookmark mark="minusTwoNew"/>minus two. See how instead of squaring two, we now square x plus two?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            
            self.wait_until_bookmark("minusTwo")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("shift")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,-2)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            shiftUpdater = lambda m: m.set_x(g.get_center()[0])
            cursor.add_updater(shiftUpdater)
            self.add(g.copy().set_color(GREY))
            self.play(g.animate.shift(LEFT*2*xUnit), run_time=1.5)
            cursor.remove_updater(shiftUpdater)
            cursor.blinking=True

            self.wait_until_bookmark("lNeg2")
            cursor.blinking=False
            self.play(ApplyWave(cursor, amplitude=0.4, direction=UP))
            cursor.blinking = True

            self.wait_until_bookmark("explain1")
            self.play(Write(t1), Unwrite(funcTerm))
            
            self.wait_until_bookmark("l0")
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(l02.get_end())))
            self.play(Create(l02))

            self.wait_until_bookmark("explainTwo")
            self.play(Write(t2))

            self.wait_until_bookmark("explain3")
            self.play(Write(t3))

            self.wait_until_bookmark("fNew")
            cursor.blinking=False
            x,y,_ = funcTermShifted[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTermShifted), run_time=0.3)

            self.wait_until_bookmark("xNew")
            x,y,_ = funcTermShifted[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquaredNew")
            x,y,_ = funcTermShifted[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("twoNew")
            x,y,_ = funcTermShifted[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusTwoNew")
            x,y,_ = funcTermShifted[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)



#####################################
#####################################
TASK_Func_4_2_I_5_q = SophiaTaskDefinition(
    answerOptions = ["$f(x)=(x+1.5)^2-3x$", "$f(x)=(x+1.5)^2-3(x+1.5)$", "$f(x)=(x-1.5)^2-3x$", "$f(x)=(x-1.5)^2-3(x-1.5)$"],
    correctAnswerIndex = 3,
    questionText = "What is the term of the shifted function? (1.5 to the right)"
)
class Func_4_2_I_5_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting sideways")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f = lambda x: x**2-3*x
        g = plane.plot(f, color=BLUE, x_range=[-1.3, 2, 0.0001])
        funcTerm = MathTex("f","(x)", "=","x^2", "-3x", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        xUnit = plane.c2p(1,0)-plane.c2p(0,0)
        unit_func = lambda x: x**2
        unit_plot = plane.plot(unit_func, color=BLUE)

        # Action Sequence
        with self.voiceover(
                text="""
                Shifting a parabola <bookmark mark="left"/>left is achieved by adding a number to what we plug in for x. Shifting a parabola <bookmark mark="right"/>right is
                achieved by subtracting a number from what we plug in for x. <bookmark mark="reset"/>  Now let's apply this insight to a slightly harder function.
                We want to shift the function <bookmark mark="f"/>f of <bookmark mark="x"/>x equals <bookmark mark="xSquared"/>x squared minus <bookmark mark="minusThree"/>three x
                to <bookmark mark="shift"/>the right by one point five. What is the term of the shifted function?
                """
        ) as tracker:
            
            self.wait_until_bookmark("left")
            cursor.blinking=False
            unit_updater = lambda m: m.set_x(unit_plot.get_center()[0])
            cursor.add_updater(unit_updater)
            self.play(unit_plot.animate.shift(LEFT*xUnit), run_time=1)

            self.wait_until_bookmark("right")
            self.play(unit_plot.animate.shift(RIGHT*2*xUnit), run_time=1)

            self.wait_until_bookmark("reset")
            cursor.remove_updater(unit_updater)
            x,y,_ = plane.c2p(0,0)
            self.play(Write(g), Unwrite(unit_plot), CursorMoveTo(cursor, x, y))
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            
            self.wait_until_bookmark("minusThree")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("shift")
            cursor.blinking=False
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(g.copy().set_color(GREY))
            self.play(g.animate.shift(RIGHT*1.5*xUnit), cursor.animate.shift(1.5*RIGHT*xUnit), run_time=1.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_2_I_5_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting sideways")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f = lambda x: x**2-3*x
        g = plane.plot(f, color=BLUE, x_range=[-1.3, 2, 0.0001])
        funcTerm = MathTex("f","(x)", "=","x^2", "-3x", color=c1t, font_size=fs3).next_to(cords, DOWN, buff=1)
        arrow = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(funcTerm, DOWN, buff=0.2)
        funcTermNew = MathTex("f","(x)", "=","(x","+1.5)^2", "-3(x+1.5)", color=c1t, font_size=fs3).next_to(arrow, DOWN, buff=0.2)
        xUnit = plane.c2p(1,0)-plane.c2p(0,0)
        self.add(g)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's wrong. We know that to shift a function right, we need to subtract a number from what we plug in for x.
                We want to shift the function <bookmark mark="shiftRight"/>right by one point five, so we need to subtract one point five from what we plug in for x. The only thing we need to be careful about is
                that there are two occurences of x, and we need to add one point five to both. We're starting with the function <bookmark mark="f"/> f of <bookmark mark="x"/> x equals
                <bookmark mark="xSquared"/> x squared <bookmark mark="minusThreeX"/>minus three x. We then add one point five to both occurences of x and put brackets around it.
                Then, the term of the shifted function is <bookmark mark="fNew"/>f of <bookmark mark="xNew"/>x equals open bracket
                <bookmark mark="xSquaredNew"/>x plus <bookmark mark="onePointFive"/>one point five close bracket squared, <bookmark mark="minusThreeNew"/>minus three times open bracket <bookmark mark="xNew2"/>
                x plus one point five close bracket.
                """
        ) as tracker:
            
            self.wait_until_bookmark("shiftRight")
            cursor.blinking=False
            self.play(g.animate.shift(RIGHT*1.5*xUnit), cursor.animate.shift(1.5*RIGHT*xUnit), run_time=1.5)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusThreeX")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("fNew")
            cursor.blinking=False
            x,y,_ = funcTermNew[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTermNew), Write(arrow), run_time=0.3)

            self.wait_until_bookmark("xNew")
            x,y,_ = funcTermNew[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquaredNew")
            x,y,_ = funcTermNew[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("onePointFive")
            x,y,_ = funcTermNew[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusThreeNew")
            x,y,_ = funcTermNew[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_2_I_5_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting sideways")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f = lambda x: x**2-3*x
        g = plane.plot(f, color=BLUE, x_range=[-1.3, 2, 0.0001])
        funcTerm = MathTex("f","(x)", "=","x^2", "-3x", color=c1t, font_size=fs3).next_to(cords, DOWN, buff=1)
        arrow = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(funcTerm, DOWN, buff=0.2)
        funcTermNew = MathTex("f","(x)", "=","(x","+1.5)^2", "-3(x+1.5)", color=c1t, font_size=fs3).next_to(arrow, DOWN, buff=0.2)
        xUnit = plane.c2p(1,0)-plane.c2p(0,0)
        self.add(g)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's wrong. We know that to shift a function right, we need to subtract a number from what we plug in for x.
                We want to shift the function <bookmark mark="shiftRight"/>right by one point five, so we need to subtract one point five from what we plug in for x. The only thing we need to be careful about is
                that there are two occurences of x, and we need to add one point five to both. We're starting with the function <bookmark mark="f"/> f of <bookmark mark="x"/> x equals
                <bookmark mark="xSquared"/> x squared <bookmark mark="minusThreeX"/>minus three x. We then add one point five to both occurences of x and put brackets around it.
                Then, the term of the shifted function is <bookmark mark="fNew"/>f of <bookmark mark="xNew"/>x equals open bracket
                <bookmark mark="xSquaredNew"/>x plus <bookmark mark="onePointFive"/>one point five close bracket squared, <bookmark mark="minusThreeNew"/>minus three times open bracket <bookmark mark="xNew2"/>
                x plus one point five close bracket.
                """
        ) as tracker:
            
            self.wait_until_bookmark("shiftRight")
            cursor.blinking=False
            self.play(g.animate.shift(RIGHT*1.5*xUnit), cursor.animate.shift(1.5*RIGHT*xUnit), run_time=1.5)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusThreeX")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("fNew")
            cursor.blinking=False
            x,y,_ = funcTermNew[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTermNew), Write(arrow), run_time=0.3)

            self.wait_until_bookmark("xNew")
            x,y,_ = funcTermNew[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquaredNew")
            x,y,_ = funcTermNew[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("onePointFive")
            x,y,_ = funcTermNew[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusThreeNew")
            x,y,_ = funcTermNew[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_2_I_5_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting sideways")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f = lambda x: x**2-3*x
        g = plane.plot(f, color=BLUE, x_range=[-1.3, 2, 0.0001])
        funcTerm = MathTex("f","(x)", "=","x^2", "-3x", color=c1t, font_size=fs3).next_to(cords, DOWN, buff=1)
        arrow = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(funcTerm, DOWN, buff=0.2)
        funcTermNew = MathTex("f","(x)", "=","(x","+1.5)^2", "-3(x+1.5)", color=c1t, font_size=fs3).next_to(arrow, DOWN, buff=0.2)
        xUnit = plane.c2p(1,0)-plane.c2p(0,0)
        self.add(g)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's wrong. We know that to shift a function right, we need to subtract a number from what we plug in for x.
                We want to shift the function <bookmark mark="shiftRight"/>right by one point five, so we need to subtract one point five from what we plug in for x. The only thing we need to be careful about is
                that there are two occurences of x, and we need to add one point five to both. We're starting with the function <bookmark mark="f"/> f of <bookmark mark="x"/> x equals
                <bookmark mark="xSquared"/> x squared <bookmark mark="minusThreeX"/>minus three x. We then add one point five to both occurences of x and put brackets around it.
                Then, the term of the shifted function is <bookmark mark="fNew"/>f of <bookmark mark="xNew"/>x equals open bracket
                <bookmark mark="xSquaredNew"/>x plus <bookmark mark="onePointFive"/>one point five close bracket squared, <bookmark mark="minusThreeNew"/>minus three times open bracket <bookmark mark="xNew2"/>
                x plus one point five close bracket.
                """
        ) as tracker:
            
            self.wait_until_bookmark("shiftRight")
            cursor.blinking=False
            self.play(g.animate.shift(RIGHT*1.5*xUnit), cursor.animate.shift(1.5*RIGHT*xUnit), run_time=1.5)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusThreeX")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("fNew")
            cursor.blinking=False
            x,y,_ = funcTermNew[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTermNew), Write(arrow), run_time=0.3)

            self.wait_until_bookmark("xNew")
            x,y,_ = funcTermNew[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquaredNew")
            x,y,_ = funcTermNew[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("onePointFive")
            x,y,_ = funcTermNew[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusThreeNew")
            x,y,_ = funcTermNew[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_2_I_5_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Shifting sideways")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f = lambda x: x**2-3*x
        g = plane.plot(f, color=BLUE, x_range=[-1.3, 2, 0.0001])
        funcTerm = MathTex("f","(x)", "=","x^2", "-3x", color=c1t, font_size=fs3).next_to(cords, DOWN, buff=1)
        arrow = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(funcTerm, DOWN, buff=0.2)
        funcTermNew = MathTex("f","(x)", "=","(x","+1.5)^2", "-3(x+1.5)", color=c1t, font_size=fs3).next_to(arrow, DOWN, buff=0.2)
        xUnit = plane.c2p(1,0)-plane.c2p(0,0)
        self.add(g)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's it. well done. We know that to shift a function right, we need to subtract a number from what we plug in for x.
                We want to shift the function <bookmark mark="shiftRight"/>right by one point five, so we need to subtract one point five from what we plug in for x. The only thing we need to be careful about is
                that there are two occurences of x, and we need to add one point five to both. We're starting with the function <bookmark mark="f"/> f of <bookmark mark="x"/> x equals
                <bookmark mark="xSquared"/> x squared <bookmark mark="minusThreeX"/>minus three x. We then add one point five to both occurences of x and put brackets around it.
                Then, the term of the shifted function is <bookmark mark="fNew"/>f of <bookmark mark="xNew"/>x equals open bracket
                <bookmark mark="xSquaredNew"/>x plus <bookmark mark="onePointFive"/>one point five close bracket squared, <bookmark mark="minusThreeNew"/>minus three times open bracket <bookmark mark="xNew2"/>
                x plus one point five close bracket.
                """
        ) as tracker:
            
            self.wait_until_bookmark("shiftRight")
            cursor.blinking=False
            self.play(g.animate.shift(RIGHT*1.5*xUnit), cursor.animate.shift(1.5*RIGHT*xUnit), run_time=1.5)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTerm), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusThreeX")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("fNew")
            cursor.blinking=False
            x,y,_ = funcTermNew[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), Write(funcTermNew), Write(arrow), run_time=0.3)

            self.wait_until_bookmark("xNew")
            x,y,_ = funcTermNew[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquaredNew")
            x,y,_ = funcTermNew[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("onePointFive")
            x,y,_ = funcTermNew[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("minusThreeNew")
            x,y,_ = funcTermNew[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


PROTOTYPES = [
    PagePrototypeVideo.from_scene(Func_4_2_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_2_I_1_q, Func_4_2_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_2_I_1_a),
    PagePrototypeVideo.from_scene(Func_4_2_I_1_b),
    PagePrototypeVideo.from_scene(Func_4_2_I_1_c),
    PagePrototypeVideo.from_scene(Func_4_2_I_1_d),
    PagePrototypeVideo.from_scene(Func_4_2_I_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_2_I_2_q, Func_4_2_I_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_2_I_2_a),
    PagePrototypeVideo.from_scene(Func_4_2_I_2_b),
    PagePrototypeVideo.from_scene(Func_4_2_I_2_c),
    PagePrototypeVideo.from_scene(Func_4_2_I_2_d),
    PagePrototypeVideo.from_scene(Func_4_2_I_3),
    PagePrototypeVideo.from_scene(Func_4_2_I_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_2_I_4_q, Func_4_2_I_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_2_I_4_a),
    PagePrototypeVideo.from_scene(Func_4_2_I_4_b),
    PagePrototypeVideo.from_scene(Func_4_2_I_4_c),
    PagePrototypeVideo.from_scene(Func_4_2_I_4_d),
    PagePrototypeVideo.from_scene(Func_4_2_I_5_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_2_I_5_q, Func_4_2_I_5_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_2_I_5_a),
    PagePrototypeVideo.from_scene(Func_4_2_I_5_b),
    PagePrototypeVideo.from_scene(Func_4_2_I_5_c),
    PagePrototypeVideo.from_scene(Func_4_2_I_5_d),
]
scenes/Func/Func_4: Quadratic Functions/Func_4_2.py
Sophia-Edu-Labs/sophia-math
# 4_3: Quadratic Functions: Scaling

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition



#####################################
#####################################
TASK_Func_4_3_I_1_q = SophiaTaskDefinition(
    answerOptions = ["The parabola remains the same", "The parabola gets much flatter", "The parabola is reflected along the x-axis", "The parabola is shifted down"],
    correctAnswerIndex = 2,
    questionText = "What happens if we set a to $-1$?"
)

class Func_4_3_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Scaling Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a = ValueTracker(1)
        f1 = lambda x: a.get_value()*x**2
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[-(4/a.get_value())**0.5,(4/a.get_value())**0.5]))
        funcTerm = MathTex("f","(x)", "=","a","x^2", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        aLarge = Tex("$a$ large ","$\\Rightarrow$", "Parabola steeper", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=0.4)
        aSmall = Tex("$a$ small ","$\\Rightarrow$", "Parabola flatter", color=c1t, font_size=fs3).next_to(aLarge, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                Parabolas can also be modified by scaling them. For example, we<bookmark mark="cursorInPos"/> can make them <bookmark mark="steeper"/>steeper, so that they rise faster.
                Or we can make them <bookmark mark="flatter"/>flatter, so that they rise more slowly. If<bookmark mark="f"/> we write the function as f of <bookmark mark="x"/> x equals
                <bookmark mark="a"/> a times <bookmark mark="xSquared"/>x squared, then the value of a determines how steep the<bookmark mark="cursorInPos2"/> parabola is.
                For <bookmark mark="large"/> larger values of a, the parabola is steeper, and for <bookmark mark="small"/> smaller values of a, the parabola is flatter.
                But what will happen, if a is below zero, like negative one for example?
                """
        ) as tracker:

            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("cursorInPos")
            cursor.blinking=False
            x,y,_ = plane.c2p(2**0.5,2)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True
            cursor_updater = lambda m: m.move_to(plane.c2p((2/a.get_value())**0.5,2))
            cursor.add_updater(cursor_updater)

            self.wait_until_bookmark("steeper")
            cursor.blinking=False
            self.play(a.animate.set_value(2), run_time=2)

            self.wait_until_bookmark("flatter")
            self.play(a.animate.set_value(0.5), run_time=2)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(Create(funcTerm), a.animate(run_time=0.5).set_value(1))
            cursor.remove_updater(cursor_updater)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            
            self.wait_until_bookmark("x")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("a")
            x,y,_ = funcTerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("xSquared")
            x,y,_ = funcTerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("cursorInPos2")
            cursor.blinking=False
            x,y,_ = plane.c2p(2**0.5,2)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True
            cursor.add_updater(lambda m: m.move_to(plane.c2p((2/a.get_value())**0.5,2)))

            self.wait_until_bookmark("large")
            cursor.blinking=False
            self.play(Write(aLarge) ,a.animate(run_time=2).set_value(2), run_time=0.5)

            self.wait_until_bookmark("small")
            self.play(Write(aSmall), a.animate(run_time=2).set_value(0.5), run_time=0.5)
            cursor.blinking=True            


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_3_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Scaling Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a = ValueTracker(1)
        f1 = lambda x: a.get_value()*x**2
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE))
        funcTerm = MathTex("f","(x)", "=","a","x^2", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        aLarge = Tex("$a$ large ","$\\Rightarrow$", "Parabola steeper", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=0.4)
        aSmall = Tex("$a$ small ","$\\Rightarrow$", "Parabola flatter", color=c1t, font_size=fs3).next_to(aLarge, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it. If we set a to negative one, we multiply every value with <bookmark mark="cursorInPos"/>negative one.
                That means every value,<bookmark mark="flip"/> and thus the entire function is reflected along the x-axis.
                """
        ) as tracker:

            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("cursorInPos")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True
            cursor.add_updater(lambda m: m.move_to(plane.c2p(1,f1(1))))

            self.wait_until_bookmark("flip")
            cursor.blinking=False
            self.play(a.animate.set_value(-1), run_time=4)

        self.wait(4)

class Func_4_3_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Scaling Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a = ValueTracker(1)
        f1 = lambda x: a.get_value()*x**2
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE))
        funcTerm = MathTex("f","(x)", "=","a","x^2", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        aLarge = Tex("$a$ large ","$\\Rightarrow$", "Parabola steeper", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=0.4)
        aSmall = Tex("$a$ small ","$\\Rightarrow$", "Parabola flatter", color=c1t, font_size=fs3).next_to(aLarge, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it. If we set a to negative one, we multiply every value with <bookmark mark="cursorInPos"/>negative one.
                That means every value,<bookmark mark="flip"/> and thus the entire function is reflected along the x-axis.
                """
        ) as tracker:

            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("cursorInPos")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True
            cursor.add_updater(lambda m: m.move_to(plane.c2p(1,f1(1))))

            self.wait_until_bookmark("flip")
            cursor.blinking=False
            self.play(a.animate.set_value(-1), run_time=4)

        self.wait(4)

class Func_4_3_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Scaling Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a = ValueTracker(1)
        f1 = lambda x: a.get_value()*x**2
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE))
        funcTerm = MathTex("f","(x)", "=","a","x^2", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        aLarge = Tex("$a$ large ","$\\Rightarrow$", "Parabola steeper", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=0.4)
        aSmall = Tex("$a$ small ","$\\Rightarrow$", "Parabola flatter", color=c1t, font_size=fs3).next_to(aLarge, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's it, very good. If we set a to negative one, we multiply every value with <bookmark mark="cursorInPos"/>negative one.
                That means every value,<bookmark mark="flip"/> and thus the entire function is reflected along the x-axis.
                """
        ) as tracker:

            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("cursorInPos")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True
            cursor.add_updater(lambda m: m.move_to(plane.c2p(1,f1(1))))

            self.wait_until_bookmark("flip")
            cursor.blinking=False
            self.play(a.animate.set_value(-1), run_time=4)

        self.wait(4)


class Func_4_3_I_1_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Scaling Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a = ValueTracker(1)
        f1 = lambda x: a.get_value()*x**2
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE))
        funcTerm = MathTex("f","(x)", "=","a","x^2", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        aLarge = Tex("$a$ large ","$\\Rightarrow$", "Parabola steeper", color=c1t, font_size=fs3).next_to(funcTerm, DOWN, buff=0.4)
        aSmall = Tex("$a$ small ","$\\Rightarrow$", "Parabola flatter", color=c1t, font_size=fs3).next_to(aLarge, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it. If we set a to negative one, we multiply every value with <bookmark mark="cursorInPos"/>negative one.
                That means every value,<bookmark mark="flip"/> and thus the entire function is reflected along the x-axis.
                """
        ) as tracker:

            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("cursorInPos")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True
            cursor.add_updater(lambda m: m.move_to(plane.c2p(1,f1(1))))

            self.wait_until_bookmark("flip")
            cursor.blinking=False
            self.play(a.animate.set_value(-1), run_time=4)

        self.wait(4)



#####################################
#####################################
########## Pracitce Part ############
#####################################
#####################################


#####################################
#####################################
########## General Qs ###############
#####################################
#####################################
class ScaleQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Scaling Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b = ValueTracker(1), ValueTracker(1)
        f1 = lambda x: b.get_value()*a.get_value()*x**2
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[max(-2.2,-(4/a.get_value())**0.5),min(2.2,(4/a.get_value())**0.5), 0.001]))

        xx, yy = self.point
        sign = 1 if yy > 0 else -1
        abs = np.abs(yy/xx**2)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro}<bookmark mark="cursorInPos"/>
                Now, we want to<bookmark mark="scale"/> scale it, so that it goes through the point <bookmark mark="markPoint"/>{self.point[0], self.point[1]}.
                {self.question}
                """
        ) as tracker:

            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("cursorInPos")
            cursor.blinking=False
            x,y,_ = plane.c2p(xx, f1(xx))
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True
            cursor.add_updater(lambda m: m.move_to(plane.c2p(xx, f1(xx))))

            self.wait_until_bookmark("scale")
            cursor.blinking=False
            self.play(a.animate.set_value(abs), b.animate.set_value(sign), run_time=2)

            self.wait_until_bookmark("markPoint")
            self.play(ApplyWave(cursor))
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class ScaleAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Scaling Parabolas")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a, b = ValueTracker(1), ValueTracker(1)
        f1 = lambda x: b.get_value()*a.get_value()*x**2
        g1 = always_redraw(lambda: plane.plot(f1, color=BLUE, x_range=[max(-2.2,-(4/a.get_value())**0.5),min(2.2,(4/a.get_value())**0.5), 0.001]))
        
        xx, yy = self.point
        sign = 1 if yy > 0 else -1
        self.flip == "" if sign==1 else self.flip
        abs = np.abs(yy/xx**2)
        square = MathTex(f"{xx}^2 = {xx**2}", color=c1t, font_size = fs2).next_to(cords, DOWN, buff=0.4)
        arrow = MathTex("\\Downarrow", color=c1t, font_size = fs2).next_to(square, DOWN, buff=0.2)
        solution = MathTex(f"a = ", f"\\frac{{{yy}}}{{{xx**2}}}", "=", f"{sign*abs}", color=c1t, font_size = fs2).next_to(arrow, DOWN, buff=0.2)


        # Action Sequence
        with self.voiceover(
                text=f"""
                If we plug {xx} into the unit parabola, we obtain <bookmark mark="square"/>the value {xx**2}.
                That means<bookmark mark="cursorInPos"/>, we have to <bookmark mark="scale"/>scale it by a factor of a equals {np.abs(yy)} over {xx**2},
                which equals {abs}. <bookmark mark="flip"/>{self.flip}
                That means, <bookmark mark="final"/> the correct factor is <bookmark mark="af"/>a equals <bookmark mark="afrac"/>{yy} over {xx**2} which is equal to <bookmark mark="ff"/>{sign*abs}
                """
        ) as tracker:

            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_pencil_sound(1)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.play(Create(g1), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("square")
            cursor.blinking=False
            x,y,_ = square.get_center()+0.4*DOWN
            self.play(Create(square), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("cursorInPos")
            cursor.blinking=False
            x,y,_ = plane.c2p(xx, f1(xx))
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True
            cU = lambda m: m.move_to(plane.c2p(xx, f1(xx)))
            cursor.add_updater(cU)

            self.wait_until_bookmark("scale")
            cursor.blinking=False
            self.play(a.animate.set_value(abs), run_time=2)

            self.wait_until_bookmark("flip")
            if sign <0:
                self.play(b.animate.set_value(sign))
            cursor.remove_updater(cU)
            cursor.blinking=True

            self.wait_until_bookmark("final")
            cursor.blinking=False
            self.play(Create(arrow), Create(solution), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("af")
            cursor.blinking=False
            x,y,_ = solution[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("afrac")
            x,y,_ = solution[1].get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("ff")
            x,y,_ = solution[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.5)
            cursor.blinking=True
            

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
########## Concrete Qs ##############
#####################################
#####################################

#####################################
#####################################
TASK_Func_4_3_P_1_q = SophiaTaskDefinition(
    answerOptions = ["$-0.5$", "$0.5$", "$-2$", "$2$"],
    correctAnswerIndex = 0,
    questionText = "What value do we choose for $a$, so that the function goes through the point $(2,-2)$?"
)
class Func_4_3_P_1_q(ScaleQuestionScene):

    def construct(self):

        self.intro = "Okay, so we're starting with the Unit Parabola"
        self.point = [2,-2]
        self.question = "How do we scale it, so that it goes through the point (2,-2)?"
        super().construct()


class Func_4_3_P_1_a(ScaleAnswerScene):

    def construct(self):

        self.intro = "That's correct."
        self.point = [2,-2]
        self.question = "How do we scale it, so that it goes through the point (2,-2)?"
        self.flip = "And we also have to flip it, because the point is below the x-axis."
        super().construct()


class Func_4_3_P_1_b(ScaleAnswerScene):

    def construct(self):

        self.intro = "No, that's not it."
        self.point = [2,-2]
        self.question = "How do we scale it, so that it goes through the point (2,-2)?"
        self.flip = "And we also have to flip it, because the point is below the x-axis."
        super().construct()

class Func_4_3_P_1_c(ScaleAnswerScene):

    def construct(self):

        self.intro = "No, that's not it."
        self.point = [2,-2]
        self.question = "How do we scale it, so that it goes through the point (2,-2)?"
        self.flip = "And we also have to flip it, because the point is below the x-axis."
        super().construct()

class Func_4_3_P_1_d(ScaleAnswerScene):

    def construct(self):

        self.intro = "No, that's not it."
        self.point = [2,-2]
        self.question = "How do we scale it, so that it goes through the point (2,-2)?"
        self.flip = "And we also have to flip it, because the point is below the x-axis."
        super().construct()

#####################################
#####################################
TASK_Func_4_3_P_2_q = SophiaTaskDefinition(
    answerOptions = ["$\\tfrac 12$", "$-\\tfrac 12$", "$1$", "$-1$"],
    correctAnswerIndex = 3,
    questionText = "What value do we choose for $a$??"
)
class Func_4_3_P_2_q(ScaleQuestionScene):

    def construct(self):

        self.intro = "Again, starting from the Unit Parabola"
        self.point = [-2,-4]
        self.question = "How do we scale it, so that it goes through the point (-2,-4)?"
        super().construct()


class Func_4_3_P_2_a(ScaleAnswerScene):

    def construct(self):

        self.intro = "no, that's not right..."
        self.point = [-2,-4]
        self.question = "How do we scale it, so that it goes through the point (-2,-4)?"
        self.flip = "And we have to flip it too, because the point is negative."
        super().construct()

class Func_4_3_P_2_b(ScaleAnswerScene):

    def construct(self):

        self.intro = "no, that's not right..."
        self.point = [-2,-4]
        self.question = "How do we scale it, so that it goes through the point (-2,-4)?"
        self.flip = "And we have to flip it too, because the point is negative."
        super().construct()

class Func_4_3_P_2_c(ScaleAnswerScene):

    def construct(self):

        self.intro = "no, that's not right..."
        self.point = [-2,-4]
        self.question = "How do we scale it, so that it goes through the point (-2,-4)?"
        self.flip = "And we have to flip it too, because the point is negative."
        super().construct()

class Func_4_3_P_2_d(ScaleAnswerScene):

    def construct(self):

        self.intro = "Congrats, you got it right"
        self.point = [-2,-4]
        self.question = "How do we scale it, so that it goes through the point (-2,-4)?"
        self.flip = "And we have to flip it too, because the point is negative."
        super().construct()

#####################################
#####################################
TASK_Func_4_3_P_3_q = SophiaTaskDefinition(
    answerOptions = ["$\\tfrac 12$", "$-\\tfrac 12$", "$1$", "$-1$"],
    correctAnswerIndex = 0,
    questionText = "What value do we choose for $a$??"
)
class Func_4_3_P_3_q(ScaleQuestionScene):

    def construct(self):

        self.intro = "Like previously, we're starting with f of x equals x squared"
        self.point = [1,0.5]
        self.question = "How do we scale it, so that it goes through the point (1,0.5)?"
        super().construct()


class Func_4_3_P_3_a(ScaleAnswerScene):

    def construct(self):

        self.intro = "Yep, that's right, well done."
        self.point = [-2,-4]
        self.question = "How do we scale it, so that it goes through the point (1,0.5)?"
        self.flip = ""
        super().construct()

class Func_4_3_P_3_b(ScaleAnswerScene):

    def construct(self):

        self.intro = "no, that's not right..."
        self.point = [-2,-4]
        self.question = "How do we scale it, so that it goes through the point (1,0.5)?"
        self.flip = ""
        super().construct()

class Func_4_3_P_3_c(ScaleAnswerScene):

    def construct(self):

        self.intro = "no, that's not right..."
        self.point = [-2,-4]
        self.question = "How do we scale it, so that it goes through the point (1,0.5)?"
        self.flip = ""
        super().construct()

class Func_4_3_P_3_d(ScaleAnswerScene):

    def construct(self):

        self.intro = "no, that's not right..."
        self.point = [-2,-4]
        self.question = "How do we scale it, so that it goes through the point (1,0.5)?"
        self.flip = ""
        super().construct()


PROTOTYPES = [
    PagePrototypeVideo.from_scene(Func_4_3_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_3_I_1_q, Func_4_3_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_3_I_1_a),
    PagePrototypeVideo.from_scene(Func_4_3_I_1_b),
    PagePrototypeVideo.from_scene(Func_4_3_I_1_c),
    PagePrototypeVideo.from_scene(Func_4_3_I_1_d),
    PagePrototypeVideo.from_scene(Func_4_3_P_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_3_P_1_q, Func_4_3_P_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_3_P_1_a),
    PagePrototypeVideo.from_scene(Func_4_3_P_1_b),
    PagePrototypeVideo.from_scene(Func_4_3_P_1_c),
    PagePrototypeVideo.from_scene(Func_4_3_P_1_d),
    PagePrototypeVideo.from_scene(Func_4_3_P_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_3_P_2_q, Func_4_3_P_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_3_P_2_a),
    PagePrototypeVideo.from_scene(Func_4_3_P_2_b),
    PagePrototypeVideo.from_scene(Func_4_3_P_2_c),
    PagePrototypeVideo.from_scene(Func_4_3_P_2_d),
    PagePrototypeVideo.from_scene(Func_4_3_P_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_3_P_3_q, Func_4_3_P_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_3_P_3_a),
    PagePrototypeVideo.from_scene(Func_4_3_P_3_b),
    PagePrototypeVideo.from_scene(Func_4_3_P_3_c),
    PagePrototypeVideo.from_scene(Func_4_3_P_3_d),
]
scenes/Func/Func_4: Quadratic Functions/Func_4_3.py
Sophia-Edu-Labs/sophia-math
# 4_5: Forms of Quadratic Functions

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition



#####################################
#####################################
TASK_Func_4_5_I_1_q = SophiaTaskDefinition(
    answerOptions = ["$f(x)=x^2-2$", "g(x)=x^2(x-1)", "h(x)=(x-2)(x+2)"],
    correctAnswerIndex = 1,
    questionText = "Which is not a quadratic function?"
)
class Func_4_5_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Quadratic Functions")
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = lambda x: x**2
        g1 = plane.plot(f1, color=BLUE)

        f = MathTex("f","(x)", "=", "x^2", "-", "2", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        g = MathTex("g","(x)", "=", "x^2", "\\cdot", "(x-","1",")", color=c2t, font_size=fs2).next_to(f, DOWN, buff=0.2)
        h = MathTex("h","(x)", "=", "(x-","2",")", "\\cdot", "(x+","2",")", color=c3t, font_size=fs2).next_to(g, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                What can quadratic functions look like?
                And what do quadratic functions never look like?
                Let's start with these three functions:
                The first is <bookmark mark="f"/> f of <bookmark mark="fx"/>x equals <bookmark mark="fx2"/> x squared minus <bookmark mark="f2"/> 2.
                The second is <bookmark mark="g"/> g of <bookmark mark="gx"/>x equals <bookmark mark="gx2"/> x squared times open bracket
                <bookmark mark="gxb"/> x minus<bookmark mark="g1"/> one close bracket.
                And the third is <bookmark mark="h"/> h of x<bookmark mark="hx"/> equals open bracket <bookmark mark="hb1x"/>x minus <bookmark mark="hb12"/>two close bracket
                times open bracket <bookmark mark="hb2x"/> x plus <bookmark mark="hb22"/>two close bracket.
                Now which of the three is not a quadratic function?
                """
        ) as tracker:

            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("f")
            x,y,_ = f[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(f), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("fx2")
            x,y,_ = f[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("f2")
            x,y,_ = f[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("g")
            cursor.blinking=False
            x,y,_ = g[0].get_center()+0.4*DOWN
            self.play(Write(g), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("gx")
            x,y,_ = g[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("gx2")
            x,y,_ = g[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("gxb")
            x,y,_ = g[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("g1")
            x,y,_ = g[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("h")
            cursor.blinking=False
            x,y,_ = h[0].get_center()+0.4*DOWN
            self.play(Write(h), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hx")
            x,y,_ = h[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb1x")
            x,y,_ = h[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb12")
            x,y,_ = h[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb2x")
            x,y,_ = h[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb22")
            x,y,_ = h[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Quadratic Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f = MathTex("f","(x)", "=", "x^2", "-", "2", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1)
        g = MathTex("g","(x)", "=", "x^2", "\\cdot", "(x-","1",")", color=c2t, font_size=fs2).next_to(f, DOWN, buff=0.4)
        a1 = MathTex("\\Downarrow", color=c3t, font_size=fs2).next_to(g, DOWN, buff=0.2)
        g2 = MathTex("g","(x)", "=", "x^3", "-", "x^2", color=c2t, font_size=fs2).next_to(a1, DOWN, buff=0.2)
        h = MathTex("h","(x)", "=", "(x-","2",")", "\\cdot", "(x+","2",")", color=c3t, font_size=fs2).next_to(g2, DOWN, buff=0.4)
        a2 = MathTex("\\Downarrow", color=c3t, font_size=fs2).next_to(h, DOWN, buff=0.2)
        h2 = MathTex("h","(x)", "=", "x^2", "-", "4", color=c3t, font_size=fs2).next_to(a2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's wrong.
                This question was about the structures of quadratic functions.
                The first function, <bookmark mark="f"/> f of <bookmark mark="fx"/>x equals <bookmark mark="fx2"/> x squared minus <bookmark mark="f2"/> 2
                is clearly a quadratic function. It is a unit parabola, shifted down by two.
                The second one, <bookmark mark="g"/> g of <bookmark mark="gx"/>x equals <bookmark mark="gx2"/> x squared times open bracket
                <bookmark mark="gxb"/> x minus<bookmark mark="g1"/> one close bracket is tricky. At first glance, you might think it's a quadratic function, because
                it has an x squared term. But it's not. It's a cubic function. If you multiply the x squared with the two elements in the bracket, <bookmark mark="m1"/>
                you get x to the power of three. So g is not a quadratic function.
                Finally, <bookmark mark="h"/> h of x<bookmark mark="hx"/> equals open bracket <bookmark mark="hb1x"/>x minus <bookmark mark="hb12"/>two close bracket
                times open bracket <bookmark mark="hb2x"/> x plus <bookmark mark="hb22"/>two close bracket is also tricky. Why? Because at first glance, you might be
                tempted to think that it's a linear function, because there doesn't seem to be an x squared term. But similar to g, if you multiply <bookmark mark="m2"/>
                the two brackets, you get x squared. So h is also a quadratic function.
                """
        ) as tracker:



            self.wait_until_bookmark("f")
            x,y,_ = f[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(f), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("fx2")
            x,y,_ = f[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("f2")
            x,y,_ = f[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("g")
            cursor.blinking=False
            x,y,_ = g[0].get_center()+0.4*DOWN
            self.play(Write(g), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("gx")
            x,y,_ = g[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("gx2")
            x,y,_ = g[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("gxb")
            x,y,_ = g[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("g1")
            x,y,_ = g[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("m1")
            cursor.blinking=False
            x,y,_ = g2.get_center()+0.4*DOWN
            self.play(Write(a1), Write(g2), CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("h")
            cursor.blinking=False
            x,y,_ = h[0].get_center()+0.4*DOWN
            self.play(Write(h), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hx")
            x,y,_ = h[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb1x")
            x,y,_ = h[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb12")
            x,y,_ = h[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb2x")
            x,y,_ = h[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb22")
            x,y,_ = h[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("m2")
            cursor.blinking=False
            x,y,_ = h2.get_center()+0.4*DOWN
            self.play(Write(a2), Write(h2), CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Quadratic Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f = MathTex("f","(x)", "=", "x^2", "-", "2", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1)
        g = MathTex("g","(x)", "=", "x^2", "\\cdot", "(x-","1",")", color=c2t, font_size=fs2).next_to(f, DOWN, buff=0.4)
        a1 = MathTex("\\Downarrow", color=c3t, font_size=fs2).next_to(g, DOWN, buff=0.2)
        g2 = MathTex("g","(x)", "=", "x^3", "-", "x^2", color=c2t, font_size=fs2).next_to(a1, DOWN, buff=0.2)
        h = MathTex("h","(x)", "=", "(x-","2",")", "\\cdot", "(x+","2",")", color=c3t, font_size=fs2).next_to(g2, DOWN, buff=0.4)
        a2 = MathTex("\\Downarrow", color=c3t, font_size=fs2).next_to(h, DOWN, buff=0.2)
        h2 = MathTex("h","(x)", "=", "x^2", "-", "4", color=c3t, font_size=fs2).next_to(a2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                You got it! Nice...
                This question was about the structures of quadratic functions.
                The first function, <bookmark mark="f"/> f of <bookmark mark="fx"/>x equals <bookmark mark="fx2"/> x squared minus <bookmark mark="f2"/> 2
                is clearly a quadratic function. It is a unit parabola, shifted down by two.
                The second one, <bookmark mark="g"/> g of <bookmark mark="gx"/>x equals <bookmark mark="gx2"/> x squared times open bracket
                <bookmark mark="gxb"/> x minus<bookmark mark="g1"/> one close bracket is tricky. At first glance, you might think it's a quadratic function, because
                it has an x squared term. But it's not. It's a cubic function. If you multiply the x squared with the two elements in the bracket, <bookmark mark="m1"/>
                you get x to the power of three. So g is not a quadratic function.
                Finally, <bookmark mark="h"/> h of x<bookmark mark="hx"/> equals open bracket <bookmark mark="hb1x"/>x minus <bookmark mark="hb12"/>two close bracket
                times open bracket <bookmark mark="hb2x"/> x plus <bookmark mark="hb22"/>two close bracket is also tricky. Why? Because at first glance, you might be
                tempted to think that it's a linear function, because there doesn't seem to be an x squared term. But similar to g, if you multiply <bookmark mark="m2"/>
                the two brackets, you get x squared. So h is also a quadratic function.
                """
        ) as tracker:



            self.wait_until_bookmark("f")
            x,y,_ = f[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(f), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("fx2")
            x,y,_ = f[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("f2")
            x,y,_ = f[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("g")
            cursor.blinking=False
            x,y,_ = g[0].get_center()+0.4*DOWN
            self.play(Write(g), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("gx")
            x,y,_ = g[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("gx2")
            x,y,_ = g[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("gxb")
            x,y,_ = g[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("g1")
            x,y,_ = g[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("m1")
            cursor.blinking=False
            x,y,_ = g2.get_center()+0.4*DOWN
            self.play(Write(a1), Write(g2), CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("h")
            cursor.blinking=False
            x,y,_ = h[0].get_center()+0.4*DOWN
            self.play(Write(h), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hx")
            x,y,_ = h[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb1x")
            x,y,_ = h[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb12")
            x,y,_ = h[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb2x")
            x,y,_ = h[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb22")
            x,y,_ = h[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("m2")
            cursor.blinking=False
            x,y,_ = h2.get_center()+0.4*DOWN
            self.play(Write(a2), Write(h2), CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Quadratic Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f = MathTex("f","(x)", "=", "x^2", "-", "2", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1)
        g = MathTex("g","(x)", "=", "x^2", "\\cdot", "(x-","1",")", color=c2t, font_size=fs2).next_to(f, DOWN, buff=0.4)
        a1 = MathTex("\\Downarrow", color=c3t, font_size=fs2).next_to(g, DOWN, buff=0.2)
        g2 = MathTex("g","(x)", "=", "x^3", "-", "x^2", color=c2t, font_size=fs2).next_to(a1, DOWN, buff=0.2)
        h = MathTex("h","(x)", "=", "(x-","2",")", "\\cdot", "(x+","2",")", color=c3t, font_size=fs2).next_to(g2, DOWN, buff=0.4)
        a2 = MathTex("\\Downarrow", color=c3t, font_size=fs2).next_to(h, DOWN, buff=0.2)
        h2 = MathTex("h","(x)", "=", "x^2", "-", "4", color=c3t, font_size=fs2).next_to(a2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's wrong.
                This question was about the structures of quadratic functions.
                The first function, <bookmark mark="f"/> f of <bookmark mark="fx"/>x equals <bookmark mark="fx2"/> x squared minus <bookmark mark="f2"/> 2
                is clearly a quadratic function. It is a unit parabola, shifted down by two.
                The second one, <bookmark mark="g"/> g of <bookmark mark="gx"/>x equals <bookmark mark="gx2"/> x squared times open bracket
                <bookmark mark="gxb"/> x minus<bookmark mark="g1"/> one close bracket is tricky. At first glance, you might think it's a quadratic function, because
                it has an x squared term. But it's not. It's a cubic function. If you multiply the x squared with the two elements in the bracket, <bookmark mark="m1"/>
                you get x to the power of three. So g is not a quadratic function.
                Finally, <bookmark mark="h"/> h of x<bookmark mark="hx"/> equals open bracket <bookmark mark="hb1x"/>x minus <bookmark mark="hb12"/>two close bracket
                times open bracket <bookmark mark="hb2x"/> x plus <bookmark mark="hb22"/>two close bracket is also tricky. Why? Because at first glance, you might be
                tempted to think that it's a linear function, because there doesn't seem to be an x squared term. But similar to g, if you multiply <bookmark mark="m2"/>
                the two brackets, you get x squared. So h is also a quadratic function.
                """
        ) as tracker:



            self.wait_until_bookmark("f")
            x,y,_ = f[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(f), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("fx2")
            x,y,_ = f[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("f2")
            x,y,_ = f[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("g")
            cursor.blinking=False
            x,y,_ = g[0].get_center()+0.4*DOWN
            self.play(Write(g), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("gx")
            x,y,_ = g[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("gx2")
            x,y,_ = g[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("gxb")
            x,y,_ = g[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("g1")
            x,y,_ = g[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("m1")
            cursor.blinking=False
            x,y,_ = g2.get_center()+0.4*DOWN
            self.play(Write(a1), Write(g2), CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("h")
            cursor.blinking=False
            x,y,_ = h[0].get_center()+0.4*DOWN
            self.play(Write(h), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hx")
            x,y,_ = h[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb1x")
            x,y,_ = h[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb12")
            x,y,_ = h[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb2x")
            x,y,_ = h[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("hb22")
            x,y,_ = h[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("m2")
            cursor.blinking=False
            x,y,_ = h2.get_center()+0.4*DOWN
            self.play(Write(a2), Write(h2), CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
TASK_Func_4_5_I_2_q = SophiaTaskDefinition(
    answerOptions = ["We can easily determine the location of the vertex", "We can easily determine the location of the zeros", "We can easily determine the location of the y-intercept"],
    correctAnswerIndex = 0,
    questionText = "What is the advantage of the vertex form?"
)
class Func_4_5_I_2_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")
        
        #Create the coordinate system
        cords = self.add_cords([0,4, 1], [-5, 5, 1], x_ticks=[0,1,2,3,4],y_ticks=[-5,-3,-1,1,3,5]).shift(DOWN*0.6)
        plane = cords[0]

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a = ValueTracker(1)
        f1 = lambda x: -2*(x-2)**2+3
        g1 = plane.plot(f1, color=BLUE, x_range=[0,4,0.0001])
        f1 = MathTex("f","(x)", "=", "-2","(x-", "2", ")^2", "+", "3", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)

        funcTerm = MathTex("f","(x)", "=","a","x^2", "+bx", "+", "c", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)

        # Action Sequence
        with self.voiceover(
                text="""
                Why do we want to write quadratic functions in different forms? Isn't it enough to have them in the shape
                <bookmark mark="funcTerm"/> f of <bookmark mark="funcTermX"/>x equals <bookmark mark="funcTermAx2"/> a
                x squared plus <bookmark mark="funcTermB"/> b x <bookmark mark="funcTermC"/>plus c?
                Well, like always, the answer is: it depends! <bookmark mark="fOut"/>Sometimes, it's easier to understand the structure of a function
                if it's written in a different form. Let's look at an example: <bookmark mark="1f"/>f of <bookmark mark="1x"/>x equals <bookmark mark="1neg2"/> negative
                two times open bracket <bookmark mark="1x2"/>x minus<bookmark mark="1xM2"/> two close bracket squared plus
                <bookmark mark="13"/> three. This is a quadratic function. But it's not written in the form we just talked about.
                Instead, it's written in the so-called <bookmark mark="vertexForm"/>Vertex Form. Now look at the <bookmark mark="graph"/> graph of this function
                and try to tell me: What is the advantage of using the vertex form? I'll give you a hint: Think about the name of the form.
                """
        ) as tracker:
            
            self.wait_until_bookmark("funcTerm")
            cursor.blinking=False
            x,y,_ = funcTerm[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("funcTermX")
            x,y,_ = funcTerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("funcTermAx2")
            x,y,_ = (funcTerm[3].get_center()+funcTerm[4].get_center())/2+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("funcTermB")
            x,y,_ = funcTerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("funcTermC")
            x,y,_ = funcTerm[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("fOut")
            self.play(Unwrite(funcTerm))

            self.wait_until_bookmark("1f")
            cursor.blinking = False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)
            
            self.wait_until_bookmark("1x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.1)

            self.wait_until_bookmark("1neg2")
            cursor.blinking=False
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("1x2")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            
            self.wait_until_bookmark("1xM2")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("13")
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("vertexForm")
            x,y,_ = title.get_center()+0.6*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True
                                                                        
            self.wait_until_bookmark("graph")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(CursorMoveTo(cursor, x, y), Write(cords), run_time=0.3)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.play(Create(g1))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_5_I_2_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")
        
        #Create the coordinate system
        cords = self.add_cords([0,4, 1], [-5, 5, 1], x_ticks=[0,1,2,3,4],y_ticks=[-5,-3,-1,1,3,5]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a = ValueTracker(1)
        f1 = lambda x: -2*(x-2)**2+3
        g1 = plane.plot(f1, color=BLUE, x_range=[0,4,0.0001])
        f1 = MathTex("f","(x)", "=", "-2","(x-", "2", ")^2", "+", "3", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.2)
        f2 = MathTex("f","(2)", "=", "-2","(2-2)^2", "+", "3", "=3", color=c1t, font_size=fs2).scale(0.9).next_to(a, DOWN, buff=0.2)
        self.add(f1, g1)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's it. Unsurprisingly, the vertex form is called vertex form because it makes it easy to determine the location of the vertex.
                So, how do we find the vertex from the vertex form? First, remember that the <bookmark  mark="vertex"/>vertex is the point where
                the function reaches its minimum or maximum. Since the parabola we have here is facing downwards, the vertex is the highest point.
                Now look at the term of the function. It consists of two parts: The part that is <bookmark mark="square"/>squared, and the <bookmark mark="3"/>three that is added.
                Now, we want to find the value of <bookmark mark="x"/>x for which the value of f is the highest, and we want to find that highest value.
                Now look at the two parts again. The <bookmark mark="square2"/>squared part is multiplied with negative two, so we want it to be as small as possible.
                Since it's squared, it's always greater than or equal to zero, so the best we can do is zero. And we reach the zero, if we plug in two for x.
                Now all that is left is <bookmark mark="three"/> the second part, which only consists of a three. <bookmark mark="sol"/> That means, that the highest value of f is three.
                In summary, we found that the x value of the vertex is two, and that the y value of the vertex is three.
                We found this, because we started from the vertex form and then first, read off how to get<bookmark mark="square3"/> the squared term to zero, and then looked at
                the<bookmark mark="33"/> second part.
                """
        ) as tracker:
            
            self.wait_until_bookmark("vertex")
            x,y,_ = plane.c2p(2,3)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("square")
            cursor.blinking=False
            x,y,_ = (f1[3].get_center()+f1[3].get_center())/2+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("3")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("x")
            cursor.blinking=False
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("square2")
            cursor.blinking=False
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("three")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol")
            cursor.blinking=False
            x,y,_ = f2.get_center()+0.4*DOWN
            self.play(Write(a), Write(f2), CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("square3")
            cursor.blinking=False
            x,y,_ = f2[4].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("33")
            cursor.blinking=False
            x,y,_ = f2[6].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_2_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")
        
        #Create the coordinate system
        cords = self.add_cords([0,4, 1], [-5, 5, 1], x_ticks=[0,1,2,3,4],y_ticks=[-5,-3,-1,1,3,5]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a = ValueTracker(1)
        f1 = lambda x: -2*(x-2)**2+3
        g1 = plane.plot(f1, color=BLUE, x_range=[0,4,0.0001])
        f1 = MathTex("f","(x)", "=", "-2","(x-", "2", ")^2", "+", "3", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.2)
        f2 = MathTex("f","(2)", "=", "-2","(2-2)^2", "+", "3", "=3", color=c1t, font_size=fs2).scale(0.9).next_to(a, DOWN, buff=0.2)
        self.add(f1, g1)

        # Action Sequence
        with self.voiceover(
                text="""
                Nope, that's wrong. Unsurprisingly, the vertex form is called vertex form because it makes it easy to determine the location of the vertex.
                So, how do we find the vertex from the vertex form? First, remember that the <bookmark  mark="vertex"/>vertex is the point where
                the function reaches its minimum or maximum. Since the parabola we have here is facing downwards, the vertex is the highest point.
                Now look at the term of the function. It consists of two parts: The part that is <bookmark mark="square"/>squared, and the <bookmark mark="3"/>three that is added.
                Now, we want to find the value of <bookmark mark="x"/>x for which the value of f is the highest, and we want to find that highest value.
                Now look at the two parts again. The <bookmark mark="square2"/>squared part is multiplied with negative two, so we want it to be as small as possible.
                Since it's squared, it's always greater than or equal to zero, so the best we can do is zero. And we reach the zero, if we plug in two for x.
                Now all that is left is <bookmark mark="three"/> the second part, which only consists of a three. <bookmark mark="sol"/> That means, that the highest value of f is three.
                In summary, we found that the x value of the vertex is two, and that the y value of the vertex is three.
                We found this, because we started from the vertex form and then first, read off how to get<bookmark mark="square3"/> the squared term to zero, and then looked at
                the<bookmark mark="33"/> second part.
                """
        ) as tracker:
            
            self.wait_until_bookmark("vertex")
            x,y,_ = plane.c2p(2,3)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("square")
            cursor.blinking=False
            x,y,_ = (f1[3].get_center()+f1[3].get_center())/2+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("3")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("x")
            cursor.blinking=False
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("square2")
            cursor.blinking=False
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("three")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol")
            cursor.blinking=False
            x,y,_ = f2.get_center()+0.4*DOWN
            self.play(Write(a), Write(f2), CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("square3")
            cursor.blinking=False
            x,y,_ = f2[4].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("33")
            cursor.blinking=False
            x,y,_ = f2[6].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_5_I_2_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")
        
        #Create the coordinate system
        cords = self.add_cords([0,4, 1], [-5, 5, 1], x_ticks=[0,1,2,3,4],y_ticks=[-5,-3,-1,1,3,5]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        a = ValueTracker(1)
        f1 = lambda x: -2*(x-2)**2+3
        g1 = plane.plot(f1, color=BLUE, x_range=[0,4,0.0001])
        f1 = MathTex("f","(x)", "=", "-2","(x-", "2", ")^2", "+", "3", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.2)
        f2 = MathTex("f","(2)", "=", "-2","(2-2)^2", "+", "3", "=3", color=c1t, font_size=fs2).scale(0.9).next_to(a, DOWN, buff=0.2)
        self.add(f1, g1)

        # Action Sequence
        with self.voiceover(
                text="""
                Nope, that's wrong. Unsurprisingly, the vertex form is called vertex form because it makes it easy to determine the location of the vertex.
                So, how do we find the vertex from the vertex form? First, remember that the <bookmark  mark="vertex"/>vertex is the point where
                the function reaches its minimum or maximum. Since the parabola we have here is facing downwards, the vertex is the highest point.
                Now look at the term of the function. It consists of two parts: The part that is <bookmark mark="square"/>squared, and the <bookmark mark="3"/>three that is added.
                Now, we want to find the value of <bookmark mark="x"/>x for which the value of f is the highest, and we want to find that highest value.
                Now look at the two parts again. The <bookmark mark="square2"/>squared part is multiplied with negative two, so we want it to be as small as possible.
                Since it's squared, it's always greater than or equal to zero, so the best we can do is zero. And we reach the zero, if we plug in two for x.
                Now all that is left is <bookmark mark="three"/> the second part, which only consists of a three. <bookmark mark="sol"/> That means, that the highest value of f is three.
                In summary, we found that the x value of the vertex is two, and that the y value of the vertex is three.
                We found this, because we started from the vertex form and then first, read off how to get<bookmark mark="square3"/> the squared term to zero, and then looked at
                the<bookmark mark="33"/> second part.
                """
        ) as tracker:
            
            self.wait_until_bookmark("vertex")
            x,y,_ = plane.c2p(2,3)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("square")
            cursor.blinking=False
            x,y,_ = (f1[3].get_center()+f1[3].get_center())/2+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("3")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("x")
            cursor.blinking=False
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("square2")
            cursor.blinking=False
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("three")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol")
            cursor.blinking=False
            x,y,_ = f2.get_center()+0.4*DOWN
            self.play(Write(a), Write(f2), CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("square3")
            cursor.blinking=False
            x,y,_ = f2[4].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("33")
            cursor.blinking=False
            x,y,_ = f2[6].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_4_5_I_3_q = SophiaTaskDefinition(
    answerOptions = ["(-1,-2)", "(1,2)", "(1,-2)", "(-1,2)"],
    correctAnswerIndex = 0,
    questionText = "What are the coordinates of the vertex?"
)
class Func_4_5_I_3_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = lambda x: -2*(x-2)**2+3
        f1 = MathTex("f","(x)", "=", "(x+", "1", ")^2", "-", "2", color=c1t, font_size=fs2)

        # Action Sequence
        with self.voiceover(
                text="""
                Now your turn. Take the function <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="one"/> one close bracket squared
                <bookmark mark="two"/>minus two. Luckily for you, it's already in vertex form. Now what is
                the location of the vertex? What is the x value, that we need to plug in, and what is the 
                y value of the vertex?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("one")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("two")
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_3_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = lambda x: -2*(x-2)**2+3
        f1 = MathTex("f","(x)", "=", "(x+", "1", ")^2", "-", "2", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1)
        bracket = VGroup(f1[3], f1[4], f1[5])
        f2 = MathTex("\\underbrace{(x+1)^2}_{\\geq0}", color=c1t, font_size=fs2).move_to(bracket)
        f2.shift(bracket.get_top()-f2.get_top())
        a1 = Tex("$\\Downarrow$\\,\\,", "\\,\\,x=-1", font_size=fs2, color=c1t).next_to(f1, DOWN, buff=0.8)
        f3 = MathTex("f(-1)=(-1+1)^2-2=-2", color=c1t, font_size=fs2).scale(0.9).next_to(a1, DOWN, buff=0.5)
        a2 = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f3, DOWN, buff=0.5)
        f4 = Tex("Vertex: (-1,-2)", color=c1t, font_size=fs2).next_to(a2, DOWN, buff=0.5)

        f1.move_to(ORIGIN)
        # Action Sequence
        with self.voiceover(
                text="""
                That is correct! Nice work! 
                So our function is <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="one"/> one close bracket squared
                <bookmark mark="two"/>minus two.
                First, note that the parabola is facing up, so the vertex is the lowest point. <bookmark mark="moveUp"/>
                Now, we want to find the value of<bookmark mark="ofX"/> x for which the value of f is the lowest, and we want to find that lowest value.
                Again, look at the two parts of the function. The <bookmark mark="square"/>squared part is always greater than or equal to zero, so the best we can do is zero.
                And we reach the zero, <bookmark mark="a1"/>if we plug in negative one for x.
                Now all that is left is <bookmark mark="negTwo"/> the second part, which only consists of a negative two.
                <bookmark mark="sol"/> That means, that the lowest value of f is negative two.
                <bookmark mark="summary"/>In summary, we found that<bookmark mark="sum2"/> the x value of the vertex is negative one, and that the y value of the vertex is negative two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("one")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("two")
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("moveUp")
            self.play(f1.animate.next_to(title, DOWN, buff=1))

            self.wait_until_bookmark("ofX")
            cursor.blinking=False
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("square")
            cursor.blinking=False
            x,y,_ = f2.get_center()+0.7*DOWN
            self.play(Write(f2), run_time=1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("a1")
            cursor.blinking=False
            x,y,_ = a1[1].get_center()+0.4*DOWN
            self.play(Write(a1), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("negTwo")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("sol")
            cursor.blinking=False
            x,y,_ = f3.get_center()+0.4*DOWN
            self.play(Write(f3), CursorMoveTo(cursor, x, y), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("summary")
            cursor.blinking=False
            x,y,_ = a2.get_center()+0.4*RIGHT
            self.play(Write(a2), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("sum2")
            cursor.blinking=False
            x,y,_ = f4.get_center()+0.4*DOWN
            self.play(Write(f4), CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_5_I_3_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = lambda x: -2*(x-2)**2+3
        f1 = MathTex("f","(x)", "=", "(x+", "1", ")^2", "-", "2", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1)
        bracket = VGroup(f1[3], f1[4], f1[5])
        f2 = MathTex("\\underbrace{(x+1)^2}_{\\geq0}", color=c1t, font_size=fs2).move_to(bracket)
        f2.shift(bracket.get_top()-f2.get_top())
        a1 = Tex("$\\Downarrow$\\,\\,", "\\,\\,x=-1", font_size=fs2, color=c1t).next_to(f1, DOWN, buff=0.8)
        f3 = MathTex("f(-1)=(-1+1)^2-2=-2", color=c1t, font_size=fs2).scale(0.9).next_to(a1, DOWN, buff=0.5)
        a2 = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f3, DOWN, buff=0.5)
        f4 = Tex("Vertex: (-1,-2)", color=c1t, font_size=fs2).next_to(a2, DOWN, buff=0.5)

        f1.move_to(ORIGIN)
        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right. 
                So our function is <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="one"/> one close bracket squared
                <bookmark mark="two"/>minus two.
                First, note that the parabola is facing up, so the vertex is the lowest point. <bookmark mark="moveUp"/>
                Now, we want to find the value of<bookmark mark="ofX"/> x for which the value of f is the lowest, and we want to find that lowest value.
                Again, look at the two parts of the function. The <bookmark mark="square"/>squared part is always greater than or equal to zero, so the best we can do is zero.
                And we reach the zero, <bookmark mark="a1"/>if we plug in negative one for x.
                Now all that is left is <bookmark mark="negTwo"/> the second part, which only consists of a negative two.
                <bookmark mark="sol"/> That means, that the lowest value of f is negative two.
                <bookmark mark="summary"/>In summary, we found that<bookmark mark="sum2"/> the x value of the vertex is negative one, and that the y value of the vertex is negative two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("one")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("two")
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("moveUp")
            self.play(f1.animate.next_to(title, DOWN, buff=1))

            self.wait_until_bookmark("ofX")
            cursor.blinking=False
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("square")
            cursor.blinking=False
            x,y,_ = f2.get_center()+0.7*DOWN
            self.play(Write(f2), run_time=1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("a1")
            cursor.blinking=False
            x,y,_ = a1[1].get_center()+0.4*DOWN
            self.play(Write(a1), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("negTwo")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("sol")
            cursor.blinking=False
            x,y,_ = f3.get_center()+0.4*DOWN
            self.play(Write(f3), CursorMoveTo(cursor, x, y), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("summary")
            cursor.blinking=False
            x,y,_ = a2.get_center()+0.4*RIGHT
            self.play(Write(a2), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("sum2")
            cursor.blinking=False
            x,y,_ = f4.get_center()+0.4*DOWN
            self.play(Write(f4), CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_3_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = lambda x: -2*(x-2)**2+3
        f1 = MathTex("f","(x)", "=", "(x+", "1", ")^2", "-", "2", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1)
        bracket = VGroup(f1[3], f1[4], f1[5])
        f2 = MathTex("\\underbrace{(x+1)^2}_{\\geq0}", color=c1t, font_size=fs2).move_to(bracket)
        f2.shift(bracket.get_top()-f2.get_top())
        a1 = Tex("$\\Downarrow$\\,\\,", "\\,\\,x=-1", font_size=fs2, color=c1t).next_to(f1, DOWN, buff=0.8)
        f3 = MathTex("f(-1)=(-1+1)^2-2=-2", color=c1t, font_size=fs2).scale(0.9).next_to(a1, DOWN, buff=0.5)
        a2 = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f3, DOWN, buff=0.5)
        f4 = Tex("Vertex: (-1,-2)", color=c1t, font_size=fs2).next_to(a2, DOWN, buff=0.5)

        f1.move_to(ORIGIN)
        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                So our function is <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="one"/> one close bracket squared
                <bookmark mark="two"/>minus two.
                First, note that the parabola is facing up, so the vertex is the lowest point. <bookmark mark="moveUp"/>
                Now, we want to find the value of<bookmark mark="ofX"/> x for which the value of f is the lowest, and we want to find that lowest value.
                Again, look at the two parts of the function. The <bookmark mark="square"/>squared part is always greater than or equal to zero, so the best we can do is zero.
                And we reach the zero, <bookmark mark="a1"/>if we plug in negative one for x.
                Now all that is left is <bookmark mark="negTwo"/> the second part, which only consists of a negative two.
                <bookmark mark="sol"/> That means, that the lowest value of f is negative two.
                <bookmark mark="summary"/>In summary, we found that<bookmark mark="sum2"/> the x value of the vertex is negative one, and that the y value of the vertex is negative two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("one")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("two")
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("moveUp")
            self.play(f1.animate.next_to(title, DOWN, buff=1))

            self.wait_until_bookmark("ofX")
            cursor.blinking=False
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("square")
            cursor.blinking=False
            x,y,_ = f2.get_center()+0.7*DOWN
            self.play(Write(f2), run_time=1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("a1")
            cursor.blinking=False
            x,y,_ = a1[1].get_center()+0.4*DOWN
            self.play(Write(a1), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("negTwo")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("sol")
            cursor.blinking=False
            x,y,_ = f3.get_center()+0.4*DOWN
            self.play(Write(f3), CursorMoveTo(cursor, x, y), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("summary")
            cursor.blinking=False
            x,y,_ = a2.get_center()+0.4*RIGHT
            self.play(Write(a2), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("sum2")
            cursor.blinking=False
            x,y,_ = f4.get_center()+0.4*DOWN
            self.play(Write(f4), CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_5_I_3_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = lambda x: -2*(x-2)**2+3
        f1 = MathTex("f","(x)", "=", "(x+", "1", ")^2", "-", "2", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1)
        bracket = VGroup(f1[3], f1[4], f1[5])
        f2 = MathTex("\\underbrace{(x+1)^2}_{\\geq0}", color=c1t, font_size=fs2).move_to(bracket)
        f2.shift(bracket.get_top()-f2.get_top())
        a1 = Tex("$\\Downarrow$\\,\\,", "\\,\\,x=-1", font_size=fs2, color=c1t).next_to(f1, DOWN, buff=0.8)
        f3 = MathTex("f(-1)=(-1+1)^2-2=-2", color=c1t, font_size=fs2).scale(0.9).next_to(a1, DOWN, buff=0.5)
        a2 = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f3, DOWN, buff=0.5)
        f4 = Tex("Vertex: (-1,-2)", color=c1t, font_size=fs2).next_to(a2, DOWN, buff=0.5)

        f1.move_to(ORIGIN)
        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right. 
                So our function is <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="one"/> one close bracket squared
                <bookmark mark="two"/>minus two.
                First, note that the parabola is facing up, so the vertex is the lowest point. <bookmark mark="moveUp"/>
                Now, we want to find the value of<bookmark mark="ofX"/> x for which the value of f is the lowest, and we want to find that lowest value.
                Again, look at the two parts of the function. The <bookmark mark="square"/>squared part is always greater than or equal to zero, so the best we can do is zero.
                And we reach the zero, <bookmark mark="a1"/>if we plug in negative one for x.
                Now all that is left is <bookmark mark="negTwo"/> the second part, which only consists of a negative two.
                <bookmark mark="sol"/> That means, that the lowest value of f is negative two.
                <bookmark mark="summary"/>In summary, we found that<bookmark mark="sum2"/> the x value of the vertex is negative one, and that the y value of the vertex is negative two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("one")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("two")
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("moveUp")
            self.play(f1.animate.next_to(title, DOWN, buff=1))

            self.wait_until_bookmark("ofX")
            cursor.blinking=False
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("square")
            cursor.blinking=False
            x,y,_ = f2.get_center()+0.7*DOWN
            self.play(Write(f2), run_time=1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("a1")
            cursor.blinking=False
            x,y,_ = a1[1].get_center()+0.4*DOWN
            self.play(Write(a1), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("negTwo")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("sol")
            cursor.blinking=False
            x,y,_ = f3.get_center()+0.4*DOWN
            self.play(Write(f3), CursorMoveTo(cursor, x, y), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("summary")
            cursor.blinking=False
            x,y,_ = a2.get_center()+0.4*RIGHT
            self.play(Write(a2), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("sum2")
            cursor.blinking=False
            x,y,_ = f4.get_center()+0.4*DOWN
            self.play(Write(f4), CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)




#####################################
#####################################
TASK_Func_4_5_I_4_q = SophiaTaskDefinition(
    answerOptions = ["(a,c)", "(b,c)", "(a+b,c)", "(-b,c)"],
    correctAnswerIndex = 3,
    questionText = "What are the coordinates of the vertex?"
)
class Func_4_5_I_4_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = lambda x: -2*(x-2)**2+3
        f1 = MathTex("f","(x)", "=", "a\\cdot", "(x+", "b", ")^2", "+", "c", color=c1t, font_size=fs2)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, let's make our lives easy now.
                Consider a quadratic function in the vertex form: <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                <bookmark mark="a"/> "a" times open bracket <bookmark mark="x1"/>x plus <bookmark mark="b"/> b close bracket squared
                <bookmark mark="c"/>plus c.
                Let me tell you: Just by looking at this function, you can tell the coordinates of the vertex.
                What are they?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1[0]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(Write(f1[1]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("a")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(Write(f1[2]), Write(f1[3]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(Write(f1[4]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(Write(f1[5]), Write(f1[6]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("c")
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(Write(f1[-2]), Write(f1[-1]), CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)



class Func_4_5_I_4_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "a\\cdot", "(x+", "b", ")^2", "+", "c", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1)
        bracket = VGroup(f1[4], f1[5], f1[6])
        f2 = MathTex("\\underbrace{(x+b)^2}_{\\geq0}", color=c1t, font_size=fs2).move_to(bracket)
        f2.shift(bracket.get_top()-f2.get_top())
        a1 = Tex("$\\Downarrow$\\,\\,", "\\,\\,x=-b", font_size=fs2, color=c1t).next_to(f1, DOWN, buff=0.8)
        f3 = MathTex("f(-b)=a\\cdot(-b+b)^2+c=c", color=c1t, font_size=fs2).scale(0.9).next_to(a1, DOWN, buff=0.5)
        a2 = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f3, DOWN, buff=0.5)
        f4 = Tex("Vertex: (-b,c)", color=c1t, font_size=fs2).next_to(a2, DOWN, buff=0.5)

        f1.move_to(ORIGIN)
        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right. 
                So the general vertex form is <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                <bookmark mark="a"/> "a" times open bracket <bookmark mark="x1"/>x plus <bookmark mark="b"/> b close bracket squared
                <bookmark mark="c"/>plus c. 
                We don't know if the parabola is facing up or down, so we don't know if the vertex is the highest or lowest point.  <bookmark mark="moveUp"/>
                But that doesn't matter, since in both cases, we want to find the <bookmark mark="ofX"/>x value that makes the squared term be as small as possible.
                Again, look at the two parts of the function. The <bookmark mark="square"/>squared part is always greater than or equal to zero, so the best we can do is zero.
                And we reach the zero, <bookmark mark="a1"/>if we plug in negative b for x.
                Now all that is left is <bookmark mark="negTwo"/> the second part, which only consists of a constant c.
                <bookmark mark="sol"/> That means, that the extreme value of f is equal to c.
                <bookmark mark="summary"/>In summary, we found that<bookmark mark="sum2"/> the x value of the vertex is negative b, and that the y value of the vertex is equal to
                the constant c.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1[0]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(Write(f1[1]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("a")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(Write(f1[2]), Write(f1[3]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(Write(f1[4]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(Write(f1[5]), Write(f1[6]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("c")
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(Write(f1[-2]), Write(f1[-1]), CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("moveUp")
            self.play(f1.animate.next_to(title, DOWN, buff=1))

            self.wait_until_bookmark("ofX")
            cursor.blinking=False
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("square")
            cursor.blinking=False
            x,y,_ = f2.get_center()+0.7*DOWN
            self.play(Write(f2), run_time=1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("a1")
            cursor.blinking=False
            x,y,_ = a1[1].get_center()+0.4*DOWN
            self.play(Write(a1), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("negTwo")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("sol")
            cursor.blinking=False
            x,y,_ = f3.get_center()+0.4*DOWN
            self.play(Write(f3), CursorMoveTo(cursor, x, y), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("summary")
            cursor.blinking=False
            x,y,_ = a2.get_center()+0.4*RIGHT
            self.play(Write(a2), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("sum2")
            cursor.blinking=False
            x,y,_ = f4.get_center()+0.4*DOWN
            self.play(Write(f4), CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_5_I_4_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "a\\cdot", "(x+", "b", ")^2", "+", "c", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1)
        bracket = VGroup(f1[4], f1[5], f1[6])
        f2 = MathTex("\\underbrace{(x+b)^2}_{\\geq0}", color=c1t, font_size=fs2).move_to(bracket)
        f2.shift(bracket.get_top()-f2.get_top())
        a1 = Tex("$\\Downarrow$\\,\\,", "\\,\\,x=-b", font_size=fs2, color=c1t).next_to(f1, DOWN, buff=0.8)
        f3 = MathTex("f(-b)=a\\cdot(-b+b)^2+c=c", color=c1t, font_size=fs2).scale(0.9).next_to(a1, DOWN, buff=0.5)
        a2 = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f3, DOWN, buff=0.5)
        f4 = Tex("Vertex: (-b,c)", color=c1t, font_size=fs2).next_to(a2, DOWN, buff=0.5)

        f1.move_to(ORIGIN)
        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right. 
                So the general vertex form is <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                <bookmark mark="a"/> "a" times open bracket <bookmark mark="x1"/>x plus <bookmark mark="b"/> b close bracket squared
                <bookmark mark="c"/>plus c. 
                We don't know if the parabola is facing up or down, so we don't know if the vertex is the highest or lowest point.  <bookmark mark="moveUp"/>
                But that doesn't matter, since in both cases, we want to find the <bookmark mark="ofX"/>x value that makes the squared term be as small as possible.
                Again, look at the two parts of the function. The <bookmark mark="square"/>squared part is always greater than or equal to zero, so the best we can do is zero.
                And we reach the zero, <bookmark mark="a1"/>if we plug in negative b for x.
                Now all that is left is <bookmark mark="negTwo"/> the second part, which only consists of a constant c.
                <bookmark mark="sol"/> That means, that the extreme value of f is equal to c.
                <bookmark mark="summary"/>In summary, we found that<bookmark mark="sum2"/> the x value of the vertex is negative b, and that the y value of the vertex is equal to
                the constant c.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1[0]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(Write(f1[1]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("a")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(Write(f1[2]), Write(f1[3]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(Write(f1[4]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(Write(f1[5]), Write(f1[6]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("c")
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(Write(f1[-2]), Write(f1[-1]), CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("moveUp")
            self.play(f1.animate.next_to(title, DOWN, buff=1))

            self.wait_until_bookmark("ofX")
            cursor.blinking=False
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("square")
            cursor.blinking=False
            x,y,_ = f2.get_center()+0.7*DOWN
            self.play(Write(f2), run_time=1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("a1")
            cursor.blinking=False
            x,y,_ = a1[1].get_center()+0.4*DOWN
            self.play(Write(a1), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("negTwo")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("sol")
            cursor.blinking=False
            x,y,_ = f3.get_center()+0.4*DOWN
            self.play(Write(f3), CursorMoveTo(cursor, x, y), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("summary")
            cursor.blinking=False
            x,y,_ = a2.get_center()+0.4*RIGHT
            self.play(Write(a2), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("sum2")
            cursor.blinking=False
            x,y,_ = f4.get_center()+0.4*DOWN
            self.play(Write(f4), CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_5_I_4_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "a\\cdot", "(x+", "b", ")^2", "+", "c", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1)
        bracket = VGroup(f1[4], f1[5], f1[6])
        f2 = MathTex("\\underbrace{(x+b)^2}_{\\geq0}", color=c1t, font_size=fs2).move_to(bracket)
        f2.shift(bracket.get_top()-f2.get_top())
        a1 = Tex("$\\Downarrow$\\,\\,", "\\,\\,x=-b", font_size=fs2, color=c1t).next_to(f1, DOWN, buff=0.8)
        f3 = MathTex("f(-b)=a\\cdot(-b+b)^2+c=c", color=c1t, font_size=fs2).scale(0.9).next_to(a1, DOWN, buff=0.5)
        a2 = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f3, DOWN, buff=0.5)
        f4 = Tex("Vertex: (-b,c)", color=c1t, font_size=fs2).next_to(a2, DOWN, buff=0.5)

        f1.move_to(ORIGIN)
        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right. 
                So the general vertex form is <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                <bookmark mark="a"/> "a" times open bracket <bookmark mark="x1"/>x plus <bookmark mark="b"/> b close bracket squared
                <bookmark mark="c"/>plus c. 
                We don't know if the parabola is facing up or down, so we don't know if the vertex is the highest or lowest point.  <bookmark mark="moveUp"/>
                But that doesn't matter, since in both cases, we want to find the <bookmark mark="ofX"/>x value that makes the squared term be as small as possible.
                Again, look at the two parts of the function. The <bookmark mark="square"/>squared part is always greater than or equal to zero, so the best we can do is zero.
                And we reach the zero, <bookmark mark="a1"/>if we plug in negative b for x.
                Now all that is left is <bookmark mark="negTwo"/> the second part, which only consists of a constant c.
                <bookmark mark="sol"/> That means, that the extreme value of f is equal to c.
                <bookmark mark="summary"/>In summary, we found that<bookmark mark="sum2"/> the x value of the vertex is negative b, and that the y value of the vertex is equal to
                the constant c.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1[0]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(Write(f1[1]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("a")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(Write(f1[2]), Write(f1[3]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(Write(f1[4]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(Write(f1[5]), Write(f1[6]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("c")
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(Write(f1[-2]), Write(f1[-1]), CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("moveUp")
            self.play(f1.animate.next_to(title, DOWN, buff=1))

            self.wait_until_bookmark("ofX")
            cursor.blinking=False
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("square")
            cursor.blinking=False
            x,y,_ = f2.get_center()+0.7*DOWN
            self.play(Write(f2), run_time=1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("a1")
            cursor.blinking=False
            x,y,_ = a1[1].get_center()+0.4*DOWN
            self.play(Write(a1), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("negTwo")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("sol")
            cursor.blinking=False
            x,y,_ = f3.get_center()+0.4*DOWN
            self.play(Write(f3), CursorMoveTo(cursor, x, y), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("summary")
            cursor.blinking=False
            x,y,_ = a2.get_center()+0.4*RIGHT
            self.play(Write(a2), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("sum2")
            cursor.blinking=False
            x,y,_ = f4.get_center()+0.4*DOWN
            self.play(Write(f4), CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_5_I_4_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Vertex Form")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "a\\cdot", "(x+", "b", ")^2", "+", "c", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1)
        bracket = VGroup(f1[4], f1[5], f1[6])
        f2 = MathTex("\\underbrace{(x+b)^2}_{\\geq0}", color=c1t, font_size=fs2).move_to(bracket)
        f2.shift(bracket.get_top()-f2.get_top())
        a1 = Tex("$\\Downarrow$\\,\\,", "\\,\\,x=-b", font_size=fs2, color=c1t).next_to(f1, DOWN, buff=0.8)
        f3 = MathTex("f(-b)=a\\cdot(-b+b)^2+c=c", color=c1t, font_size=fs2).scale(0.9).next_to(a1, DOWN, buff=0.5)
        a2 = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f3, DOWN, buff=0.5)
        f4 = Tex("Vertex: (-b,c)", color=c1t, font_size=fs2).next_to(a2, DOWN, buff=0.5)

        f1.move_to(ORIGIN)
        # Action Sequence
        with self.voiceover(
                text="""
                Correct, well done, well done. 
                So the general vertex form is <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                <bookmark mark="a"/> "a" times open bracket <bookmark mark="x1"/>x plus <bookmark mark="b"/> b close bracket squared
                <bookmark mark="c"/>plus c. 
                We don't know if the parabola is facing up or down, so we don't know if the vertex is the highest or lowest point.  <bookmark mark="moveUp"/>
                But that doesn't matter, since in both cases, we want to find the <bookmark mark="ofX"/>x value that makes the squared term be as small as possible.
                Again, look at the two parts of the function. The <bookmark mark="square"/>squared part is always greater than or equal to zero, so the best we can do is zero.
                And we reach the zero, <bookmark mark="a1"/>if we plug in negative b for x.
                Now all that is left is <bookmark mark="negTwo"/> the second part, which only consists of a constant c.
                <bookmark mark="sol"/> That means, that the extreme value of f is equal to c.
                <bookmark mark="summary"/>In summary, we found that<bookmark mark="sum2"/> the x value of the vertex is negative b, and that the y value of the vertex is equal to
                the constant c.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1[0]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(Write(f1[1]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("a")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(Write(f1[2]), Write(f1[3]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(Write(f1[4]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b")
            x,y,_ = f1[5].get_center()+0.4*DOWN
            self.play(Write(f1[5]), Write(f1[6]), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("c")
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(Write(f1[-2]), Write(f1[-1]), CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("moveUp")
            self.play(f1.animate.next_to(title, DOWN, buff=1))

            self.wait_until_bookmark("ofX")
            cursor.blinking=False
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("square")
            cursor.blinking=False
            x,y,_ = f2.get_center()+0.7*DOWN
            self.play(Write(f2), run_time=1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("a1")
            cursor.blinking=False
            x,y,_ = a1[1].get_center()+0.4*DOWN
            self.play(Write(a1), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("negTwo")
            cursor.blinking=False
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("sol")
            cursor.blinking=False
            x,y,_ = f3.get_center()+0.4*DOWN
            self.play(Write(f3), CursorMoveTo(cursor, x, y), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("summary")
            cursor.blinking=False
            x,y,_ = a2.get_center()+0.4*RIGHT
            self.play(Write(a2), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("sum2")
            cursor.blinking=False
            x,y,_ = f4.get_center()+0.4*DOWN
            self.play(Write(f4), CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
TASK_Func_4_5_I_5_q = SophiaTaskDefinition(
    answerOptions = ["We can easily determine the location of the vertex", "We can easily determine the location of the zeros", "We can easily determine the location of the y-intercept"],
    correctAnswerIndex = 1,
    questionText = "What is the advantage of the factored form?"
)
class Func_4_5_I_5_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x-", "2)", "\\cdot", "(x+", "1", ")", color=c1t, font_size=fs2)
        f = lambda x: (x-2)*(x+1)
        g = plane.plot(f, color=BLUE, x_range=[-2.2,2.2,0.001])

        # Action Sequence
        with self.voiceover(
                text="""
                New Video, new form of quadratic functions. Now we're looking at the factored form.
                Consider the following example: <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x minus <bookmark mark="2"/>2 close bracket times
                open bracket <bookmark mark="x2"/>x plus <bookmark mark="1"/>1 close bracket.
                <bookmark mark="cords"/> If you look at <bookmark mark="plot"/>the plot of this function,
                and compare it with the factored form of its term, can you think of what the advantage
                of the factored form might be?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("2")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("1")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Write(cords), f1.animate.next_to(cords, DOWN, buff=0.6))

            self.wait_until_bookmark("plot")
            cursor.blinking=False
            x,y,_ = g.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g.get_end())))
            self.play(Create(g))
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_5_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x-", "2)", "\\cdot", "(x+", "1", ")", color=c1t, font_size=fs2)
        self.add(f1)
        b1 = VGroup(f1[3], f1[4])
        b2 = VGroup(f1[-3], f1[-2], f1[-1])
        b1b = MathTex("\\underbrace{(x-2)}_{=0\\text{ if }x=2}", color=c1t, font_size=fs2).move_to(b1)
        b2b = MathTex("\\underbrace{(x+1)}_{=0\\text{ if }x=-1}", color=c1t, font_size=fs2).move_to(b2)
        b1b.shift(b1.get_top()-b1b.get_top())
        b2b.shift(b2.get_top()-b2b.get_top())
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.6)
        sol = Tex("Zeros at ", "$x=2$", " and ", "$x=-1$", color=c1t, font_size=fs3).next_to(a, DOWN, buff=0.4)

        calcs = Group(f1, b1b, b2b, a, sol)

        f = lambda x: (x-2)*(x+1)
        g = plane.plot(f, color=BLUE, x_range=[-2.2,2.2,0.001])

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not what the factored form is good for.
                Let's go back to our example function. <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x minus <bookmark mark="2"/>2 close bracket times
                open bracket <bookmark mark="x2"/>x plus <bookmark mark="1"/>1 close bracket.
                Say we want to determine the zeros of that function. F is written as a product of two factors.
                The first is the <bookmark mark="b1"/> bracket x minus 2, and the second is the <bookmark mark="b2"/> bracket x plus 1.
                Now for the function to be zero, we need the product to be zero, which is the case if at least
                one of the factors is zero. The first factor is zero <bookmark mark="b1b"/>if x equals 2, an the second factor is zero
                <bookmark mark="b2b"/>if x equals negative 1.
                This means <bookmark mark="arrow"/> that the zeros of the function are at<bookmark mark="z1"/> x equals 2 and
                <bookmark mark="z2"/> at x equals negative 1.
                We can<bookmark mark="cords"/> also verify this graphically: When we look at the <bookmark mark="plot"/>plot of the function,
                we can see that one of the zeros is at<bookmark mark="zg1"/> x equals 2, and the other one is at<bookmark mark="zg2"/> x equals negative 1.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("2")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("1")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            cursor.blinking=False
            x,y,_ = b1.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2")
            x,y,_ = b2.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1b")
            cursor.blinking=False
            x,y,_ = b1b.get_center()+0.6*DOWN
            self.play(Write(b1b), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2b")
            x,y,_ = b2b.get_center()+0.6*DOWN
            self.play(Write(b2b), CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("arrow")
            cursor.blinking=False
            x,y,_ = a.get_center()+0.4*RIGHT
            self.play(Write(a), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            cursor.blinking=False
            x,y,_ = sol[1].get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("z2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Write(cords), calcs.animate.next_to(cords, DOWN, buff=0.6))

            self.wait_until_bookmark("plot")
            cursor.blinking=False
            x,y,_ = g.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g.get_end())))
            self.play(Create(g))
            cursor.blinking=True

            self.wait_until_bookmark("zg1")
            cursor.blinking=False
            x,y,_ = plane.c2p(2,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))

            self.wait_until_bookmark("zg2")
            x,y,_ = plane.c2p(-1,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))
            self.wait(0.5)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_5_I_5_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x-", "2)", "\\cdot", "(x+", "1", ")", color=c1t, font_size=fs2)
        self.add(f1)
        b1 = VGroup(f1[3], f1[4])
        b2 = VGroup(f1[-3], f1[-2], f1[-1])
        b1b = MathTex("\\underbrace{(x-2)}_{=0\\text{ if }x=2}", color=c1t, font_size=fs2).move_to(b1)
        b2b = MathTex("\\underbrace{(x+1)}_{=0\\text{ if }x=-1}", color=c1t, font_size=fs2).move_to(b2)
        b1b.shift(b1.get_top()-b1b.get_top())
        b2b.shift(b2.get_top()-b2b.get_top())
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.6)
        sol = Tex("Zeros at ", "$x=2$", " and ", "$x=-1$", color=c1t, font_size=fs3).next_to(a, DOWN, buff=0.4)

        calcs = Group(f1, b1b, b2b, a, sol)

        f = lambda x: (x-2)*(x+1)
        g = plane.plot(f, color=BLUE, x_range=[-2.2,2.2,0.001])

        # Action Sequence
        with self.voiceover(
                text="""
                Yes, that's exactly what the factored form is good for.
                Let's go back to our example function. <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x minus <bookmark mark="2"/>2 close bracket times
                open bracket <bookmark mark="x2"/>x plus <bookmark mark="1"/>1 close bracket.
                Say we want to determine the zeros of that function. F is written as a product of two factors.
                The first is the <bookmark mark="b1"/> bracket x minus 2, and the second is the <bookmark mark="b2"/> bracket x plus 1.
                Now for the function to be zero, we need the product to be zero, which is the case if at least
                one of the factors is zero. The first factor is zero <bookmark mark="b1b"/>if x equals 2, an the second factor is zero
                <bookmark mark="b2b"/>if x equals negative 1.
                This means <bookmark mark="arrow"/> that the zeros of the function are at<bookmark mark="z1"/> x equals 2 and
                <bookmark mark="z2"/> at x equals negative 1.
                We can<bookmark mark="cords"/> also verify this graphically: When we look at the <bookmark mark="plot"/>plot of the function,
                we can see that one of the zeros is at<bookmark mark="zg1"/> x equals 2, and the other one is at<bookmark mark="zg2"/> x equals negative 1.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("2")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("1")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            cursor.blinking=False
            x,y,_ = b1.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2")
            x,y,_ = b2.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1b")
            cursor.blinking=False
            x,y,_ = b1b.get_center()+0.6*DOWN
            self.play(Write(b1b), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2b")
            x,y,_ = b2b.get_center()+0.6*DOWN
            self.play(Write(b2b), CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("arrow")
            cursor.blinking=False
            x,y,_ = a.get_center()+0.4*RIGHT
            self.play(Write(a), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            cursor.blinking=False
            x,y,_ = sol[1].get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("z2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Write(cords), calcs.animate.next_to(cords, DOWN, buff=0.6))

            self.wait_until_bookmark("plot")
            cursor.blinking=False
            x,y,_ = g.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g.get_end())))
            self.play(Create(g))
            cursor.blinking=True

            self.wait_until_bookmark("zg1")
            cursor.blinking=False
            x,y,_ = plane.c2p(2,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))

            self.wait_until_bookmark("zg2")
            x,y,_ = plane.c2p(-1,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))
            self.wait(0.5)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_5_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x-", "2)", "\\cdot", "(x+", "1", ")", color=c1t, font_size=fs2)
        self.add(f1)
        b1 = VGroup(f1[3], f1[4])
        b2 = VGroup(f1[-3], f1[-2], f1[-1])
        b1b = MathTex("\\underbrace{(x-2)}_{=0\\text{ if }x=2}", color=c1t, font_size=fs2).move_to(b1)
        b2b = MathTex("\\underbrace{(x+1)}_{=0\\text{ if }x=-1}", color=c1t, font_size=fs2).move_to(b2)
        b1b.shift(b1.get_top()-b1b.get_top())
        b2b.shift(b2.get_top()-b2b.get_top())
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.6)
        sol = Tex("Zeros at ", "$x=2$", " and ", "$x=-1$", color=c1t, font_size=fs3).next_to(a, DOWN, buff=0.4)

        calcs = Group(f1, b1b, b2b, a, sol)

        f = lambda x: (x-2)*(x+1)
        g = plane.plot(f, color=BLUE, x_range=[-2.2,2.2,0.001])

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not what the factored form is good for.
                Let's go back to our example function. <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x minus <bookmark mark="2"/>2 close bracket times
                open bracket <bookmark mark="x2"/>x plus <bookmark mark="1"/>1 close bracket.
                Say we want to determine the zeros of that function. F is written as a product of two factors.
                The first is the <bookmark mark="b1"/> bracket x minus 2, and the second is the <bookmark mark="b2"/> bracket x plus 1.
                Now for the function to be zero, we need the product to be zero, which is the case if at least
                one of the factors is zero. The first factor is zero <bookmark mark="b1b"/>if x equals 2, an the second factor is zero
                <bookmark mark="b2b"/>if x equals negative 1.
                This means <bookmark mark="arrow"/> that the zeros of the function are at<bookmark mark="z1"/> x equals 2 and
                <bookmark mark="z2"/> at x equals negative 1.
                We can<bookmark mark="cords"/> also verify this graphically: When we look at the <bookmark mark="plot"/>plot of the function,
                we can see that one of the zeros is at<bookmark mark="zg1"/> x equals 2, and the other one is at<bookmark mark="zg2"/> x equals negative 1.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("2")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("1")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            cursor.blinking=False
            x,y,_ = b1.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2")
            x,y,_ = b2.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1b")
            cursor.blinking=False
            x,y,_ = b1b.get_center()+0.6*DOWN
            self.play(Write(b1b), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2b")
            x,y,_ = b2b.get_center()+0.6*DOWN
            self.play(Write(b2b), CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("arrow")
            cursor.blinking=False
            x,y,_ = a.get_center()+0.4*RIGHT
            self.play(Write(a), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            cursor.blinking=False
            x,y,_ = sol[1].get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("z2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Write(cords), calcs.animate.next_to(cords, DOWN, buff=0.6))

            self.wait_until_bookmark("plot")
            cursor.blinking=False
            x,y,_ = g.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g.get_end())))
            self.play(Create(g))
            cursor.blinking=True

            self.wait_until_bookmark("zg1")
            cursor.blinking=False
            x,y,_ = plane.c2p(2,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))

            self.wait_until_bookmark("zg2")
            x,y,_ = plane.c2p(-1,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))
            self.wait(0.5)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_4_5_I_6_q = SophiaTaskDefinition(
    answerOptions = ["(-2,-3)", "(2,-3)", "(-2,3)", "(2,3)"],
    correctAnswerIndex = 2,
    questionText = "Where are the two zeros of $f(x)=(x+2)(x-3)$?"
)
class Func_4_5_I_6_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x+", "2)", "\\cdot", "(x-", "3", ")", color=c1t, font_size=fs2)

        # Action Sequence
        with self.voiceover(
                text="""
                Look at this quadratic function in factored form <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="2"/>2 close bracket times
                open bracket <bookmark mark="x2"/>x minus <bookmark mark="3"/>3 close bracket.
                What are the zeroes of this function?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("2")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("3")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_4_5_I_6_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")

        #Create the coordinate system
        cords = self.add_cords([-3,3, 1], [-10, 10, 2], x_ticks=[-3,-2,-1,1,2,3],y_ticks=[-8,-4,4,8]).shift(DOWN*0.6)
        plane = cords[0]

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True).shift(UP)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x+", "2)", "\\cdot", "(x-", "3", ")", color=c1t, font_size=fs2)
        self.add(f1)
        b1 = VGroup(f1[3], f1[4])
        b2 = VGroup(f1[-3], f1[-2], f1[-1])
        b1b = MathTex("\\underbrace{(x+2)}_{0\\text{ if }x=-2}", color=c1t, font_size=fs2).move_to(b1)
        b2b = MathTex("\\underbrace{(x-3)}_{0\\text{ if }x=3}", color=c1t, font_size=fs2).move_to(b2)
        b1b.shift(b1.get_top()-b1b.get_top())
        b2b.shift(b2.get_top()-b2b.get_top())
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.6)
        sol = Tex("Zeros at ", "$x=-2$", " and ", "$x=3$", color=c1t, font_size=fs3).next_to(a, DOWN, buff=0.4)

        calcs = Group(f1, b1b, b2b, a, sol)

        f = lambda x: (x+2)*(x-3)
        g = plane.plot(f, color=BLUE, x_range=[-3.1,3.1,0.001])

        # Action Sequence
        with self.voiceover(
                text="""
                No, those are not the two zeros.
                So look at the function <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="2"/>2 close bracket times
                open bracket <bookmark mark="x2"/>x minus <bookmark mark="3"/>3 close bracket.
                Say we want to determine the zeros of that function. f is written as a product of two factors.
                The first is the <bookmark mark="b1"/> bracket x plus 2, and the second is the <bookmark mark="b2"/> bracket x minus 3.
                Now for the function to be zero, we need the product to be zero, which is the case if at least
                one of the factors is zero. The first factor is zero <bookmark mark="b1b"/>if x equals negative 2, an the second factor is zero
                <bookmark mark="b2b"/>if x equals 3.
                This means <bookmark mark="arrow"/> that the zeros of the function are at<bookmark mark="z1"/> x equals negative 2 and
                <bookmark mark="z2"/> at x equals 3.
                We can<bookmark mark="cords"/> also verify this graphically: When we look at the <bookmark mark="plot"/>plot of the function,
                we can see that one of the zeros is at<bookmark mark="zg1"/> x equals negative 2, and the other one is at<bookmark mark="zg2"/> x equals 3.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("2")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("3")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            cursor.blinking=False
            x,y,_ = b1.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2")
            x,y,_ = b2.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1b")
            cursor.blinking=False
            x,y,_ = b1b.get_center()+0.6*DOWN
            self.play(Write(b1b), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2b")
            x,y,_ = b2b.get_center()+0.6*DOWN
            self.play(Write(b2b), CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("arrow")
            cursor.blinking=False
            x,y,_ = a.get_center()+0.4*RIGHT
            self.play(Write(a), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            cursor.blinking=False
            x,y,_ = sol[1].get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("z2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Write(cords), calcs.animate.next_to(cords, DOWN, buff=0.6))

            self.wait_until_bookmark("plot")
            cursor.blinking=False
            x,y,_ = g.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g.get_end())))
            self.play(Create(g))
            cursor.blinking=True

            self.wait_until_bookmark("zg1")
            cursor.blinking=False
            x,y,_ = plane.c2p(-2,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))

            self.wait_until_bookmark("zg2")
            x,y,_ = plane.c2p(3,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))
            self.wait(0.5)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_6_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")

        #Create the coordinate system
        cords = self.add_cords([-3,3, 1], [-10, 10, 2], x_ticks=[-3,-2,-1,1,2,3],y_ticks=[-8,-4,4,8]).shift(DOWN*0.6)
        plane = cords[0]

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True).shift(UP)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x+", "2)", "\\cdot", "(x-", "3", ")", color=c1t, font_size=fs2)
        self.add(f1)
        b1 = VGroup(f1[3], f1[4])
        b2 = VGroup(f1[-3], f1[-2], f1[-1])
        b1b = MathTex("\\underbrace{(x+2)}_{0\\text{ if }x=-2}", color=c1t, font_size=fs2).move_to(b1)
        b2b = MathTex("\\underbrace{(x-3)}_{0\\text{ if }x=3}", color=c1t, font_size=fs2).move_to(b2)
        b1b.shift(b1.get_top()-b1b.get_top())
        b2b.shift(b2.get_top()-b2b.get_top())
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.6)
        sol = Tex("Zeros at ", "$x=-2$", " and ", "$x=3$", color=c1t, font_size=fs3).next_to(a, DOWN, buff=0.4)

        calcs = Group(f1, b1b, b2b, a, sol)

        f = lambda x: (x+2)*(x-3)
        g = plane.plot(f, color=BLUE, x_range=[-3.1,3.1,0.001])

        # Action Sequence
        with self.voiceover(
                text="""
                No, those are not the two zeros.
                So look at the function <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="2"/>2 close bracket times
                open bracket <bookmark mark="x2"/>x minus <bookmark mark="3"/>3 close bracket.
                Say we want to determine the zeros of that function. f is written as a product of two factors.
                The first is the <bookmark mark="b1"/> bracket x plus 2, and the second is the <bookmark mark="b2"/> bracket x minus 3.
                Now for the function to be zero, we need the product to be zero, which is the case if at least
                one of the factors is zero. The first factor is zero <bookmark mark="b1b"/>if x equals negative 2, an the second factor is zero
                <bookmark mark="b2b"/>if x equals 3.
                This means <bookmark mark="arrow"/> that the zeros of the function are at<bookmark mark="z1"/> x equals negative 2 and
                <bookmark mark="z2"/> at x equals 3.
                We can<bookmark mark="cords"/> also verify this graphically: When we look at the <bookmark mark="plot"/>plot of the function,
                we can see that one of the zeros is at<bookmark mark="zg1"/> x equals negative 2, and the other one is at<bookmark mark="zg2"/> x equals 3.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("2")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("3")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            cursor.blinking=False
            x,y,_ = b1.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2")
            x,y,_ = b2.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1b")
            cursor.blinking=False
            x,y,_ = b1b.get_center()+0.6*DOWN
            self.play(Write(b1b), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2b")
            x,y,_ = b2b.get_center()+0.6*DOWN
            self.play(Write(b2b), CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("arrow")
            cursor.blinking=False
            x,y,_ = a.get_center()+0.4*RIGHT
            self.play(Write(a), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            cursor.blinking=False
            x,y,_ = sol[1].get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("z2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Write(cords), calcs.animate.next_to(cords, DOWN, buff=0.6))

            self.wait_until_bookmark("plot")
            cursor.blinking=False
            x,y,_ = g.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g.get_end())))
            self.play(Create(g))
            cursor.blinking=True

            self.wait_until_bookmark("zg1")
            cursor.blinking=False
            x,y,_ = plane.c2p(-2,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))

            self.wait_until_bookmark("zg2")
            x,y,_ = plane.c2p(3,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))
            self.wait(0.5)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)



class Func_4_5_I_6_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")

        #Create the coordinate system
        cords = self.add_cords([-3,3, 1], [-10, 10, 2], x_ticks=[-3,-2,-1,1,2,3],y_ticks=[-8,-4,4,8]).shift(DOWN*0.6)
        plane = cords[0]

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True).shift(UP)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x+", "2)", "\\cdot", "(x-", "3", ")", color=c1t, font_size=fs2)
        self.add(f1)
        b1 = VGroup(f1[3], f1[4])
        b2 = VGroup(f1[-3], f1[-2], f1[-1])
        b1b = MathTex("\\underbrace{(x+2)}_{0\\text{ if }x=-2}", color=c1t, font_size=fs2).move_to(b1)
        b2b = MathTex("\\underbrace{(x-3)}_{0\\text{ if }x=3}", color=c1t, font_size=fs2).move_to(b2)
        b1b.shift(b1.get_top()-b1b.get_top())
        b2b.shift(b2.get_top()-b2b.get_top())
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.6)
        sol = Tex("Zeros at ", "$x=-2$", " and ", "$x=3$", color=c1t, font_size=fs3).next_to(a, DOWN, buff=0.4)

        calcs = Group(f1, b1b, b2b, a, sol)

        f = lambda x: (x+2)*(x-3)
        g = plane.plot(f, color=BLUE, x_range=[-3.1,3.1,0.001])

        # Action Sequence
        with self.voiceover(
                text="""
                Exactly, those are the two zeros.
                So look at the function <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="2"/>2 close bracket times
                open bracket <bookmark mark="x2"/>x minus <bookmark mark="3"/>3 close bracket.
                Say we want to determine the zeros of that function. f is written as a product of two factors.
                The first is the <bookmark mark="b1"/> bracket x plus 2, and the second is the <bookmark mark="b2"/> bracket x minus 3.
                Now for the function to be zero, we need the product to be zero, which is the case if at least
                one of the factors is zero. The first factor is zero <bookmark mark="b1b"/>if x equals negative 2, an the second factor is zero
                <bookmark mark="b2b"/>if x equals 3.
                This means <bookmark mark="arrow"/> that the zeros of the function are at<bookmark mark="z1"/> x equals negative 2 and
                <bookmark mark="z2"/> at x equals 3.
                We can<bookmark mark="cords"/> also verify this graphically: When we look at the <bookmark mark="plot"/>plot of the function,
                we can see that one of the zeros is at<bookmark mark="zg1"/> x equals negative 2, and the other one is at<bookmark mark="zg2"/> x equals 3.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("2")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("3")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            cursor.blinking=False
            x,y,_ = b1.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2")
            x,y,_ = b2.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1b")
            cursor.blinking=False
            x,y,_ = b1b.get_center()+0.6*DOWN
            self.play(Write(b1b), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2b")
            x,y,_ = b2b.get_center()+0.6*DOWN
            self.play(Write(b2b), CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("arrow")
            cursor.blinking=False
            x,y,_ = a.get_center()+0.4*RIGHT
            self.play(Write(a), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            cursor.blinking=False
            x,y,_ = sol[1].get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("z2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Write(cords), calcs.animate.next_to(cords, DOWN, buff=0.6))

            self.wait_until_bookmark("plot")
            cursor.blinking=False
            x,y,_ = g.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g.get_end())))
            self.play(Create(g))
            cursor.blinking=True

            self.wait_until_bookmark("zg1")
            cursor.blinking=False
            x,y,_ = plane.c2p(-2,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))

            self.wait_until_bookmark("zg2")
            x,y,_ = plane.c2p(3,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))
            self.wait(0.5)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_6_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")

        #Create the coordinate system
        cords = self.add_cords([-3,3, 1], [-10, 10, 2], x_ticks=[-3,-2,-1,1,2,3],y_ticks=[-8,-4,4,8]).shift(DOWN*0.6)
        plane = cords[0]

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True).shift(UP)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x+", "2)", "\\cdot", "(x-", "3", ")", color=c1t, font_size=fs2)
        self.add(f1)
        b1 = VGroup(f1[3], f1[4])
        b2 = VGroup(f1[-3], f1[-2], f1[-1])
        b1b = MathTex("\\underbrace{(x+2)}_{0\\text{ if }x=-2}", color=c1t, font_size=fs2).move_to(b1)
        b2b = MathTex("\\underbrace{(x-3)}_{0\\text{ if }x=3}", color=c1t, font_size=fs2).move_to(b2)
        b1b.shift(b1.get_top()-b1b.get_top())
        b2b.shift(b2.get_top()-b2b.get_top())
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.6)
        sol = Tex("Zeros at ", "$x=-2$", " and ", "$x=3$", color=c1t, font_size=fs3).next_to(a, DOWN, buff=0.4)

        calcs = Group(f1, b1b, b2b, a, sol)

        f = lambda x: (x+2)*(x-3)
        g = plane.plot(f, color=BLUE, x_range=[-3.1,3.1,0.001])

        # Action Sequence
        with self.voiceover(
                text="""
                No, those are not the two zeros.
                So look at the function <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="2"/>2 close bracket times
                open bracket <bookmark mark="x2"/>x minus <bookmark mark="3"/>3 close bracket.
                Say we want to determine the zeros of that function. f is written as a product of two factors.
                The first is the <bookmark mark="b1"/> bracket x plus 2, and the second is the <bookmark mark="b2"/> bracket x minus 3.
                Now for the function to be zero, we need the product to be zero, which is the case if at least
                one of the factors is zero. The first factor is zero <bookmark mark="b1b"/>if x equals negative 2, an the second factor is zero
                <bookmark mark="b2b"/>if x equals 3.
                This means <bookmark mark="arrow"/> that the zeros of the function are at<bookmark mark="z1"/> x equals negative 2 and
                <bookmark mark="z2"/> at x equals 3.
                We can<bookmark mark="cords"/> also verify this graphically: When we look at the <bookmark mark="plot"/>plot of the function,
                we can see that one of the zeros is at<bookmark mark="zg1"/> x equals negative 2, and the other one is at<bookmark mark="zg2"/> x equals 3.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("2")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("3")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            cursor.blinking=False
            x,y,_ = b1.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2")
            x,y,_ = b2.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1b")
            cursor.blinking=False
            x,y,_ = b1b.get_center()+0.6*DOWN
            self.play(Write(b1b), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2b")
            x,y,_ = b2b.get_center()+0.6*DOWN
            self.play(Write(b2b), CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("arrow")
            cursor.blinking=False
            x,y,_ = a.get_center()+0.4*RIGHT
            self.play(Write(a), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            cursor.blinking=False
            x,y,_ = sol[1].get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("z2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Write(cords), calcs.animate.next_to(cords, DOWN, buff=0.6))

            self.wait_until_bookmark("plot")
            cursor.blinking=False
            x,y,_ = g.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g.get_end())))
            self.play(Create(g))
            cursor.blinking=True

            self.wait_until_bookmark("zg1")
            cursor.blinking=False
            x,y,_ = plane.c2p(-2,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))

            self.wait_until_bookmark("zg2")
            x,y,_ = plane.c2p(3,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy().clear_updaters().set_color(GREEN))
            self.wait(0.5)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

    
#####################################
#####################################
TASK_Func_4_5_I_7_q = SophiaTaskDefinition(
    answerOptions = ["(a,b)", "(0,b)", "(a,0)", "(-a,-b)"],
    correctAnswerIndex = 3,
    questionText = "Where are the two zeros of $f(x)=(x+a)(x+b)$?"
)
class Func_4_5_I_7_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x+", "a)", "\\cdot", "(x+", "b", ")", color=c1t, font_size=fs2)

        # Action Sequence
        with self.voiceover(
                text="""
                Now look at the general case of the factored form: <bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="a"/>"a" close bracket times
                open bracket <bookmark mark="x2"/>x plus <bookmark mark="b"/>b close bracket.
                What are the zeroes of this function?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("a")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("b")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_7_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")


        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True).shift(UP)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x+", "a)", "\\cdot", "(x+", "b", ")", color=c1t, font_size=fs2)
        self.add(f1)
        b1 = VGroup(f1[3], f1[4])
        b2 = VGroup(f1[-3], f1[-2], f1[-1])
        b1b = MathTex("\\underbrace{(x+a)}_{0\\text{ if }x=-a}", color=c1t, font_size=fs2).move_to(b1)
        b2b = MathTex("\\underbrace{(x+b)}_{0\\text{ if }x=-b}", color=c1t, font_size=fs2).move_to(b2)
        b1b.shift(b1.get_top()-b1b.get_top())
        b2b.shift(b2.get_top()-b2b.get_top())
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.6)
        sol = Tex("Zeros at ", "$x=-a$", " and ", "$x=-b$", color=c1t, font_size=fs3).next_to(a, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text="""
                No, those are not the two zeros.
                So look at the function<bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="a"/>"a" close bracket times
                open bracket <bookmark mark="x2"/>x plus <bookmark mark="b"/>b close bracket.
                Say we want to determine the zeros of that function. f is written as a product of two factors.
                The first is the <bookmark mark="b1"/> bracket x plus "a", and the second is the <bookmark mark="b2"/> bracket x plus b.
                Now for the function to be zero, we need the product to be zero, which is the case if at least
                one of the factors is zero. The first factor is zero <bookmark mark="b1b"/>if x equals negative a, an the second factor is zero
                <bookmark mark="b2b"/>if x equals negative b.
                This means <bookmark mark="arrow"/> that the zeros of the function are at<bookmark mark="z1"/> x equals negative "a" and
                <bookmark mark="z2"/> at x equals negative b.
                Now you can easily read off the zeros from the factored form. Cool, right?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("a")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("b")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            cursor.blinking=False
            x,y,_ = b1.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2")
            x,y,_ = b2.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1b")
            cursor.blinking=False
            x,y,_ = b1b.get_center()+0.6*DOWN
            self.play(Write(b1b), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2b")
            x,y,_ = b2b.get_center()+0.6*DOWN
            self.play(Write(b2b), CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("arrow")
            cursor.blinking=False
            x,y,_ = a.get_center()+0.4*RIGHT
            self.play(Write(a), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            cursor.blinking=False
            x,y,_ = sol[1].get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("z2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_7_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")


        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True).shift(UP)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x+", "a)", "\\cdot", "(x+", "b", ")", color=c1t, font_size=fs2)
        self.add(f1)
        b1 = VGroup(f1[3], f1[4])
        b2 = VGroup(f1[-3], f1[-2], f1[-1])
        b1b = MathTex("\\underbrace{(x+a)}_{0\\text{ if }x=-a}", color=c1t, font_size=fs2).move_to(b1)
        b2b = MathTex("\\underbrace{(x+b)}_{0\\text{ if }x=-b}", color=c1t, font_size=fs2).move_to(b2)
        b1b.shift(b1.get_top()-b1b.get_top())
        b2b.shift(b2.get_top()-b2b.get_top())
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.6)
        sol = Tex("Zeros at ", "$x=-a$", " and ", "$x=-b$", color=c1t, font_size=fs3).next_to(a, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text="""
                No, those are not the two zeros.
                So look at the function<bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="a"/>"a" close bracket times
                open bracket <bookmark mark="x2"/>x plus <bookmark mark="b"/>b close bracket.
                Say we want to determine the zeros of that function. f is written as a product of two factors.
                The first is the <bookmark mark="b1"/> bracket x plus "a", and the second is the <bookmark mark="b2"/> bracket x plus b.
                Now for the function to be zero, we need the product to be zero, which is the case if at least
                one of the factors is zero. The first factor is zero <bookmark mark="b1b"/>if x equals negative a, an the second factor is zero
                <bookmark mark="b2b"/>if x equals negative b.
                This means <bookmark mark="arrow"/> that the zeros of the function are at<bookmark mark="z1"/> x equals negative "a" and
                <bookmark mark="z2"/> at x equals negative b.
                Now you can easily read off the zeros from the factored form. Cool, right?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("a")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("b")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            cursor.blinking=False
            x,y,_ = b1.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2")
            x,y,_ = b2.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1b")
            cursor.blinking=False
            x,y,_ = b1b.get_center()+0.6*DOWN
            self.play(Write(b1b), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2b")
            x,y,_ = b2b.get_center()+0.6*DOWN
            self.play(Write(b2b), CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("arrow")
            cursor.blinking=False
            x,y,_ = a.get_center()+0.4*RIGHT
            self.play(Write(a), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            cursor.blinking=False
            x,y,_ = sol[1].get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("z2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_7_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")


        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True).shift(UP)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x+", "a)", "\\cdot", "(x+", "b", ")", color=c1t, font_size=fs2)
        self.add(f1)
        b1 = VGroup(f1[3], f1[4])
        b2 = VGroup(f1[-3], f1[-2], f1[-1])
        b1b = MathTex("\\underbrace{(x+a)}_{0\\text{ if }x=-a}", color=c1t, font_size=fs2).move_to(b1)
        b2b = MathTex("\\underbrace{(x+b)}_{0\\text{ if }x=-b}", color=c1t, font_size=fs2).move_to(b2)
        b1b.shift(b1.get_top()-b1b.get_top())
        b2b.shift(b2.get_top()-b2b.get_top())
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.6)
        sol = Tex("Zeros at ", "$x=-a$", " and ", "$x=-b$", color=c1t, font_size=fs3).next_to(a, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text="""
                No, those are not the two zeros.
                So look at the function<bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="a"/>"a" close bracket times
                open bracket <bookmark mark="x2"/>x plus <bookmark mark="b"/>b close bracket.
                Say we want to determine the zeros of that function. f is written as a product of two factors.
                The first is the <bookmark mark="b1"/> bracket x plus "a", and the second is the <bookmark mark="b2"/> bracket x plus b.
                Now for the function to be zero, we need the product to be zero, which is the case if at least
                one of the factors is zero. The first factor is zero <bookmark mark="b1b"/>if x equals negative a, an the second factor is zero
                <bookmark mark="b2b"/>if x equals negative b.
                This means <bookmark mark="arrow"/> that the zeros of the function are at<bookmark mark="z1"/> x equals negative "a" and
                <bookmark mark="z2"/> at x equals negative b.
                Now you can easily read off the zeros from the factored form. Cool, right?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("a")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("b")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            cursor.blinking=False
            x,y,_ = b1.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2")
            x,y,_ = b2.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1b")
            cursor.blinking=False
            x,y,_ = b1b.get_center()+0.6*DOWN
            self.play(Write(b1b), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2b")
            x,y,_ = b2b.get_center()+0.6*DOWN
            self.play(Write(b2b), CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("arrow")
            cursor.blinking=False
            x,y,_ = a.get_center()+0.4*RIGHT
            self.play(Write(a), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            cursor.blinking=False
            x,y,_ = sol[1].get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("z2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_5_I_7_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Factored Form")


        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True).shift(UP)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f","(x)", "=", "(x+", "a)", "\\cdot", "(x+", "b", ")", color=c1t, font_size=fs2)
        self.add(f1)
        b1 = VGroup(f1[3], f1[4])
        b2 = VGroup(f1[-3], f1[-2], f1[-1])
        b1b = MathTex("\\underbrace{(x+a)}_{0\\text{ if }x=-a}", color=c1t, font_size=fs2).move_to(b1)
        b2b = MathTex("\\underbrace{(x+b)}_{0\\text{ if }x=-b}", color=c1t, font_size=fs2).move_to(b2)
        b1b.shift(b1.get_top()-b1b.get_top())
        b2b.shift(b2.get_top()-b2b.get_top())
        a = MathTex("\\Downarrow", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.6)
        sol = Tex("Zeros at ", "$x=-a$", " and ", "$x=-b$", color=c1t, font_size=fs3).next_to(a, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text="""
                That is correct, great job!
                So look at the function<bookmark mark="f"/> f of <bookmark mark="x"/>x equals
                open bracket <bookmark mark="x1"/>x plus <bookmark mark="a"/>"a" close bracket times
                open bracket <bookmark mark="x2"/>x plus <bookmark mark="b"/>b close bracket.
                Say we want to determine the zeros of that function. f is written as a product of two factors.
                The first is the <bookmark mark="b1"/> bracket x plus "a", and the second is the <bookmark mark="b2"/> bracket x plus b.
                Now for the function to be zero, we need the product to be zero, which is the case if at least
                one of the factors is zero. The first factor is zero <bookmark mark="b1b"/>if x equals negative a, an the second factor is zero
                <bookmark mark="b2b"/>if x equals negative b.
                This means <bookmark mark="arrow"/> that the zeros of the function are at<bookmark mark="z1"/> x equals negative "a" and
                <bookmark mark="z2"/> at x equals negative b.
                Now you can easily read off the zeros from the factored form. Cool, right?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("a")
            x,y,_ = f1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("x2")
            x,y,_ = f1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("b")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("b1")
            cursor.blinking=False
            x,y,_ = b1.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2")
            x,y,_ = b2.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("b1b")
            cursor.blinking=False
            x,y,_ = b1b.get_center()+0.6*DOWN
            self.play(Write(b1b), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2b")
            x,y,_ = b2b.get_center()+0.6*DOWN
            self.play(Write(b2b), CursorMoveToCurved(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("arrow")
            cursor.blinking=False
            x,y,_ = a.get_center()+0.4*RIGHT
            self.play(Write(a), CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            cursor.blinking=False
            x,y,_ = sol[1].get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("z2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.4)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
class Func_4_5_I_8(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Forms of Quadratic Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        f1 = MathTex("f", "(x)", "=", "a", "x", "^2", "+", "b", "x", "+", "c", color=c1t, font_size=fs2).next_to(title, DOWN, buff=1.6)
        f2 = MathTex("f", "(x)", "=", "a","(x+", "b",")^2", "+", "c", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.4)
        f3 = MathTex("f", "(x)", "=", "(x-", "a", ")", "\\cdot", "(x-", "b", ")", color=c1t, font_size=fs2).next_to(f2, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, quick recap of the forms of quadratic functions we have seen thus far.
                First, there is the standard form <bookmark mark="f1"/> f of <bookmark mark="x1"/>x equals
                <bookmark mark="a1"/>a times x squared <bookmark mark="b1"/>plus b times x <bookmark mark="c1"/>plus c.
                It is useful for quickly recognizing the coefficients of the x squared term, the x term and the constant.
                Then there is the vertex form <bookmark mark="f2"/> f of <bookmark mark="x2"/>x equals
                <bookmark mark="a2"/>a times open <bookmark mark="x21"/>bracket x <bookmark mark="b2"/>plus b close bracket squared <bookmark mark="c2"/>plus c.
                It is used, because you can easily read of the location of the vertex from it.
                And finally, there is the factored form <bookmark mark="f3"/> f of <bookmark mark="x3"/>x equals
                open <bookmark mark="x31"/>bracket x <bookmark mark="a3"/>minus a close bracket times
                open <bookmark mark="x32"/>bracket x <bookmark mark="b3"/>minus b close bracket. The factored form is useful,
                because it allows you to quickly read off the zeros of the function. So three different forms, three different
                sets of advantages and disadvantages.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f1")
            cursor.blinking=False
            x,y,_ = f1[0].get_center()+0.4*DOWN
            self.play(Write(f1), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x1")
            x,y,_ = f1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("a1")
            x,y,_ = f1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("b1")
            x,y,_ = f1[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("c1")
            x,y,_ = f1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("f2")
            cursor.blinking=False
            x,y,_ = f2[0].get_center()+0.4*DOWN
            self.play(Write(f2), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x2")
            x,y,_ = f2[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("a2")
            x,y,_ = f2[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("x21")
            x,y,_ = f2[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("b2")
            x,y,_ = f2[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("c2")
            x,y,_ = f2[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

            self.wait_until_bookmark("f3")
            cursor.blinking=False
            x,y,_ = f3[0].get_center()+0.4*DOWN
            self.play(Write(f3), CursorMoveTo(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("x3")
            x,y,_ = f3[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.2)

            self.wait_until_bookmark("a3")
            x,y,_ = f3[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)

            self.wait_until_bookmark("b3")
            x,y,_ = f3[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.4)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
##### Prototypes ####################
#####################################
#####################################
PROTOTYPES = [
    PagePrototypeVideo.from_scene(Func_4_5_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_5_I_1_q, Func_4_5_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_5_I_1_a),
    PagePrototypeVideo.from_scene(Func_4_5_I_1_b),
    PagePrototypeVideo.from_scene(Func_4_5_I_1_c),
    PagePrototypeVideo.from_scene(Func_4_5_I_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_5_I_2_q, Func_4_5_I_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_5_I_2_a),
    PagePrototypeVideo.from_scene(Func_4_5_I_2_b),
    PagePrototypeVideo.from_scene(Func_4_5_I_2_c),
    PagePrototypeVideo.from_scene(Func_4_5_I_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_5_I_3_q, Func_4_5_I_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_5_I_3_a),
    PagePrototypeVideo.from_scene(Func_4_5_I_3_b),
    PagePrototypeVideo.from_scene(Func_4_5_I_3_c),
    PagePrototypeVideo.from_scene(Func_4_5_I_3_d),
    PagePrototypeVideo.from_scene(Func_4_5_I_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_5_I_4_q, Func_4_5_I_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_5_I_4_a),
    PagePrototypeVideo.from_scene(Func_4_5_I_4_b),
    PagePrototypeVideo.from_scene(Func_4_5_I_4_c),
    PagePrototypeVideo.from_scene(Func_4_5_I_4_d),
    PagePrototypeVideo.from_scene(Func_4_5_I_5_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_5_I_5_q, Func_4_5_I_5_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_5_I_5_a),
    PagePrototypeVideo.from_scene(Func_4_5_I_5_b),
    PagePrototypeVideo.from_scene(Func_4_5_I_5_c),
    PagePrototypeVideo.from_scene(Func_4_5_I_6_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_5_I_6_q, Func_4_5_I_6_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_5_I_6_a),
    PagePrototypeVideo.from_scene(Func_4_5_I_6_b),
    PagePrototypeVideo.from_scene(Func_4_5_I_6_c),
    PagePrototypeVideo.from_scene(Func_4_5_I_6_d),
    PagePrototypeVideo.from_scene(Func_4_5_I_7_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_4_5_I_7_q, Func_4_5_I_7_q.__name__),
    PagePrototypeVideo.from_scene(Func_4_5_I_7_a),
    PagePrototypeVideo.from_scene(Func_4_5_I_7_b),
    PagePrototypeVideo.from_scene(Func_4_5_I_7_c),
    PagePrototypeVideo.from_scene(Func_4_5_I_7_d),
    PagePrototypeVideo.from_scene(Func_4_5_I_8),
]
scenes/Func/Func_4: Quadratic Functions/Func_4_5.py
Sophia-Edu-Labs/sophia-math
# # 4_6: Quadratic Functions: Three points to parabola.

# # Import necessary libraries and modules
# from abc import ABCMeta, abstractmethod
# from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
# from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
#                                           CursorPositionTracking,
#                                           CursorResizeDefault, SophiaScene,
#                                           assets_folder, avatars_folder,
#                                           generated_avatars_folder, AltCursor,
#                                           SophiaCursorScene, CursorMoveTo,
#                                           CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
# from sophialib.styles.styleconstants import *
# from sophialib.styles.sophiaobjects import *
# from manim import *
# from PIL import Image
# import numpy as np
# from pathlib import Path
# from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition



# #####################################
# #####################################
# TASK_Func_4_6_I_1_q = SophiaTaskDefinition(
#     answerOptions = ["$f(x)=2x+2$", "f(x)=x+4", "f(x)=2x", "f(x)=x^2"],
#     correctAnswerIndex = 2,
#     questionText = "What is the term of the linear function that goes through (0,0) and (2,4)?"
# )
# class Func_4_6_I_1_q(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         self.add_title("Quadratic Functions")
        
#         #Create the coordinate system
#         cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
#         plane = cords[0]

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         x,y,_ = plane.c2p(0,-4)
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = False
#         cursor.add_updater(cursor_sound_updater)
#         cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
#         self.add(cursor)

#         f = MathTex("f", "(x)", "=", "a", "x", "+","b", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=1)


#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 We want to find out: How many points do you need, to determine the term of a quadratic function?
#                 If you have a linear function, you can compute the term and plot it using only two points
#                 on that line. <bookmark mark="cords"/>As an example, say f goes through the <bookmark mark="point1"/>
#                 points (0, 0)and <bookmark mark="point2"/>(2, 4). From these <bookmark mark="cursorBack"/>two points, we can
#                 infer the termm of the linear function <bookmark mark="f"/>f of <bookmark mark="fx"/>x equals
#                 <bookmark mark="a"/>a x plus <bookmark mark="b"/>b.
#                 What is it?
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("cords")
#             self.play(Create(cords))

#             self.wait_until_bookmark("point1")
#             x,y,_ = plane.c2p(0,0)
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             self.add(cursor.copy().set_color(GREEN).clear_updaters())

#             self.wait_until_bookmark("point2")
#             x,y,_ = plane.c2p(2,4)
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             self.add(cursor.copy().set_color(GREEN).clear_updaters())

#             self.wait_until_bookmark("cursorBack")
#             x,y,_ = plane.c2p(0,-4)
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("f")
#             cursor.blinking=False
#             x,y,_ = f[0].get_center()+0.4*DOWN
#             self.play(Create(f), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("fx")
#             x,y,_ = f[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a")
#             x,y,_ = f[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("b")
#             x,y,_ = f[6].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)


# class Func_4_6_I_1_a(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         self.add_title("Quadratic Functions")
        
#         #Create the coordinate system
#         cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
#         plane = cords[0]
#         self.add(cords)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         x,y,_ = plane.c2p(0,-4)
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = False
#         cursor.add_updater(cursor_sound_updater)
#         cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
#         self.add(cursor)

#         f = MathTex("f", "(x)", "=", "a", "x", "+","b", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.4)
#         fTrue = MathTex("f", "(x)", "=", "2", "x", color=c1t, font_size=fs2).move_to(f)
#         f1 = MathTex("f", "(0)", "=", "a\\cdot0", "+b=", "0", color=c1t, font_size=fs2).next_to(f, DOWN, buff=0.4)
#         follows = Tex("$\\Rightarrow$ b = 0", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.1)
#         f2 = MathTex("f", "(2)", "=", "a", "\\cdot2", "=4", color=c1t, font_size=fs2).next_to(follows, DOWN, buff=0.4)
#         follows2 = Tex("$\\Rightarrow$ a = 2", color=c1t, font_size=fs2).next_to(f2, DOWN, buff=0.1)
#         c1 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(0,0))
#         c2 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(2,4))

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not the right function term. 
#                 So we know the term has the form<bookmark mark="f"/> f of<bookmark mark="x"/> x equals<bookmark mark="a"/>
#                 a x<bookmark mark="b"/> plus b.
#                 Now, we can plug the two points into the term. The first point<bookmark mark="p1"/> is (0, 0), so we get <bookmark mark="f2"/>
#                 f of<bookmark mark="02"/> 0 equals<bookmark mark="a2"/> "a" times<bookmark mark="022"/> 0 plus b.
#                 We can see that<bookmark mark="follows1"/> b equals 0, because 0 times anything is 0.
#                 The second point<bookmark mark="p2"/> is (2, 4), so we get<bookmark mark="f3"/> f of<bookmark mark="03"/> 2
#                 equals<bookmark mark="a3"/> "a" times<bookmark mark="023"/> 2 which is equal to<bookmark mark="b3"/> 4.
#                 Now we can see that<bookmark mark="follows2"/> "a" equals 2, because we need "a" times two to be equal to four.
#                 So, the linear function that goes through the two points<bookmark mark="fin"/> is f of x equals 2 x.
#                 """
#         ) as tracker:
            

#             self.wait_until_bookmark("f")
#             cursor.blinking=False
#             x,y,_ = f[0].get_center()+0.4*DOWN
#             self.play(Create(f), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("x")
#             x,y,_ = f[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a")
#             x,y,_ = f[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("b")
#             x,y,_ = f[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("p1")
#             cursor.blinking=False
#             x,y,_ = plane.c2p(0,0)
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             self.add(c1)
#             cursor.blinking=True

#             self.wait_until_bookmark("f2")
#             cursor.blinking=False
#             x,y,_ = f1[0].get_center()+0.4*DOWN
#             self.play(Create(f1), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("02")
#             x,y,_ = f1[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a2")
#             x,y,_ = f1[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("022")
#             x,y,_ = f1[4].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("follows1")
#             cursor.blinking=False
#             x,y,_ = follows.get_center()+0.4*DOWN
#             self.play(Write(follows), CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("p2")
#             cursor.blinking=False
#             x,y,_ = plane.c2p(2,4)
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             self.add(c2)
#             cursor.blinking=True

#             self.wait_until_bookmark("f3")
#             cursor.blinking=False
#             x,y,_ = f2[0].get_center()+0.4*DOWN
#             self.play(Create(f2), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("03")
#             x,y,_ = f2[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a3")
#             x,y,_ = f2[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("023")
#             x,y,_ = f2[4].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("b3")
#             x,y,_ = f2[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("follows2")
#             cursor.blinking=False
#             x,y,_ = follows2.get_center()+0.4*DOWN
#             self.play(Write(follows2), CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("fin")
#             cursor.blinking=False
#             x,y,_ = fTrue.get_center()+0.4*DOWN
#             self.play(ReplacementTransform(f,fTrue), CursorMoveTo(cursor,x,y), Unwrite(f1), Unwrite(f2), Unwrite(follows), Unwrite(follows2), run_time=0.3)
#             cursor.blinking=True

#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)


# class Func_4_6_I_1_b(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         self.add_title("Quadratic Functions")
        
#         #Create the coordinate system
#         cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
#         plane = cords[0]
#         self.add(cords)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         x,y,_ = plane.c2p(0,-4)
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = False
#         cursor.add_updater(cursor_sound_updater)
#         cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
#         self.add(cursor)

#         f = MathTex("f", "(x)", "=", "a", "x", "+","b", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.4)
#         fTrue = MathTex("f", "(x)", "=", "2", "x", color=c1t, font_size=fs2).move_to(f)
#         f1 = MathTex("f", "(0)", "=", "a\\cdot0", "+b=", "0", color=c1t, font_size=fs2).next_to(f, DOWN, buff=0.4)
#         follows = Tex("$\\Rightarrow$ b = 0", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.1)
#         f2 = MathTex("f", "(2)", "=", "a", "\\cdot2", "=4", color=c1t, font_size=fs2).next_to(follows, DOWN, buff=0.4)
#         follows2 = Tex("$\\Rightarrow$ a = 2", color=c1t, font_size=fs2).next_to(f2, DOWN, buff=0.1)
#         c1 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(0,0))
#         c2 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(2,4))

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not the right function term. 
#                 So we know the term has the form<bookmark mark="f"/> f of<bookmark mark="x"/> x equals<bookmark mark="a"/>
#                 a x<bookmark mark="b"/> plus b.
#                 Now, we can plug the two points into the term. The first point<bookmark mark="p1"/> is (0, 0), so we get <bookmark mark="f2"/>
#                 f of<bookmark mark="02"/> 0 equals<bookmark mark="a2"/> "a" times<bookmark mark="022"/> 0 plus b.
#                 We can see that<bookmark mark="follows1"/> b equals 0, because 0 times anything is 0.
#                 The second point<bookmark mark="p2"/> is (2, 4), so we get<bookmark mark="f3"/> f of<bookmark mark="03"/> 2
#                 equals<bookmark mark="a3"/> "a" times<bookmark mark="023"/> 2 which is equal to<bookmark mark="b3"/> 4.
#                 Now we can see that<bookmark mark="follows2"/> "a" equals 2, because we need "a" times two to be equal to four.
#                 So, the linear function that goes through the two points<bookmark mark="fin"/> is f of x equals 2 x.
#                 """
#         ) as tracker:
            

#             self.wait_until_bookmark("f")
#             cursor.blinking=False
#             x,y,_ = f[0].get_center()+0.4*DOWN
#             self.play(Create(f), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("x")
#             x,y,_ = f[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a")
#             x,y,_ = f[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("b")
#             x,y,_ = f[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("p1")
#             cursor.blinking=False
#             x,y,_ = plane.c2p(0,0)
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             self.add(c1)
#             cursor.blinking=True

#             self.wait_until_bookmark("f2")
#             cursor.blinking=False
#             x,y,_ = f1[0].get_center()+0.4*DOWN
#             self.play(Create(f1), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("02")
#             x,y,_ = f1[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a2")
#             x,y,_ = f1[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("022")
#             x,y,_ = f1[4].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("follows1")
#             cursor.blinking=False
#             x,y,_ = follows.get_center()+0.4*DOWN
#             self.play(Write(follows), CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("p2")
#             cursor.blinking=False
#             x,y,_ = plane.c2p(2,4)
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             self.add(c2)
#             cursor.blinking=True

#             self.wait_until_bookmark("f3")
#             cursor.blinking=False
#             x,y,_ = f2[0].get_center()+0.4*DOWN
#             self.play(Create(f2), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("03")
#             x,y,_ = f2[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a3")
#             x,y,_ = f2[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("023")
#             x,y,_ = f2[4].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("b3")
#             x,y,_ = f2[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("follows2")
#             cursor.blinking=False
#             x,y,_ = follows2.get_center()+0.4*DOWN
#             self.play(Write(follows2), CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("fin")
#             cursor.blinking=False
#             x,y,_ = fTrue.get_center()+0.4*DOWN
#             self.play(ReplacementTransform(f,fTrue), CursorMoveTo(cursor,x,y), Unwrite(f1), Unwrite(f2), Unwrite(follows), Unwrite(follows2), run_time=0.3)
#             cursor.blinking=True

#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)


# class Func_4_6_I_1_c(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         self.add_title("Quadratic Functions")
        
#         #Create the coordinate system
#         cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
#         plane = cords[0]
#         self.add(cords)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         x,y,_ = plane.c2p(0,-4)
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = False
#         cursor.add_updater(cursor_sound_updater)
#         cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
#         self.add(cursor)

#         f = MathTex("f", "(x)", "=", "a", "x", "+","b", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.4)
#         fTrue = MathTex("f", "(x)", "=", "2", "x", color=c1t, font_size=fs2).move_to(f)
#         f1 = MathTex("f", "(0)", "=", "a\\cdot0", "+b=", "0", color=c1t, font_size=fs2).next_to(f, DOWN, buff=0.4)
#         follows = Tex("$\\Rightarrow$ b = 0", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.1)
#         f2 = MathTex("f", "(2)", "=", "a", "\\cdot2", "=4", color=c1t, font_size=fs2).next_to(follows, DOWN, buff=0.4)
#         follows2 = Tex("$\\Rightarrow$ a = 2", color=c1t, font_size=fs2).next_to(f2, DOWN, buff=0.1)
#         c1 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(0,0))
#         c2 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(2,4))

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Yep, that's the right function term. 
#                 So we know the term has the form<bookmark mark="f"/> f of<bookmark mark="x"/> x equals<bookmark mark="a"/>
#                 a x<bookmark mark="b"/> plus b.
#                 Now, we can plug the two points into the term. The first point<bookmark mark="p1"/> is (0, 0), so we get <bookmark mark="f2"/>
#                 f of<bookmark mark="02"/> 0 equals<bookmark mark="a2"/> "a" times<bookmark mark="022"/> 0 plus b.
#                 We can see that<bookmark mark="follows1"/> b equals 0, because 0 times anything is 0.
#                 The second point<bookmark mark="p2"/> is (2, 4), so we get<bookmark mark="f3"/> f of<bookmark mark="03"/> 2
#                 equals<bookmark mark="a3"/> "a" times<bookmark mark="023"/> 2 which is equal to<bookmark mark="b3"/> 4.
#                 Now we can see that<bookmark mark="follows2"/> "a" equals 2, because we need "a" times two to be equal to four.
#                 So, the linear function that goes through the two points<bookmark mark="fin"/> is f of x equals 2 x.
#                 """
#         ) as tracker:
            

#             self.wait_until_bookmark("f")
#             cursor.blinking=False
#             x,y,_ = f[0].get_center()+0.4*DOWN
#             self.play(Create(f), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("x")
#             x,y,_ = f[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a")
#             x,y,_ = f[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("b")
#             x,y,_ = f[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("p1")
#             cursor.blinking=False
#             x,y,_ = plane.c2p(0,0)
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             self.add(c1)
#             cursor.blinking=True

#             self.wait_until_bookmark("f2")
#             cursor.blinking=False
#             x,y,_ = f1[0].get_center()+0.4*DOWN
#             self.play(Create(f1), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("02")
#             x,y,_ = f1[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a2")
#             x,y,_ = f1[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("022")
#             x,y,_ = f1[4].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("follows1")
#             cursor.blinking=False
#             x,y,_ = follows.get_center()+0.4*DOWN
#             self.play(Write(follows), CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("p2")
#             cursor.blinking=False
#             x,y,_ = plane.c2p(2,4)
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             self.add(c2)
#             cursor.blinking=True

#             self.wait_until_bookmark("f3")
#             cursor.blinking=False
#             x,y,_ = f2[0].get_center()+0.4*DOWN
#             self.play(Create(f2), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("03")
#             x,y,_ = f2[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a3")
#             x,y,_ = f2[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("023")
#             x,y,_ = f2[4].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("b3")
#             x,y,_ = f2[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("follows2")
#             cursor.blinking=False
#             x,y,_ = follows2.get_center()+0.4*DOWN
#             self.play(Write(follows2), CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("fin")
#             cursor.blinking=False
#             x,y,_ = fTrue.get_center()+0.4*DOWN
#             self.play(ReplacementTransform(f,fTrue), CursorMoveTo(cursor,x,y), Unwrite(f1), Unwrite(f2), Unwrite(follows), Unwrite(follows2), run_time=0.3)
#             cursor.blinking=True

#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)


# class Func_4_6_I_1_d(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         self.add_title("Quadratic Functions")
        
#         #Create the coordinate system
#         cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
#         plane = cords[0]
#         self.add(cords)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         x,y,_ = plane.c2p(0,-4)
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = False
#         cursor.add_updater(cursor_sound_updater)
#         cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
#         self.add(cursor)

#         f = MathTex("f", "(x)", "=", "a", "x", "+","b", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.4)
#         fTrue = MathTex("f", "(x)", "=", "2", "x", color=c1t, font_size=fs2).move_to(f)
#         f1 = MathTex("f", "(0)", "=", "a\\cdot0", "+b=", "0", color=c1t, font_size=fs2).next_to(f, DOWN, buff=0.4)
#         follows = Tex("$\\Rightarrow$ b = 0", color=c1t, font_size=fs2).next_to(f1, DOWN, buff=0.1)
#         f2 = MathTex("f", "(2)", "=", "a", "\\cdot2", "=4", color=c1t, font_size=fs2).next_to(follows, DOWN, buff=0.4)
#         follows2 = Tex("$\\Rightarrow$ a = 2", color=c1t, font_size=fs2).next_to(f2, DOWN, buff=0.1)
#         c1 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(0,0))
#         c2 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(2,4))

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not the right function term. 
#                 So we know the term has the form<bookmark mark="f"/> f of<bookmark mark="x"/> x equals<bookmark mark="a"/>
#                 a x<bookmark mark="b"/> plus b.
#                 Now, we can plug the two points into the term. The first point<bookmark mark="p1"/> is (0, 0), so we get <bookmark mark="f2"/>
#                 f of<bookmark mark="02"/> 0 equals<bookmark mark="a2"/> "a" times<bookmark mark="022"/> 0 plus b.
#                 We can see that<bookmark mark="follows1"/> b equals 0, because 0 times anything is 0.
#                 The second point<bookmark mark="p2"/> is (2, 4), so we get<bookmark mark="f3"/> f of<bookmark mark="03"/> 2
#                 equals<bookmark mark="a3"/> "a" times<bookmark mark="023"/> 2 which is equal to<bookmark mark="b3"/> 4.
#                 Now we can see that<bookmark mark="follows2"/> "a" equals 2, because we need "a" times two to be equal to four.
#                 So, the linear function that goes through the two points<bookmark mark="fin"/> is f of x equals 2 x.
#                 """
#         ) as tracker:
            

#             self.wait_until_bookmark("f")
#             cursor.blinking=False
#             x,y,_ = f[0].get_center()+0.4*DOWN
#             self.play(Create(f), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("x")
#             x,y,_ = f[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a")
#             x,y,_ = f[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("b")
#             x,y,_ = f[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("p1")
#             cursor.blinking=False
#             x,y,_ = plane.c2p(0,0)
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             self.add(c1)
#             cursor.blinking=True

#             self.wait_until_bookmark("f2")
#             cursor.blinking=False
#             x,y,_ = f1[0].get_center()+0.4*DOWN
#             self.play(Create(f1), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("02")
#             x,y,_ = f1[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a2")
#             x,y,_ = f1[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("022")
#             x,y,_ = f1[4].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("follows1")
#             cursor.blinking=False
#             x,y,_ = follows.get_center()+0.4*DOWN
#             self.play(Write(follows), CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("p2")
#             cursor.blinking=False
#             x,y,_ = plane.c2p(2,4)
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             self.add(c2)
#             cursor.blinking=True

#             self.wait_until_bookmark("f3")
#             cursor.blinking=False
#             x,y,_ = f2[0].get_center()+0.4*DOWN
#             self.play(Create(f2), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("03")
#             x,y,_ = f2[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a3")
#             x,y,_ = f2[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("023")
#             x,y,_ = f2[4].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("b3")
#             x,y,_ = f2[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("follows2")
#             cursor.blinking=False
#             x,y,_ = follows2.get_center()+0.4*DOWN
#             self.play(Write(follows2), CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("fin")
#             cursor.blinking=False
#             x,y,_ = fTrue.get_center()+0.4*DOWN
#             self.play(ReplacementTransform(f,fTrue), CursorMoveTo(cursor,x,y), Unwrite(f1), Unwrite(f2), Unwrite(follows), Unwrite(follows2), run_time=0.3)
#             cursor.blinking=True

#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)


# #####################################
# #####################################
# class Func_4_6_I_2(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         self.add_title("Quadratic Functions")
        
#         #Create the coordinate system
#         cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
#         plane = cords[0]

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         x,y,_ = plane.c2p(0,-4)
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = False
#         cursor.add_updater(cursor_sound_updater)
#         cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
#         c1 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(0,0))
#         c2 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(2,4))

#         self.add(cords, cursor, c1, c2)

#         fLinear = lambda x: 2*x
#         gLinear = plane.plot(fLinear, color=BLUE).reverse_points()

#         fQuadratic1 = lambda x: x**2
#         gQuadratic1 = plane.plot(fQuadratic1, color=BLUE).reverse_points()
#         fQuadratic2 = lambda x: -x**2+4*x
#         gQuadratic2 = plane.plot(fQuadratic2, color=PURPLE, x_range=[-1, 2, 0.001]).reverse_points()

#         fQ1 = MathTex("f", "(x)", "=", "x", "^2", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.4)
#         fQ2 = MathTex("g", "(x)", "=", "-", "x", "^2", "+", "4", "x", color=c1t, font_size=fs2).next_to(fQ1, DOWN, buff=0.2)

        
#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Now for a linear function, two points are enough to determine the function term.
#                 The reason for that is very intuitive: If you have two points, you can <bookmark mark="Line"/>
#                 draw a line through them. And a linear function is just a line. With a quadratic function,
#                 it's not that easy. 
#                 The <bookmark mark="g1"/> graph you see now belongs to the unit parabola function<bookmark mark="f1"/>
#                 f of<bookmark mark="fx1"/> x equals <bookmark mark="x21"/>x squared and as you can see, it goes
#                 through the two green points. Now consider the function <bookmark mark="fx2"/> g of x equals<bookmark mark="x22"/>
#                 minus x squared plus<bookmark mark="4x2"/> 4 x . <bookmark mark="cursor"/> If you look at
#                 <bookmark mark="graph2"/> the graph of this function, you can see that it also goes through the two green points.
#                 So you see, two points are not enough to determine a quadratic function. In fact, you need three points.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("Line")
#             self.add_pencil_sound(1)
#             self.play(Create(gLinear), run_time=1)

#             self.wait_until_bookmark("g1")
#             cursor.blinking=False
#             x,y,_ = gQuadratic1.get_start()
#             self.play(Unwrite(gLinear), CursorMoveTo(cursor,x,y), run_time=0.5)
#             self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(gQuadratic1.get_end())))
#             self.add_pencil_sound(1.5)
#             self.play(Create(gQuadratic1))
#             cursor.blinking=True

#             self.wait_until_bookmark("f1")
#             cursor.blinking=False
#             x,y,_ = fQ1[0].get_center()+0.4*DOWN
#             self.play(Create(fQ1), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("fx1")
#             x,y,_ = fQ1[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("x21")
#             x,y,_ = fQ1[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("fx2")
#             cursor.blinking=False
#             x,y,_ = fQ2[0].get_center()+0.4*DOWN
#             self.play(Create(fQ2), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("x22")
#             x,y,_ = fQ2[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("4x2")
#             x,y,_ = fQ2[7].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("cursor")
#             cursor.blinking=False
#             x,y,_ = gQuadratic2.get_start()
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

#             self.wait_until_bookmark("graph2")
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
#             self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(gQuadratic2.get_end())))
#             self.add_pencil_sound(1.5)
#             self.play(Create(gQuadratic2))
#             cursor.blinking=True

#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)


# #####################################
# #####################################
# TASK_Func_4_6_I_3_q = SophiaTaskDefinition(
#     answerOptions = ["$f(x)=2x+2$", "f(x)=x+4", "f(x)=2x", "f(x)=x^2"],
#     correctAnswerIndex = 2,
#     questionText = "What is the term of the quadratic function that goes through (-2,-2), (0,2) and (2,-2)?"
# )
# class Func_4_6_I_3_q(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         self.add_title("Quadratic Functions")
        
#         #Create the coordinate system
#         cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
#         plane = cords[0]

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         x,y,_ = plane.c2p(0,0)
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = False
#         cursor.add_updater(cursor_sound_updater)
#         cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)

#         self.add(cords, cursor)

#         fQuadratic1 = lambda x: -x**2+2
#         gQuadratic1 = plane.plot(fQuadratic1, color=BLUE)
#         p1 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(-2,-2))
#         p2 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(0,2))
#         p3 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(2,-2))
        
#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Consider the following three points: <bookmark mark="p1"/> (-2, -2), <bookmark mark="p2"/> 
#                 (0, 2) and <bookmark mark="p3"/>(2, -2). There is<bookmark mark="cursorPos"/> exactly one
#                 quadratic <bookmark mark="plot"/>function that goes through all three points. 
#                 What is the term of that function?
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("p1")
#             cursor.blinking=False
#             x,y,_ = p1.get_center()
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
#             self.add(p1)
            
#             self.wait_until_bookmark("p2")
#             x,y,_ = p2.get_center()
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
#             self.add(p2)

#             self.wait_until_bookmark("p3")
#             x,y,_ = p3.get_center()
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
#             self.add(p3)
#             cursor.blinking=True

#             self.wait_until_bookmark("cursorPos")
#             cursor.blinking=False
#             x,y,_ = gQuadratic1.get_start()
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
#             self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(gQuadratic1.get_end())))
#             self.add_pencil_sound(1.5)
#             self.play(Create(gQuadratic1))
#             Qmark = self.draw_qmark(cursor, DOWN*2, 3.5, apply_waves=0)
#             self.play(ApplyWave(Qmark))
#             self.play(ApplyWave(Qmark))

#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)


# class Func_4_6_I_3_a(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Quadratic Functions")
        
#         #Create the coordinate system
#         cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
#         plane = cords[0]

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         x,y,_ = plane.c2p(0,0)
#         cursor = AltCursor(stroke_width=0.0, blinking=False, x=x, y=y)
#         cursor.autoFadeBackground = False
#         cursor.add_updater(cursor_sound_updater)
#         cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)

#         self.add(cords, cursor)

#         fQuadratic1 = lambda x: -x**2+2
#         gQuadratic1 = plane.plot(fQuadratic1, color=BLUE)
#         p1 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(-2,-2))
#         p2 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(0,2))
#         p3 = Dot(radius = 0.1, color=GREEN).move_to(plane.c2p(2,-2))
#         points = VGroup(p1, p2, p3)

#         f_sol = MathTex("f", "(x)", "=", "-", "x", "^2", "+", "2", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.4)
#         f_sol2 = MathTex("\\Rightarrow", "f", "(x)", "=", "-", "x", "^2", "+", "2", color=c1t, font_size=fs2)
#         f_general = MathTex("f", "(x)", "=", "a", "x", "^2", "+", "b", "x", "+", "c", color=c1t, font_size=fs2).move_to(f_sol)

#         e01a = MathTex("f", "(-2)", "=", "a", "(-2)", "^2", "+", "b", "(-2)", "+", "c", color=c1t, font_size=fs3).next_to(f_general, DOWN, buff=0.6).shift(UP*3)
#         e01b = MathTex("1)\\,", "4a", "-2b", "+", "c", "=-2", color=c1t, font_size=fs3).next_to(e01a, DOWN, buff=0.2)
#         e01c = MathTex("1)\\,", "4a", "-2b", "+", "2", "=-2", color=c1t, font_size=fs3)

#         e02a = MathTex("f", "(0)", "=", "a", "(0)", "^2", "+", "b", "(0)", "+", "c", color=c1t, font_size=fs3).next_to(e01b, DOWN, buff=0.6)
#         e02b = MathTex("2)\\,","c", "=2", color=c1t, font_size=fs3).next_to(e02a, DOWN, buff=0.2)

#         e03a = MathTex("f", "(2)", "=", "a", "(2)", "^2", "+", "b", "(2)", "+", "c", color=c1t, font_size=fs3).next_to(e02b, DOWN, buff=0.6)
#         e03b = MathTex("3)\\,","4a", "+2b", "+", "c", "=-2", color=c1t, font_size=fs3).next_to(e03a, DOWN, buff=0.2)
#         e03c = MathTex("3)\\,","4a", "+2b", "+", "2", "=-2", color=c1t, font_size=fs3)

#         e04 = MathTex("4","8a", "+", "4", "=-4", color=c1t, font_size=fs3)
#         e04b = MathTex("\\Rightarrow","a", "=-1", color=c1t, font_size=fs3)
#         e04c = MathTex("\\Rightarrow","b", "=0", color=c1t, font_size=fs3)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 That is correct. Well done!
#                 The term<bookmark mark="unWriteSmile"/> of the <bookmark mark="plot"/>quadratic function that goes through the
#                 <bookmark mark="points"/>three points is <bookmark mark="fS"/> f of <bookmark mark="xSol"/> x equals minus 
#                 <bookmark mark="xSquaredSol"/>x squared plus<bookmark mark="twoSol"/> 2... But how do we get there?
#                 Two options. The first one is to guess and then plug in the values to see if it's actually correct.
#                 The second way is a bit more involved.
#                 We start with the general form of squared functions:<bookmark mark="fG"/> f of x equals<bookmark mark="xG"/> a x squared
#                 plus<bookmark mark="bG"/> b x plus<bookmark mark="cG"/> c. Now we plug in the three points and get three equations.
#                 <bookmark mark="shiftUp"/>We get the first equation by plugging in the first point (-2, -2). We then get <bookmark mark="f01a"/>
#                 f of <bookmark mark="fx01a"/> negative two equals<bookmark mark="a01a"/> a times<bookmark mark="x01a"/> negative two squared
#                 plus<bookmark mark="b01a"/> b times negative two plus <bookmark mark="c01a"/> c. We can simplify this to <bookmark mark="a01b"/>
#                 4a minus 2b plus c equals negative two.
#                 """
#         ) as tracker:

#             cursor, smile = self.draw_smile(cursor, loc=DOWN*2, run_time=2.5)
#             self.play(CursorMoveTo(cursor,x,y))
#             cursor.blinking=True

#             self.wait_until_bookmark("unWriteSmile")
#             self.play(Unwrite(smile), run_time=0.5)

#             self.wait_until_bookmark("plot")
#             cursor.blinking=False
#             x,y,_ = gQuadratic1.get_start()
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             self.add(cursor.copy()._start_fading(1.5).add_updater(lambda m: m.move_to(gQuadratic1.get_end())))
#             self.add_pencil_sound(1)
#             self.play(Create(gQuadratic1), run_time=1)
#             cursor.blinking=True

#             self.wait_until_bookmark("points")
#             self.play(Write(points))

#             self.wait_until_bookmark("fS")
#             cursor.blinking=False
#             x,y,_ = f_sol[0].get_center()+0.4*DOWN
#             self.play(Create(f_sol), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("xSol")
#             x,y,_ = f_sol[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("xSquaredSol")
#             x,y,_ = f_sol[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("twoSol")
#             x,y,_ = f_sol[7].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("fG")
#             cursor.blinking=False
#             x,y,_ = f_general[0].get_center()+0.4*DOWN
#             self.play(TransformMatchingTex(f_sol,f_general), CursorMoveTo(cursor,x,y), run_time=0.8)

#             self.wait_until_bookmark("xG")
#             x,y,_ = f_general[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("bG")
#             x,y,_ = f_general[7].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("cG")
#             x,y,_ = f_general[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("shiftUp")
#             self.play(Unwrite(points), f_general.animate.shift(UP*3), Unwrite(cords), Unwrite(gQuadratic1), run_time=0.5)

#             self.wait_until_bookmark("f01a")
#             cursor.blinking=False
#             x,y,_ = e01a[0].get_center()+0.4*DOWN
#             self.play(Create(e01a), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("fx01a")
#             x,y,_ = e01a[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a01a")
#             x,y,_ = e01a[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("x01a")
#             x,y,_ = e01a[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("b01a")
#             x,y,_ = e01a[7].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            
#             self.wait_until_bookmark("c01a")
#             x,y,_ = e01a[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("a01b")
#             cursor.blinking=False
#             x,y,_ = e01b.get_center()+0.4*DOWN
#             self.play(Create(e01b), CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True
            

#         with self.voiceover(
#                 text="""
#                 We get the second equation by plugging in the second point (0, 2). We then get <bookmark mark="f02a"/> f of <bookmark mark="fx02a"/>
#                 zero equals<bookmark mark="a02a"/> a times<bookmark mark="x02a"/> zero squared plus<bookmark mark="b02a"/> b times zero plus
#                 <bookmark mark="c02a"/> c. We can simplify this to <bookmark mark="c02b"/> c equals two.
#                 We get the third equation by plugging in the third point (2, -2). We then get <bookmark mark="f03a"/> f of <bookmark mark="fx03a"/>
#                 two equals<bookmark mark="a03a"/> a times<bookmark mark="x03a"/> two squared plus<bookmark mark="b03a"/> b times two plus
#                 <bookmark mark="c03a"/> c. We can simplify this to <bookmark mark="a03b"/> 4a plus 2b plus c equals negative two.
#                 <bookmark mark="decoration"/>
#                 Now we have three equations with three unknowns. We can solve this system of equations to get the values for a, b and c.
#                 So let's <bookmark mark="clean"/> clean up a bit so that we only have the three simplified equations left.
#                 Now the first thing we can do, is <bookmark mark="cEq2"/> plug in c equals 2 into the first and third equation.
#                 This gives us <bookmark mark="plugInC"/> 4a minus 2b plus two equals negative two <bookmark mark="and"/>and 4a plus 2b plus two equals negative two.
#                 Next, we add <bookmark mark="add"/> the two equations together. This gives us <bookmark mark="e04"/> 8a plus four equals negative four.
#                 We can then <bookmark mark="solveA"/> solve for a and get a equals negative one. Finally, if we plug in a equals negative one into
#                 the first equation, we get that <bookmark mark="b0"/> b equals zero. So the term of the quadratic function that goes through the three points
#                 is <bookmark mark="fSol"/> f of x equals minus x squared plus two.
#                 """
#             ) as tracker:


#             self.wait_until_bookmark("f02a")
#             cursor.blinking=False
#             x,y,_ = e02a[0].get_center()+0.4*DOWN
#             self.play(Create(e02a), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("fx02a")
#             x,y,_ = e02a[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a02a")
#             x,y,_ = e02a[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("x02a")
#             x,y,_ = e02a[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("b02a")
#             x,y,_ = e02a[7].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("c02a")
#             x,y,_ = e02a[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("c02b")
#             cursor.blinking=False
#             x,y,_ = e02b.get_center()+0.4*DOWN
#             self.play(Create(e02b), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("f03a")
#             x,y,_ = e03a[0].get_center()+0.4*DOWN
#             self.play(Create(e03a), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("fx03a")
#             x,y,_ = e03a[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("a03a")
#             x,y,_ = e03a[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("x03a")
#             x,y,_ = e03a[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("b03a")
#             x,y,_ = e03a[7].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("c03a")
#             x,y,_ = e03a[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("a03b")
#             cursor.blinking=False
#             x,y,_ = e03b.get_center()+0.4*DOWN
#             self.play(Create(e03b), CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("decoration")
#             decoration = self.draw_decorative_line(cursor, downshift=3, run_time=4)

#             self.wait_until_bookmark("clean")
#             self.play(Unwrite(e01a), Unwrite(e02a),  Unwrite(e03a), Unwrite(f_general), e01b.animate.next_to(title, DOWN, buff=1), e02b.animate.next_to(title, DOWN, buff=1.6), e03b.animate.next_to(title, DOWN, buff=2.2))
#             self.play(e03b.animate.shift(RIGHT*(e01b.get_left()-e03b.get_left())), e02b.animate.shift(RIGHT*(e01b.get_left()-e02b.get_left())), Unwrite(decoration), run_time=0.5)

#             self.wait_until_bookmark("cEq2")
#             cursor.blinking=False
#             x,y,_ = e02b.get_right()+0.4*RIGHT
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("plugInC")
#             x,y,_ = e01c.get_left()+0.4*LEFT
#             cursor.blinking=False
#             self.play(TransformMatchingTex(e01b, e01c.move_to(e01b)), TransformMatchingTex(e03b, e03c.move_to(e03b)), CursorMoveTo(cursor,x,y), run_time=1)

#             self.wait_until_bookmark("and")
#             x,y,_ = e03c.get_left()+0.4*LEFT
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("add")
#             x,y,_ = e01c.get_left()+0.4*LEFT
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("e04")
#             cursor.blinking=False
#             e04.next_to(e03c, DOWN, buff=0.4).shift(RIGHT*((e01c.get_left()-e04.get_left())))
#             x,y,_ = e04.get_center()+0.4*DOWN
#             self.play(Create(e04), CursorMoveTo(cursor,x,y), run_time=0.3)

#             self.wait_until_bookmark("solveA")
#             cursor.blinking=False
#             e04b.next_to(e04, DOWN, buff=0.4).shift(RIGHT*((e01c.get_left()-e04b.get_left())))
#             x,y,_ = e04b.get_center()+0.4*DOWN
#             self.play(Write(e04b), CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("b0")
#             cursor.blinking=False
#             e04c.next_to(e04b, DOWN, buff=0.4).shift(RIGHT*((e01c.get_left()-e04c.get_left())))
#             x,y,_ = e04c.get_center()+0.4*DOWN
#             self.play(Write(e04c), CursorMoveTo(cursor,x,y), run_time=0.3)
#             cursor.blinking=True
            
#             self.wait_until_bookmark("fSol")
#             cursor.blinking=False
#             f_sol2.next_to(e04c, DOWN, buff=0.4).shift(RIGHT*((e01c.get_left()-f_sol2.get_left())))
#             x,y,_ = f_sol2[0].get_center()+0.4*DOWN
#             self.play(Write(f_sol2), CursorMoveTo(cursor,x,y), run_time=0.3)


#         # Wait for 4 seconds at the end of the animation
#         self.wait(4)



# ####################################
# ####################################
# #### Prototypes ####################
# ####################################
# ####################################
# PROTOTYPES = [
#     PagePrototypeVideo.from_scene(Func_4_6_I_1_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_4_6_I_1_q, Func_4_6_I_1_q.__name__),
#     PagePrototypeVideo.from_scene(Func_4_6_I_1_a),
#     PagePrototypeVideo.from_scene(Func_4_6_I_1_b),
#     PagePrototypeVideo.from_scene(Func_4_6_I_1_c),
#     PagePrototypeVideo.from_scene(Func_4_6_I_2),
#     PagePrototypeVideo.from_scene(Func_4_6_I_3_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_4_6_I_3_q, Func_4_6_I_3_q.__name__),
#     PagePrototypeVideo.from_scene(Func_4_6_I_3_a),
#     PagePrototypeVideo.from_scene(Func_4_6_I_3_b),
#     PagePrototypeVideo.from_scene(Func_4_6_I_3_c),
#     PagePrototypeVideo.from_scene(Func_4_6_I_3_d),
#     PagePrototypeVideo.from_scene(Func_4_6_I_4_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_4_6_I_4_q, Func_4_6_I_4_q.__name__),
#     PagePrototypeVideo.from_scene(Func_4_6_I_4_a),
#     PagePrototypeVideo.from_scene(Func_4_6_I_4_b),
#     PagePrototypeVideo.from_scene(Func_4_6_I_4_c),
#     PagePrototypeVideo.from_scene(Func_4_6_I_4_d),
#     PagePrototypeVideo.from_scene(Func_4_6_I_5_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_4_6_I_5_q, Func_4_6_I_5_q.__name__),
#     PagePrototypeVideo.from_scene(Func_4_6_I_5_a),
#     PagePrototypeVideo.from_scene(Func_4_6_I_5_b),
#     PagePrototypeVideo.from_scene(Func_4_6_I_5_c),
#     PagePrototypeVideo.from_scene(Func_4_6_I_6_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_4_6_I_6_q, Func_4_6_I_6_q.__name__),
#     PagePrototypeVideo.from_scene(Func_4_6_I_6_a),
#     PagePrototypeVideo.from_scene(Func_4_6_I_6_b),
#     PagePrototypeVideo.from_scene(Func_4_6_I_6_c),
#     PagePrototypeVideo.from_scene(Func_4_6_I_6_d),
#     PagePrototypeVideo.from_scene(Func_4_6_I_7_q),
#     PagePrototypeQuestion.from_task_definition(TASK_Func_4_6_I_7_q, Func_4_6_I_7_q.__name__),
#     PagePrototypeVideo.from_scene(Func_4_6_I_7_a),
#     PagePrototypeVideo.from_scene(Func_4_6_I_7_b),
#     PagePrototypeVideo.from_scene(Func_4_6_I_7_c),
#     PagePrototypeVideo.from_scene(Func_4_6_I_7_d),

# ]
scenes/Func/Func_4: Quadratic Functions/Func_4_6.py
Sophia-Edu-Labs/sophia-math
# 5_1: Power Functions: Intro, Term

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition



#####################################
#####################################
class Func_5_1_I_1(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]

        func1 = MathTex("f", "(x)", "=",  "a","x^n", color=c1t, font_size=fs2)
        conds = VGroup(MathTex("a\\in\\mathbb{R}", color=c3t, font_size=fs3), MathTex("n\\in\\mathbb{Z}", color=c3t, font_size=fs3)).arrange(RIGHT, buff=0.3).next_to(func1, DOWN, buff=0.2)
        powerFunc = VGroup(func1, conds)
        
        funcn1 = MathTex("f", "(x)", "=",  "a","x", color=BLUE, font_size=fs2)
        funcn2 = MathTex("f", "(x)", "=",  "a","x^2", color=GREEN, font_size=fs2)
        funcn3 = MathTex("f", "(x)", "=",  "a","x^3", color=PURPLE, font_size=fs2)
        funcn4 = MathTex("f", "(x)", "=",  "a","x^4", color=ORANGE, font_size=fs2)

        f1 = lambda x: x
        f2 = lambda x: x**2
        f3 = lambda x: x**3
        f4 = lambda x: x**4

        g1 = plane.plot(f1, color=BLUE)
        g2 = plane.plot(f2, color=GREEN)
        g3 = plane.plot(f3, color=PURPLE, x_range=[-1.66,1.66, 0.001])
        g4 = plane.plot(f4, color=ORANGE)


        # Action Sequence
        with self.voiceover(
                text="""
                Let's jump into powerfunctions with the definition:
                A power function is a function of the form<bookmark mark="form"/> f of <bookmark mark="fx"/>x equals <bookmark mark="a"/> a
                times <bookmark mark="x"/>x to the power of n, where <bookmark mark="real"/>a is a real number and n is an <bookmark mark="int"/>integer.
                Now you've probably already seen at least two <bookmark mark="shiftDown"/> examples of power functions.
                If you choose <bookmark mark="n1"/> n equals 1, you get a linear function f of x equals a times x.
                If you choose <bookmark mark="n2"/> n equals 2, you get a quadratic function f of x equals a times x squared.
                If you choose <bookmark mark="n3"/> n equals 3, you get a cubic function f of x equals a times x cubed.
                Now for a bit of <bookmark mark="cleanUp"/> vocabulary. The value that is raised to a power is called the base.
                In our example, since we're dealing with x to the power of n, <bookmark mark="base"/>x is the base.
                The power to which the base is raised is called the exponent.
                In our example, since we're dealing with x to the power of <bookmark mark="exponent"/>n, n is the exponent.
                """
        ) as tracker:

            self.wait_until_bookmark("form")
            cursor.blinking=False
            x,y,_ = func1[0].get_center()+0.4*DOWN
            self.play(Write(func1), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("fx")
            x,y,_ = func1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("a")
            x,y,_ = func1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = func1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("real")
            x,y,_ = conds[0].get_center()+0.4*DOWN
            self.play(Write(conds), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("int")
            x,y,_ = conds[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("shiftDown")
            x,y,_ = plane.c2p(0,0)
            self.play(Write(cords), powerFunc.animate.next_to(cords, DOWN, buff=0.4), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("n1")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(Write(funcn1.next_to(powerFunc, DOWN, buff=0.2)), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("n2")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(Write(funcn2.next_to(funcn1, DOWN, buff=0.2)), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("n3")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(Write(funcn3.next_to(funcn2, DOWN, buff=0.2)), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

            self.wait_until_bookmark("cleanUp")
            self.play(Unwrite(g1), Unwrite(g2), Unwrite(g3), Unwrite(cords), powerFunc.animate.shift(UP*1.2))

            self.wait_until_bookmark("base")
            cursor.blinking=False
            b1 = Bubble(["x is the base"], width=1.8, height=0.6, start_point = func1[-1].get_center()+0.1*UP+0.2*LEFT, center=[-1,2.4,0], loc="b2")
            x,y,_ = func1[-1].get_center()+0.2*UP+0.1*LEFT
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(b1.get_end())))
            self.add_bubble_sound(1.5)
            self.play(Create(b1), Create(b1.text))
            cursor.blinking=True

            self.wait_until_bookmark("exponent")
            cursor.blinking=False
            b2 = Bubble(["n is the exponent"], width=2.2, height=0.5, start_point = func1[-1].get_center()+0.3*UP+0.1*RIGHT, center=[1,1.6,0], loc="b1")
            x,y,_ = func1[-1].get_center()+0.3*UP+0.1*RIGHT
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(b2.get_end())))
            self.add_bubble_sound(1.5)
            self.play(Create(b2), Create(b2.text))
            x,y,_ = func1.get_right()+0.5*RIGHT
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_5_1_I_2_q = SophiaTaskDefinition(
    answerOptions = ["Base: $3$, Exponent: $4$", "Base: $y$, Exponent: $3$", "Base: $y$, Exponent: $4$", "Base: $4$, Exponent: $y$"],
    correctAnswerIndex = 2,
    questionText = "Considering the expression $3y^4$, which is the base, and which is the exponent?"
)
class Func_5_1_I_2_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]

        func1 = MathTex("3","y","^4", color=c1t, font_size=fs1)
        base = Tex("Base?", color=c3t, font_size=fs1)
        exponent = Tex("Exponent?", color=c3t, font_size=fs1)
        baseExponent = VGroup(base, exponent).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(func1, DOWN, buff=0.6)

        # Action Sequence
        with self.voiceover(
                text="""
                quick check to make sure you keep the definitions in mind.
                Look at the expression<bookmark mark="three"/> 3 times <bookmark mark="y"/>y to the power of <bookmark mark="4"/>4.
                In this example, what <bookmark mark="base"/>is the base, and <bookmark mark="exponent"/>what is the exponent.
                """
        ) as tracker:
            
            self.wait_until_bookmark("three")
            cursor.blinking=False
            x,y,_ = func1[0].get_center()+0.4*DOWN
            self.play(Write(func1), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("y")
            x,y,_ = func1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("4")
            x,y,_ = func1[2].get_center()+0.3*DOWN+0.1*RIGHT
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("base")
            cursor.blinking=False
            x,y,_ = base.get_left()+0.2*(LEFT)
            self.play(Write(base), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("exponent")
            x,y,_ = exponent.get_left()+0.2*LEFT
            self.play(Write(exponent), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.wait(1)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_5_1_I_2_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True).shift(1.5*DOWN)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]

        func1 = MathTex("3","y","^4", color=c1t, font_size=fs1)
        self.add(func1)
        bubbleBase = Bubble(["y is the Base"], width=1.8, height=0.6, start_point = func1[1].get_center()+0.4*DOWN, center=[1,-2.4,0], loc="t2")
        bubbleExponent = Bubble(["4 is the Exponent"], width=2.2, height=0.5, start_point = func1[2].get_center()+0.2*UP, center=[-1,2.4,0], loc="b1")
        
        # Action Sequence
        with self.voiceover(
                text="""
                No, not quite.
                The base is whatever we raise to a power, so in this case, the base is <bookmark mark="y"/> y.
                The exponent is the power to which the base is raised, so in this case, the exponent is <bookmark mark="4"/> 4.
                """
        ) as tracker:
            
            self.wait_until_bookmark("y")
            cursor.blinking=False
            x,y,_ = func1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(bubbleBase.get_end())))
            self.add_bubble_sound(1.5)
            self.play(Create(bubbleBase), Create(bubbleBase.text))
            cursor.blinking=True

            self.wait_until_bookmark("4")
            cursor.blinking=False
            x,y,_ = func1[2].get_center()+0.2*UP
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(bubbleExponent.get_end())))
            self.add_bubble_sound(1.5)
            self.play(Create(bubbleExponent), Create(bubbleExponent.text))
            self.play(CursorMoveTo(cursor, 1,0))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_5_1_I_2_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True).shift(1.5*DOWN)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]

        func1 = MathTex("3","y","^4", color=c1t, font_size=fs1)
        self.add(func1)
        bubbleBase = Bubble(["y is the Base"], width=1.8, height=0.6, start_point = func1[1].get_center()+0.4*DOWN, center=[1,-2.4,0], loc="t2")
        bubbleExponent = Bubble(["4 is the Exponent"], width=2.2, height=0.5, start_point = func1[2].get_center()+0.2*UP, center=[-1,2.4,0], loc="b1")
        
        # Action Sequence
        with self.voiceover(
                text="""
                No, not quite.
                The base is whatever we raise to a power, so in this case, the base is <bookmark mark="y"/> y.
                The exponent is the power to which the base is raised, so in this case, the exponent is <bookmark mark="4"/> 4.
                """
        ) as tracker:
            
            self.wait_until_bookmark("y")
            cursor.blinking=False
            x,y,_ = func1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(bubbleBase.get_end())))
            self.add_bubble_sound(1.5)
            self.play(Create(bubbleBase), Create(bubbleBase.text))
            cursor.blinking=True

            self.wait_until_bookmark("4")
            cursor.blinking=False
            x,y,_ = func1[2].get_center()+0.2*UP
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(bubbleExponent.get_end())))
            self.add_bubble_sound(1.5)
            self.play(Create(bubbleExponent), Create(bubbleExponent.text))
            self.play(CursorMoveTo(cursor, 1,0))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_5_1_I_2_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True).shift(1.5*DOWN)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]

        func1 = MathTex("3","y","^4", color=c1t, font_size=fs1)
        self.add(func1)
        bubbleBase = Bubble(["y is the Base"], width=1.8, height=0.6, start_point = func1[1].get_center()+0.4*DOWN, center=[1,-2.4,0], loc="t2")
        bubbleExponent = Bubble(["4 is the Exponent"], width=2.2, height=0.5, start_point = func1[2].get_center()+0.2*UP, center=[-1,2.4,0], loc="b1")
        
        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's right.
                The base is whatever we raise to a power, so in this case, the base is <bookmark mark="y"/> y.
                The exponent is the power to which the base is raised, so in this case, the exponent is <bookmark mark="4"/> 4.
                """
        ) as tracker:
            
            self.wait_until_bookmark("y")
            cursor.blinking=False
            x,y,_ = func1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(bubbleBase.get_end())))
            self.add_bubble_sound(1.5)
            self.play(Create(bubbleBase), Create(bubbleBase.text))
            cursor.blinking=True

            self.wait_until_bookmark("4")
            cursor.blinking=False
            x,y,_ = func1[2].get_center()+0.2*UP
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(bubbleExponent.get_end())))
            self.add_bubble_sound(1.5)
            self.play(Create(bubbleExponent), Create(bubbleExponent.text))
            self.play(CursorMoveTo(cursor, 1,0))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_5_1_I_2_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True).shift(1.5*DOWN)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]

        func1 = MathTex("3","y","^4", color=c1t, font_size=fs1)
        self.add(func1)
        bubbleBase = Bubble(["y is the Base"], width=1.8, height=0.6, start_point = func1[1].get_center()+0.4*DOWN, center=[1,-2.4,0], loc="t2")
        bubbleExponent = Bubble(["4 is the Exponent"], width=2.2, height=0.5, start_point = func1[2].get_center()+0.2*UP, center=[-1,2.4,0], loc="b1")
        
        # Action Sequence
        with self.voiceover(
                text="""
                No, not quite.
                The base is whatever we raise to a power, so in this case, the base is <bookmark mark="y"/> y.
                The exponent is the power to which the base is raised, so in this case, the exponent is <bookmark mark="4"/> 4.
                """
        ) as tracker:
            
            self.wait_until_bookmark("y")
            cursor.blinking=False
            x,y,_ = func1[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(bubbleBase.get_end())))
            self.add_bubble_sound(1.5)
            self.play(Create(bubbleBase), Create(bubbleBase.text))
            cursor.blinking=True

            self.wait_until_bookmark("4")
            cursor.blinking=False
            x,y,_ = func1[2].get_center()+0.2*UP
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(bubbleExponent.get_end())))
            self.add_bubble_sound(1.5)
            self.play(Create(bubbleExponent), Create(bubbleExponent.text))
            self.play(CursorMoveTo(cursor, 1,0))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_5_1_I_3_q = SophiaTaskDefinition(
    answerOptions = ["Functions with an even degree are always positive, while functions with an odd degree can be negative.", "Functions with an even degree are always negative, while functions with an odd degree can be positive.", "Functions with an even degree are always positive, while functions with an odd degree can be positive or negative.", "Functions with an even degree are always negative, while functions with an odd degree can be positive or negative."],
    correctAnswerIndex = 0,
    questionText = "What's the difference between functions with an even degree and functions with an odd degree?"
)
class Func_5_1_I_3_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]

        func1 = MathTex("f", "(x)", "=",  "a","x^n", color=c1t, font_size=fs2)
        conds = VGroup(MathTex("a\\in\\mathbb{R}", color=c3t, font_size=fs3), MathTex("n\\in\\mathbb{Z}", color=c3t, font_size=fs3)).arrange(RIGHT, buff=0.3).next_to(func1, DOWN, buff=0.2)
        powerFunc = VGroup(func1, conds)
        
        funcn1 = MathTex("f", "(x)", "=",  "a","x", color=BLUE, font_size=fs2)
        funcn2 = MathTex("f", "(x)", "=",  "a","x^2", color=GREEN, font_size=fs2)
        funcn3 = MathTex("f", "(x)", "=",  "a","x^3", color=PURPLE, font_size=fs2)
        funcn4 = MathTex("f", "(x)", "=",  "a","x^4", color=ORANGE, font_size=fs2)

        f1 = lambda x: x
        f2 = lambda x: x**2
        f3 = lambda x: x**3
        f4 = lambda x: x**4

        g1 = plane.plot(f1, color=BLUE)
        g2 = plane.plot(f2, color=GREEN)
        g3 = plane.plot(f3, color=PURPLE, x_range=[-4**(1/3),4**(1/3), 0.01])
        g4 = plane.plot(f4, color=ORANGE,  x_range=[-2**0.5,2**0.5,0.01])



        # Action Sequence
        with self.voiceover(
                text="""
                Back to power functions with the general structure <bookmark mark="form"/> f of <bookmark mark="fx"/>x equals <bookmark mark="a"/> a
                times <bookmark mark="x"/>x to the power of n, and quick reminder, <bookmark mark="real"/>a is a real number and n is an <bookmark mark="int"/>integer.
                If we now take another look at the <bookmark mark="shiftDown"/> examples of power functions that we've seen, namely
                the <bookmark mark="n1"/>linear function f of x equals a times x n equals 1,
                the <bookmark mark="n2"/>quadratic function f of x equals a times x squared.
                and the <bookmark mark="n3"/>cubic function f of x equals a times x cubed...
                <bookmark mark="shift"/>
                We'll also add the <bookmark mark="n4"/> function f of x equals a times x to the power of 4, which is of degree four.
                Now here's a question for you: What is the main difference between functions with an even number of degree,
                like the quadratic function, and functions with an odd number of degree, like the cubic function?
                """
        ) as tracker:

            self.wait_until_bookmark("form")
            cursor.blinking=False
            x,y,_ = func1[0].get_center()+0.4*DOWN
            self.play(Write(func1), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("fx")
            x,y,_ = func1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("a")
            x,y,_ = func1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("x")
            x,y,_ = func1[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("real")
            x,y,_ = conds[0].get_center()+0.4*DOWN
            self.play(Write(conds), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("int")
            x,y,_ = conds[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("shiftDown")
            x,y,_ = plane.c2p(0,0)
            self.play(Write(cords), powerFunc.animate.next_to(cords, DOWN, buff=0.4), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("n1")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(Write(funcn1.next_to(powerFunc, DOWN, buff=0.2)), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("n2")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(Write(funcn2.next_to(funcn1, DOWN, buff=0.2)), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("n3")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(Write(funcn3.next_to(funcn2, DOWN, buff=0.2)), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

            self.wait_until_bookmark("shift")
            self.play(funcn1.animate.shift(UP*0.4), funcn2.animate.shift(UP*0.45), funcn3.animate.shift(UP*0.5), Unwrite(conds))

            self.wait_until_bookmark("n4")
            cursor.blinking=False
            x,y,_ = g4.get_start()
            self.play(Write(funcn4.next_to(funcn3, DOWN, buff=0.15)), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g4.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g4))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_5_1_I_3_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        funcn1 = MathTex("f", "(x)", "=",  "a","x", color=BLUE, font_size=fs2).next_to(plane, DOWN, buff=0.6)
        funcn3 = MathTex("f", "(x)", "=",  "a","x^3", color=PURPLE, font_size=fs2).next_to(funcn1, DOWN, buff=0.2)

        funcn2 = MathTex("f", "(x)", "=",  "a","x^2", color=GREEN, font_size=fs2).next_to(funcn3, DOWN, buff=0.6)
        funcn4 = MathTex("f", "(x)", "=",  "a","x^4", color=ORANGE, font_size=fs2).next_to(funcn2, DOWN, buff=0.2)

        f1 = lambda x: x
        f2 = lambda x: x**2
        f3 = lambda x: x**3
        f4 = lambda x: x**4

        g1 = plane.plot(f1, color=BLUE)
        g1c = g1.copy()
        g2 = plane.plot(f2, color=GREEN)
        g3 = plane.plot(f3, color=PURPLE, x_range=[-4**(1/3),4**(1/3), 0.01])
        g3c = g3.copy()
        g4 = plane.plot(f4, color=ORANGE,  x_range=[-2**0.5,2**0.5,0.01])



        # Action Sequence
        with self.voiceover(
                text="""
                Yes, well done!
                Let's first look at the two functions with an odd degree. That means that the exponent is an odd number, like in x, x cubed, x to the power of five and so on...
                First, we have  <bookmark mark="n1"/>the linear function f of x equals a times x, which is the same as a times x to the power of one. As you can see,
                the function values are negative for negative x values and positive for positive x values. So they are sometimes positive and sometimes negative.
                Next, there is the <bookmark mark="n3"/>cubic function f of x equals a times x cubed, so x to the power of three. Again, the function values are negative for negative x values and positive for positive x values.
                So they are sometimes positive and sometimes negative.
                Now, <bookmark mark="unWriteOdd"/>let's look at the two functions with an even degree. That means that the exponent is an even number, like in x squared, x to the power of four and so on...
                So first we have the <bookmark mark="n2"/>quadratic function f of x equals a times x squared. As you can see, the function values are always positive,
                both for positive and for negative x values. This is because if you multiply a negative number by itself, it always results in a positive number: Negative times negative is positive.
                And finally, there is the <bookmark mark="n4"/> function f of x equals a times x to the power of 4, which is of degree four. Again, the function values are always positive.
                So, <bookmark mark="unWriteEven"/>to sum up, functions with an <bookmark mark="even"/> even degree are always positive, while functions with an <bookmark mark="odd"/>odd degree can be positive or negative.
                """
        ) as tracker:

            self.wait_until_bookmark("n1")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(Write(funcn1), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("n3")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(Write(funcn3), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

            self.wait_until_bookmark("unWriteOdd")
            self.play(Unwrite(g1), Unwrite(g3))

            self.wait_until_bookmark("n2")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(Write(funcn2), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("n4")
            cursor.blinking=False
            x,y,_ = g4.get_start()
            self.play(Write(funcn4), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g4.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g4))
            cursor.blinking=True

            self.wait_until_bookmark("unWriteEven")
            self.play(Unwrite(g1), Unwrite(g3))

            self.wait_until_bookmark("odd")
            self.play(Unwrite(g2), Unwrite(g4), Write(g1c), Write(g3c), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_5_1_I_3_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        funcn1 = MathTex("f", "(x)", "=",  "a","x", color=BLUE, font_size=fs2).next_to(plane, DOWN, buff=0.6)
        funcn3 = MathTex("f", "(x)", "=",  "a","x^3", color=PURPLE, font_size=fs2).next_to(funcn1, DOWN, buff=0.2)

        funcn2 = MathTex("f", "(x)", "=",  "a","x^2", color=GREEN, font_size=fs2).next_to(funcn3, DOWN, buff=0.6)
        funcn4 = MathTex("f", "(x)", "=",  "a","x^4", color=ORANGE, font_size=fs2).next_to(funcn2, DOWN, buff=0.2)

        f1 = lambda x: x
        f2 = lambda x: x**2
        f3 = lambda x: x**3
        f4 = lambda x: x**4

        g1 = plane.plot(f1, color=BLUE)
        g1c = g1.copy()
        g2 = plane.plot(f2, color=GREEN)
        g3 = plane.plot(f3, color=PURPLE, x_range=[-4**(1/3),4**(1/3), 0.01])
        g3c = g3.copy()
        g4 = plane.plot(f4, color=ORANGE,  x_range=[-2**0.5,2**0.5,0.01])



        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right...
                Let's first look at the two functions with an odd degree. That means that the exponent is an odd number, like in x, x cubed, x to the power of five and so on...
                First, we have  <bookmark mark="n1"/>the linear function f of x equals a times x, which is the same as a times x to the power of one. As you can see,
                the function values are negative for negative x values and positive for positive x values. So they are sometimes positive and sometimes negative.
                Next, there is the <bookmark mark="n3"/>cubic function f of x equals a times x cubed, so x to the power of three. Again, the function values are negative for negative x values and positive for positive x values.
                So they are sometimes positive and sometimes negative.
                Now, <bookmark mark="unWriteOdd"/>let's look at the two functions with an even degree. That means that the exponent is an even number, like in x squared, x to the power of four and so on...
                So first we have the <bookmark mark="n2"/>quadratic function f of x equals a times x squared. As you can see, the function values are always positive,
                both for positive and for negative x values. This is because if you multiply a negative number by itself, it always results in a positive number: Negative times negative is positive.
                And finally, there is the <bookmark mark="n4"/> function f of x equals a times x to the power of 4, which is of degree four. Again, the function values are always positive.
                So, <bookmark mark="unWriteEven"/>to sum up, functions with an <bookmark mark="even"/> even degree are always positive, while functions with an <bookmark mark="odd"/>odd degree can be positive or negative.
                """
        ) as tracker:

            self.wait_until_bookmark("n1")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(Write(funcn1), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("n3")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(Write(funcn3), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

            self.wait_until_bookmark("unWriteOdd")
            self.play(Unwrite(g1), Unwrite(g3))

            self.wait_until_bookmark("n2")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(Write(funcn2), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("n4")
            cursor.blinking=False
            x,y,_ = g4.get_start()
            self.play(Write(funcn4), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g4.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g4))
            cursor.blinking=True

            self.wait_until_bookmark("unWriteEven")
            self.play(Unwrite(g1), Unwrite(g3))

            self.wait_until_bookmark("odd")
            self.play(Unwrite(g2), Unwrite(g4), Write(g1c), Write(g3c), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_5_1_I_3_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        funcn1 = MathTex("f", "(x)", "=",  "a","x", color=BLUE, font_size=fs2).next_to(plane, DOWN, buff=0.6)
        funcn3 = MathTex("f", "(x)", "=",  "a","x^3", color=PURPLE, font_size=fs2).next_to(funcn1, DOWN, buff=0.2)

        funcn2 = MathTex("f", "(x)", "=",  "a","x^2", color=GREEN, font_size=fs2).next_to(funcn3, DOWN, buff=0.6)
        funcn4 = MathTex("f", "(x)", "=",  "a","x^4", color=ORANGE, font_size=fs2).next_to(funcn2, DOWN, buff=0.2)

        f1 = lambda x: x
        f2 = lambda x: x**2
        f3 = lambda x: x**3
        f4 = lambda x: x**4

        g1 = plane.plot(f1, color=BLUE)
        g1c = g1.copy()
        g2 = plane.plot(f2, color=GREEN)
        g3 = plane.plot(f3, color=PURPLE, x_range=[-4**(1/3),4**(1/3), 0.01])
        g3c = g3.copy()
        g4 = plane.plot(f4, color=ORANGE,  x_range=[-2**0.5,2**0.5,0.01])



        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right...
                Let's first look at the two functions with an odd degree. That means that the exponent is an odd number, like in x, x cubed, x to the power of five and so on...
                First, we have  <bookmark mark="n1"/>the linear function f of x equals a times x, which is the same as a times x to the power of one. As you can see,
                the function values are negative for negative x values and positive for positive x values. So they are sometimes positive and sometimes negative.
                Next, there is the <bookmark mark="n3"/>cubic function f of x equals a times x cubed, so x to the power of three. Again, the function values are negative for negative x values and positive for positive x values.
                So they are sometimes positive and sometimes negative.
                Now, <bookmark mark="unWriteOdd"/>let's look at the two functions with an even degree. That means that the exponent is an even number, like in x squared, x to the power of four and so on...
                So first we have the <bookmark mark="n2"/>quadratic function f of x equals a times x squared. As you can see, the function values are always positive,
                both for positive and for negative x values. This is because if you multiply a negative number by itself, it always results in a positive number: Negative times negative is positive.
                And finally, there is the <bookmark mark="n4"/> function f of x equals a times x to the power of 4, which is of degree four. Again, the function values are always positive.
                So, <bookmark mark="unWriteEven"/>to sum up, functions with an <bookmark mark="even"/> even degree are always positive, while functions with an <bookmark mark="odd"/>odd degree can be positive or negative.
                """
        ) as tracker:

            self.wait_until_bookmark("n1")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(Write(funcn1), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("n3")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(Write(funcn3), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

            self.wait_until_bookmark("unWriteOdd")
            self.play(Unwrite(g1), Unwrite(g3))

            self.wait_until_bookmark("n2")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(Write(funcn2), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("n4")
            cursor.blinking=False
            x,y,_ = g4.get_start()
            self.play(Write(funcn4), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g4.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g4))
            cursor.blinking=True

            self.wait_until_bookmark("unWriteEven")
            self.play(Unwrite(g1), Unwrite(g3))

            self.wait_until_bookmark("odd")
            self.play(Unwrite(g2), Unwrite(g4), Write(g1c), Write(g3c), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_5_1_I_3_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        
        funcn1 = MathTex("f", "(x)", "=",  "a","x", color=BLUE, font_size=fs2).next_to(plane, DOWN, buff=0.6)
        funcn3 = MathTex("f", "(x)", "=",  "a","x^3", color=PURPLE, font_size=fs2).next_to(funcn1, DOWN, buff=0.2)

        funcn2 = MathTex("f", "(x)", "=",  "a","x^2", color=GREEN, font_size=fs2).next_to(funcn3, DOWN, buff=0.6)
        funcn4 = MathTex("f", "(x)", "=",  "a","x^4", color=ORANGE, font_size=fs2).next_to(funcn2, DOWN, buff=0.2)

        f1 = lambda x: x
        f2 = lambda x: x**2
        f3 = lambda x: x**3
        f4 = lambda x: x**4

        g1 = plane.plot(f1, color=BLUE)
        g1c = g1.copy()
        g2 = plane.plot(f2, color=GREEN)
        g3 = plane.plot(f3, color=PURPLE, x_range=[-4**(1/3),4**(1/3), 0.01])
        g3c = g3.copy()
        g4 = plane.plot(f4, color=ORANGE,  x_range=[-2**0.5,2**0.5,0.01])



        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right...
                Let's first look at the two functions with an odd degree. That means that the exponent is an odd number, like in x, x cubed, x to the power of five and so on...
                First, we have  <bookmark mark="n1"/>the linear function f of x equals a times x, which is the same as a times x to the power of one. As you can see,
                the function values are negative for negative x values and positive for positive x values. So they are sometimes positive and sometimes negative.
                Next, there is the <bookmark mark="n3"/>cubic function f of x equals a times x cubed, so x to the power of three. Again, the function values are negative for negative x values and positive for positive x values.
                So they are sometimes positive and sometimes negative.
                Now, <bookmark mark="unWriteOdd"/>let's look at the two functions with an even degree. That means that the exponent is an even number, like in x squared, x to the power of four and so on...
                So first we have the <bookmark mark="n2"/>quadratic function f of x equals a times x squared. As you can see, the function values are always positive,
                both for positive and for negative x values. This is because if you multiply a negative number by itself, it always results in a positive number: Negative times negative is positive.
                And finally, there is the <bookmark mark="n4"/> function f of x equals a times x to the power of 4, which is of degree four. Again, the function values are always positive.
                So, <bookmark mark="unWriteEven"/>to sum up, functions with an <bookmark mark="even"/> even degree are always positive, while functions with an <bookmark mark="odd"/>odd degree can be positive or negative.
                """
        ) as tracker:

            self.wait_until_bookmark("n1")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(Write(funcn1), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g1))
            cursor.blinking=True

            self.wait_until_bookmark("n3")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(Write(funcn3), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

            self.wait_until_bookmark("unWriteOdd")
            self.play(Unwrite(g1), Unwrite(g3))

            self.wait_until_bookmark("n2")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(Write(funcn2), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("n4")
            cursor.blinking=False
            x,y,_ = g4.get_start()
            self.play(Write(funcn4), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g4.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g4))
            cursor.blinking=True

            self.wait_until_bookmark("unWriteEven")
            self.play(Unwrite(g1), Unwrite(g3))

            self.wait_until_bookmark("odd")
            self.play(Unwrite(g2), Unwrite(g4), Write(g1c), Write(g3c), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_5_1_I_4_q = SophiaTaskDefinition(
    answerOptions = ["Blue: Odd, Orange: Even", "Blue: Even, Orange: Even", "Blue: Odd, Orange: Odd", "Blue: Even, Orange: Odd"],
    correctAnswerIndex = 3,
    questionText = "Do the blue and the orange function have an even or an odd degree?"
)
class Func_5_1_I_4_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        func1 = MathTex("f", "(x)", "=",  "a","x^n", color=c1t, font_size=fs2)
        conds = VGroup(MathTex("a\\in\\mathbb{R}", color=c3t, font_size=fs3), MathTex("n\\in\\mathbb{Z}", color=c3t, font_size=fs3)).arrange(RIGHT, buff=0.3).next_to(func1, DOWN, buff=0.2)
        powerFunc = VGroup(func1, conds)
        
        f2 = lambda x: -x**2
        f3 = lambda x: 0.5*x**3

        g2 = plane.plot(f2, color=BLUE)
        g3 = plane.plot(f3, color=ORANGE)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, here comes the next question:
                Look at the <bookmark mark="n2"/> blue function, and look at the <bookmark mark="n3"/> orange function.
                Do they each have an even degree, or an odd degree?
                """
        ) as tracker:


            self.wait_until_bookmark("n2")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("n3")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_5_1_I_4_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        func1 = MathTex("f", "(x)", "=",  "a","x^n", color=c1t, font_size=fs2)
        conds = VGroup(MathTex("a\\in\\mathbb{R}", color=c3t, font_size=fs3), MathTex("n\\in\\mathbb{Z}", color=c3t, font_size=fs3)).arrange(RIGHT, buff=0.3).next_to(func1, DOWN, buff=0.2)
        powerFunc = VGroup(func1, conds)
        
        f2 = lambda x: -x**2
        f3 = lambda x: 0.5*x**3

        g2 = plane.plot(f2, color=BLUE)
        g3 = plane.plot(f3, color=ORANGE)

        funcTerm2 = Tex("$-1$", "$\\cdot$","$x^2$", "$\\,\\,\\,\\,\\Rightarrow$ Even degree", color=BLUE, font_size=fs2).next_to(plane, DOWN, buff=0.6)
        funcTerm3 = Tex("$0.5$", "$\\cdot$","$x^3$", "$\\,\\,\\,\\,\\Rightarrow$ Odd degree", color=ORANGE, font_size=fs2).next_to(funcTerm2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right...
                The <bookmark mark="n2"/> blue function belongs to the <bookmark mark="blueTerm"/> Term negative one times <bookmark mark="x2"/>
                x squared. This means, that the<bookmark mark="degE"/> degree of the blue function is even, because it has degree two. But because it's multiplied by negative one,
                the function values are always negative, instead of always positive.
                The <bookmark mark="n3"/> orange function belongs to the <bookmark mark="orangeTerm"/> Term 0.5 times <bookmark mark="x3"/>
                x cubed. This means, that the <bookmark mark="degO"/>degree of the orange function is odd, because it has degree three.
                """
        ) as tracker:


            self.wait_until_bookmark("n2")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("blueTerm")
            cursor.blinking=False
            x,y,_ = funcTerm2[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm2), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("x2")
            x,y,_ = funcTerm2[2].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("degE")
            x,y,_ = funcTerm2[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("n3")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

            self.wait_until_bookmark("orangeTerm")
            cursor.blinking=False
            x,y,_ = funcTerm3[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm3), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("x3")
            x,y,_ = funcTerm3[2].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            
            self.wait_until_bookmark("degO")
            x,y,_ = funcTerm3[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_5_1_I_4_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        func1 = MathTex("f", "(x)", "=",  "a","x^n", color=c1t, font_size=fs2)
        conds = VGroup(MathTex("a\\in\\mathbb{R}", color=c3t, font_size=fs3), MathTex("n\\in\\mathbb{Z}", color=c3t, font_size=fs3)).arrange(RIGHT, buff=0.3).next_to(func1, DOWN, buff=0.2)
        powerFunc = VGroup(func1, conds)
        
        f2 = lambda x: -x**2
        f3 = lambda x: 0.5*x**3

        g2 = plane.plot(f2, color=BLUE)
        g3 = plane.plot(f3, color=ORANGE)

        funcTerm2 = Tex("$-1$", "$\\cdot$","$x^2$", "$\\,\\,\\,\\,\\Rightarrow$ Even degree", color=BLUE, font_size=fs2).next_to(plane, DOWN, buff=0.6)
        funcTerm3 = Tex("$0.5$", "$\\cdot$","$x^3$", "$\\,\\,\\,\\,\\Rightarrow$ Odd degree", color=ORANGE, font_size=fs2).next_to(funcTerm2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right...
                The <bookmark mark="n2"/> blue function belongs to the <bookmark mark="blueTerm"/> Term negative one times <bookmark mark="x2"/>
                x squared. This means, that the<bookmark mark="degE"/> degree of the blue function is even, because it has degree two. But because it's multiplied by negative one,
                the function values are always negative, instead of always positive.
                The <bookmark mark="n3"/> orange function belongs to the <bookmark mark="orangeTerm"/> Term 0.5 times <bookmark mark="x3"/>
                x cubed. This means, that the <bookmark mark="degO"/>degree of the orange function is odd, because it has degree three.
                """
        ) as tracker:


            self.wait_until_bookmark("n2")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("blueTerm")
            cursor.blinking=False
            x,y,_ = funcTerm2[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm2), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("x2")
            x,y,_ = funcTerm2[2].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("degE")
            x,y,_ = funcTerm2[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("n3")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

            self.wait_until_bookmark("orangeTerm")
            cursor.blinking=False
            x,y,_ = funcTerm3[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm3), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("x3")
            x,y,_ = funcTerm3[2].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            
            self.wait_until_bookmark("degO")
            x,y,_ = funcTerm3[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_5_1_I_4_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        func1 = MathTex("f", "(x)", "=",  "a","x^n", color=c1t, font_size=fs2)
        conds = VGroup(MathTex("a\\in\\mathbb{R}", color=c3t, font_size=fs3), MathTex("n\\in\\mathbb{Z}", color=c3t, font_size=fs3)).arrange(RIGHT, buff=0.3).next_to(func1, DOWN, buff=0.2)
        powerFunc = VGroup(func1, conds)
        
        f2 = lambda x: -x**2
        f3 = lambda x: 0.5*x**3

        g2 = plane.plot(f2, color=BLUE)
        g3 = plane.plot(f3, color=ORANGE)

        funcTerm2 = Tex("$-1$", "$\\cdot$","$x^2$", "$\\,\\,\\,\\,\\Rightarrow$ Even degree", color=BLUE, font_size=fs2).next_to(plane, DOWN, buff=0.6)
        funcTerm3 = Tex("$0.5$", "$\\cdot$","$x^3$", "$\\,\\,\\,\\,\\Rightarrow$ Odd degree", color=ORANGE, font_size=fs2).next_to(funcTerm2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right...
                The <bookmark mark="n2"/> blue function belongs to the <bookmark mark="blueTerm"/> Term negative one times <bookmark mark="x2"/>
                x squared. This means, that the<bookmark mark="degE"/> degree of the blue function is even, because it has degree two. But because it's multiplied by negative one,
                the function values are always negative, instead of always positive.
                The <bookmark mark="n3"/> orange function belongs to the <bookmark mark="orangeTerm"/> Term 0.5 times <bookmark mark="x3"/>
                x cubed. This means, that the <bookmark mark="degO"/>degree of the orange function is odd, because it has degree three.
                """
        ) as tracker:


            self.wait_until_bookmark("n2")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("blueTerm")
            cursor.blinking=False
            x,y,_ = funcTerm2[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm2), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("x2")
            x,y,_ = funcTerm2[2].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("degE")
            x,y,_ = funcTerm2[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("n3")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

            self.wait_until_bookmark("orangeTerm")
            cursor.blinking=False
            x,y,_ = funcTerm3[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm3), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("x3")
            x,y,_ = funcTerm3[2].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            
            self.wait_until_bookmark("degO")
            x,y,_ = funcTerm3[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_5_1_I_4_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        func1 = MathTex("f", "(x)", "=",  "a","x^n", color=c1t, font_size=fs2)
        conds = VGroup(MathTex("a\\in\\mathbb{R}", color=c3t, font_size=fs3), MathTex("n\\in\\mathbb{Z}", color=c3t, font_size=fs3)).arrange(RIGHT, buff=0.3).next_to(func1, DOWN, buff=0.2)
        powerFunc = VGroup(func1, conds)
        
        f2 = lambda x: -x**2
        f3 = lambda x: 0.5*x**3

        g2 = plane.plot(f2, color=BLUE)
        g3 = plane.plot(f3, color=ORANGE)

        funcTerm2 = Tex("$-1$", "$\\cdot$","$x^2$", "$\\,\\,\\,\\,\\Rightarrow$ Even degree", color=BLUE, font_size=fs2).next_to(plane, DOWN, buff=0.6)
        funcTerm3 = Tex("$0.5$", "$\\cdot$","$x^3$", "$\\,\\,\\,\\,\\Rightarrow$ Odd degree", color=ORANGE, font_size=fs2).next_to(funcTerm2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                Yes, that's it!
                The <bookmark mark="n2"/> blue function belongs to the <bookmark mark="blueTerm"/> Term negative one times <bookmark mark="x2"/>
                x squared. This means, that the<bookmark mark="degE"/> degree of the blue function is even, because it has degree two. But because it's multiplied by negative one,
                the function values are always negative, instead of always positive.
                The <bookmark mark="n3"/> orange function belongs to the <bookmark mark="orangeTerm"/> Term 0.5 times <bookmark mark="x3"/>
                x cubed. This means, that the <bookmark mark="degO"/>degree of the orange function is odd, because it has degree three.
                """
        ) as tracker:


            self.wait_until_bookmark("n2")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("blueTerm")
            cursor.blinking=False
            x,y,_ = funcTerm2[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm2), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("x2")
            x,y,_ = funcTerm2[2].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("degE")
            x,y,_ = funcTerm2[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("n3")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

            self.wait_until_bookmark("orangeTerm")
            cursor.blinking=False
            x,y,_ = funcTerm3[0].get_center()+0.4*DOWN
            self.play(Write(funcTerm3), CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("x3")
            x,y,_ = funcTerm3[2].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            
            self.wait_until_bookmark("degO")
            x,y,_ = funcTerm3[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
class Func_5_1_I_5(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-8, 8, 2], x_ticks=[-2,-1,1,2],y_ticks=[-8,-4,4,8]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        func1 = MathTex("f", "(x)", "=",  "a","x^n", color=c1t, font_size=fs2)
        conds = VGroup(MathTex("a\\in\\mathbb{R}", color=c3t, font_size=fs3), MathTex("n\\in\\mathbb{Z}", color=c3t, font_size=fs3)).arrange(RIGHT, buff=0.3).next_to(func1, DOWN, buff=0.2)
        powerFunc = VGroup(func1, conds)
        
        f2 = lambda x: x**2
        f3 = lambda x: x**3
        f4 = lambda x: -x**3

        g2 = plane.plot(f2, color=BLUE)
        g3 = plane.plot(f3, color=ORANGE)
        g3c = g3.copy()

        odd1 = Tex("Odd functions:", font_size=fs2, color=c1t)
        odd2 = Tex("$f(-x) = -f(x)$", font_size=fs2, color=c1t)
        odd3 = Tex("$\\Rightarrow$ Rotational", font_size=fs3, color=c1t)
        odd4 = Tex("symmetry around origin", font_size=fs3, color=c1t)
        odd = VGroup(odd1, odd2, odd3, odd4).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(plane, DOWN, buff=0.4)


        # Action Sequence
        with self.voiceover(
                text="""
                Now we've seen the difference between functions of even and odd degree: Functions of <bookmark mark="even"/>even degree
                are always positive or always negative, while functions of <bookmark mark="odd"/>odd degree can be both positive and negative.
                There is a cool way to visually describe this, by using symmetry.
                Let's start with <bookmark mark="odd2"/> odd functions. 
                Looking at the orange function, see how the function value of a number x is the same as the negative value of negative x?
                So for example, f of <bookmark mark="p1"/>one is one, and f of<bookmark mark="n1"/>negative one is negative one.
                So f of negative one is the same as negative f of one.
                Another example: The value of f at <bookmark mark="p2"/> two is two times two times two, which is eight, and the
                value of f at <bookmark mark="n2"/>negative two is  negative two times negative two times negative two, which is negative eight.
                So the rule that we can observe here is that <bookmark mark="odd3"/> f of negative x is equal to negative f of x.
                Graphically, this means that there is a <bookmark mark="rotate"/> rotational symmetry around the origin.
                If you <bookmark mark="rotate2"/> rotate the function around the origin by 180 degrees, you get the same function again.
                And since this is true for all functions of odd degrees, for example x to the power of five, we call all functions that have this property
                "odd functions".
                """
        ) as tracker:
            
            self.wait_until_bookmark("even")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("odd")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(Unwrite(g2), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

            self.wait_until_bookmark("odd2")
            self.play(Write(odd1))

            self.wait_until_bookmark("p1")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("n1")
            x,y,_ = plane.c2p(-1,-1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("p2")
            cursor.blinking=False
            x,y,_ = plane.c2p(2,8)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("n2")
            x,y,_ = plane.c2p(-2,-8)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("odd3")
            self.play(Write(odd2))

            self.wait_until_bookmark("rotate")
            self.play(Write(odd3), Write(odd4), Rotate(g3, angle=PI, run_time=2))

            self.wait_until_bookmark("rotate2")
            self.play(Rotate(g3, angle=PI, run_time=2))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
class Func_5_1_I_6(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        func1 = MathTex("f", "(x)", "=",  "a","x^n", color=c1t, font_size=fs2)
        conds = VGroup(MathTex("a\\in\\mathbb{R}", color=c3t, font_size=fs3), MathTex("n\\in\\mathbb{Z}", color=c3t, font_size=fs3)).arrange(RIGHT, buff=0.3).next_to(func1, DOWN, buff=0.2)
        powerFunc = VGroup(func1, conds)
        
        f2 = lambda x: x**2
        f3 = lambda x: x**3
        f4 = lambda x: -x**3

        g2 = plane.plot(f2, color=BLUE)
        g3 = plane.plot(f3, color=ORANGE)
        g3c = g3.copy()

        even1 = Tex("Even functions:", font_size=fs2, color=c1t)
        even2 = Tex("$f(-x) = f(x)$", font_size=fs2, color=c1t)
        even3 = Tex("$\\Rightarrow$ symmetrical", font_size=fs3, color=c1t)
        even4 = Tex("around the y-axis", font_size=fs3, color=c1t)
        even = VGroup(even1, even2, even3, even4).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(plane, DOWN, buff=0.4)


        # Action Sequence
        with self.voiceover(
                text="""
                The symmetry of power functions with an <bookmark mark="even"/>even degree is this:
                <bookmark mark="even2"/>f of negative x is equal to f of x.
                So looking at the function f of x equals x squared for example, we see that <bookmark mark="p1"/>
                f of one is one, and <bookmark mark="n1"/>f of negative one is also one.
                Or that <bookmark mark="p2"/>f of two is four, and <bookmark mark="n2"/>f of negative two is also four.
                Graphically, this means that the function is <bookmark mark="sym1"/>symmetrical around the y-axis.
                This means, that we can <bookmark mark="sym2"/>reflect the function at the y-axis, and get the same function again.
                And since this is true for all functions of even degrees, for example x to the power of four, we call all functions that have this property
                "even functions".
                """
        ) as tracker:
            
            self.wait_until_bookmark("even")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), Write(even1), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("even2")
            self.play(Write(even2))

            self.wait_until_bookmark("p1")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("n1")
            x,y,_ = plane.c2p(-1,1)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("p2")
            cursor.blinking=False
            x,y,_ = plane.c2p(2,4)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)

            self.wait_until_bookmark("n2")
            x,y,_ = plane.c2p(-2,4)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sym1")
            cursor.blinking=False
            self.play(CursorMarkAxis(cursor, plane, axis='y'), Write(even3), Write(even4), Rotate(g2, angle=PI, axis=UP, run_time=2))

            self.wait_until_bookmark("sym2")
            self.play(Rotate(g2, angle=PI, axis=UP, run_time=2))
            self.wait(1)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveResize(cursor, x, y, 0.2, 0.2), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
class Func_5_1_I_7(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Even and Odd Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        func1 = MathTex("f", "(x)", "=",  "a","x^n", color=c1t, font_size=fs2)
        conds = VGroup(MathTex("a\\in\\mathbb{R}", color=c3t, font_size=fs3), MathTex("n\\in\\mathbb{Z}", color=c3t, font_size=fs3)).arrange(RIGHT, buff=0.3).next_to(func1, DOWN, buff=0.2)
        powerFunc = VGroup(func1, conds)
        
        f2 = lambda x: x**2
        f3 = lambda x: x**3
        f4 = lambda x: -x**3

        g2 = plane.plot(f2, color=BLUE)
        g3 = plane.plot(f3, color=ORANGE, x_range=[-4**(1/3),4**(1/3), 0.01])
        g3c = g3.copy()

        even1 = Tex("Even functions:", font_size=fs2, color=BLUE)
        even2 = Tex("$f(-x) = f(x)$", font_size=fs2, color=BLUE)
        odd1 = Tex("Odd functions:", font_size=fs2, color=ORANGE)
        odd2 = Tex("$f(-x) = -f(x)$", font_size=fs2, color=ORANGE)
        odd = VGroup(odd1, odd2)
        all = VGroup(even1, even2, odd1, odd2).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(plane, DOWN, buff=0.4)
        odd.shift(DOWN*0.2)
        


        # Action Sequence
        with self.voiceover(
                text="""
                Summary of even and odd functions:

                For <bookmark mark="even"/>even functions, it holds that <bookmark mark="even2"/>f of negative x is equal to f of x.
                Graphically, this means that the function is <bookmark mark="sym1"/>symmetrical around the y-axis.
                All power functions with an even degree, like x squared, x to the power of four and so on
                are even functions, but there are other examples of even functions.

                For <bookmark mark="odd"/>odd functions on the other hand, it holds that <bookmark mark="odd2"/>f of negative x is equal to negative f of x.
                Graphically, this means that the function is <bookmark mark="rotate"/>rotational symmetrical around the origin.
                All power functions with an odd degree, like x, x cubed and so on are odd functions, but there are other examples of odd functions as well.
                """
        ) as tracker:
            
            self.wait_until_bookmark("even")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), Write(even1), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("even2")
            self.play(Write(even2))

            self.wait_until_bookmark("sym1")
            cursor.blinking=False
            self.play(CursorMarkAxis(cursor, plane, axis='y'), Rotate(g2, angle=PI, axis=UP, run_time=2))
            self.play(Rotate(g2, angle=PI, axis=UP, run_time=2))

            self.wait_until_bookmark("odd")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(Unwrite(g2), CursorMoveResize(cursor, x, y, 0.2, 0.2), Write(odd1), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

            self.wait_until_bookmark("odd2")
            self.play(Write(odd2))

            self.wait_until_bookmark("rotate")
            self.play(Rotate(g3, angle=PI, run_time=2))
            self.play(Rotate(g3, angle=PI, run_time=2))
            


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
#########Pratice Part ###############
#####################################
#####################################


#####################################
#####################################
######## General Q-Types ############
#####################################
#####################################

#####################################
#####################################
class EvenOddQuestionScene(SophiaCursorScene, metaclass = ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        x,y,_ = plane.c2p(0,0)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        func1 = MathTex("f", "(x)", "=",  "a","x^n", color=c1t, font_size=fs2)
        conds = VGroup(MathTex("a\\in\\mathbb{R}", color=c3t, font_size=fs3), MathTex("n\\in\\mathbb{Z}", color=c3t, font_size=fs3)).arrange(RIGHT, buff=0.3).next_to(func1, DOWN, buff=0.2)
        powerFunc = VGroup(func1, conds)

        g2 = plane.plot(self.f2, color=self.c1[0])
        g3 = plane.plot(self.f3, color=self.c2[0])

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro}
                Look at the <bookmark mark="n2"/> {self.c1[1]} function, and look at the <bookmark mark="n3"/> {self.c2[1]} function.
                Are they even functions, odd functions, or neither?
                """
        ) as tracker:


            self.wait_until_bookmark("n2")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("n3")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

#####################################
#####################################
class EvenOddAnswerScene(SophiaCursorScene, metaclass = ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Power Functions")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)
        x,y,_ = plane.c2p(0,0)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        testVals = np.array([0.8,1.332, 1.4135,12.41412])
        s1 = "even" if np.all(self.f2(testVals) == self.f2(-testVals)) else "odd" if np.all(self.f2(testVals) == -self.f2(-testVals)) else "neither even nor odd"
        s2 = "even" if np.all(self.f3(testVals) == self.f3(-testVals)) else "odd" if np.all(self.f3(testVals) == -self.f3(-testVals)) else "neither even nor odd"

        text1 = f"""The {self.c1[1]} function is neither even nor odd, because it's neither symmetric <bookmark mark="r11"/> around the origin, nor is it <bookmark mark="r12"/>symmetric around the y-axis."""
        text2 = f"""The {self.c2[1]} function is neither even nor odd, because it's neither symmetric <bookmark mark="r21"/> around the origin, nor is it <bookmark mark="r22"/>symmetric around the y-axis."""
        
        if s1 == "even":
            text1 = f"""The {self.c1[1]} function is even, because it is symmetric <bookmark mark="r12"/> around the y-axis."""
        elif s1 == "odd":
            text1 = f"""The {self.c1[1]} function is odd, because it is symmetric <bookmark mark="r11"/> around the origin."""

        if s2 == "even":
            text2 = f"""The {self.c2[1]} function is even, because it is symmetric <bookmark mark="r22"/> around the y-axis."""
        elif s2 == "odd":
            text2 = f"""The {self.c2[1]} function is odd, because it is symmetric <bookmark mark="r21"/> around the origin."""


        g2 = plane.plot(self.f2, color=self.c1[0])
        g3 = plane.plot(self.f3, color=self.c2[0])

        funcTerm2 = Tex("$-1$", "$\\cdot$","$x^2$", "$\\,\\,\\,\\,\\Rightarrow$ Even degree", color=BLUE, font_size=fs2).next_to(plane, DOWN, buff=0.6)
        funcTerm3 = Tex("$0.5$", "$\\cdot$","$x^3$", "$\\,\\,\\,\\,\\Rightarrow$ Odd degree", color=ORANGE, font_size=fs2).next_to(funcTerm2, DOWN, buff=0.2)

        r1 = VGroup(Tex(f"The {self.c1[1]} function is", color=self.c1[0], font_size=fs3), Tex(s1, color=self.c1[0], font_size=fs3)).arrange(DOWN, buff=0.2, aligned_edge=LEFT)
        r2 = VGroup(Tex(f"The {self.c2[1]} function is", color=self.c2[0], font_size=fs3), Tex(s2, color=self.c2[0], font_size=fs3)).arrange(DOWN, buff=0.2, aligned_edge=LEFT)
        r = VGroup(r1, r2).arrange(DOWN, buff=0.4, aligned_edge=LEFT).next_to(plane, DOWN, buff=0.6)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro}
                Let's first look at <bookmark mark="f1"/>the {self.c1[1]} function.
                {text1} <bookmark mark="unWrite"/>
                And now let's look at <bookmark mark="f2"/>the {self.c2[1]} function.
                {text2}
                So: The {self.c1[1]} function is <bookmark mark="r1"/>{s1}, and the {self.c2[1]} function is <bookmark mark="r2"/>{s2}.
                """
        ) as tracker:


            self.wait_until_bookmark("f1")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            if not s1 == "even":
                self.wait_until_bookmark("r11")
                copy = g2.copy().set_color(GREY).set_stroke_width(1)
                self.bring_to_back(copy)
                self.add(copy)
                self.play(Rotate(g2, about_point=plane.c2p(0,0), angle=PI))
                self.wait(1.5)
                self.play(Rotate(g2, about_point=plane.c2p(0,0), angle=PI, run_time=0.3))
                self.remove(copy)

            if not s1 == "odd":
                self.wait_until_bookmark("r12")
                copy = g2.copy().set_color(GREY).set_stroke_width(1)
                self.bring_to_back(copy)
                self.add(copy)
                cursor.blinking=False
                self.play(CursorMarkAxis(cursor, plane, axis='y'), Rotate(g2, about_point=plane.c2p(0,0), angle=PI, axis=UP, run_time=1.5), run_time=0.5)
                self.wait(1.5)
                x,y,_ = plane.c2p(0,0)
                self.play(CursorMoveResize(cursor, x, y, 0.2, 0.2), Rotate(g2, about_point=plane.c2p(0,0), angle=PI, axis=UP), run_time=0.3)
                cursor.blinking=True
                self.remove(copy)

            self.wait_until_bookmark("unWrite")
            self.play(Unwrite(g2))

            self.wait_until_bookmark("f2")
            cursor.blinking=False
            x,y,_ = g3.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g3))
            cursor.blinking=True

            if not s2 == "even":
                self.wait_until_bookmark("r21")
                copy = g3.copy().set_color(GREY).set_stroke_width(1)
                self.bring_to_back(copy)
                self.add(copy)
                self.play(Rotate(g3, about_point=plane.c2p(0,0), angle=PI))
                self.wait(1.5)
                self.play(Rotate(g3, about_point=plane.c2p(0,0), angle=PI, run_time=0.3))
                self.remove(copy)

            if not s2 == "odd":
                self.wait_until_bookmark("r22")
                copy = g3.copy().set_color(GREY).set_stroke_width(1)
                self.bring_to_back(copy)
                self.add(copy)
                cursor.blinking=False
                self.play(CursorMarkAxis(cursor, plane, axis='y'), Rotate(g3, about_point=plane.c2p(0,0), angle=PI, axis=UP, run_time=1.5), run_time=0.5)
                self.wait(1.5)
                x,y,_ = plane.c2p(0,0)
                self.play(CursorMoveResize(cursor, x, y, 0.2, 0.2), Rotate(g3, about_point=plane.c2p(0,0), angle=PI, axis=UP), run_time=0.3)
                cursor.blinking=True
                self.remove(copy)

            self.wait_until_bookmark("r1")
            cursor.blinking=False
            x,y,_ = r1.get_center()+0.6*DOWN
            self.play(Write(r1), CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("r2")
            cursor.blinking=False
            x,y,_ = r2.get_center()+0.6*DOWN
            self.play(Write(r2), CursorMoveTo(cursor, x, y), run_time=0.3)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
######## Specific Questions #########
#####################################
#####################################

#####################################
#####################################
TASK_Func_5_1_P_1_q = SophiaTaskDefinition(
    answerOptions = ["Blue: Even, Orange: Neither", "Blue: Even, Orange: Even", "Blue: Odd, Orange: Neither", "Blue: Even, Orange: Odd"],
    correctAnswerIndex = 0,
    questionText = "Do the blue and the orange function have an even or an odd degree?"
)
class Func_5_1_P_1_q(EvenOddQuestionScene):

    def construct(self):

        self.intro = "Ok, let's practice the concept of even and odd functions:"
        self.c1 = [BLUE, "blue"]
        self.c2 = [ORANGE, "orange"]

        self.f2 = lambda x: x**2+1
        self.f3 = lambda x: 0.5*x**3+1

        super().construct()

class Func_5_1_P_1_a(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [BLUE, "blue"]
        self.c2 = [ORANGE, "orange"]

        self.f2 = lambda x: -x**2
        self.f3 = lambda x: 0.5*x**3+1

        self.intro = "Yep, that is correct!"

        super().construct()

class Func_5_1_P_1_b(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [BLUE, "blue"]
        self.c2 = [ORANGE, "orange"]

        self.f2 = lambda x: -x**2
        self.f3 = lambda x: 0.5*x**3+1

        self.intro = "No, that's not right..."

        super().construct()
    
class Func_5_1_P_1_c(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [BLUE, "blue"]
        self.c2 = [ORANGE, "orange"]

        self.f2 = lambda x: -x**2
        self.f3 = lambda x: 0.5*x**3+1

        self.intro = "No, that's not right..."

        super().construct()

class Func_5_1_P_1_d(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [BLUE, "blue"]
        self.c2 = [ORANGE, "orange"]

        self.f2 = lambda x: -x**2
        self.f3 = lambda x: 0.5*x**3+1

        self.intro = "No, that's not right..."

        super().construct()

#####################################
#####################################
TASK_Func_5_1_P_2_q = SophiaTaskDefinition(
    answerOptions = ["Purple: Even, Green: Neither", "Purple: Neither, Green: Odd", "Purple: Even, Green: Even", "Purple: Odd, Green: Neither"],
    correctAnswerIndex = 1,
    questionText = "Do the purple and the green function have an even or an odd degree?"
)
class Func_5_1_P_2_q(EvenOddQuestionScene):

    def construct(self):

        self.intro = "Two more examples:"
        self.c1 = [PURPLE, "purple"]
        self.c2 = [GREEN, "green"]

        self.f2 = lambda x: (x**2-2*x)/2
        self.f3 = lambda x: 2*x

        super().construct()

class Func_5_1_P_2_a(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [PURPLE, "purple"]
        self.c2 = [GREEN, "green"]

        self.f2 = lambda x: (x**2-2*x)/2
        self.f3 = lambda x: 2*x

        self.intro = "No, that's not it"

        super().construct()

class Func_5_1_P_2_b(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [PURPLE, "purple"]
        self.c2 = [GREEN, "green"]

        self.f2 = lambda x: (x**2-2*x)/2
        self.f3 = lambda x: 2*x

        self.intro = "Correct, well done!"

        super().construct()

class Func_5_1_P_2_c(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [PURPLE, "purple"]
        self.c2 = [GREEN, "green"]

        self.f2 = lambda x: (x**2-2*x)/2
        self.f3 = lambda x: 2*x

        self.intro = "No, that's not it"

        super().construct()

class Func_5_1_P_2_d(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [PURPLE, "purple"]
        self.c2 = [GREEN, "green"]

        self.f2 = lambda x: (x**2-2*x)/2
        self.f3 = lambda x: 2*x

        self.intro = "No, that's not it"

        super().construct()


#####################################
#####################################
TASK_Func_5_1_P_3_q = SophiaTaskDefinition(
    answerOptions = ["Red: Even, Yellow: Odd", "Red: Odd, Yellow: Even", "Red: Odd, Yellow: Neither", "Red: Even, Yellow: Neither"],
    correctAnswerIndex = 3,
    questionText = "Do the red and the yellow function have an even or an odd degree?"
)
class Func_5_1_P_3_q(EvenOddQuestionScene):

    def construct(self):

        self.intro = "Next set of examples:"
        self.c1 = [RED, "red"]
        self.c2 = [YELLOW, "yellow"]

        self.f2 = lambda x: (x**4)/2 - 1
        self.f3 = lambda x: x + 2

        super().construct()

class Func_5_1_P_3_a(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [RED, "red"]
        self.c2 = [YELLOW, "yellow"]

        self.f2 = lambda x: (x**4)/2 - 1
        self.f3 = lambda x: x + 2

        self.intro = "No, that's incorrect."

        super().construct()

class Func_5_1_P_3_b(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [RED, "red"]
        self.c2 = [YELLOW, "yellow"]

        self.f2 = lambda x: (x**4)/2 - 1
        self.f3 = lambda x: x + 2

        self.intro = "No, that's incorrect."

        super().construct()

class Func_5_1_P_3_c(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [RED, "red"]
        self.c2 = [YELLOW, "yellow"]

        self.f2 = lambda x: (x**4)/2 - 1
        self.f3 = lambda x: x + 2

        self.intro = "No, that's incorrect."

        super().construct()

class Func_5_1_P_3_d(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [RED, "red"]
        self.c2 = [YELLOW, "yellow"]

        self.f2 = lambda x: (x**4)/2 - 1
        self.f3 = lambda x: x + 2

        self.intro = "Yes, you're correct!"

        super().construct()

#####################################
#####################################
TASK_Func_5_1_P_4_q = SophiaTaskDefinition(
    answerOptions = ["PINK: Odd, Teal: Odd", "PINK: Even, Teal: Odd", "PINK: Odd, Teal: Even", "PINK: Even, Teal: Even"],
    correctAnswerIndex = 1,
    questionText = "Do the PINK and the teal function have an even or an odd degree?"
)
class Func_5_1_P_4_q(EvenOddQuestionScene):

    def construct(self):

        self.intro = "Last example for today:"
        self.c1 = [PINK, "PINK"]
        self.c2 = [TEAL, "teal"]

        self.f2 = lambda x: (x**4 + 2)/6
        self.f3 = lambda x: (x**3 + x)/2.5

        super().construct()

class Func_5_1_P_4_a(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [PINK, "PINK"]
        self.c2 = [TEAL, "teal"]

        self.f2 = lambda x: (x**4 + 2)/6
        self.f3 = lambda x: (x**3 + x)/2.5

        self.intro = "No, that's incorrect."

        super().construct()

class Func_5_1_P_4_b(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [PINK, "PINK"]
        self.c2 = [TEAL, "teal"]

        self.f2 = lambda x: (x**4 + 2)/6
        self.f3 = lambda x: (x**3 + x)/2.5

        self.intro = "Yes, you're correct!"

        super().construct()

class Func_5_1_P_4_c(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [PINK, "PINK"]
        self.c2 = [TEAL, "teal"]

        self.f2 = lambda x: (x**4 + 2)/6
        self.f3 = lambda x: (x**3 + x)/2.5

        self.intro = "No, that's incorrect."

        super().construct()

class Func_5_1_P_4_d(EvenOddAnswerScene):

    def construct(self):

        self.c1 = [PINK, "PINK"]
        self.c2 = [TEAL, "teal"]

        self.f2 = lambda x: (x**4 + 2)/6
        self.f3 = lambda x: (x**3 + x)/2.5

        self.intro = "No, that's incorrect."

        super().construct()



PROTOTYPES=[
    PagePrototypeVideo.from_scene(Func_5_1_I_1),
    PagePrototypeVideo.from_scene(Func_5_1_I_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_5_1_I_2_q, Func_5_1_I_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_5_1_I_2_a),
    PagePrototypeVideo.from_scene(Func_5_1_I_2_b),
    PagePrototypeVideo.from_scene(Func_5_1_I_2_c),
    PagePrototypeVideo.from_scene(Func_5_1_I_2_d),
    PagePrototypeVideo.from_scene(Func_5_1_I_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_5_1_I_3_q, Func_5_1_I_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_5_1_I_3_a),
    PagePrototypeVideo.from_scene(Func_5_1_I_3_b),
    PagePrototypeVideo.from_scene(Func_5_1_I_3_c),
    PagePrototypeVideo.from_scene(Func_5_1_I_3_d),
    PagePrototypeVideo.from_scene(Func_5_1_I_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_5_1_I_4_q, Func_5_1_I_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_5_1_I_4_a),
    PagePrototypeVideo.from_scene(Func_5_1_I_4_b),
    PagePrototypeVideo.from_scene(Func_5_1_I_4_c),
    PagePrototypeVideo.from_scene(Func_5_1_I_4_d),
    PagePrototypeVideo.from_scene(Func_5_1_I_5),
    PagePrototypeVideo.from_scene(Func_5_1_I_6),
    PagePrototypeVideo.from_scene(Func_5_1_I_7),
    PagePrototypeVideo.from_scene(Func_5_1_P_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_5_1_P_1_q, Func_5_1_P_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_5_1_P_1_a),
    PagePrototypeVideo.from_scene(Func_5_1_P_1_b),
    PagePrototypeVideo.from_scene(Func_5_1_P_1_c),
    PagePrototypeVideo.from_scene(Func_5_1_P_1_d),
    PagePrototypeVideo.from_scene(Func_5_1_P_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_5_1_P_2_q, Func_5_1_P_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_5_1_P_2_a),
    PagePrototypeVideo.from_scene(Func_5_1_P_2_b),
    PagePrototypeVideo.from_scene(Func_5_1_P_2_c),
    PagePrototypeVideo.from_scene(Func_5_1_P_2_d),
    PagePrototypeVideo.from_scene(Func_5_1_P_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_5_1_P_3_q, Func_5_1_P_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_5_1_P_3_a),
    PagePrototypeVideo.from_scene(Func_5_1_P_3_b),
    PagePrototypeVideo.from_scene(Func_5_1_P_3_c),
    PagePrototypeVideo.from_scene(Func_5_1_P_3_d),
    PagePrototypeVideo.from_scene(Func_5_1_P_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_5_1_P_4_q, Func_5_1_P_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_5_1_P_4_a),
    PagePrototypeVideo.from_scene(Func_5_1_P_4_b),
    PagePrototypeVideo.from_scene(Func_5_1_P_4_c),
    PagePrototypeVideo.from_scene(Func_5_1_P_4_d),

]
scenes/Func/Func_5: Power Functions/Func_5_1.py
Sophia-Edu-Labs/sophia-math
# 5_2: Power Functions: n-th root

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition


#####################################
#####################################
TASK_Func_5_2_I_1_q = SophiaTaskDefinition(
    answerOptions = ["$\sqrt{2}$", "$2$", "$4$", "24"],
    correctAnswerIndex = 1,
    questionText = "What is $\sqrt[3]{8}$?"
)
class Func_5_2_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("n-th Roots")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        root_general = MathTex("\\sqrt{x}","\\cdot","\\sqrt{x}","=", "x", color=c1t, font_size = fs1).shift(UP*2)
        root_four = MathTex("\\sqrt{4}","=", "2", color=c1t, font_size = fs1).next_to(root_general, DOWN, buff=0.4)
        root_nine = MathTex("\\sqrt{9}","=", "3", color=c1t, font_size = fs1).next_to(root_four, DOWN, buff=0.4)
        root_general_2 = MathTex("\\sqrt[2]{x}","\\cdot","\\sqrt[2]{x}","=", "x", color=c1t, font_size = fs1).shift(UP*2)
        root_four_2 = MathTex("\\sqrt[2]{4}","=", "2", color=c1t, font_size = fs1).next_to(root_general, DOWN, buff=0.4)
        root_nine_2 = MathTex("\\sqrt[2]{9}","=", "3", color=c1t, font_size = fs1).next_to(root_four, DOWN, buff=0.4)

        root_general_3 = MathTex("\\sqrt[3]{x}","\\cdot","\\sqrt[3]{x}","\\cdot","\\sqrt[3]{x}","=", "x", color=c1t, font_size = fs1).next_to(root_nine_2, DOWN, buff=1.2)
        root_four_3 = MathTex("\\sqrt[2]{8}","=", "?", color=c1t, font_size = fs1).next_to(root_general_3, DOWN, buff=0.4)


        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]


        # Action Sequence
        with self.voiceover(
                text="""
                Remember the concept of a square root?
                The square root of a number x is the number that you have to multiply by itself to get x.
                So <bookmark mark="rootx1"/>the square root of x times<bookmark mark="rootx2"/> the square
                root of x is equal<bookmark mark="rootx3"/> to x.

                For example, the square root of <bookmark mark="root4"/>four is two, because two times two is four.
                And the square root of <bookmark mark="root9"/>nine is three, because three times three is nine.
                
                The reason we call square roots square roots is because we want to know what number we have to
                square to get the number under the root, so the number we have to multiply by itself two times.
                The concept of the square is often signified by <bookmark mark="2root"/>writing a two on the
                left side of the root symbol. And again, the two means that we're looking for the number that
                we have to multiply by itself two times to get the number under the root. <bookmark mark="deco"/>

                Now that there are square roots, you might be wondering if there are also other roots, and the
                answer is yes. For example, there's cube roots, which are the numbers that you have to multiply
                by itself three times to get the number under the root. So <bookmark mark="Crootx1"/>the cube
                root of x times<bookmark mark="Crootx2"/> the cube root of x times <bookmark mark="Crootx3"/>
                the cube root of x is <bookmark mark="Crootx4"/>equal to x. 
                
                Following that pattern, <bookmark mark="q"/>can you tell me what the cube root of eight is?
                """
        ) as tracker:

            self.wait_until_bookmark("rootx1")
            cursor.blinking=False
            x,y,_ = root_general[0].get_center()+0.4*DOWN
            self.play(Write(root_general), CursorMoveTo(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("rootx2")
            x,y,_ = root_general[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("rootx3")
            x,y,_ = root_general[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("root4")
            cursor.blinking=False
            x,y,_ = root_four.get_center()+0.4*DOWN
            self.play(Write(root_four), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True
            
            self.wait_until_bookmark("root9")
            cursor.blinking=False
            x,y,_ = root_nine.get_center()+0.4*DOWN
            self.play(Write(root_nine), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("2root")
            self.play(TransformMatchingTex(root_general, root_general_2), TransformMatchingTex(root_four, root_four_2), TransformMatchingTex(root_nine, root_nine_2), run_time=2)

            self.wait_until_bookmark("deco")
            self.draw_decorative_line(cursor, 0.6, run_time=4)

            self.wait_until_bookmark("Crootx1")
            cursor.blinking=False
            x,y,_ = root_general_3[0].get_center()+0.4*DOWN
            self.play(Write(root_general_3), CursorMoveTo(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("Crootx2")
            x,y,_ = root_general_3[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("Crootx3")
            x,y,_ = root_general_3[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("Crootx4")
            x,y,_ = root_general_3[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("q")
            cursor.blinking=False
            x,y,_ = root_four_3.get_center()+0.4*DOWN
            self.play(Write(root_four_3), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_5_2_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("n-th Roots")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        root_eight = MathTex("\\sqrt[3]{8}","=", "?", color=c1t, font_size = fs1).shift(UP*1.2)
        cube2 = MathTex("2", "\\cdot", "2", "\\cdot", "2", "=", "2^3", "=", "8", color=c1t, font_size = fs1).next_to(root_eight, DOWN, buff=0.4)
        sol = MathTex("\\Rightarrow", "\\sqrt[3]{8}","=", "2", color=c1t, font_size = fs1).next_to(cube2, DOWN, buff=0.4)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]


        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it.
                We're <bookmark mark="intro"/>looking for the cube root of 8, also known as the third root of 8.
                That means, we're looking for the number that we can cube, or multiply by itself three times to get 8.
                You can easily <bookmark mark="two1"/>check that 2 <bookmark mark="two2"/>times 2
                <bookmark mark="two3"/>times 2, or <bookmark mark="twoCubed"/>2 to the power of 3<bookmark mark="eight"/>
                equals 8.
                Therefore, <bookmark mark="sol"/>the cube root of 8 <bookmark mark="sol2"/>is 2.
                """
        ) as tracker:
            
            self.wait_until_bookmark("intro")
            cursor.blinking=False
            x,y,_ = root_eight.get_center()+0.4*DOWN
            self.play(Write(root_eight), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("two1")
            cursor.blinking=False
            x,y,_ = cube2[0].get_center()+0.4*DOWN
            self.play(Write(cube2), CursorMoveTo(cursor, x,y), run_time=0.3)

            self.wait_until_bookmark("two2")
            x,y,_ = cube2[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.3)

            self.wait_until_bookmark("two3")
            x,y,_ = cube2[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.3)

            self.wait_until_bookmark("twoCubed")
            x,y,_ = cube2[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            
            self.wait_until_bookmark("eight")
            x,y,_ = cube2[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=False

            self.wait_until_bookmark("sol")
            x,y,_ = sol.get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("sol2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=True
        
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_5_2_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("n-th Roots")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        root_eight = MathTex("\\sqrt[3]{8}","=", "?", color=c1t, font_size = fs1).shift(UP*1.2)
        cube2 = MathTex("2", "\\cdot", "2", "\\cdot", "2", "=", "2^3", "=", "8", color=c1t, font_size = fs1).next_to(root_eight, DOWN, buff=0.4)
        sol = MathTex("\\Rightarrow", "\\sqrt[3]{8}","=", "2", color=c1t, font_size = fs1).next_to(cube2, DOWN, buff=0.4)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]


        # Action Sequence
        with self.voiceover(
                text="""
                Nice, you got it!
                We're <bookmark mark="intro"/>looking for the cube root of 8, also known as the third root of 8.
                That means, we're looking for the number that we can cube, or multiply by itself three times to get 8.
                You can easily <bookmark mark="two1"/>check that 2 <bookmark mark="two2"/>times 2
                <bookmark mark="two3"/>times 2, or <bookmark mark="twoCubed"/>2 to the power of 3<bookmark mark="eight"/>
                equals 8.
                Therefore, <bookmark mark="sol"/>the cube root of 8 <bookmark mark="sol2"/>is 2.
                """
        ) as tracker:
            
            self.wait_until_bookmark("intro")
            cursor.blinking=False
            x,y,_ = root_eight.get_center()+0.4*DOWN
            self.play(Write(root_eight), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("two1")
            cursor.blinking=False
            x,y,_ = cube2[0].get_center()+0.4*DOWN
            self.play(Write(cube2), CursorMoveTo(cursor, x,y), run_time=0.3)

            self.wait_until_bookmark("two2")
            x,y,_ = cube2[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.3)

            self.wait_until_bookmark("two3")
            x,y,_ = cube2[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.3)

            self.wait_until_bookmark("twoCubed")
            x,y,_ = cube2[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            
            self.wait_until_bookmark("eight")
            x,y,_ = cube2[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=False

            self.wait_until_bookmark("sol")
            x,y,_ = sol.get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("sol2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=True
        
        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_5_2_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("n-th Roots")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        root_eight = MathTex("\\sqrt[3]{8}","=", "?", color=c1t, font_size = fs1).shift(UP*1.2)
        cube2 = MathTex("2", "\\cdot", "2", "\\cdot", "2", "=", "2^3", "=", "8", color=c1t, font_size = fs1).next_to(root_eight, DOWN, buff=0.4)
        sol = MathTex("\\Rightarrow", "\\sqrt[3]{8}","=", "2", color=c1t, font_size = fs1).next_to(cube2, DOWN, buff=0.4)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]


        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it.
                We're <bookmark mark="intro"/>looking for the cube root of 8, also known as the third root of 8.
                That means, we're looking for the number that we can cube, or multiply by itself three times to get 8.
                You can easily <bookmark mark="two1"/>check that 2 <bookmark mark="two2"/>times 2
                <bookmark mark="two3"/>times 2, or <bookmark mark="twoCubed"/>2 to the power of 3<bookmark mark="eight"/>
                equals 8.
                Therefore, <bookmark mark="sol"/>the cube root of 8 <bookmark mark="sol2"/>is 2.
                """
        ) as tracker:
            
            self.wait_until_bookmark("intro")
            cursor.blinking=False
            x,y,_ = root_eight.get_center()+0.4*DOWN
            self.play(Write(root_eight), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("two1")
            cursor.blinking=False
            x,y,_ = cube2[0].get_center()+0.4*DOWN
            self.play(Write(cube2), CursorMoveTo(cursor, x,y), run_time=0.3)

            self.wait_until_bookmark("two2")
            x,y,_ = cube2[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.3)

            self.wait_until_bookmark("two3")
            x,y,_ = cube2[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.3)

            self.wait_until_bookmark("twoCubed")
            x,y,_ = cube2[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            
            self.wait_until_bookmark("eight")
            x,y,_ = cube2[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=False

            self.wait_until_bookmark("sol")
            x,y,_ = sol.get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("sol2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=True
        
        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_5_2_I_1_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("n-th Roots")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        root_eight = MathTex("\\sqrt[3]{8}","=", "?", color=c1t, font_size = fs1).shift(UP*1.2)
        cube2 = MathTex("2", "\\cdot", "2", "\\cdot", "2", "=", "2^3", "=", "8", color=c1t, font_size = fs1).next_to(root_eight, DOWN, buff=0.4)
        sol = MathTex("\\Rightarrow", "\\sqrt[3]{8}","=", "2", color=c1t, font_size = fs1).next_to(cube2, DOWN, buff=0.4)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]


        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it.
                We're <bookmark mark="intro"/>looking for the cube root of 8, also known as the third root of 8.
                That means, we're looking for the number that we can cube, or multiply by itself three times to get 8.
                You can easily <bookmark mark="two1"/>check that 2 <bookmark mark="two2"/>times 2
                <bookmark mark="two3"/>times 2, or <bookmark mark="twoCubed"/>2 to the power of 3<bookmark mark="eight"/>
                equals 8.
                Therefore, <bookmark mark="sol"/>the cube root of 8 <bookmark mark="sol2"/>is 2.
                """
        ) as tracker:
            
            self.wait_until_bookmark("intro")
            cursor.blinking=False
            x,y,_ = root_eight.get_center()+0.4*DOWN
            self.play(Write(root_eight), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("two1")
            cursor.blinking=False
            x,y,_ = cube2[0].get_center()+0.4*DOWN
            self.play(Write(cube2), CursorMoveTo(cursor, x,y), run_time=0.3)

            self.wait_until_bookmark("two2")
            x,y,_ = cube2[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.3)

            self.wait_until_bookmark("two3")
            x,y,_ = cube2[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.3)

            self.wait_until_bookmark("twoCubed")
            x,y,_ = cube2[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            
            self.wait_until_bookmark("eight")
            x,y,_ = cube2[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=False

            self.wait_until_bookmark("sol")
            x,y,_ = sol.get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveTo(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("sol2")
            x,y,_ = sol[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=True
        
        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
TASK_Func_5_2_I_2_q = SophiaTaskDefinition(
    answerOptions = ["$4$", "$-2$", "$\{-2,2\}$", "$2$"],
    correctAnswerIndex = 2,
    questionText = "What is $\sqrt[4]{16}$?"
)
class Func_5_2_I_2_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("n-th Roots")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        root_general_2 = MathTex("\\sqrt[2]{x}","\\cdot","\\sqrt[2]{x}","=", "x", color=c1t, font_size = fs1).shift(UP)
        root_general_3 = MathTex("\\sqrt[3]{x}","\\cdot","\\sqrt[3]{x}","\\cdot","\\sqrt[3]{x}","=", "x", color=c1t, font_size = fs1).next_to(root_general_2, DOWN, buff=0.2)
        root_general_4 = MathTex("\\sqrt[3]{x}","\\cdot","\\sqrt[3]{x}","\\cdot","\\sqrt[3]{x}","\\cdot","\\sqrt[3]{x}","=", "x", color=c1t, font_size = fs1).next_to(root_general_3, DOWN, buff=0.2)
        dots = MathTex("\\hdots", color=c1t, font_size=fs1).next_to(root_general_4, DOWN, buff=0.1)
        root_general_n = MathTex("\\sqrt[n]{x}","\\cdot", "\\overset{\\text{n times}}{\\hdots}","\\cdot", "\\sqrt[n]{x}", "=", "x", color=c1t, font_size = fs2).next_to(dots, DOWN, buff=0.2)
        root_four_4 = MathTex("\\sqrt[4]{16}","=", "?", color=c1t, font_size = fs1).next_to(root_general_n, DOWN, buff=0.4)


        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]


        # Action Sequence
        with self.voiceover(
                text="""
                Square roots or second roots are the numbers that you have to multiply by itself two times to get the number under the root.
                <bookmark mark="cube"/>Cube roots or third roots are the numbers that you have to multiply by itself three times to get the
                number under the root.
                And so <bookmark mark="dots"/>it continues for any number, so the fourth root of a number is the number that you have to
                multiply by itself 4 times to get the number under the root, the fifth root of a number is the number that you have to
                multiply by itself 5 times to get the number under the root, and so on. So <bookmark mark="n"/>the nth root of a number is
                the number that you have to multiply by itself n times to get the number under the root.

                Now, with that in mind, <bookmark mark="q"/>can you tell me what the fourth root of 16 is?
                """
        ) as tracker:
            
            cursor.blinking=False
            x,y,_ = root_general_2.get_center()+0.4*DOWN
            self.play(Write(root_general_2), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("cube")
            cursor.blinking=False
            x,y,_ = root_general_3.get_center()+0.4*DOWN
            self.play(Write(root_general_3), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("dots")
            cursor.blinking=False
            x,y,_ = dots.get_center()+0.4*DOWN
            self.play(Write(dots), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("n")
            cursor.blinking=False
            x,y,_ = root_general_n.get_center()+0.4*DOWN
            self.play(Write(root_general_n), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("q")
            cursor.blinking=False
            x,y,_ = root_four_4.get_center()+0.4*DOWN
            self.play(Write(root_four_4), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_5_2_I_2_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("n-th Roots")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        root_four_4 = MathTex("\\sqrt[4]{16}","=", "?", color=c1t, font_size = fs1).shift(UP)
        root_four_two = MathTex("2", "\\cdot", "2", "\\cdot", "2", "\\cdot", "2", "=", "16", color=c1t, font_size = fs2)
        sol_1 = MathTex("\\Rightarrow", "\\sqrt[4]{16}","=", "2", color=c1t, font_size = fs2)
        root_four_negtwo = MathTex("-2", "\\cdot", "-2", "\\cdot", "-2", "\\cdot", "-2", "=", "16", color=c1t, font_size = fs2)
        sol_2 = MathTex("\\Rightarrow", "\\sqrt[4]{16}","=", "\\{-2,","2\\}", color=c1t, font_size = fs2)
        sols = VGroup(root_four_two, sol_1, root_four_negtwo, sol_2).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(root_four_4, DOWN, buff=0.4)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]


        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                We're looking <bookmark mark="root4"/>for the fourth root of sixteen, so we're looking for the number that we can multiply by itself
                four times to get 16.
                You can easily check, that if you multiply <bookmark mark="rootTwo"/>two by itself four times, you get 16. So <bookmark mark="two1"/>
                since two <bookmark mark="two2"/>times two<bookmark mark="two3"/> times two<bookmark mark="two4"/> times two <bookmark mark="sxtn1"/>
                equals 16, <bookmark mark="sol"/>the fourth root of 16 <bookmark mark="sol2"/>is 2.
                You can also <bookmark  mark="rootNegTwo"/> check that if you multiply -2 by itself four times, you also get 16.
                So <bookmark mark="negTwo1"/> since negative 2 <bookmark mark="negTwo2"/>times negative 2<bookmark mark="negTwo3"/> times negative 2
                <bookmark mark="negTwo4"/> times negative 2 <bookmark mark="sxtn2"/> equals 16, <bookmark mark="sol3"/>the fourth root of 16
                <bookmark mark="sol4"/>is either negative 2 or <bookmark mark="sol5"/>2.
                """
        ) as tracker:
            
            self.wait_until_bookmark("root4")
            cursor.blinking=False
            x,y,_ = root_four_4.get_center()+0.4*DOWN
            self.play(Write(root_four_4), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("rootTwo")
            cursor.blinking=False
            x,y,_ = root_four_two.get_center()+0.4*DOWN
            self.play(Write(root_four_two), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("two1")
            cursor.blinking=False
            x,y,_ = root_four_two[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("two2")
            x,y,_ = root_four_two[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("two3")
            x,y,_ = root_four_two[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("two4")
            x,y,_ = root_four_two[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sxtn1")
            x,y,_ = root_four_two[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol")
            x,y,_ = sol_1.get_center()+0.4*DOWN
            self.play(Write(sol_1), CursorMoveTo(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("sol2")
            x,y,_ = sol_1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("rootNegTwo")
            cursor.blinking=False
            x,y,_ = root_four_negtwo.get_center()+0.4*DOWN
            self.play(Write(root_four_negtwo), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("negTwo1")
            cursor.blinking=False
            x,y,_ = root_four_negtwo[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negTwo2")
            x,y,_ = root_four_negtwo[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negTwo3")
            x,y,_ = root_four_negtwo[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negTwo4")
            x,y,_ = root_four_negtwo[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sxtn2")
            x,y,_ = root_four_negtwo[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol3")
            x,y,_ = sol_2[1].get_center()+0.4*DOWN
            self.play(Write(sol_2), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol4")
            x,y,_ = sol_2[-2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol5")
            x,y,_ = sol_2[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_5_2_I_2_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("n-th Roots")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        root_four_4 = MathTex("\\sqrt[4]{16}","=", "?", color=c1t, font_size = fs1).shift(UP)
        root_four_two = MathTex("2", "\\cdot", "2", "\\cdot", "2", "\\cdot", "2", "=", "16", color=c1t, font_size = fs2)
        sol_1 = MathTex("\\Rightarrow", "\\sqrt[4]{16}","=", "2", color=c1t, font_size = fs2)
        root_four_negtwo = MathTex("-2", "\\cdot", "-2", "\\cdot", "-2", "\\cdot", "-2", "=", "16", color=c1t, font_size = fs2)
        sol_2 = MathTex("\\Rightarrow", "\\sqrt[4]{16}","=", "\\{-2,","2\\}", color=c1t, font_size = fs2)
        sols = VGroup(root_four_two, sol_1, root_four_negtwo, sol_2).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(root_four_4, DOWN, buff=0.4)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]


        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                We're looking <bookmark mark="root4"/>for the fourth root of sixteen, so we're looking for the number that we can multiply by itself
                four times to get 16.
                You can easily check, that if you multiply <bookmark mark="rootTwo"/>two by itself four times, you get 16. So <bookmark mark="two1"/>
                since two <bookmark mark="two2"/>times two<bookmark mark="two3"/> times two<bookmark mark="two4"/> times two <bookmark mark="sxtn1"/>
                equals 16, <bookmark mark="sol"/>the fourth root of 16 <bookmark mark="sol2"/>is 2.
                You can also <bookmark  mark="rootNegTwo"/> check that if you multiply -2 by itself four times, you also get 16.
                So <bookmark mark="negTwo1"/> since negative 2 <bookmark mark="negTwo2"/>times negative 2<bookmark mark="negTwo3"/> times negative 2
                <bookmark mark="negTwo4"/> times negative 2 <bookmark mark="sxtn2"/> equals 16, <bookmark mark="sol3"/>the fourth root of 16
                <bookmark mark="sol4"/>is either negative 2 or <bookmark mark="sol5"/>2.
                """
        ) as tracker:
            
            self.wait_until_bookmark("root4")
            cursor.blinking=False
            x,y,_ = root_four_4.get_center()+0.4*DOWN
            self.play(Write(root_four_4), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("rootTwo")
            cursor.blinking=False
            x,y,_ = root_four_two.get_center()+0.4*DOWN
            self.play(Write(root_four_two), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("two1")
            cursor.blinking=False
            x,y,_ = root_four_two[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("two2")
            x,y,_ = root_four_two[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("two3")
            x,y,_ = root_four_two[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("two4")
            x,y,_ = root_four_two[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sxtn1")
            x,y,_ = root_four_two[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol")
            x,y,_ = sol_1.get_center()+0.4*DOWN
            self.play(Write(sol_1), CursorMoveTo(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("sol2")
            x,y,_ = sol_1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("rootNegTwo")
            cursor.blinking=False
            x,y,_ = root_four_negtwo.get_center()+0.4*DOWN
            self.play(Write(root_four_negtwo), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("negTwo1")
            cursor.blinking=False
            x,y,_ = root_four_negtwo[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negTwo2")
            x,y,_ = root_four_negtwo[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negTwo3")
            x,y,_ = root_four_negtwo[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negTwo4")
            x,y,_ = root_four_negtwo[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sxtn2")
            x,y,_ = root_four_negtwo[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol3")
            x,y,_ = sol_2[1].get_center()+0.4*DOWN
            self.play(Write(sol_2), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol4")
            x,y,_ = sol_2[-2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol5")
            x,y,_ = sol_2[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_5_2_I_2_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("n-th Roots")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        root_four_4 = MathTex("\\sqrt[4]{16}","=", "?", color=c1t, font_size = fs1).shift(UP)
        root_four_two = MathTex("2", "\\cdot", "2", "\\cdot", "2", "\\cdot", "2", "=", "16", color=c1t, font_size = fs2)
        sol_1 = MathTex("\\Rightarrow", "\\sqrt[4]{16}","=", "2", color=c1t, font_size = fs2)
        root_four_negtwo = MathTex("-2", "\\cdot", "-2", "\\cdot", "-2", "\\cdot", "-2", "=", "16", color=c1t, font_size = fs2)
        sol_2 = MathTex("\\Rightarrow", "\\sqrt[4]{16}","=", "\\{-2,","2\\}", color=c1t, font_size = fs2)
        sols = VGroup(root_four_two, sol_1, root_four_negtwo, sol_2).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(root_four_4, DOWN, buff=0.4)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]


        # Action Sequence
        with self.voiceover(
                text="""
                Yes, that's correct, well done.
                We're looking <bookmark mark="root4"/>for the fourth root of sixteen, so we're looking for the number that we can multiply by itself
                four times to get 16.
                You can easily check, that if you multiply <bookmark mark="rootTwo"/>two by itself four times, you get 16. So <bookmark mark="two1"/>
                since two <bookmark mark="two2"/>times two<bookmark mark="two3"/> times two<bookmark mark="two4"/> times two <bookmark mark="sxtn1"/>
                equals 16, <bookmark mark="sol"/>the fourth root of 16 <bookmark mark="sol2"/>is 2.
                You can also <bookmark  mark="rootNegTwo"/> check that if you multiply -2 by itself four times, you also get 16.
                So <bookmark mark="negTwo1"/> since negative 2 <bookmark mark="negTwo2"/>times negative 2<bookmark mark="negTwo3"/> times negative 2
                <bookmark mark="negTwo4"/> times negative 2 <bookmark mark="sxtn2"/> equals 16, <bookmark mark="sol3"/>the fourth root of 16
                <bookmark mark="sol4"/>is either negative 2 or <bookmark mark="sol5"/>2.
                """
        ) as tracker:
            
            self.wait_until_bookmark("root4")
            cursor.blinking=False
            x,y,_ = root_four_4.get_center()+0.4*DOWN
            self.play(Write(root_four_4), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("rootTwo")
            cursor.blinking=False
            x,y,_ = root_four_two.get_center()+0.4*DOWN
            self.play(Write(root_four_two), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("two1")
            cursor.blinking=False
            x,y,_ = root_four_two[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("two2")
            x,y,_ = root_four_two[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("two3")
            x,y,_ = root_four_two[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("two4")
            x,y,_ = root_four_two[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sxtn1")
            x,y,_ = root_four_two[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol")
            x,y,_ = sol_1.get_center()+0.4*DOWN
            self.play(Write(sol_1), CursorMoveTo(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("sol2")
            x,y,_ = sol_1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("rootNegTwo")
            cursor.blinking=False
            x,y,_ = root_four_negtwo.get_center()+0.4*DOWN
            self.play(Write(root_four_negtwo), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("negTwo1")
            cursor.blinking=False
            x,y,_ = root_four_negtwo[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negTwo2")
            x,y,_ = root_four_negtwo[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negTwo3")
            x,y,_ = root_four_negtwo[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negTwo4")
            x,y,_ = root_four_negtwo[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sxtn2")
            x,y,_ = root_four_negtwo[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol3")
            x,y,_ = sol_2[1].get_center()+0.4*DOWN
            self.play(Write(sol_2), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol4")
            x,y,_ = sol_2[-2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol5")
            x,y,_ = sol_2[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)

class Func_5_2_I_2_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("n-th Roots")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        root_four_4 = MathTex("\\sqrt[4]{16}","=", "?", color=c1t, font_size = fs1).shift(UP)
        root_four_two = MathTex("2", "\\cdot", "2", "\\cdot", "2", "\\cdot", "2", "=", "16", color=c1t, font_size = fs2)
        sol_1 = MathTex("\\Rightarrow", "\\sqrt[4]{16}","=", "2", color=c1t, font_size = fs2)
        root_four_negtwo = MathTex("-2", "\\cdot", "-2", "\\cdot", "-2", "\\cdot", "-2", "=", "16", color=c1t, font_size = fs2)
        sol_2 = MathTex("\\Rightarrow", "\\sqrt[4]{16}","=", "\\{-2,","2\\}", color=c1t, font_size = fs2)
        sols = VGroup(root_four_two, sol_1, root_four_negtwo, sol_2).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(root_four_4, DOWN, buff=0.4)

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]


        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                We're looking <bookmark mark="root4"/>for the fourth root of sixteen, so we're looking for the number that we can multiply by itself
                four times to get 16.
                You can easily check, that if you multiply <bookmark mark="rootTwo"/>two by itself four times, you get 16. So <bookmark mark="two1"/>
                since two <bookmark mark="two2"/>times two<bookmark mark="two3"/> times two<bookmark mark="two4"/> times two <bookmark mark="sxtn1"/>
                equals 16, <bookmark mark="sol"/>the fourth root of 16 <bookmark mark="sol2"/>is 2.
                You can also <bookmark  mark="rootNegTwo"/> check that if you multiply -2 by itself four times, you also get 16.
                So <bookmark mark="negTwo1"/> since negative 2 <bookmark mark="negTwo2"/>times negative 2<bookmark mark="negTwo3"/> times negative 2
                <bookmark mark="negTwo4"/> times negative 2 <bookmark mark="sxtn2"/> equals 16, <bookmark mark="sol3"/>the fourth root of 16
                <bookmark mark="sol4"/>is either negative 2 or <bookmark mark="sol5"/>2.
                """
        ) as tracker:
            
            self.wait_until_bookmark("root4")
            cursor.blinking=False
            x,y,_ = root_four_4.get_center()+0.4*DOWN
            self.play(Write(root_four_4), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("rootTwo")
            cursor.blinking=False
            x,y,_ = root_four_two.get_center()+0.4*DOWN
            self.play(Write(root_four_two), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("two1")
            cursor.blinking=False
            x,y,_ = root_four_two[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("two2")
            x,y,_ = root_four_two[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("two3")
            x,y,_ = root_four_two[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("two4")
            x,y,_ = root_four_two[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sxtn1")
            x,y,_ = root_four_two[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol")
            x,y,_ = sol_1.get_center()+0.4*DOWN
            self.play(Write(sol_1), CursorMoveTo(cursor, x,y), run_time=0.5)

            self.wait_until_bookmark("sol2")
            x,y,_ = sol_1[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("rootNegTwo")
            cursor.blinking=False
            x,y,_ = root_four_negtwo.get_center()+0.4*DOWN
            self.play(Write(root_four_negtwo), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("negTwo1")
            cursor.blinking=False
            x,y,_ = root_four_negtwo[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negTwo2")
            x,y,_ = root_four_negtwo[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negTwo3")
            x,y,_ = root_four_negtwo[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negTwo4")
            x,y,_ = root_four_negtwo[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sxtn2")
            x,y,_ = root_four_negtwo[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol3")
            x,y,_ = sol_2[1].get_center()+0.4*DOWN
            self.play(Write(sol_2), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol4")
            x,y,_ = sol_2[-2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("sol5")
            x,y,_ = sol_2[-1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x,y), run_time=0.2)
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################
class Func_5_2_I_3(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("n-th Roots")

        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        f1 = lambda x: x**2
        f2 = lambda x: (x**3)/2

        g1 = plane.plot(f1, color=BLUE)
        g2 = plane.plot(f2, color=GREEN)

        fTex1 = MathTex("f", "(x)",  "=",  "x^2", color=BLUE).next_to(cords, DOWN, buff=0.4)
        fTex2 = MathTex("f", "(x)",  "=",  "0.5", "x^3", color=GREEN).next_to(cords, DOWN, buff=0.4)

        divLine = Line([0,-2.5,0], [0,2,0], color=c1t)
        even = Tex("even exponent", font_size=fs3, color=BLUE)
        odd = Tex("odd exponent", font_size=fs3, color=GREEN)
        even_odd = VGroup(even, odd).arrange(RIGHT, buff=0.6).next_to(divLine, UP, buff=0.2)
        neg_1_to_2 = MathTex("(-1)^2", "=", "1", font_size=fs3, color=BLUE).next_to(even, DOWN, buff=0.2)
        neg_1_to_3 = MathTex("(-1)^3", "=", "-1", font_size=fs3, color=GREEN).next_to(odd, DOWN, buff=0.2)
        neg_1_to_4 = MathTex("(-1)^4", "=", "1", font_size=fs3, color=BLUE).next_to(neg_1_to_2, DOWN, buff=0.2)
        neg_1_to_5 = MathTex("(-1)^5", "=", "-1", font_size=fs3, color=GREEN).next_to(neg_1_to_3, DOWN, buff=0.2)

        dots_even = MathTex("\\hdots", font_size=fs3, color=BLUE).next_to(neg_1_to_4, DOWN, buff=0.2)
        dots_odd = MathTex("\\hdots", font_size=fs3, color=GREEN).next_to(neg_1_to_5, DOWN, buff=0.2)

        one_root_2 = MathTex("\\sqrt[2]{1}", "=", "\\pm 1", font_size=fs3, color=BLUE).next_to(dots_even, DOWN, buff=0.6)
        one_root_3 = MathTex("\\sqrt[3]{1}", "=", " 1", font_size=fs3, color=GREEN).next_to(dots_odd, DOWN, buff=0.6)
        one_root_4 = MathTex("\\sqrt[4]{1}", "=", "\\pm 1", font_size=fs3, color=BLUE).next_to(one_root_2, DOWN, buff=0.2)
        one_root_5 = MathTex("\\sqrt[5]{1}", "=", " 1", font_size=fs3, color=GREEN).next_to(one_root_3, DOWN, buff=0.2)

        neg_1_root_2 = MathTex("\\sqrt[2]{-1}", font_size=fs3, color=BLUE).next_to(one_root_4, DOWN, buff=0.6)
        sout_2 = Cross(color=RED).move_to(neg_1_root_2).scale(neg_1_root_2.get_width()/Cross().get_width())
        neg_1_root_3 = MathTex("\\sqrt[3]{-1}", "=", "-1", font_size=fs3, color=GREEN).next_to(one_root_5, DOWN, buff=0.6)
        neg_1_root_4 = MathTex("\\sqrt[4]{-1}", font_size=fs3, color=BLUE).next_to(neg_1_root_2, DOWN, buff=0.2)
        sout_4 = Cross(color=RED).move_to(neg_1_root_4).scale(neg_1_root_4.get_width()/Cross().get_width())
        neg_1_root_5 = MathTex("\\sqrt[5]{-1}", "=", "-1", font_size=fs3, color=GREEN).next_to(neg_1_root_3, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so for power functions, there's a difference between even and odd functions:
                <bookmark mark="even"/>Even functions are functions where the exponent is an even number, like 2, 4, 6, and
                they are <bookmark mark="evenSymmetry"/>symmetric around the y-axis.
                <bookmark mark="odd"/>Odd functions are functions where the exponent is an odd number, like 1, 3, 5, and
                they are <bookmark mark="oddSymmetry"/>symmetric around the origin.
                
                The core <bookmark mark="cleanUp"/>difference between the two comes from this:

                If you raise a negative number to an even power, the result is always positive.
                So <bookmark mark="neg_1_to_2"/>negative one squared is one, or <bookmark mark="neg_1_to_4"/>negative one to
                the power of four is also one, because each two negatives cancel each other out

                If you raise a negative number to an odd power however, the result is always negative.
                So <bookmark mark="neg_1_to_3"/>negative one to the power of three is negative one, because the two negatives
                cancel each other out, but the third one remains.
                And <bookmark mark="neg_1_to_5"/>negative one to the power of five is also negative, and <bookmark mark="so_on"/>so on...

                This also has important implications for the roots of these functions.
                The <bookmark mark="one_root_2"/>square root of one is always both one and negative one, because both of them squared is one.
                The same goes for <bookmark mark="one_root_4"/>the fourth root of one, the sixth root of one, and so on...
                So for all even roots of a positive number, there are two solutions: one positive and one negative.

                The <bookmark mark="one_root_3"/>cube root of one however, is only one, because one to the power of three is one, but
                negative one to the power of three is negative one. The same goes for <bookmark mark="one_root_5"/>the fifth root of one, and so on...

                But now, what about negative numbers?
                Well, the<bookmark mark="neg_1_root_2"/> square root of negative one doesn't exist, because there is no number that you can
                multiply by itself to get negative one. This is, because negative times negative is always positive.
                The same goes for <bookmark mark="neg_1_root_4"/>the fourth root of negative one, the sixth root of negative one, and so on...

                The <bookmark mark="neg_1_root_3"/>cube root of negative one however, exists and is equal to negative one,
                because negative one to the power of three is negative one. The same goes for <bookmark mark="neg_1_root_5"/>the fifth root
                of negative one, and so on...

                So for all odd roots of a negative number, there is only a solution, and it's negative. For all even roots of a negative
                number, there is no solution.
                """
        , subcaption='NOT AVAILABLE DUE TO BUG') as tracker:

            self.wait_until_bookmark("even")
            cursor.blinking=False
            x,y,_ = g1.get_start()
            self.play(Write(fTex1), CursorMoveTo(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g1.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g1))
            cursor.blinking=True
            
            self.wait_until_bookmark("evenSymmetry")
            copy = g1.copy().set_color(GREY).set_stroke_width(1)
            self.add(copy)
            self.bring_to_back(copy)
            self.play(Rotate(g1, about_point=plane.c2p(0,0),axis=UP ,angle=PI))
            self.wait(0.5)
            self.play(Rotate(g1, about_point=plane.c2p(0,0),axis=UP , angle=PI, run_time=0.3))
            self.remove(copy)

            self.wait_until_bookmark("odd")
            cursor.blinking=False
            x,y,_ = g2.get_start()
            self.play(TransformMatchingTex(fTex1, fTex2), CursorMoveTo(cursor, x, y), Unwrite(g1), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g2))
            cursor.blinking=True

            self.wait_until_bookmark("oddSymmetry")
            copy = g2.copy().set_color(GREY).set_stroke_width(1)
            self.add(copy)
            self.bring_to_back(copy)
            self.play(Rotate(g2, about_point=plane.c2p(0,0), angle=PI))
            self.wait(0.5)
            self.play(Rotate(g2, about_point=plane.c2p(0,0), angle=PI, run_time=0.3))
            self.remove(copy)

            self.wait_until_bookmark("cleanUp")
            out = VGroup(cords, g2, fTex2)
            self.play(out.animate.shift(RIGHT*5))
            self.play(Write(even), Write(odd), Write(divLine), run_time=0.5)

            self.wait_until_bookmark("neg_1_to_2")
            cursor.blinking=False
            x,y,_ = neg_1_to_2.get_center()+0.4*DOWN
            self.play(Write(neg_1_to_2), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("neg_1_to_4")
            x,y,_ = neg_1_to_4.get_center()+0.4*DOWN
            self.play(Write(neg_1_to_4), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("neg_1_to_3")
            x,y,_ = neg_1_to_3.get_center()+0.4*DOWN
            self.play(Write(neg_1_to_3), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("neg_1_to_5")
            x,y,_ = neg_1_to_5.get_center()+0.4*DOWN
            self.play(Write(neg_1_to_5), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking = True

            self.wait_until_bookmark("so_on")
            self.play(Write(dots_even), Write(dots_odd))
            
            self.wait_until_bookmark("one_root_2")
            cursor.blinking=False
            x,y,_ = one_root_2.get_center()+0.4*DOWN
            self.play(Write(one_root_2), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("one_root_4")
            x,y,_ = one_root_4.get_center()+0.4*DOWN
            self.play(Write(one_root_4), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("one_root_3")
            x,y,_ = one_root_3.get_center()+0.4*DOWN
            self.play(Write(one_root_3), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("one_root_5")
            x,y,_ = one_root_5.get_center()+0.4*DOWN
            self.play(Write(one_root_5), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking = True

            self.wait_until_bookmark("neg_1_root_2")
            cursor.blinking=False
            x,y,_ = neg_1_root_2.get_center()+0.4*DOWN
            self.play(Write(neg_1_root_2), Write(sout_2), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("neg_1_root_4")
            x,y,_ = neg_1_root_4.get_center()+0.4*DOWN
            self.play(Write(neg_1_root_4), Write(sout_4), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("neg_1_root_3")
            x,y,_ = neg_1_root_3.get_center()+0.4*DOWN
            self.play(Write(neg_1_root_3), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("neg_1_root_5")
            x,y,_ = neg_1_root_5.get_center()+0.4*DOWN
            self.play(Write(neg_1_root_5), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking = True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)



#####################################
#####################################
TASK_Func_5_2_I_4_q = SophiaTaskDefinition(
    answerOptions = ["$x<0$: no solution, $x>0$: two solutions", "$x<0$: two solutions, $x>0$: no solution", "$x>0$: one solution, $x<0$: one solution", "$x>0$: no solutions, $x<0$: no solutions"],
    correctAnswerIndex = 0,
    questionText = "Consider $\\sqrt[k]{x}$, where k is an even number. How many solutions are there for $x>0$, and how many for $x<0$?"
)
class Func_5_2_I_4_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Even Roots")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        root_general = Tex("$\\sqrt[k]{x}$", ",     ", "k is even", color=c1t, font_size = fs1).shift(UP*2)
        Q1 = Tex("How many solutions...", color=c1t, font_size = fs2)
        Q2a = Tex("if x is positive..?", color=c3t, font_size = fs2)
        Q2b = Tex("if x is negative..?", color=c3t, font_size = fs2)
        Q2 = VGroup(Q2a, Q2b)
        Q = VGroup(Q1, Q2a, Q2b).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(root_general, DOWN, buff=0.4)
        Q2.shift(RIGHT*0.6+DOWN*0.2)
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]


        # Action Sequence
        with self.voiceover(
                text="""
                Let's say we're taking <bookmark mark="root"/>an even root of a number x, like the square root, or the fourth root.
                <bookmark mark="Q1"/>How many solutions do we get, <bookmark mark="Q2a"/>if the number x that we're taking the root
                of is positive?
                And how many solutions do we get, <bookmark mark="Q2b"/>if the number x that we're taking the root of is negative?
                """
        ) as tracker:

            self.wait_until_bookmark("root")
            cursor.blinking=False
            x,y,_ = root_general.get_center()+0.4*DOWN
            self.play(Write(root_general), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("Q1")
            cursor.blinking=False
            x,y,_ = Q1.get_center()+0.4*DOWN
            self.play(Write(Q1), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("Q2a")
            cursor.blinking=False
            x,y,_ = Q2a.get_center()+0.4*DOWN
            self.play(Write(Q2a), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("Q2b")
            cursor.blinking=False
            x,y,_ = Q2b.get_center()+0.4*DOWN
            self.play(Write(Q2b), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True


class Func_5_2_I_4_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("$\\sqrt[k]{x}$, k is even")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        divLine = Line([0,-1.8,0], [0,2,0], color=c1t)
        pos = Tex("x positive", font_size=fs3, color=BLUE)
        neg = Tex("x negative", font_size=fs3, color=GREEN)
        pos_neg = VGroup(pos, neg).arrange(RIGHT, buff=0.6).next_to(divLine, UP, buff=0.2)
        self.add(divLine, pos_neg)

        ex_1_pos = MathTex("\\sqrt[2]{4}", "=", "\\pm 2", font_size=fs3, color=BLUE).next_to(pos, DOWN, buff=0.8)
        ex_1_neg = MathTex("\\sqrt[2]{-4}", font_size=fs3, color=GREEN).next_to(neg, DOWN, buff=0.8)
        sout_1 = Cross(color=RED, stroke_width=2).move_to(ex_1_neg).scale(ex_1_neg.get_width()/Cross().get_width())
        ex_2_pos = MathTex("\\sqrt[4]{16}", "=", "\\pm 2", font_size=fs3, color=BLUE).next_to(ex_1_pos, DOWN, buff=0.2)
        ex_2_neg = MathTex("\\sqrt[4]{-16}", font_size=fs3, color=GREEN).next_to(ex_1_neg, DOWN, buff=0.2)
        sout_2 = Cross(color=RED, stroke_width=2).move_to(ex_2_neg).scale(ex_2_neg.get_width()/Cross().get_width())

        result_pos_1 = Tex("x positive", font_size=fs3, color=BLUE).next_to(ex_2_pos, DOWN, buff=0.8)
        result_pos_2 = MathTex("\\Downarrow", font_size=fs3, color=BLUE).next_to(result_pos_1, DOWN, buff=0.2)
        result_pos3 = Tex("Two solutions", font_size=fs3, color=BLUE).next_to(result_pos_2, DOWN, buff=0.2)

        result_neg_1 = Tex("x negative", font_size=fs3, color=GREEN).next_to(ex_2_neg, DOWN, buff=0.8)
        result_neg_2 = MathTex("\\Downarrow", font_size=fs3, color=GREEN).next_to(result_neg_1, DOWN, buff=0.2)
        result_neg3 = Tex("No solution", font_size=fs3, color=GREEN).next_to(result_neg_2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                That's correct. Well done!!!
                If x is positive, then we're taking an even root of a positive number.
                For example, <bookmark mark="posEx1a"/>the square root of 4, or
                <bookmark mark="posEx2a"/>the fourth root of 16.
                In that case, there are always two solutions: one positive and one negative.
                For example, <bookmark mark="posEx1b"/>the square root of 4 is 2, but also negative 2.
                And <bookmark mark="posEx2b"/>the fourth root of 16 is 2, but also negative 2.
                So, <bookmark mark="result_pos_1"/>if x is positive, <bookmark mark="result_pos_3"/>
                there are always two solutions.

                If <bookmark mark="xNeg"/>x is negative however, then we're taking an even root of a negative number.
                For example, <bookmark mark="negEx1a"/>the square root of negative 4, or
                <bookmark mark="negEx2a"/>the fourth root of negative 16.
                In these cases, there are <bookmark mark="strike_out"/>no solutions,
                because whenever you multiply a negative number by itself an even number of times,
                the result is always positive.
                So, <bookmark mark="result_neg_1"/>if x is negative, <bookmark mark="result_neg_3"/>
                there are no solutions. <bookmark mark="default"/>
                
                So quick summary, if we're taking an even root of a number x, then
                there are <bookmark mark="summary_two"/>two solutions if x is positive,
                and <bookmark mark="summary_no"/>no solutions if x is negative.
                """
        ) as tracker:

            self.wait_until_bookmark("posEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx2a")
            x,y,_ = ex_2_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx1b")
            x,y,_ = ex_1_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[1]), Write(ex_1_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("posEx2b")
            cursor.blinking=False
            x,y,_ = ex_2_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[1]), Write(ex_2_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("result_pos_1")
            cursor.blinking=False
            x,y,_ = result_pos_1.get_center()+0.4*DOWN
            self.play(Write(result_pos_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_pos_3")
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(Write(result_pos_2), Write(result_pos3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("xNeg")
            cursor.blinking=False
            x,y,_ = neg.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_neg.get_center()+0.4*DOWN
            self.play(Write(ex_1_neg), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negEx2a")
            x,y,_ = ex_2_neg.get_center()+0.4*DOWN
            self.play(Write(ex_2_neg), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("strike_out")
            self.play(Write(sout_1), Write(sout_2))

            self.wait_until_bookmark("result_neg_1")
            cursor.blinking=False
            x,y,_ = result_neg_1.get_center()+0.4*DOWN
            self.play(Write(result_neg_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_neg_3")
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(Write(result_neg_2), Write(result_neg3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("default")
            cursor.blinking=False
            x,y,_ = ORIGIN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_two")
            cursor.blinking=False
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_no")
            cursor.blinking=False
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

        self.wait(4)


class Func_5_2_I_4_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("$\\sqrt[k]{x}$, k is even")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        divLine = Line([0,-1.8,0], [0,2,0], color=c1t)
        pos = Tex("x positive", font_size=fs3, color=BLUE)
        neg = Tex("x negative", font_size=fs3, color=GREEN)
        pos_neg = VGroup(pos, neg).arrange(RIGHT, buff=0.6).next_to(divLine, UP, buff=0.2)
        self.add(divLine, pos_neg)

        ex_1_pos = MathTex("\\sqrt[2]{4}", "=", "\\pm 2", font_size=fs3, color=BLUE).next_to(pos, DOWN, buff=0.8)
        ex_1_neg = MathTex("\\sqrt[2]{-4}", font_size=fs3, color=GREEN).next_to(neg, DOWN, buff=0.8)
        sout_1 = Cross(color=RED, stroke_width=2).move_to(ex_1_neg).scale(ex_1_neg.get_width()/Cross().get_width())
        ex_2_pos = MathTex("\\sqrt[4]{16}", "=", "\\pm 2", font_size=fs3, color=BLUE).next_to(ex_1_pos, DOWN, buff=0.2)
        ex_2_neg = MathTex("\\sqrt[4]{-16}", font_size=fs3, color=GREEN).next_to(ex_1_neg, DOWN, buff=0.2)
        sout_2 = Cross(color=RED, stroke_width=2).move_to(ex_2_neg).scale(ex_2_neg.get_width()/Cross().get_width())

        result_pos_1 = Tex("x positive", font_size=fs3, color=BLUE).next_to(ex_2_pos, DOWN, buff=0.8)
        result_pos_2 = MathTex("\\Downarrow", font_size=fs3, color=BLUE).next_to(result_pos_1, DOWN, buff=0.2)
        result_pos3 = Tex("Two solutions", font_size=fs3, color=BLUE).next_to(result_pos_2, DOWN, buff=0.2)

        result_neg_1 = Tex("x negative", font_size=fs3, color=GREEN).next_to(ex_2_neg, DOWN, buff=0.8)
        result_neg_2 = MathTex("\\Downarrow", font_size=fs3, color=GREEN).next_to(result_neg_1, DOWN, buff=0.2)
        result_neg3 = Tex("No solution", font_size=fs3, color=GREEN).next_to(result_neg_2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right...
                If x is positive, then we're taking an even root of a positive number.
                For example, <bookmark mark="posEx1a"/>the square root of 4, or
                <bookmark mark="posEx2a"/>the fourth root of 16.
                In that case, there are always two solutions: one positive and one negative.
                For example, <bookmark mark="posEx1b"/>the square root of 4 is 2, but also negative 2.
                And <bookmark mark="posEx2b"/>the fourth root of 16 is 2, but also negative 2.
                So, <bookmark mark="result_pos_1"/>if x is positive, <bookmark mark="result_pos_3"/>
                there are always two solutions.

                If <bookmark mark="xNeg"/>x is negative however, then we're taking an even root of a negative number.
                For example, <bookmark mark="negEx1a"/>the square root of negative 4, or
                <bookmark mark="negEx2a"/>the fourth root of negative 16.
                In these cases, there are <bookmark mark="strike_out"/>no solutions,
                because whenever you multiply a negative number by itself an even number of times,
                the result is always positive.
                So, <bookmark mark="result_neg_1"/>if x is negative, <bookmark mark="result_neg_3"/>
                there are no solutions. <bookmark mark="default"/>
                
                So quick summary, if we're taking an even root of a number x, then
                there are <bookmark mark="summary_two"/>two solutions if x is positive,
                and <bookmark mark="summary_no"/>no solutions if x is negative.
                """
        ) as tracker:

            self.wait_until_bookmark("posEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx2a")
            x,y,_ = ex_2_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx1b")
            x,y,_ = ex_1_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[1]), Write(ex_1_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("posEx2b")
            cursor.blinking=False
            x,y,_ = ex_2_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[1]), Write(ex_2_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("result_pos_1")
            cursor.blinking=False
            x,y,_ = result_pos_1.get_center()+0.4*DOWN
            self.play(Write(result_pos_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_pos_3")
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(Write(result_pos_2), Write(result_pos3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("xNeg")
            cursor.blinking=False
            x,y,_ = neg.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_neg.get_center()+0.4*DOWN
            self.play(Write(ex_1_neg), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negEx2a")
            x,y,_ = ex_2_neg.get_center()+0.4*DOWN
            self.play(Write(ex_2_neg), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("strike_out")
            self.play(Write(sout_1), Write(sout_2))

            self.wait_until_bookmark("result_neg_1")
            cursor.blinking=False
            x,y,_ = result_neg_1.get_center()+0.4*DOWN
            self.play(Write(result_neg_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_neg_3")
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(Write(result_neg_2), Write(result_neg3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("default")
            cursor.blinking=False
            x,y,_ = ORIGIN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_two")
            cursor.blinking=False
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_no")
            cursor.blinking=False
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

        self.wait(4)

class Func_5_2_I_4_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("$\\sqrt[k]{x}$, k is even")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        divLine = Line([0,-1.8,0], [0,2,0], color=c1t)
        pos = Tex("x positive", font_size=fs3, color=BLUE)
        neg = Tex("x negative", font_size=fs3, color=GREEN)
        pos_neg = VGroup(pos, neg).arrange(RIGHT, buff=0.6).next_to(divLine, UP, buff=0.2)
        self.add(divLine, pos_neg)

        ex_1_pos = MathTex("\\sqrt[2]{4}", "=", "\\pm 2", font_size=fs3, color=BLUE).next_to(pos, DOWN, buff=0.8)
        ex_1_neg = MathTex("\\sqrt[2]{-4}", font_size=fs3, color=GREEN).next_to(neg, DOWN, buff=0.8)
        sout_1 = Cross(color=RED, stroke_width=2).move_to(ex_1_neg).scale(ex_1_neg.get_width()/Cross().get_width())
        ex_2_pos = MathTex("\\sqrt[4]{16}", "=", "\\pm 2", font_size=fs3, color=BLUE).next_to(ex_1_pos, DOWN, buff=0.2)
        ex_2_neg = MathTex("\\sqrt[4]{-16}", font_size=fs3, color=GREEN).next_to(ex_1_neg, DOWN, buff=0.2)
        sout_2 = Cross(color=RED, stroke_width=2).move_to(ex_2_neg).scale(ex_2_neg.get_width()/Cross().get_width())

        result_pos_1 = Tex("x positive", font_size=fs3, color=BLUE).next_to(ex_2_pos, DOWN, buff=0.8)
        result_pos_2 = MathTex("\\Downarrow", font_size=fs3, color=BLUE).next_to(result_pos_1, DOWN, buff=0.2)
        result_pos3 = Tex("Two solutions", font_size=fs3, color=BLUE).next_to(result_pos_2, DOWN, buff=0.2)

        result_neg_1 = Tex("x negative", font_size=fs3, color=GREEN).next_to(ex_2_neg, DOWN, buff=0.8)
        result_neg_2 = MathTex("\\Downarrow", font_size=fs3, color=GREEN).next_to(result_neg_1, DOWN, buff=0.2)
        result_neg3 = Tex("No solution", font_size=fs3, color=GREEN).next_to(result_neg_2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right...
                If x is positive, then we're taking an even root of a positive number.
                For example, <bookmark mark="posEx1a"/>the square root of 4, or
                <bookmark mark="posEx2a"/>the fourth root of 16.
                In that case, there are always two solutions: one positive and one negative.
                For example, <bookmark mark="posEx1b"/>the square root of 4 is 2, but also negative 2.
                And <bookmark mark="posEx2b"/>the fourth root of 16 is 2, but also negative 2.
                So, <bookmark mark="result_pos_1"/>if x is positive, <bookmark mark="result_pos_3"/>
                there are always two solutions.

                If <bookmark mark="xNeg"/>x is negative however, then we're taking an even root of a negative number.
                For example, <bookmark mark="negEx1a"/>the square root of negative 4, or
                <bookmark mark="negEx2a"/>the fourth root of negative 16.
                In these cases, there are <bookmark mark="strike_out"/>no solutions,
                because whenever you multiply a negative number by itself an even number of times,
                the result is always positive.
                So, <bookmark mark="result_neg_1"/>if x is negative, <bookmark mark="result_neg_3"/>
                there are no solutions. <bookmark mark="default"/>
                
                So quick summary, if we're taking an even root of a number x, then
                there are <bookmark mark="summary_two"/>two solutions if x is positive,
                and <bookmark mark="summary_no"/>no solutions if x is negative.
                """
        ) as tracker:

            self.wait_until_bookmark("posEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx2a")
            x,y,_ = ex_2_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx1b")
            x,y,_ = ex_1_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[1]), Write(ex_1_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("posEx2b")
            cursor.blinking=False
            x,y,_ = ex_2_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[1]), Write(ex_2_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("result_pos_1")
            cursor.blinking=False
            x,y,_ = result_pos_1.get_center()+0.4*DOWN
            self.play(Write(result_pos_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_pos_3")
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(Write(result_pos_2), Write(result_pos3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("xNeg")
            cursor.blinking=False
            x,y,_ = neg.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_neg.get_center()+0.4*DOWN
            self.play(Write(ex_1_neg), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negEx2a")
            x,y,_ = ex_2_neg.get_center()+0.4*DOWN
            self.play(Write(ex_2_neg), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("strike_out")
            self.play(Write(sout_1), Write(sout_2))

            self.wait_until_bookmark("result_neg_1")
            cursor.blinking=False
            x,y,_ = result_neg_1.get_center()+0.4*DOWN
            self.play(Write(result_neg_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_neg_3")
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(Write(result_neg_2), Write(result_neg3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("default")
            cursor.blinking=False
            x,y,_ = ORIGIN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_two")
            cursor.blinking=False
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_no")
            cursor.blinking=False
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

        self.wait(4)

class Func_5_2_I_4_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("$\\sqrt[k]{x}$, k is even")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        divLine = Line([0,-1.8,0], [0,2,0], color=c1t)
        pos = Tex("x positive", font_size=fs3, color=BLUE)
        neg = Tex("x negative", font_size=fs3, color=GREEN)
        pos_neg = VGroup(pos, neg).arrange(RIGHT, buff=0.6).next_to(divLine, UP, buff=0.2)
        self.add(divLine, pos_neg)

        ex_1_pos = MathTex("\\sqrt[2]{4}", "=", "\\pm 2", font_size=fs3, color=BLUE).next_to(pos, DOWN, buff=0.8)
        ex_1_neg = MathTex("\\sqrt[2]{-4}", font_size=fs3, color=GREEN).next_to(neg, DOWN, buff=0.8)
        sout_1 = Cross(color=RED, stroke_width=2).move_to(ex_1_neg).scale(ex_1_neg.get_width()/Cross().get_width())
        ex_2_pos = MathTex("\\sqrt[4]{16}", "=", "\\pm 2", font_size=fs3, color=BLUE).next_to(ex_1_pos, DOWN, buff=0.2)
        ex_2_neg = MathTex("\\sqrt[4]{-16}", font_size=fs3, color=GREEN).next_to(ex_1_neg, DOWN, buff=0.2)
        sout_2 = Cross(color=RED, stroke_width=2).move_to(ex_2_neg).scale(ex_2_neg.get_width()/Cross().get_width())

        result_pos_1 = Tex("x positive", font_size=fs3, color=BLUE).next_to(ex_2_pos, DOWN, buff=0.8)
        result_pos_2 = MathTex("\\Downarrow", font_size=fs3, color=BLUE).next_to(result_pos_1, DOWN, buff=0.2)
        result_pos3 = Tex("Two solutions", font_size=fs3, color=BLUE).next_to(result_pos_2, DOWN, buff=0.2)

        result_neg_1 = Tex("x negative", font_size=fs3, color=GREEN).next_to(ex_2_neg, DOWN, buff=0.8)
        result_neg_2 = MathTex("\\Downarrow", font_size=fs3, color=GREEN).next_to(result_neg_1, DOWN, buff=0.2)
        result_neg3 = Tex("No solution", font_size=fs3, color=GREEN).next_to(result_neg_2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right...
                If x is positive, then we're taking an even root of a positive number.
                For example, <bookmark mark="posEx1a"/>the square root of 4, or
                <bookmark mark="posEx2a"/>the fourth root of 16.
                In that case, there are always two solutions: one positive and one negative.
                For example, <bookmark mark="posEx1b"/>the square root of 4 is 2, but also negative 2.
                And <bookmark mark="posEx2b"/>the fourth root of 16 is 2, but also negative 2.
                So, <bookmark mark="result_pos_1"/>if x is positive, <bookmark mark="result_pos_3"/>
                there are always two solutions.

                If <bookmark mark="xNeg"/>x is negative however, then we're taking an even root of a negative number.
                For example, <bookmark mark="negEx1a"/>the square root of negative 4, or
                <bookmark mark="negEx2a"/>the fourth root of negative 16.
                In these cases, there are <bookmark mark="strike_out"/>no solutions,
                because whenever you multiply a negative number by itself an even number of times,
                the result is always positive.
                So, <bookmark mark="result_neg_1"/>if x is negative, <bookmark mark="result_neg_3"/>
                there are no solutions. <bookmark mark="default"/>
                
                So quick summary, if we're taking an even root of a number x, then
                there are <bookmark mark="summary_two"/>two solutions if x is positive,
                and <bookmark mark="summary_no"/>no solutions if x is negative.
                """
        ) as tracker:

            self.wait_until_bookmark("posEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx2a")
            x,y,_ = ex_2_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx1b")
            x,y,_ = ex_1_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[1]), Write(ex_1_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("posEx2b")
            cursor.blinking=False
            x,y,_ = ex_2_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[1]), Write(ex_2_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("result_pos_1")
            cursor.blinking=False
            x,y,_ = result_pos_1.get_center()+0.4*DOWN
            self.play(Write(result_pos_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_pos_3")
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(Write(result_pos_2), Write(result_pos3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("xNeg")
            cursor.blinking=False
            x,y,_ = neg.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_neg.get_center()+0.4*DOWN
            self.play(Write(ex_1_neg), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negEx2a")
            x,y,_ = ex_2_neg.get_center()+0.4*DOWN
            self.play(Write(ex_2_neg), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("strike_out")
            self.play(Write(sout_1), Write(sout_2))

            self.wait_until_bookmark("result_neg_1")
            cursor.blinking=False
            x,y,_ = result_neg_1.get_center()+0.4*DOWN
            self.play(Write(result_neg_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_neg_3")
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(Write(result_neg_2), Write(result_neg3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("default")
            cursor.blinking=False
            x,y,_ = ORIGIN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_two")
            cursor.blinking=False
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_no")
            cursor.blinking=False
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
TASK_Func_5_2_I_5_q = SophiaTaskDefinition(
        answerOptions = ["$x<0$: no solution, $x>0$: two solutions", "$x<0$: two solutions, $x>0$: no solution", "$x>0$: one solution, $x<0$: one solution", "$x>0$: no solutions, $x<0$: no solutions"],
    correctAnswerIndex = 2,
    questionText = "Consider $\\sqrt[k]{x}$, where k is an odd number. How many solutions are there for $x>0$, and how many for $x<0$?"
)

class Func_5_2_I_5_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Odd Roots")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        root_general = Tex("$\\sqrt[k]{x}$", ",     ", "k is odd", color=c1t, font_size = fs1).shift(UP*2)
        Q1 = Tex("How many solutions...", color=c1t, font_size = fs2)
        Q2a = Tex("if x is positive..?", color=c3t, font_size = fs2)
        Q2b = Tex("if x is negative..?", color=c3t, font_size = fs2)
        Q2 = VGroup(Q2a, Q2b)
        Q = VGroup(Q1, Q2a, Q2b).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(root_general, DOWN, buff=0.4)
        Q2.shift(RIGHT*0.6+DOWN*0.2)
        
        #Create the coordinate system
        cords = self.add_cords([-2,2, 1], [-4, 4, 1], x_ticks=[-2,-1,1,2],y_ticks=[-4,-2,2,4]).shift(DOWN*0.6)
        plane = cords[0]


        # Action Sequence
        with self.voiceover(
                text="""
                Now we want to take <bookmark mark="root"/>an odd root of a number x, like the cube root, or the fifth root.
                <bookmark mark="Q1"/>How many solutions do we get, <bookmark mark="Q2a"/>if we're taking an odd root of a positive
                number x?
                And how many solutions do we get, <bookmark mark="Q2b"/>if we take an odd root of a negative number x?
                """
        ) as tracker:

            self.wait_until_bookmark("root")
            cursor.blinking=False
            x,y,_ = root_general.get_center()+0.4*DOWN
            self.play(Write(root_general), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("Q1")
            cursor.blinking=False
            x,y,_ = Q1.get_center()+0.4*DOWN
            self.play(Write(Q1), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("Q2a")
            cursor.blinking=False
            x,y,_ = Q2a.get_center()+0.4*DOWN
            self.play(Write(Q2a), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("Q2b")
            cursor.blinking=False
            x,y,_ = Q2b.get_center()+0.4*DOWN
            self.play(Write(Q2b), CursorMoveTo(cursor, x,y), run_time=0.5)
            cursor.blinking=True


class Func_5_2_I_5_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("$\\sqrt[k]{x}$, k is odd")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        divLine = Line([0,-1.8,0], [0,2,0], color=c1t)
        pos = Tex("x positive", font_size=fs3, color=BLUE)
        neg = Tex("x negative", font_size=fs3, color=GREEN)
        pos_neg = VGroup(pos, neg).arrange(RIGHT, buff=0.6).next_to(divLine, UP, buff=0.2)
        self.add(divLine, pos_neg)

        ex_1_pos = MathTex("\\sqrt[3]{8}", "=", " 2", font_size=fs3, color=BLUE).next_to(pos, DOWN, buff=0.8)
        ex_1_neg = MathTex("\\sqrt[3]{-8}", "=", "-2",  font_size=fs3, color=GREEN).next_to(neg, DOWN, buff=0.8)
        ex_2_pos = MathTex("\\sqrt[5]{32}", "=", "2", font_size=fs3, color=BLUE).next_to(ex_1_pos, DOWN, buff=0.2)
        ex_2_neg = MathTex("\\sqrt[5]{-32}", "=", "-2", font_size=fs3, color=GREEN).next_to(ex_1_neg, DOWN, buff=0.2)

        result_pos_1 = Tex("x positive", font_size=fs3, color=BLUE).next_to(ex_2_pos, DOWN, buff=0.8)
        result_pos_2 = MathTex("\\Downarrow", font_size=fs3, color=BLUE).next_to(result_pos_1, DOWN, buff=0.2)
        result_pos3 = Tex("One solution", font_size=fs3, color=BLUE).next_to(result_pos_2, DOWN, buff=0.2)

        result_neg_1 = Tex("x negative", font_size=fs3, color=GREEN).next_to(ex_2_neg, DOWN, buff=0.8)
        result_neg_2 = MathTex("\\Downarrow", font_size=fs3, color=GREEN).next_to(result_neg_1, DOWN, buff=0.2)
        result_neg3 = Tex("One solution", font_size=fs3, color=GREEN).next_to(result_neg_2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right...
                If x is positive, then we're taking an odd root of a positive number.
                For example, <bookmark mark="posEx1a"/>the cube root of 8, or
                <bookmark mark="posEx2a"/>the fifth root of 32.
                In that case, there is always one solution, and it is positive.
                For example, <bookmark mark="posEx1b"/>the square root of 8 is 2.
                And <bookmark mark="posEx2b"/>the fifth root of 32 is 2 as well.
                So, <bookmark mark="result_pos_1"/>if x is positive, <bookmark mark="result_pos_3"/>
                there is always one solution, and it's positive.

                If <bookmark mark="xNeg"/>x is negative however, then we're taking an odd root of a negative number.
                For example, <bookmark mark="negEx1a"/>the cube root of negative 8, or
                <bookmark mark="negEx2a"/>the fifth root of negative 32.
                In these cases, there is always one solution, and it is negative.
                For example, <bookmark mark="negEx1b"/>the cube root of negative 8 is negative 2.
                And <bookmark mark="negEx2b"/>the fifth root of negative 32 is negative 2 as well.
                So, <bookmark mark="result_neg_1"/>if x is negative, <bookmark mark="result_neg_3"/>
                there is always one solution, and it's negative. <bookmark mark="default"/>
                
                So quick summary, if we're taking an odd root of a number x, then
                there is <bookmark mark="summary_a"/>one solution if x is positive,
                and <bookmark mark="summary_b"/>one solution if x is negative.
                """
        ) as tracker:

            self.wait_until_bookmark("posEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx2a")
            x,y,_ = ex_2_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx1b")
            x,y,_ = ex_1_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[1]), Write(ex_1_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("posEx2b")
            cursor.blinking=False
            x,y,_ = ex_2_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[1]), Write(ex_2_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("result_pos_1")
            cursor.blinking=False
            x,y,_ = result_pos_1.get_center()+0.4*DOWN
            self.play(Write(result_pos_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_pos_3")
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(Write(result_pos_2), Write(result_pos3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("xNeg")
            cursor.blinking=False
            x,y,_ = neg.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_neg[0].get_center()+0.4*DOWN
            self.play(Write(ex_1_neg[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negEx2a")
            x,y,_ = ex_2_neg[0].get_center()+0.4*DOWN
            self.play(Write(ex_2_neg[0]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx1b")
            cursor.blinking=False
            x,y,_ = ex_1_neg[2].get_center()+0.4*DOWN
            self.play(Write(ex_1_neg[1]), Write(ex_1_neg[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx2b")
            cursor.blinking=False
            x,y,_ = ex_2_neg[2].get_center()+0.4*DOWN
            self.play(Write(ex_2_neg[1]), Write(ex_2_neg[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("result_neg_1")
            cursor.blinking=False
            x,y,_ = result_neg_1.get_center()+0.4*DOWN
            self.play(Write(result_neg_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_neg_3")
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(Write(result_neg_2), Write(result_neg3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("default")
            cursor.blinking=False
            x,y,_ = ORIGIN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_a")
            cursor.blinking=False
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_b")
            cursor.blinking=False
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

        self.wait(4)


class Func_5_2_I_5_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("$\\sqrt[k]{x}$, k is odd")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        divLine = Line([0,-1.8,0], [0,2,0], color=c1t)
        pos = Tex("x positive", font_size=fs3, color=BLUE)
        neg = Tex("x negative", font_size=fs3, color=GREEN)
        pos_neg = VGroup(pos, neg).arrange(RIGHT, buff=0.6).next_to(divLine, UP, buff=0.2)
        self.add(divLine, pos_neg)

        ex_1_pos = MathTex("\\sqrt[3]{8}", "=", " 2", font_size=fs3, color=BLUE).next_to(pos, DOWN, buff=0.8)
        ex_1_neg = MathTex("\\sqrt[3]{-8}", "=", "-2",  font_size=fs3, color=GREEN).next_to(neg, DOWN, buff=0.8)
        ex_2_pos = MathTex("\\sqrt[5]{32}", "=", "2", font_size=fs3, color=BLUE).next_to(ex_1_pos, DOWN, buff=0.2)
        ex_2_neg = MathTex("\\sqrt[5]{-32}", "=", "-2", font_size=fs3, color=GREEN).next_to(ex_1_neg, DOWN, buff=0.2)

        result_pos_1 = Tex("x positive", font_size=fs3, color=BLUE).next_to(ex_2_pos, DOWN, buff=0.8)
        result_pos_2 = MathTex("\\Downarrow", font_size=fs3, color=BLUE).next_to(result_pos_1, DOWN, buff=0.2)
        result_pos3 = Tex("One solution", font_size=fs3, color=BLUE).next_to(result_pos_2, DOWN, buff=0.2)

        result_neg_1 = Tex("x negative", font_size=fs3, color=GREEN).next_to(ex_2_neg, DOWN, buff=0.8)
        result_neg_2 = MathTex("\\Downarrow", font_size=fs3, color=GREEN).next_to(result_neg_1, DOWN, buff=0.2)
        result_neg3 = Tex("One solution", font_size=fs3, color=GREEN).next_to(result_neg_2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right...
                If x is positive, then we're taking an odd root of a positive number.
                For example, <bookmark mark="posEx1a"/>the cube root of 8, or
                <bookmark mark="posEx2a"/>the fifth root of 32.
                In that case, there is always one solution, and it is positive.
                For example, <bookmark mark="posEx1b"/>the square root of 8 is 2.
                And <bookmark mark="posEx2b"/>the fifth root of 32 is 2 as well.
                So, <bookmark mark="result_pos_1"/>if x is positive, <bookmark mark="result_pos_3"/>
                there is always one solution, and it's positive.

                If <bookmark mark="xNeg"/>x is negative however, then we're taking an odd root of a negative number.
                For example, <bookmark mark="negEx1a"/>the cube root of negative 8, or
                <bookmark mark="negEx2a"/>the fifth root of negative 32.
                In these cases, there is always one solution, and it is negative.
                For example, <bookmark mark="negEx1b"/>the cube root of negative 8 is negative 2.
                And <bookmark mark="negEx2b"/>the fifth root of negative 32 is negative 2 as well.
                So, <bookmark mark="result_neg_1"/>if x is negative, <bookmark mark="result_neg_3"/>
                there is always one solution, and it's negative. <bookmark mark="default"/>
                
                So quick summary, if we're taking an odd root of a number x, then
                there is <bookmark mark="summary_a"/>one solution if x is positive,
                and <bookmark mark="summary_b"/>one solution if x is negative.
                """
        ) as tracker:

            self.wait_until_bookmark("posEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx2a")
            x,y,_ = ex_2_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx1b")
            x,y,_ = ex_1_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[1]), Write(ex_1_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("posEx2b")
            cursor.blinking=False
            x,y,_ = ex_2_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[1]), Write(ex_2_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("result_pos_1")
            cursor.blinking=False
            x,y,_ = result_pos_1.get_center()+0.4*DOWN
            self.play(Write(result_pos_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_pos_3")
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(Write(result_pos_2), Write(result_pos3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("xNeg")
            cursor.blinking=False
            x,y,_ = neg.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_neg[0].get_center()+0.4*DOWN
            self.play(Write(ex_1_neg[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negEx2a")
            x,y,_ = ex_2_neg[0].get_center()+0.4*DOWN
            self.play(Write(ex_2_neg[0]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx1b")
            cursor.blinking=False
            x,y,_ = ex_1_neg[2].get_center()+0.4*DOWN
            self.play(Write(ex_1_neg[1]), Write(ex_1_neg[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx2b")
            cursor.blinking=False
            x,y,_ = ex_2_neg[2].get_center()+0.4*DOWN
            self.play(Write(ex_2_neg[1]), Write(ex_2_neg[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("result_neg_1")
            cursor.blinking=False
            x,y,_ = result_neg_1.get_center()+0.4*DOWN
            self.play(Write(result_neg_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_neg_3")
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(Write(result_neg_2), Write(result_neg3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("default")
            cursor.blinking=False
            x,y,_ = ORIGIN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_a")
            cursor.blinking=False
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_b")
            cursor.blinking=False
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

        self.wait(4)


class Func_5_2_I_5_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("$\\sqrt[k]{x}$, k is odd")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        divLine = Line([0,-1.8,0], [0,2,0], color=c1t)
        pos = Tex("x positive", font_size=fs3, color=BLUE)
        neg = Tex("x negative", font_size=fs3, color=GREEN)
        pos_neg = VGroup(pos, neg).arrange(RIGHT, buff=0.6).next_to(divLine, UP, buff=0.2)
        self.add(divLine, pos_neg)

        ex_1_pos = MathTex("\\sqrt[3]{8}", "=", " 2", font_size=fs3, color=BLUE).next_to(pos, DOWN, buff=0.8)
        ex_1_neg = MathTex("\\sqrt[3]{-8}", "=", "-2",  font_size=fs3, color=GREEN).next_to(neg, DOWN, buff=0.8)
        ex_2_pos = MathTex("\\sqrt[5]{32}", "=", "2", font_size=fs3, color=BLUE).next_to(ex_1_pos, DOWN, buff=0.2)
        ex_2_neg = MathTex("\\sqrt[5]{-32}", "=", "-2", font_size=fs3, color=GREEN).next_to(ex_1_neg, DOWN, buff=0.2)

        result_pos_1 = Tex("x positive", font_size=fs3, color=BLUE).next_to(ex_2_pos, DOWN, buff=0.8)
        result_pos_2 = MathTex("\\Downarrow", font_size=fs3, color=BLUE).next_to(result_pos_1, DOWN, buff=0.2)
        result_pos3 = Tex("One solution", font_size=fs3, color=BLUE).next_to(result_pos_2, DOWN, buff=0.2)

        result_neg_1 = Tex("x negative", font_size=fs3, color=GREEN).next_to(ex_2_neg, DOWN, buff=0.8)
        result_neg_2 = MathTex("\\Downarrow", font_size=fs3, color=GREEN).next_to(result_neg_1, DOWN, buff=0.2)
        result_neg3 = Tex("One solution", font_size=fs3, color=GREEN).next_to(result_neg_2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                You got it. Excellent job!
                If x is positive, then we're taking an odd root of a positive number.
                For example, <bookmark mark="posEx1a"/>the cube root of 8, or
                <bookmark mark="posEx2a"/>the fifth root of 32.
                In that case, there is always one solution, and it is positive.
                For example, <bookmark mark="posEx1b"/>the square root of 8 is 2.
                And <bookmark mark="posEx2b"/>the fifth root of 32 is 2 as well.
                So, <bookmark mark="result_pos_1"/>if x is positive, <bookmark mark="result_pos_3"/>
                there is always one solution, and it's positive.

                If <bookmark mark="xNeg"/>x is negative however, then we're taking an odd root of a negative number.
                For example, <bookmark mark="negEx1a"/>the cube root of negative 8, or
                <bookmark mark="negEx2a"/>the fifth root of negative 32.
                In these cases, there is always one solution, and it is negative.
                For example, <bookmark mark="negEx1b"/>the cube root of negative 8 is negative 2.
                And <bookmark mark="negEx2b"/>the fifth root of negative 32 is negative 2 as well.
                So, <bookmark mark="result_neg_1"/>if x is negative, <bookmark mark="result_neg_3"/>
                there is always one solution, and it's negative. <bookmark mark="default"/>
                
                So quick summary, if we're taking an odd root of a number x, then
                there is <bookmark mark="summary_a"/>one solution if x is positive,
                and <bookmark mark="summary_b"/>one solution if x is negative.
                """
        ) as tracker:

            self.wait_until_bookmark("posEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx2a")
            x,y,_ = ex_2_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx1b")
            x,y,_ = ex_1_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[1]), Write(ex_1_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("posEx2b")
            cursor.blinking=False
            x,y,_ = ex_2_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[1]), Write(ex_2_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("result_pos_1")
            cursor.blinking=False
            x,y,_ = result_pos_1.get_center()+0.4*DOWN
            self.play(Write(result_pos_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_pos_3")
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(Write(result_pos_2), Write(result_pos3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("xNeg")
            cursor.blinking=False
            x,y,_ = neg.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_neg[0].get_center()+0.4*DOWN
            self.play(Write(ex_1_neg[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negEx2a")
            x,y,_ = ex_2_neg[0].get_center()+0.4*DOWN
            self.play(Write(ex_2_neg[0]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx1b")
            cursor.blinking=False
            x,y,_ = ex_1_neg[2].get_center()+0.4*DOWN
            self.play(Write(ex_1_neg[1]), Write(ex_1_neg[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx2b")
            cursor.blinking=False
            x,y,_ = ex_2_neg[2].get_center()+0.4*DOWN
            self.play(Write(ex_2_neg[1]), Write(ex_2_neg[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("result_neg_1")
            cursor.blinking=False
            x,y,_ = result_neg_1.get_center()+0.4*DOWN
            self.play(Write(result_neg_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_neg_3")
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(Write(result_neg_2), Write(result_neg3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("default")
            cursor.blinking=False
            x,y,_ = ORIGIN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_a")
            cursor.blinking=False
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_b")
            cursor.blinking=False
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

        self.wait(4)


class Func_5_2_I_5_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("$\\sqrt[k]{x}$, k is odd")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        divLine = Line([0,-1.8,0], [0,2,0], color=c1t)
        pos = Tex("x positive", font_size=fs3, color=BLUE)
        neg = Tex("x negative", font_size=fs3, color=GREEN)
        pos_neg = VGroup(pos, neg).arrange(RIGHT, buff=0.6).next_to(divLine, UP, buff=0.2)
        self.add(divLine, pos_neg)

        ex_1_pos = MathTex("\\sqrt[3]{8}", "=", " 2", font_size=fs3, color=BLUE).next_to(pos, DOWN, buff=0.8)
        ex_1_neg = MathTex("\\sqrt[3]{-8}", "=", "-2",  font_size=fs3, color=GREEN).next_to(neg, DOWN, buff=0.8)
        ex_2_pos = MathTex("\\sqrt[5]{32}", "=", "2", font_size=fs3, color=BLUE).next_to(ex_1_pos, DOWN, buff=0.2)
        ex_2_neg = MathTex("\\sqrt[5]{-32}", "=", "-2", font_size=fs3, color=GREEN).next_to(ex_1_neg, DOWN, buff=0.2)

        result_pos_1 = Tex("x positive", font_size=fs3, color=BLUE).next_to(ex_2_pos, DOWN, buff=0.8)
        result_pos_2 = MathTex("\\Downarrow", font_size=fs3, color=BLUE).next_to(result_pos_1, DOWN, buff=0.2)
        result_pos3 = Tex("One solution", font_size=fs3, color=BLUE).next_to(result_pos_2, DOWN, buff=0.2)

        result_neg_1 = Tex("x negative", font_size=fs3, color=GREEN).next_to(ex_2_neg, DOWN, buff=0.8)
        result_neg_2 = MathTex("\\Downarrow", font_size=fs3, color=GREEN).next_to(result_neg_1, DOWN, buff=0.2)
        result_neg3 = Tex("One solution", font_size=fs3, color=GREEN).next_to(result_neg_2, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right...
                If x is positive, then we're taking an odd root of a positive number.
                For example, <bookmark mark="posEx1a"/>the cube root of 8, or
                <bookmark mark="posEx2a"/>the fifth root of 32.
                In that case, there is always one solution, and it is positive.
                For example, <bookmark mark="posEx1b"/>the square root of 8 is 2.
                And <bookmark mark="posEx2b"/>the fifth root of 32 is 2 as well.
                So, <bookmark mark="result_pos_1"/>if x is positive, <bookmark mark="result_pos_3"/>
                there is always one solution, and it's positive.

                If <bookmark mark="xNeg"/>x is negative however, then we're taking an odd root of a negative number.
                For example, <bookmark mark="negEx1a"/>the cube root of negative 8, or
                <bookmark mark="negEx2a"/>the fifth root of negative 32.
                In these cases, there is always one solution, and it is negative.
                For example, <bookmark mark="negEx1b"/>the cube root of negative 8 is negative 2.
                And <bookmark mark="negEx2b"/>the fifth root of negative 32 is negative 2 as well.
                So, <bookmark mark="result_neg_1"/>if x is negative, <bookmark mark="result_neg_3"/>
                there is always one solution, and it's negative. <bookmark mark="default"/>
                
                So quick summary, if we're taking an odd root of a number x, then
                there is <bookmark mark="summary_a"/>one solution if x is positive,
                and <bookmark mark="summary_b"/>one solution if x is negative.
                """
        ) as tracker:

            self.wait_until_bookmark("posEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx2a")
            x,y,_ = ex_2_pos[0].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("posEx1b")
            x,y,_ = ex_1_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_1_pos[1]), Write(ex_1_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("posEx2b")
            cursor.blinking=False
            x,y,_ = ex_2_pos[2].get_center()+0.4*DOWN
            self.play(Write(ex_2_pos[1]), Write(ex_2_pos[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("result_pos_1")
            cursor.blinking=False
            x,y,_ = result_pos_1.get_center()+0.4*DOWN
            self.play(Write(result_pos_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_pos_3")
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(Write(result_pos_2), Write(result_pos3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("xNeg")
            cursor.blinking=False
            x,y,_ = neg.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx1a")
            cursor.blinking=False
            x,y,_ = ex_1_neg[0].get_center()+0.4*DOWN
            self.play(Write(ex_1_neg[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("negEx2a")
            x,y,_ = ex_2_neg[0].get_center()+0.4*DOWN
            self.play(Write(ex_2_neg[0]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx1b")
            cursor.blinking=False
            x,y,_ = ex_1_neg[2].get_center()+0.4*DOWN
            self.play(Write(ex_1_neg[1]), Write(ex_1_neg[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("negEx2b")
            cursor.blinking=False
            x,y,_ = ex_2_neg[2].get_center()+0.4*DOWN
            self.play(Write(ex_2_neg[1]), Write(ex_2_neg[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("result_neg_1")
            cursor.blinking=False
            x,y,_ = result_neg_1.get_center()+0.4*DOWN
            self.play(Write(result_neg_1), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("result_neg_3")
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(Write(result_neg_2), Write(result_neg3), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("default")
            cursor.blinking=False
            x,y,_ = ORIGIN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_a")
            cursor.blinking=False
            x,y,_ = result_pos3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("summary_b")
            cursor.blinking=False
            x,y,_ = result_neg3.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
class Func_5_2_I_6(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("$\\sqrt[k]{x}$, k is odd")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0.4)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        vLine = Line([0.4,-1.5,0], [0.4,1.5,0], color=c1t)
        hLine = Line([-1.1,0,0], [1.9,0,0], color=c1t)

        pos = Tex("x positive", font_size=fs3, color=BLUE)
        neg = Tex("x negative", font_size=fs3, color=GREEN)
        pos_neg = VGroup(pos, neg).arrange(RIGHT, buff=0.6).next_to(vLine, UP, buff=0.2)
        
        even = Tex("k even", font_size=fs3, color=PURPLE)
        odd = Tex("k odd", font_size=fs3, color=ORANGE)
        even_odd = VGroup(even, odd).arrange(DOWN, buff=1.2).next_to(hLine, LEFT, buff=0.1)

        even_pos_examples = MathTex("\\sqrt[2]{4},", "\\sqrt[4]{16},", "...", font_size=fs4, color=c1t)
        even_pos_sol = Tex("$\\Rightarrow$Two solutions", font_size=fs4, color=c1t)
        even_pos = VGroup(even_pos_examples, even_pos_sol).arrange(DOWN, buff=0.2).next_to(vLine, LEFT, buff=0.1)
        even_pos.shift((even.get_bottom()[1]-even_pos.get_bottom()[1])*UP)

        even_neg_examples = MathTex("\\sqrt[2]{-4},", "\\sqrt[4]{-16},", "...", font_size=fs4, color=c1t)
        even_neg_sol = Tex("$\\Rightarrow$No solution", font_size=fs4, color=c1t)
        even_neg = VGroup(even_neg_examples, even_neg_sol).arrange(DOWN, buff=0.2).next_to(vLine, RIGHT, buff=0.1)
        even_neg.shift((even.get_bottom()[1]-even_neg.get_bottom()[1])*UP)

        odd_pos_examples = MathTex("\\sqrt[3]{8},", "\\sqrt[5]{32},", "...", font_size=fs4, color=c1t)
        odd_pos_sol = Tex("$\\Rightarrow$One solution", font_size=fs4, color=c1t)
        odd_pos = VGroup(odd_pos_examples, odd_pos_sol).arrange(DOWN, buff=0.2).next_to(vLine, LEFT, buff=0.1)
        odd_pos.shift((odd.get_bottom()[1]-odd_pos.get_bottom()[1])*UP)

        odd_neg_examples = MathTex("\\sqrt[3]{-8},", "\\sqrt[5]{-32},", "...", font_size=fs4, color=c1t)
        odd_neg_sol = Tex("$\\Rightarrow$One solution", font_size=fs4, color=c1t)
        odd_neg = VGroup(odd_neg_examples, odd_neg_sol).arrange(DOWN, buff=0.2).next_to(vLine, RIGHT, buff=0.1)
        odd_neg.shift((odd.get_bottom()[1]-odd_neg.get_bottom()[1])*UP)

        self.add(vLine, hLine)

        center = [0.4,0,0]

        # Action Sequence
        with self.voiceover(
                text="""
                Let's get an overview of the situation when we compute roots.
                First, we can take two kinds of roots: <bookmark mark="even"/>even roots, and
                <bookmark mark="odd"/>odd roots. <bookmark mark="default1"/> An even root is when we take
                the square root, the fourth root, the sixth root, and so on. And an odd root is when we take
                the cube root, the fifth root, the seventh root, and so on.

                And we can take roots of two kinds of numbers: <bookmark mark="pos"/>positive numbers, and
                <bookmark mark="neg"/>negative numbers. <bookmark mark="default2"/> That makes for a total of
                four cases. Let's look at each of them.

                Let's start with <bookmark mark="even_positive"/> even roots of positive numbers.
                For example, <bookmark mark="evenEx1a"/>the square root of 4, or
                <bookmark mark="evenEx2a"/>the fourth root of 16.
                In these cases, there are always <bookmark mark="even_pos_sol"/>two solutions, and they are both positive.

                Now let's look at <bookmark mark="even_negative"/> even roots of negative numbers.
                For example, <bookmark mark="evenEx1b"/>the square root of negative 4, or
                <bookmark mark="evenEx2b"/>the fourth root of negative 16.
                In these cases, <bookmark mark="even_neg_sol"/>there are no solutions. <bookmark mark="default3"/>

                So quick summary, if we're taking an even root of a number x, then there are
                <bookmark mark="even_pos_sol2"/>two solutions if x is positive, and
                <bookmark mark="even_neg_sol2"/>no solutions if x is negative.

                Now let's look at <bookmark mark="odd_positive"/> odd roots of positive numbers.
                For example, <bookmark mark="oddEx1a"/>the cube root of 8, or
                <bookmark mark="oddEx2a"/>the fifth root of 32.
                In these cases, there is always <bookmark mark="odd_pos_sol"/>one solution, and it is positive.

                Finally, let's look at <bookmark mark="odd_negative"/> odd roots of negative numbers.
                For example, <bookmark mark="oddEx1b"/>the cube root of negative 8, or
                <bookmark mark="oddEx2b"/>the fifth root of negative 32.
                In these cases, there is always <bookmark mark="odd_neg_sol"/>one solution, and it is negative.

                So, final summary, if we're taking an odd root of a number x, then
                there is <bookmark mark="odd_pos_sol2"/>one solution if x is positive,
                and <bookmark mark="odd_neg_sol2"/>one solution if x is negative. <bookmark mark="default4"/>

                So those were the four cases. Try to memorize them well!
                """
         , subcaption='NOT AVAILABLE DUE TO BUG') as tracker:

            self.wait_until_bookmark("even")
            cursor.blinking=False
            x,y,_ = even.get_center()+0.4*DOWN
            self.play(Write(even), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("odd")
            cursor.blinking=False
            x,y,_ = odd.get_center()+0.4*DOWN
            self.play(Write(odd), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("default1")
            cursor.blinking=False
            x,y,_ = center
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("pos")
            cursor.blinking=False
            x,y,_ = pos.get_center()+0.4*DOWN
            self.play(Write(pos), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("neg")
            cursor.blinking=False
            x,y,_ = neg.get_center()+0.4*DOWN
            self.play(Write(neg), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("default2")
            cursor.blinking=False
            x,y,_ = center
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("even_positive")
            cursor.blinking=False
            x,y,_ = even_pos.get_center()
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("evenEx1a")
            cursor.blinking=False
            x,y,_ = even_pos_examples[0].get_center()+0.4*DOWN
            self.play(Write(even_pos_examples[0]), CursorMoveTo(cursor, x,y), run_time=0.2)
            
            self.wait_until_bookmark("evenEx2a")
            x,y,_ = even_pos_examples[1].get_center()+0.4*DOWN
            self.play(Write(even_pos_examples[1]), CursorMoveTo(cursor, x,y), run_time=0.2)
            
            self.wait_until_bookmark("even_pos_sol")
            x,y,_ = even_pos_sol.get_center()+0.4*DOWN
            self.play(Write(even_pos_sol), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("even_negative")
            cursor.blinking=False
            x,y,_ = even_neg.get_center()
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("evenEx1b")
            cursor.blinking=False
            x,y,_ = even_neg_examples[0].get_center()+0.4*DOWN
            self.play(Write(even_neg_examples[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("evenEx2b")
            x,y,_ = even_neg_examples[1].get_center()+0.4*DOWN
            self.play(Write(even_neg_examples[1]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("even_neg_sol")
            x,y,_ = even_neg_sol.get_center()+0.4*DOWN
            self.play(Write(even_neg_sol), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("default3")
            cursor.blinking=False
            x,y,_ = center
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("even_pos_sol2")
            x,y,_ = even_pos_sol.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("even_neg_sol2")
            cursor.blinking=False
            x,y,_ = even_neg_sol.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("odd_positive")
            cursor.blinking=False
            x,y,_ = odd_pos.get_center()
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("oddEx1a")
            cursor.blinking=False
            x,y,_ = odd_pos_examples[0].get_center()+0.4*DOWN
            self.play(Write(odd_pos_examples[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("oddEx2a")
            x,y,_ = odd_pos_examples[1].get_center()+0.4*DOWN
            self.play(Write(odd_pos_examples[1]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("odd_pos_sol")
            x,y,_ = odd_pos_sol.get_center()+0.4*DOWN
            self.play(Write(odd_pos_sol), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("odd_negative")
            cursor.blinking=False
            x,y,_ = odd_neg.get_center()
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("oddEx1b")
            cursor.blinking=False
            x,y,_ = odd_neg_examples[0].get_center()+0.4*DOWN
            self.play(Write(odd_neg_examples[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("oddEx2b")
            x,y,_ = odd_neg_examples[1].get_center()+0.4*DOWN
            self.play(Write(odd_neg_examples[1]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("odd_neg_sol")
            x,y,_ = odd_neg_sol.get_center()+0.4*DOWN
            self.play(Write(odd_neg_sol), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("default4")
            cursor.blinking=False
            x,y,_ = center
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
class Func_5_2_I_6(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Roots $\\underset{\\text{inverse}}{\\Leftrightarrow}$ Powers")


        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0.4)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        two = MathTex("(", "\\sqrt{2}", ")^2", "=2", font_size=fs3, color=c1t).shift(UP*1.2)
        three = MathTex("(", "\\sqrt[4]{3}", ")^4", "=3", font_size=fs3, color=c1t).next_to(two, DOWN, buff=0.2)

        four = MathTex("\\sqrt", "{4^2}", "=4", font_size=fs3, color=c1t).next_to(three, DOWN, buff=0.4)
        five = MathTex("\\sqrt", "{5^2}", "=5", font_size=fs3, color=c1t).next_to(four, DOWN, buff=0.2)

        root_k = MathTex("\\sqrt[k]{x}", "\\Leftrightarrow", "x^{\\frac{1}{k}}", font_size=fs3, color=c1t).next_to(five, DOWN, buff=0.4)
        root_3 = MathTex("\\sqrt[3]{x}", "\\Leftrightarrow", "x^{\\frac{1}{3}}", font_size=fs3, color=c1t).next_to(root_k, DOWN, buff=0.2)
        root_5 = MathTex("\\sqrt[5]{x}", "\\Leftrightarrow", "x^{\\frac{1}{5}}", font_size=fs3, color=c1t).next_to(root_3, DOWN, buff=0.2)
        


        # Action Sequence
        with self.voiceover(
                text="""
                Now we're true experts on roots. So, let's talk about the relationship of
                roots and the power function.
                
                <bookmark mark="title"/>Roots and power functions are inverse functions of each other.
                What that means, is that if we take a number, and raise it to a power, and then take the
                root of that number, we get back the original number.

                For example, if we take <bookmark mark="example1a"/>2 and take the square root of it, and then
                <bookmark mark="example1b"/>square that number, we <bookmark mark="example1c"/>get back 2. <bookmark mark="example2"/>
                If we take <bookmark mark="example2a"/>3 and take the fourth root of it, and then <bookmark mark="example2b"/>raise
                that number to the fourth power, we <bookmark mark="example2c"/>get back 3.

                This also works the other way around: if we take a number, and take the kth root of it, and then raise
                that root to the kth power, we get back the original number.

                So for example, if we start with <bookmark mark="example3a"/>4 and square it, and then
                <bookmark mark="example3b"/>take the square root of that, we <bookmark mark="example3c"/>get back 4.
                Or if we start with <bookmark mark="example4a"/>5 and square it, and then <bookmark mark="example4b"/>take
                the square root, we <bookmark mark="example4c"/>get back 5.

                For this reason, there is another way of writing roots:
                Instead of writing <bookmark mark="root_k_1"/>the kth root of x, we can write
                <bookmark mark="root_k_2"/>x to the power of 1 over k.
                So for example, <bookmark mark="root_3_1"/>the cube root of x can be written as
                <bookmark mark="root_3_2"/>x to the power of 1 third.
                And <bookmark mark="root_5_1"/>the fifth root of x can be written as
                <bookmark mark="root_5_2"/>x to the power of 1 fifth, and so on...
                """
         ) as tracker:
            
            self.wait_until_bookmark("title")
            cursor.blinking=False
            x,y,_ = title.get_center()+0.5*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("example1a")
            cursor.blinking=False
            x,y,_ = two[1].get_center()+0.4*DOWN
            self.play(Write(two[1]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("example1b")
            x,y,_ = two[2].get_center()+0.4*DOWN
            self.play(Write(two[0]), Write(two[2]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("example1c")
            x,y,_ = two[3].get_center()+0.4*DOWN
            self.play(Write(two[3]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("example2")
            cursor.blinking=False
            x,y,_ = two[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("example2a")
            cursor.blinking=False
            x,y,_ = three[1].get_center()+0.4*DOWN
            self.play(Write(three[1]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("example2b")
            x,y,_ = three[2].get_center()+0.4*DOWN
            self.play(Write(three[0]), Write(three[2]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("example2c")
            x,y,_ = three[3].get_center()+0.4*DOWN
            self.play(Write(three[3]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("example3a")
            cursor.blinking=False
            x,y,_ = four[1].get_center()+0.4*DOWN
            self.play(Write(four[1]), CursorMoveTo(cursor, x,y), run_time=0.2)
            
            self.wait_until_bookmark("example3b")
            x,y,_ = four[0].get_center()+0.4*DOWN
            self.play(Write(four[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("example3c")
            x,y,_ = four[2].get_center()+0.4*DOWN
            self.play(Write(four[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("example4a")
            cursor.blinking=False
            x,y,_ = five[1].get_center()+0.4*DOWN
            self.play(Write(five[1]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("example4b")
            x,y,_ = five[0].get_center()+0.4*DOWN
            self.play(Write(five[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("example4c")
            x,y,_ = five[2].get_center()+0.4*DOWN
            self.play(Write(five[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("root_k_1")
            cursor.blinking=False
            x,y,_ = root_k[0].get_center()+0.4*DOWN
            self.play(Write(root_k[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("root_k_2")
            x,y,_ = root_k[2].get_center()+0.4*DOWN
            self.play(Write(root_k[1]), Write(root_k[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("root_3_1")
            cursor.blinking=False
            x,y,_ = root_3[0].get_center()+0.4*DOWN
            self.play(Write(root_3[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("root_3_2")
            x,y,_ = root_3[2].get_center()+0.4*DOWN
            self.play(Write(root_3[1]), Write(root_3[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("root_5_1")
            cursor.blinking=False
            x,y,_ = root_5[0].get_center()+0.4*DOWN
            self.play(Write(root_5[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

            self.wait_until_bookmark("root_5_2")
            x,y,_ = root_5[2].get_center()+0.4*DOWN
            self.play(Write(root_5[1]), Write(root_5[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
            cursor.blinking=True

            
        self.wait(4)


#####################################
#####################################
# class Func_5_2_I_6(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()

#         title = self.add_title("Roots $\\underset{\\text{inverse}}{\\Leftrightarrow}$ Powers")


#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=0.4)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         two = MathTex("(", "\\sqrt{2}", ")^2", "=2", font_size=fs3, color=c1t).shift(UP*1.2)
#         three = MathTex("(", "\\sqrt[4]{3}", ")^4", "=3", font_size=fs3, color=c1t).next_to(two, DOWN, buff=0.2)

#         four = MathTex("\\sqrt", "{4^2}", "=4", font_size=fs3, color=c1t).next_to(three, DOWN, buff=0.4)
#         five = MathTex("\\sqrt", "{5^2}", "=5", font_size=fs3, color=c1t).next_to(four, DOWN, buff=0.2)

#         root_k = MathTex("\\sqrt[k]{x}", "\\Leftrightarrow", "x^{\\frac{1}{k}}", font_size=fs3, color=c1t).next_to(five, DOWN, buff=0.4)
#         root_3 = MathTex("\\sqrt[3]{x}", "\\Leftrightarrow", "x^{\\frac{1}{3}}", font_size=fs3, color=c1t).next_to(root_k, DOWN, buff=0.2)
#         root_5 = MathTex("\\sqrt[5]{x}", "\\Leftrightarrow", "x^{\\frac{1}{5}}", font_size=fs3, color=c1t).next_to(root_3, DOWN, buff=0.2)
        


#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 So what's the cube root of 6 to the power of 3? Well, we can use the fact that
#                 """
#          ) as tracker:
            
#             self.wait_until_bookmark("title")
#             cursor.blinking=False
#             x,y,_ = title.get_center()+0.5*DOWN
#             self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("example1a")
#             cursor.blinking=False
#             x,y,_ = two[1].get_center()+0.4*DOWN
#             self.play(Write(two[1]), CursorMoveTo(cursor, x,y), run_time=0.2)

#             self.wait_until_bookmark("example1b")
#             x,y,_ = two[2].get_center()+0.4*DOWN
#             self.play(Write(two[0]), Write(two[2]), CursorMoveTo(cursor, x,y), run_time=0.2)

#             self.wait_until_bookmark("example1c")
#             x,y,_ = two[3].get_center()+0.4*DOWN
#             self.play(Write(two[3]), CursorMoveTo(cursor, x,y), run_time=0.2)

#             self.wait_until_bookmark("example2")
#             cursor.blinking=False
#             x,y,_ = two[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x,y), run_time=0.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("example2a")
#             cursor.blinking=False
#             x,y,_ = three[1].get_center()+0.4*DOWN
#             self.play(Write(three[1]), CursorMoveTo(cursor, x,y), run_time=0.2)

#             self.wait_until_bookmark("example2b")
#             x,y,_ = three[2].get_center()+0.4*DOWN
#             self.play(Write(three[0]), Write(three[2]), CursorMoveTo(cursor, x,y), run_time=0.2)

#             self.wait_until_bookmark("example2c")
#             x,y,_ = three[3].get_center()+0.4*DOWN
#             self.play(Write(three[3]), CursorMoveTo(cursor, x,y), run_time=0.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("example3a")
#             cursor.blinking=False
#             x,y,_ = four[1].get_center()+0.4*DOWN
#             self.play(Write(four[1]), CursorMoveTo(cursor, x,y), run_time=0.2)
            
#             self.wait_until_bookmark("example3b")
#             x,y,_ = four[0].get_center()+0.4*DOWN
#             self.play(Write(four[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

#             self.wait_until_bookmark("example3c")
#             x,y,_ = four[2].get_center()+0.4*DOWN
#             self.play(Write(four[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("example4a")
#             cursor.blinking=False
#             x,y,_ = five[1].get_center()+0.4*DOWN
#             self.play(Write(five[1]), CursorMoveTo(cursor, x,y), run_time=0.2)

#             self.wait_until_bookmark("example4b")
#             x,y,_ = five[0].get_center()+0.4*DOWN
#             self.play(Write(five[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

#             self.wait_until_bookmark("example4c")
#             x,y,_ = five[2].get_center()+0.4*DOWN
#             self.play(Write(five[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("root_k_1")
#             cursor.blinking=False
#             x,y,_ = root_k[0].get_center()+0.4*DOWN
#             self.play(Write(root_k[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

#             self.wait_until_bookmark("root_k_2")
#             x,y,_ = root_k[2].get_center()+0.4*DOWN
#             self.play(Write(root_k[1]), Write(root_k[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("root_3_1")
#             cursor.blinking=False
#             x,y,_ = root_3[0].get_center()+0.4*DOWN
#             self.play(Write(root_3[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

#             self.wait_until_bookmark("root_3_2")
#             x,y,_ = root_3[2].get_center()+0.4*DOWN
#             self.play(Write(root_3[1]), Write(root_3[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("root_5_1")
#             cursor.blinking=False
#             x,y,_ = root_5[0].get_center()+0.4*DOWN
#             self.play(Write(root_5[0]), CursorMoveTo(cursor, x,y), run_time=0.2)

#             self.wait_until_bookmark("root_5_2")
#             x,y,_ = root_5[2].get_center()+0.4*DOWN
#             self.play(Write(root_5[1]), Write(root_5[2]), CursorMoveTo(cursor, x,y), run_time=0.2)
#             cursor.blinking=True

            
#         self.wait(4)


PROTOTYPES=[
    PagePrototypeVideo.from_scene(Func_5_2_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_5_2_I_1_q, Func_5_2_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_5_2_I_1_a),
    PagePrototypeVideo.from_scene(Func_5_2_I_1_b),
    PagePrototypeVideo.from_scene(Func_5_2_I_1_c),
    PagePrototypeVideo.from_scene(Func_5_2_I_1_d),
    PagePrototypeVideo.from_scene(Func_5_2_I_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_5_2_I_2_q, Func_5_2_I_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_5_2_I_2_a),
    PagePrototypeVideo.from_scene(Func_5_2_I_2_b),
    PagePrototypeVideo.from_scene(Func_5_2_I_2_c),
    PagePrototypeVideo.from_scene(Func_5_2_I_2_d),
    PagePrototypeVideo.from_scene(Func_5_2_I_3),
    PagePrototypeVideo.from_scene(Func_5_2_I_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_5_2_I_4_q, Func_5_2_I_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_5_2_I_4_a),
    PagePrototypeVideo.from_scene(Func_5_2_I_4_b),
    PagePrototypeVideo.from_scene(Func_5_2_I_4_c),
    PagePrototypeVideo.from_scene(Func_5_2_I_4_d),
    PagePrototypeVideo.from_scene(Func_5_2_I_5_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_5_2_I_5_q, Func_5_2_I_5_q.__name__),
    PagePrototypeVideo.from_scene(Func_5_2_I_5_a),
    PagePrototypeVideo.from_scene(Func_5_2_I_5_b),
    PagePrototypeVideo.from_scene(Func_5_2_I_5_c),
    PagePrototypeVideo.from_scene(Func_5_2_I_5_d),
    PagePrototypeVideo.from_scene(Func_5_2_I_6),
]
scenes/Func/Func_5: Power Functions/Func_5_2.py
Sophia-Edu-Labs/sophia-math
# 6_1: Exponential Functions: Intro

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition



#####################################
#####################################
TASK_Func_6_1_I_1_q = SophiaTaskDefinition(
    answerOptions = ["With Rice", "With Gold"],
    correctAnswerIndex = 1,
    questionText = "How do you pay the artist?"
)
class Func_6_1_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Exponential Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        board = ImageMobject(assets_folder / "img" / "chessboard.png")
        board = board.scale(2.5/board.get_width()).move_to([-5.2, 1, 0])
        crown = ImageMobject(assets_folder / "img" / "crown.png")
        crown = crown.scale(2.5/crown.get_width()).move_to([-5.2, 1, 0])
        headphones = ImageMobject(assets_folder / "img" / "headphones.png")
        headphones = headphones.scale(2.5/headphones.get_width()).move_to([-5.2, 1, 0])
        rice = ImageMobject(assets_folder / "img" / "rice.png")
        rice = rice.scale(2.5/rice.get_width()).move_to([-5.2, 1, 0])
        goldcoin = ImageMobject(assets_folder / "img" / "goldcoin.png")
        goldcoin = goldcoin.scale(2.5/goldcoin.get_width()).move_to([-5.2, 1, 0])
        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(2.5/qmark.get_width()).move_to([-5.2, 1, 0])


        # Action Sequence
        with self.voiceover(
                text="""
                Imagine you're <bookmark mark="crown"/> the king or the queen of an ancient empire.
                Whenever you're not busy ruling your kingdom, you like to play<bookmark mark="chess"/> chess with your friends.
                So you ask the most talented artist of your empire to make you a chessboard.
                When they come back with the chessboard, you are amazed by its beauty, so you decide to
                reward them with a prize.
                But you're a little short on cash, because you spent it all<bookmark mark="headphones"/> on a brand new pair of headphones,
                so you ask them to name their price.
                The artist offers you a choice:
                You can either <bookmark mark="gold"/>pay them 1 gold coin for every square on the chessboard,
                or you can <bookmark mark="rice"/>pay them 1 grain of rice for the first square, 2 grains of rice for the second square,
                4 grains of rice for the third square, 8 grains of rice for the fourth square, and so on, until
                you've paid them for all 64 squares. <bookmark mark="qmark"/>
                Which option do you choose?
                """
        ) as tracker:

            self.wait_until_bookmark("crown")
            self.play(crown.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("chess")
            self.play(crown.animate.shift(5*RIGHT), board.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("headphones")
            self.play(board.animate.shift(5*RIGHT), headphones.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("gold")
            self.play(headphones.animate.shift(5*RIGHT), goldcoin.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("rice")
            self.play(goldcoin.animate.shift(5*RIGHT), rice.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("qmark")
            self.play(rice.animate.shift(5*RIGHT), qmark.animate.shift(5*RIGHT), run_time=0.5)

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_6_1_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Exponential Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        grain_of_rice = ImageMobject(assets_folder / "img" / "grain_of_rice.png")
        grain_of_rice = grain_of_rice.scale(0.6/grain_of_rice.get_width()).move_to([-5.2, 1, 0])

        largeNumber = MathTex("18446744073709551615", color=c1t)
        largeNumber = largeNumber.scale(4/largeNumber.get_width()).shift(DOWN)

        twentyfirst = VGroup(Tex("$21$st square", color=c1t, font_size=fs2), Tex("$>1000000000$ grains of rice", color=c1t, font_size=fs3)).arrange(DOWN, aligned_edge=LEFT, buff=0.2).shift(DOWN)
        fourtyfirst = VGroup(Tex("$41$st square", color=c1t, font_size=fs2), Tex("$>1000000000000$ grains of rice", color=c1t, font_size=fs3)).arrange(DOWN, aligned_edge=LEFT, buff=0.2).next_to(twentyfirst, DOWN, buff=0.6)
        twentyfirst.shift((twentyfirst.get_left()[0]-fourtyfirst.get_left()[0])*LEFT)


        # Action Sequence
        with self.voiceover(
                text="""
                Mhm I'm not sure that's a great idea.
                Let's see, how much rice it will cost you.
                For the first square, you pay <bookmark mark="one"/>1 grain of rice.
                For the second square, you pay an additional<bookmark mark="two"/>2 grains of rice.
                For the third square, you pay an additional<bookmark mark="four"/>4 grains of rice.
                for the fourth square, you pay an additional<bookmark mark="eight"/>8 grains of rice.
                and for the fifth square, you pay an additional<bookmark mark="sixteen"/>16 grains of rice.
                Guess how many grains of rice you will have to pay, when you finish the first out of the
                8 rows on the chessboard? One hundred and twenty eight.
                That's a lot of rice. And you're not even done with the first row yet.
                Once you've reached the <bookmark mark="twentyfirst"/>twenty-first square, you will have to pay more than a million grains of rice.
                And once you've reached the <bookmark mark="fourtyfirst"/>forty-first square, you will have to pay more than a trillion grains of rice.
                In the end, you will have to pay a total of<bookmark mark="largeNumber"/> eighteen quintillion,
                four hundred forty-six quadrillion, seven hundred forty-four trillion, seventy-three billion,
                seven hundred nine million, five hundred fifty-one thousand, six hundred and fifteen grains of rice.
                I'm not sure about rice to gold conversion rates, but I'm pretty sure that gold is the cheaper option here...
                """
        ) as tracker:

            self.wait_until_bookmark("one")
            self.play(grain_of_rice.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("two")
            copies1 = Group(*[grain_of_rice.copy().shift(np.array([2*np.random.rand()-1, 2*np.random.rand()-1,0])/1.5) for i in range(2)])
            self.play(FadeIn(copies1), run_time=0.5)

            self.wait_until_bookmark("four")
            copies2 = Group(*[grain_of_rice.copy().shift(np.array([2*np.random.rand()-1, 2*np.random.rand()-1,0])/1.5) for i in range(4)])
            self.play(FadeIn(copies2), run_time=0.5)

            self.wait_until_bookmark("eight")
            copies3 = Group(*[grain_of_rice.copy().shift(np.array([2*np.random.rand()-1, 2*np.random.rand()-1,0])/1.5) for i in range(8)])
            self.play(FadeIn(copies3), run_time=0.5)

            self.wait_until_bookmark("sixteen")
            copies4 = Group(*[grain_of_rice.copy().shift(np.array([2*np.random.rand()-1, 2*np.random.rand()-1,0])/1.5) for i in range(16)])
            self.play(FadeIn(copies4), run_time=0.5)

            self.wait_until_bookmark("twentyfirst")
            self.play(Write(twentyfirst))

            self.wait_until_bookmark("fourtyfirst")
            self.play(Write(fourtyfirst))

            self.wait_until_bookmark("largeNumber")
            self.play(Write(largeNumber), FadeOut(copies1), FadeOut(copies2), FadeOut(copies3), FadeOut(copies4), FadeOut(grain_of_rice), Unwrite(twentyfirst), Unwrite(fourtyfirst))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_6_1_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Exponential Functions")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        grain_of_rice = ImageMobject(assets_folder / "img" / "grain_of_rice.png")
        grain_of_rice = grain_of_rice.scale(0.6/grain_of_rice.get_width()).move_to([-5.2, 1, 0])

        largeNumber = MathTex("18446744073709551615", color=c1t)
        largeNumber = largeNumber.scale(4/largeNumber.get_width()).shift(DOWN)

        twentyfirst = VGroup(Tex("$21$st square", color=c1t, font_size=fs2), Tex("$>1000000000$ grains of rice", color=c1t, font_size=fs3)).arrange(DOWN, aligned_edge=LEFT, buff=0.2).shift(DOWN)
        fourtyfirst = VGroup(Tex("$41$st square", color=c1t, font_size=fs2), Tex("$>1000000000000$ grains of rice", color=c1t, font_size=fs3)).arrange(DOWN, aligned_edge=LEFT, buff=0.2).next_to(twentyfirst, DOWN, buff=0.6)
        twentyfirst.shift((twentyfirst.get_left()[0]-fourtyfirst.get_left()[0])*LEFT)


        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that seems to be the right idea.
                For comparison, let's see, how much rice it would cost you.
                For the first square, you pay <bookmark mark="one"/>1 grain of rice.
                For the second square, you pay an additional<bookmark mark="two"/>2 grains of rice.
                For the third square, you pay an additional<bookmark mark="four"/>4 grains of rice.
                for the fourth square, you pay an additional<bookmark mark="eight"/>8 grains of rice.
                and for the fifth square, you pay an additional<bookmark mark="sixteen"/>16 grains of rice.
                Guess how many grains of rice you will have to pay, when you finish the first out of the
                8 rows on the chessboard? One hundred and twenty eight.
                That's a lot of rice. And you're not even done with the first row yet.
                Once you've reached the <bookmark mark="twentyfirst"/>twenty-first square, you will have to pay more than a million grains of rice.
                And once you've reached the <bookmark mark="fourtyfirst"/>forty-first square, you will have to pay more than a trillion grains of rice.
                In the end, you will have to pay a total of<bookmark mark="largeNumber"/> eighteen quintillion,
                four hundred forty-six quadrillion, seven hundred forty-four trillion, seventy-three billion,
                seven hundred nine million, five hundred fifty-one thousand, six hundred and fifteen grains of rice.
                I'm not sure about rice to gold conversion rates, but I'm pretty sure that gold is the cheaper option here...
                """
        ) as tracker:

            self.wait_until_bookmark("one")
            self.play(grain_of_rice.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("two")
            copies1 = Group(*[grain_of_rice.copy().shift(np.array([2*np.random.rand()-1, 2*np.random.rand()-1,0])/1.5) for i in range(2)])
            self.play(FadeIn(copies1), run_time=0.5)

            self.wait_until_bookmark("four")
            copies2 = Group(*[grain_of_rice.copy().shift(np.array([2*np.random.rand()-1, 2*np.random.rand()-1,0])/1.5) for i in range(4)])
            self.play(FadeIn(copies2), run_time=0.5)

            self.wait_until_bookmark("eight")
            copies3 = Group(*[grain_of_rice.copy().shift(np.array([2*np.random.rand()-1, 2*np.random.rand()-1,0])/1.5) for i in range(8)])
            self.play(FadeIn(copies3), run_time=0.5)

            self.wait_until_bookmark("sixteen")
            copies4 = Group(*[grain_of_rice.copy().shift(np.array([2*np.random.rand()-1, 2*np.random.rand()-1,0])/1.5) for i in range(16)])
            self.play(FadeIn(copies4), run_time=0.5)

            self.wait_until_bookmark("twentyfirst")
            self.play(Write(twentyfirst))

            self.wait_until_bookmark("fourtyfirst")
            self.play(Write(fourtyfirst))

            self.wait_until_bookmark("largeNumber")
            self.play(Write(largeNumber), FadeOut(copies1), FadeOut(copies2), FadeOut(copies3), FadeOut(copies4), FadeOut(grain_of_rice), Unwrite(twentyfirst), Unwrite(fourtyfirst))

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


#####################################
#####################################

#Take this one out???
class Func_6_1_I_2(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Exponential Growth")


        # Create the coordinate system
        cords = self.add_cords([1, 64, 8], [1, 64, 8], x_ticks=[16,32, 48, 64], y_ticks=[16,32,48,64])
        plane = cords[0]
        lin_growth = Tex("Linear Growth", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        
        f_gold = lambda x: x
        g_gold = plane.plot(f_gold, color=YELLOW_C, x_range=[1,60,0.01])

        cords_2 = self.add_cords([0, 4, 1], [0, 16, 2], x_ticks = [0,1,2,3], x_labels=[16,32, 48, 64], y_ticks=[8,16,24,32], y_labels=["", "", "", ""])
        plane_2 = cords_2[0]
        exp_growth = Tex("Exponential Growth", color=c1t, font_size=fs2).next_to(cords_2, DOWN, buff=0.4)
        
        f_rice = lambda x: 2**x-1
        g_rice = plane_2.plot(f_rice, color=GREEN)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        # Action Sequence
        with self.voiceover(
                text="""
                What is the reason that in the chessboard example, the number of grains of rice you have to pay
                increases so fast? How does rice get so much more expensive than gold, so quickly?

                The answer to both of these questions is the same: Exponential Growth.
                Let's compare the two options, rice and gold, again. Specifically,
                let's describe them <bookmark mark="cords"/> using functions.

                We'll start with gold.
                The function that describes the amount of gold you have to pay for a given number of squares is
                <bookmark mark="f_gold"/> f of x equals x.
                For the first square, you have to pay one gold coin. So f of 1 equals 1.
                For the second square, you have to pay one gold coin as well. So f of 2 equals one for the first square,
                plus one for the second square, which is two. And so on. As you can see, the amount you have to pay
                increases linearly with the number of squares you have to pay for. One extra square costs exactly
                as much as each of the previous squares, and the last square costs exactly as much as the first one.
                We call this <bookmark mark="linear"/>linear growth...
                
                Now, let's <bookmark mark="clean"/> look at rice for comparison.
                The <bookmark mark="cords_rice"/>function that describes the amount of rice you have to pay for a
                given number of squares is <bookmark mark="f_rice"/> an exponential function
                For the first square, you have to pay one grain of rice. So f of 1 equals 1.
                For the second square, you have to pay two grains of rice. So f of 2 equals one for the first square,
                plus two for the second square, which is three. 
                For the third square, you have to pay four grains of rice. So f of 3 equals one for the first square,
                plus two for the second square, plus four for the third square, which is seven.
                And so on.
                As you can see, the amount you have to pay increases rapidly with the number of squares you have to pay for,
                because for each square, you have to pay twice as much as for the previous square.
                We call this <bookmark mark="exponential"/>exponential growth...
                """
        , subcaption='NOT AVAILABLE DUE TO BUG') as tracker:

            self.wait_until_bookmark("cords")
            self.play(Write(cords))

            self.wait_until_bookmark("f_gold")
            cursor.blinking=False
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m, dt: m.move_to(g_gold.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Write(g_gold))
            cursor.blinking=True

            self.wait_until_bookmark("linear")
            cursor.blinking=False
            x,y,_ = lin_growth.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(lin_growth), run_time=0.5)
            cursor.blinking=True


            self.wait_until_bookmark("clean")
            self.play(FadeOut(cords), FadeOut(g_gold), FadeOut(lin_growth))

            self.wait_until_bookmark("cords_rice")
            self.play(Write(cords_2))

            self.wait_until_bookmark("f_rice")
            cursor.blinking=False
            x,y,_ = g_rice.get_start()
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m, dt: m.move_to(g_rice.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Write(g_rice))
            cursor.blinking=True

            self.wait_until_bookmark("exponential")
            cursor.blinking=False
            x,y,_ = exp_growth.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(exp_growth), run_time=0.5)
            cursor.blinking=True

        self.wait(4)

#####################################
#####################################
class Func_6_1_I_3(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Linear Growth")

        chicken = ImageMobject(assets_folder / "img" / "chicken.png")
        chicken = chicken.scale(1.5/chicken.get_width()).move_to([-4, -1, 0])
        two_chickens = MathTex("2\\times", color=c1t).next_to(chicken, LEFT, buff=0.4).shift(RIGHT*5)

        egg = ImageMobject(assets_folder / "img" / "egg.png")
        egg = egg.scale(1.5/egg.get_width()).next_to(chicken, DOWN, buff=0.6).shift(0.2*LEFT)
        one_egg = Tex("$1/$day", color=c1t).next_to(egg, LEFT, buff=0.2).scale(0.8)
        one_egg.shift((two_chickens.get_left()-one_egg.get_left())*np.array([1,0,0]))

        farmer_male = ImageMobject(assets_folder / "img" / "farmer_male.png")
        farmer_male = farmer_male.scale(2/farmer_male.get_width()).move_to([-5.6, 1, 0])
        tom = Tex("Tom", color=c1t).next_to(farmer_male, RIGHT, buff=0.2)

        calendar = ImageMobject(assets_folder / "img" / "calendar.png")
        calendar = calendar.scale(2.5/calendar.get_width()).move_to([-5, 1, 0])


        cords = self.add_cords([0,8,1], [0,20,4], x_ticks=[1,2,3,4,5,6,7], y_ticks=[4,8,12,16,20])
        plane = cords[0]
        
        f_eggs = lambda x: 2*x
        f_tex_eggs = MathTex("f","(x)", "=", "2","x", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        lin_growth = Tex("Linear Growth", color=c1t, font_size=fs2).next_to(f_tex_eggs, DOWN, buff=0.8)
        g_eggs = plane.plot(f_eggs, color=BLUE)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        # Action Sequence
        with self.voiceover(
                text="""
                Meet <bookmark mark="tom_in_1"/> Tom.
                Tom is a <bookmark mark="chicken_in_1"/> chicken farmer.
                He has <bookmark mark="two_chickens"/>two chickens. Every day, each of them lays
                <bookmark mark="one_egg_per_day"/>one egg.
                Because Tom likes eggs so much, he collects them every day
                and counts <bookmark mark="calendar"/>how many eggs he has collected over time.

                Let's help tom by describing the number of eggs he has collected using a function.
                We'll describe the function using a <bookmark mark="cords"/>graph.

                So after <bookmark mark="one_day"/>one day, tom has <bookmark mark="two_eggs"/>
                two eggs, because each of the two chickens has laid one egg.
                After <bookmark mark="two_days"/>two days, tom has <bookmark mark="four_eggs"/>
                four eggs, because each of the two chickens has laid one egg on the first day,
                and one egg on the second day.
                And after <bookmark mark="three_days"/>three days, tom has <bookmark mark="six_eggs"/>
                six eggs, because each of the two chickens has laid one egg on the first day,
                one egg on the second day, and one egg on the third day. and so it continues...

                So <bookmark mark="plot"/> every day, tom gets two extra eggs.
                This means, that we can describe the number of eggs tom has collected using a
                <bookmark mark="func"/>function f <bookmark mark="fx"/> of x equals 
                <bookmark mark="two_times"/>two times <bookmark mark="x"/>x, where x is the
                number of days that have passed.

                If you look at the plot of this function, you can see that it is a straight line,
                because the number of eggs increases by the same amount every day.
                This is called <bookmark mark="linear"/>linear growth.

                """
    ) as tracker:
            
            self.wait_until_bookmark("tom_in_1")
            self.play(farmer_male.animate.shift(5*RIGHT), tom.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("chicken_in_1")
            self.play(chicken.animate.shift(RIGHT*5), run_time=0.5)

            self.wait_until_bookmark("two_chickens")
            self.play(Write(two_chickens))

            self.wait_until_bookmark("one_egg_per_day")
            self.play(egg.animate.shift(RIGHT*5), run_time=0.5)
            self.play(Write(one_egg), run_time=0.5)

            self.wait_until_bookmark("calendar")
            self.play(calendar.animate.shift(RIGHT*5), farmer_male.animate.shift(5*RIGHT), tom.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("cords")
            self.play(calendar.animate.shift(RIGHT*5), run_time=0.5)
            self.play(Write(cords))

            self.wait_until_bookmark("one_day")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("two_eggs")
            x,y,_ = plane.c2p(1,2)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cc_two_eggs = cursor.copy().clear_updaters()
            self.add(cc_two_eggs)

            self.wait_until_bookmark("two_days")
            x,y,_ = plane.c2p(2,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("four_eggs")
            x,y,_ = plane.c2p(2,4)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cc_four_eggs = cursor.copy().clear_updaters()
            self.add(cc_four_eggs)

            self.wait_until_bookmark("three_days")
            x,y,_ = plane.c2p(3,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("six_eggs")
            x,y,_ = plane.c2p(3,6)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cc_six_eggs = cursor.copy().clear_updaters()
            self.add(cc_six_eggs)

            self.wait_until_bookmark("plot")
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(7).add_updater(lambda m, dt: m.move_to(g_eggs.get_end())))
            cc_two_eggs._start_fading(2)
            cc_four_eggs._start_fading(2)
            cc_six_eggs._start_fading(2)
            cursor.blinking=True
            self.play(Create(g_eggs), run_time=5)

            self.wait_until_bookmark("func")
            cursor.blinking=False
            x,y,_ = f_tex_eggs[0].get_center()+0.4*DOWN
            self.play(egg.animate.shift(5*RIGHT), one_egg.animate.shift(5*RIGHT), chicken.animate.shift(5*RIGHT), two_chickens.animate.shift(5*RIGHT), CursorMoveTo(cursor,x,y), Write(f_tex_eggs), run_time=0.5)

            self.wait_until_bookmark("fx")
            x,y,_ = f_tex_eggs[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("two_times")
            x,y,_ = f_tex_eggs[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("x")
            x,y,_ = f_tex_eggs[4].get_center()+0.4*DOWN 
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("linear")
            cursor.blinking=False
            x,y,_ = lin_growth.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(lin_growth), run_time=0.5)
            cursor.blinking=True


        self.wait(4)


#####################################
#####################################
class Func_6_1_I_4(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Exponential Growth")

        chicken = ImageMobject(assets_folder / "img" / "chicken.png")
        chicken = chicken.scale(1.5/chicken.get_width()).move_to([-4, -1, 0])
        two_chickens = MathTex("2\\times", color=c1t).next_to(chicken, LEFT, buff=0.6).shift(RIGHT*5)

        egg = ImageMobject(assets_folder / "img" / "egg.png")
        egg = egg.scale(1.5/egg.get_width()).next_to(chicken, DOWN, buff=0.6).shift(0.2*LEFT)
        one_egg = Tex("$1/$week", color=c1t).next_to(egg, LEFT, buff=0.2).scale(0.8)
        one_egg.shift((two_chickens.get_left()-one_egg.get_left())*np.array([1,0,0]))

        farmer_female = ImageMobject(assets_folder / "img" / "farmer_female.png")
        farmer_female = farmer_female.scale(2/farmer_female.get_width()).move_to([-5.6, 1, 0])
        Sophie = Tex("Sophie", color=c1t).next_to(farmer_female, RIGHT, buff=0.2)

        cords = self.add_cords([1,6,1], [0,64,8], x_ticks=[1,2,3,4,5], y_ticks=[16,32, 48])
        plane = cords[0]
        
        f_eggs = lambda x: 2**x
        f_tex_eggs = MathTex("f","(x)", "=", "2","^x", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        exp_growth = Tex("Exponential Growth", color=c1t, font_size=fs2).next_to(f_tex_eggs, DOWN, buff=0.8)
        g_eggs = plane.plot(f_eggs, color=BLUE)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        # Action Sequence
        with self.voiceover(
                text="""
                Meet <bookmark mark="Sophie_in_1"/> Sophie.
                Sophie loves <bookmark mark="chicken_in_1"/> chickens.
                She currently has <bookmark mark="two_chickens_1"/>two chickens, but she wants
                many more. Each of her two chickens lays <bookmark mark="one_egg_per_week"/>
                one egg per week, and at the end of the week, the  chicken from the egg is
                hatched and old enough to lay eggs itself. Those are some fast chickens!

                Let's describe the number of chickens Sophie has using the <bookmark mark="graph"/>
                graph of a function.
                So in the <bookmark mark="one_week"/>first week, sophie has two chickens<bookmark mark="two_chickens"/>
                One week <bookmark mark="two_weeks"/>later, Sophie has <bookmark mark="four_chickens"/>
                four chickens. The two chickens she started with, and the two chickens that hatched from the eggs.

                In the <bookmark mark="three_weeks"/>next week, Sophie has four chickens that lay one egg each,
                so she gets four eggs. This means that the total number of chickens after the second week is
                <bookmark mark="eight_chickens"/>eight: the four chickens from the first week, and the four chickens
                that hatched from the eggs.

                In the <bookmark mark="four_weeks"/>fourth week, Sophie has eight chickens that lay one
                egg each, so she gets eight eggs. So the total number of chickens after the third week is
                <bookmark mark="sixteen_chickens"/>sixteen: the eight chickens from the second week, and the
                eight chickens that hatched from the eggs.

                As you can see, <bookmark mark="plot"/>the number of chickens increases really fast, and this is what we call
                exponential growth. The number of chickens doubles every week, because each of your
                chickens lays one egg per week. This means, that the number of chickens you have after
                x weeks is described by <bookmark mark="f"/> f of <bookmark mark="fx"/> x equals <bookmark mark="two"/>
                two to the <bookmark mark="power"/> power of x. Because you start with two chickens, and each time x
                increases by one, the number of chickens doubles.
                
                This is what we call <bookmark mark="exponential"/>exponential growth.
                """
        , subcaption='NOT AVAILABLE DUE TO BUG') as tracker:
            
            self.wait_until_bookmark("Sophie_in_1")
            self.play(farmer_female.animate.shift(5*RIGHT), Sophie.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("chicken_in_1")
            self.play(chicken.animate.shift(RIGHT*5), run_time=0.5)

            self.wait_until_bookmark("two_chickens_1")
            self.play(Write(two_chickens))

            self.wait_until_bookmark("one_egg_per_week")
            self.play(egg.animate.shift(RIGHT*5), run_time=0.5)
            self.play(Write(one_egg), run_time=0.5)

            self.wait_until_bookmark("graph")
            self.play(farmer_female.animate.shift(5*RIGHT), Sophie.animate.shift(5*RIGHT), run_time=0.5)
            self.play(Write(cords))

            self.wait_until_bookmark("one_week")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("two_chickens")
            x,y,_ = plane.c2p(1,2)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cc_two_chickens = cursor.copy().clear_updaters()
            self.add(cc_two_chickens)

            self.wait_until_bookmark("two_weeks")
            x,y,_ = plane.c2p(2,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("four_chickens")
            x,y,_ = plane.c2p(2,4)
            four_chickens = MathTex("4\\times", color=c1t).next_to(chicken, LEFT, buff=0.6)
            self.play(TransformMatchingTex(two_chickens, four_chickens), CursorMoveTo(cursor,x,y), run_time=0.3)
            cc_four_chickens = cursor.copy().clear_updaters()
            self.add(cc_four_chickens)

            self.wait_until_bookmark("three_weeks")
            x,y,_ = plane.c2p(3,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("eight_chickens")
            x,y,_ = plane.c2p(3,8)
            eight_chickens = MathTex("8\\times", color=c1t).next_to(chicken, LEFT, buff=0.6)
            self.play(TransformMatchingTex(four_chickens, eight_chickens), CursorMoveTo(cursor,x,y), run_time=0.3)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cc_eight_chickens = cursor.copy().clear_updaters()
            self.add(cc_eight_chickens)

            self.wait_until_bookmark("four_weeks")
            x,y,_ = plane.c2p(4,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("sixteen_chickens")
            x,y,_ = plane.c2p(4,16)
            sixteen_chickens = MathTex("16\\times", color=c1t).next_to(chicken, LEFT, buff=0.6)
            self.play(TransformMatchingTex(eight_chickens, sixteen_chickens), CursorMoveTo(cursor,x,y), run_time=0.3)
            cc_sixteen_chickens = cursor.copy().clear_updaters()
            self.add(cc_sixteen_chickens)

            self.wait_until_bookmark("plot")
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cc_func = cursor.copy()._start_fading(7).add_updater(lambda m, dt: m.move_to(g_eggs.get_end()))
            chicken_counter = DecimalNumber(16, color=c1t, num_decimal_places=0).add_updater(lambda m: m.set_value(max(16,plane.p2c(g_eggs.get_end())[1])))
            self.remove(sixteen_chickens)
            sixteen_chickens = VGroup(chicken_counter, MathTex("\\times", color=c1t)).arrange(RIGHT, buff=0.2).next_to(chicken, LEFT, buff=0.6)
            self.add(cc_func, sixteen_chickens, chicken_counter)
            cc_two_chickens._start_fading(1)
            cc_four_chickens._start_fading(2)
            cc_eight_chickens._start_fading(3.5)
            cc_sixteen_chickens._start_fading(5)
            self.play(Create(g_eggs), run_time=10)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f_tex_eggs[0].get_center()+0.4*DOWN
            self.play(egg.animate.shift(5*RIGHT), one_egg.animate.shift(5*RIGHT), chicken.animate.shift(5*RIGHT), sixteen_chickens.animate.shift(5*RIGHT), CursorMoveTo(cursor,x,y), Write(f_tex_eggs), run_time=0.5)

            self.wait_until_bookmark("fx")
            x,y,_ = f_tex_eggs[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("two")
            x,y,_ = f_tex_eggs[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("power")
            x,y,_ = f_tex_eggs[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("exponential")
            cursor.blinking=False
            x,y,_ = exp_growth.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(exp_growth), run_time=0.5)
            cursor.blinking=True


        self.wait(4)

#####################################
#####################################
TASK_Func_6_1_I_5_q = SophiaTaskDefinition(
    answerOptions = ["exponentially", "linearly"],
    correctAnswerIndex = 0,
    questionText = "Does the number of bacteria grow exponentially or linearly?"
)

class Func_6_1_I_5_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Exponential or Linear?")

        sarah = ImageMobject(assets_folder / "img" / "biologist.png")
        sarah = sarah.scale(2.5/sarah.get_width()).move_to([-5, 1.4, 0])

        bacteria = ImageMobject(assets_folder / "img" / "bacteria.png")
        bacteria = bacteria.scale(1.5/bacteria.get_width()).move_to([-6, -1, 0])
        bacteria_double = VGroup(Tex("$\\Uparrow$ Duplicate every", color=c1t, font_size=fs2), Tex("$20$ minutes", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.).next_to(bacteria, DOWN, buff=0.2).shift(RIGHT*5.8)
        
        clock = ImageMobject(assets_folder / "img" / "clock.png")
        clock = clock.scale(1.5/clock.get_width()).move_to([-5, -1, 0])



        cords = self.add_cords([1,6,1], [0,64,8], x_ticks=[1,2,3,4,5], y_ticks=[16,32, 48])
        plane = cords[0]
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        # Action Sequence
        with self.voiceover(
                text="""
                My friend <bookmark mark="sarah"/>Sarah is a doctor and she does research on
                <bookmark mark="bacteria"/>bacteria.
                Did you know, that bacteria grow, by simply duplicating themselves?
                The bacteria that Sarah is studying for example <bookmark mark="bacteria_double"/>
                duplicate once every twenty minutes. This means, that every twenty minutes, each
                of the bacteria sarah is studying, turns into<bookmark mark="show_double"/> two bacteria...
                Now Sarah wants to know: Does the number of bacteria she is analyzing grow
                <bookmark mark="linear"/>linearly, or does it grow <bookmark mark="exponential"/> exponentially?
                """
         ) as tracker:
            
            self.wait_until_bookmark("sarah")
            self.play(sarah.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("bacteria")
            self.play(bacteria.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("bacteria_double")
            self.play(Write(bacteria_double))

            self.wait_until_bookmark("show_double")
            bacteria_double = bacteria.copy()
            self.play(bacteria_double.animate.shift(1.2*bacteria.get_width()*RIGHT), run_time=0.5)

            self.wait_until_bookmark("linear")
            cursor.blinking=False
            x,y,_ = title.get_right()+0.4*DOWN+0.5*LEFT
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("exponential")
            cursor.blinking=False
            x,y,_ = title.get_left()+0.4*DOWN+0.5*RIGHT
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)

class Func_6_1_I_5_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Exponential or Linear?")

        bacteria = ImageMobject(assets_folder / "img" / "bacteria.png")
        bacteria = bacteria.scale(1.5/bacteria.get_width()).move_to([-6, -1, 0])

        exponential_growth1 = Tex("$\\Rightarrow$ The number of bacteria", color=c1t, font_size=fs3)
        exponential_growth2 = Tex("grows exponentially", color=c1t, font_size=fs3)
        exponential_growth = VGroup(exponential_growth1, exponential_growth2).arrange(DOWN, buff=0.2).next_to(bacteria, DOWN, buff=0.8).shift(5.6*RIGHT)

        # Action Sequence
        with self.voiceover(
                text="""
                That's correct, well done.
                Let's look at the number of bacteria step by step.
                At first, there's one <bookmark mark="one"/> bacteria.
                After twenty minutes, the bacteria duplicates, so there are<bookmark mark="two"/> two bacteria.
                After another twenty minutes, each of the two bacteria duplicates, so there are <bookmark mark="four"/>four bacteria.
                And after another twenty minutes, they each duplicate <bookmark mark="eight"/>again, and we get four more bacteria, to get us to eight.

                So you see, how at each of the timesteps, we get twice as many bacteria as in the previous timestep:<bookmark mark="step0"/>
                In the first timestep, we get <bookmark mark="step1"/>one bacteria, in the second timestep, we get <bookmark mark="step2"/>two bacteria
                and in the third timestep, we get <bookmark mark="step3"/>four bacteria...
                This means, that the number of bacteria grows <bookmark mark="exponential"/>exponentially, because at each timestep we get
                twice as many additional bacteria as in the previous timestep.
                """
         ) as tracker:
            
            self.wait_until_bookmark("one")
            self.play(bacteria.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("two")
            bacteria_2 = bacteria.copy()
            self.play(bacteria_2.animate.shift(1.2*bacteria.get_width()*RIGHT), run_time=0.5)

            self.wait_until_bookmark("four")
            bacteria_3 = bacteria.copy()
            bacteria_4 = bacteria_2.copy()
            self.play(bacteria_3.animate.shift(1.2*bacteria.get_height()*UP), bacteria_4.animate.shift(1.2*bacteria.get_height()*UP), run_time=0.5)

            self.wait_until_bookmark("eight")
            bacteria_5 = bacteria.copy()
            bacteria_6 = bacteria_2.copy()
            bacteria_7 = bacteria_3.copy()
            bacteria_8 = bacteria_4.copy()
            self.play(bacteria_5.animate.shift(0.6*bacteria.get_height()*UP), bacteria_6.animate.shift(0.6*bacteria.get_height()*UP), bacteria_7.animate.shift(0.6*bacteria.get_height()*UP), bacteria_8.animate.shift(0.6*bacteria.get_height()*UP), run_time=0.5)

            self.wait_until_bookmark("step0")
            self.play(bacteria_2.animate.shift(5*RIGHT), bacteria_3.animate.shift(5*RIGHT), bacteria_4.animate.shift(5*RIGHT), bacteria_5.animate.shift(5*RIGHT), bacteria_6.animate.shift(5*RIGHT), bacteria_7.animate.shift(5*RIGHT), bacteria_8.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("step1")
            self.play(bacteria_2.animate.shift(5*LEFT), run_time=0.5)

            self.wait_until_bookmark("step2")
            self.play(bacteria_3.animate.shift(5*LEFT), bacteria_4.animate.shift(5*LEFT), run_time=0.5)

            self.wait_until_bookmark("step3")
            self.play(bacteria_5.animate.shift(5*LEFT), bacteria_6.animate.shift(5*LEFT), bacteria_7.animate.shift(5*LEFT), bacteria_8.animate.shift(5*LEFT), run_time=0.5)
        
            self.wait_until_bookmark("exponential")
            self.play(Write(exponential_growth))
        
        self.wait(4)



class Func_6_1_I_5_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Exponential or Linear?")

        bacteria = ImageMobject(assets_folder / "img" / "bacteria.png")
        bacteria = bacteria.scale(1.5/bacteria.get_width()).move_to([-6, -1, 0])

        exponential_growth1 = Tex("$\\Rightarrow$ The number of bacteria", color=c1t, font_size=fs3)
        exponential_growth2 = Tex("grows exponentially", color=c1t, font_size=fs3)
        exponential_growth = VGroup(exponential_growth1, exponential_growth2).arrange(DOWN, buff=0.2).next_to(bacteria, DOWN, buff=0.8).shift(5.6*RIGHT)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                Let's look at the number of bacteria step by step.
                At first, there's one <bookmark mark="one"/> bacteria.
                After twenty minutes, the bacteria duplicates, so there are<bookmark mark="two"/> two bacteria.
                After another twenty minutes, each of the two bacteria duplicates, so there are <bookmark mark="four"/>four bacteria.
                And after another twenty minutes, they each duplicate <bookmark mark="eight"/>again, and we get four more bacteria, to get us to eight.

                So you see, how at each of the timesteps, we get twice as many bacteria as in the previous timestep:<bookmark mark="step0"/>
                In the first timestep, we get <bookmark mark="step1"/>one bacteria, in the second timestep, we get <bookmark mark="step2"/>two bacteria
                and in the third timestep, we get <bookmark mark="step3"/>four bacteria...
                This means, that the number of bacteria grows <bookmark mark="exponential"/>exponentially, because at each timestep we get
                twice as many additional bacteria as in the previous timestep.
                """
         ) as tracker:
            
            self.wait_until_bookmark("one")
            self.play(bacteria.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("two")
            bacteria_2 = bacteria.copy()
            self.play(bacteria_2.animate.shift(1.2*bacteria.get_width()*RIGHT), run_time=0.5)

            self.wait_until_bookmark("four")
            bacteria_3 = bacteria.copy()
            bacteria_4 = bacteria_2.copy()
            self.play(bacteria_3.animate.shift(1.2*bacteria.get_height()*UP), bacteria_4.animate.shift(1.2*bacteria.get_height()*UP), run_time=0.5)

            self.wait_until_bookmark("eight")
            bacteria_5 = bacteria.copy()
            bacteria_6 = bacteria_2.copy()
            bacteria_7 = bacteria_3.copy()
            bacteria_8 = bacteria_4.copy()
            self.play(bacteria_5.animate.shift(0.6*bacteria.get_height()*UP), bacteria_6.animate.shift(0.6*bacteria.get_height()*UP), bacteria_7.animate.shift(0.6*bacteria.get_height()*UP), bacteria_8.animate.shift(0.6*bacteria.get_height()*UP), run_time=0.5)

            self.wait_until_bookmark("step0")
            self.play(bacteria_2.animate.shift(5*RIGHT), bacteria_3.animate.shift(5*RIGHT), bacteria_4.animate.shift(5*RIGHT), bacteria_5.animate.shift(5*RIGHT), bacteria_6.animate.shift(5*RIGHT), bacteria_7.animate.shift(5*RIGHT), bacteria_8.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("step1")
            self.play(bacteria_2.animate.shift(5*LEFT), run_time=0.5)

            self.wait_until_bookmark("step2")
            self.play(bacteria_3.animate.shift(5*LEFT), bacteria_4.animate.shift(5*LEFT), run_time=0.5)

            self.wait_until_bookmark("step3")
            self.play(bacteria_5.animate.shift(5*LEFT), bacteria_6.animate.shift(5*LEFT), bacteria_7.animate.shift(5*LEFT), bacteria_8.animate.shift(5*LEFT), run_time=0.5)
        
            self.wait_until_bookmark("exponential")
            self.play(Write(exponential_growth))
        
        self.wait(4)


#####################################
#####################################
TASK_Func_6_1_I_6_q = SophiaTaskDefinition(
    answerOptions = ["$f(x)=2\\cdot x$", "$g(x)=2^x$", "$h(x)=x^2$"],
    correctAnswerIndex = 0,
    questionText = "Which function describes the number of bacteria at time x?"
)

class Func_6_1_I_6_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Exponential or Linear?")

        sarah = ImageMobject(assets_folder / "img" / "biologist.png")
        sarah = sarah.scale(2.5/sarah.get_width()).move_to([-5, 1.4, 0])

        bacteria = ImageMobject(assets_folder / "img" / "bacteria.png")
        bacteria = bacteria.scale(1.5/bacteria.get_width()).move_to([-6, -1, 0])
        bacteria_double = VGroup(Tex("$\\Uparrow$ Duplicate every", color=c1t, font_size=fs2), Tex("$20$ minutes", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.).next_to(bacteria, DOWN, buff=0.2).shift(RIGHT*5.8)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        f_tex = MathTex("f","(x)", "=", "2", "\\cdot", "x", color=c1t, font_size=fs2)
        g_tex = MathTex("g","(x)", "=", "2", "^x", color=c1t, font_size=fs2)
        h_tex = MathTex("h","(x)", "=", "x^2", color=c1t, font_size=fs2)
        funcs = VGroup(f_tex, g_tex, h_tex).arrange(DOWN, buff=0.4, aligned_edge=LEFT).shift(DOWN)

        t = Table(
            [["x", "time"],
            ["1", "20 Minutes"],
            ["2", "40 Minutes"],
            ["...", "..."]], element_to_mobject_config={"color": c1t}, line_config={"color": c1t}).scale(0.35).next_to(bacteria, RIGHT, buff=0.2).shift(RIGHT*5)
        rows = t.get_rows()
        t_structure = VGroup(t.get_horizontal_lines(), t.get_vertical_lines())


        # Action Sequence
        with self.voiceover(
                text="""
                <bookmark mark="sarah"/>Sarah knows, that the <bookmark mark="bacteria"/>bacteria she is studying duplicate every twenty minutes.
                Now she wants to describe the number of bacteria she is studying using a function.
                Let x<bookmark mark="table"/> be the time that is passed in units of twenty minutes, so <bookmark mark="row_1"/>x equals one means
                twenty minutes, <bookmark mark="row_2"/>x equals two means forty minutes,<bookmark mark="rowsss"/> and so on.
                <bookmark mark="clean"/>Which of these functions describe the number of bacteria at time x?
                Is it<bookmark mark="f"/> f of <bookmark mark="fx"/>x equals <bookmark mark="ftwo"/>2 times <bookmark mark="fxx"/> x?
                Or is it<bookmark mark="g"/> g of <bookmark mark="gx"/>x equals <bookmark mark="gtwo"/>two to the power of <bookmark mark="gxx"/> x?
                Or is it<bookmark mark="h"/> h of <bookmark mark="hx"/>x equals <bookmark mark="hxx"/>x squared?
                """
         ) as tracker:
            
            self.wait_until_bookmark("sarah")
            self.play(sarah.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("bacteria")
            self.play(bacteria.animate.shift(5*RIGHT), run_time=0.5)
            self.play(Write(bacteria_double))

            self.wait_until_bookmark("table")
            self.play(Write(t_structure), Write(rows[0]), run_time=0.5)

            self.wait_until_bookmark("row_1")
            self.play(Write(rows[1]), run_time=0.5)

            self.wait_until_bookmark("row_2")
            self.play(Write(rows[2]), run_time=0.5)

            self.wait_until_bookmark("rowsss")
            self.play(Write(rows[3]), run_time=0.5)

            self.wait_until_bookmark("clean")
            self.play(sarah.animate.shift(5*RIGHT), bacteria_double.animate.shift(5*RIGHT), bacteria.animate.shift(2.5*UP), t.animate.shift(2.5*UP), run_time=0.5)

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = f_tex[0].get_center()+0.4*DOWN
            self.play(Write(f_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("ftwo")
            x,y,_ = f_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fxx")
            x,y,_ = f_tex[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("g")
            cursor.blinking=False
            x,y,_ = g_tex[0].get_center()+0.4*DOWN
            self.play(Write(g_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gx")
            x,y,_ = g_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gtwo")
            x,y,_ = g_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gxx")
            x,y,_ = g_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("h")
            cursor.blinking=False
            x,y,_ = h_tex[0].get_center()+0.4*DOWN
            self.play(Write(h_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("hx")
            x,y,_ = h_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("hxx")
            x,y,_ = h_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

        self.wait(4)

class Func_6_1_I_6_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Exponential growth")

        bacteria = ImageMobject(assets_folder / "img" / "bacteria.png")
        bacteria = bacteria.scale(1.5/bacteria.get_width()).move_to([-6, -0.4, 0])

        t = MathTable(
            [["x", "0", "1", "2", "3", "..."],
            ["\\text{Bacteria}", "1", "2", "2\\cdot 2", "2\\cdot2\\cdot2", "..." ]], element_to_mobject_config={"color": c1t}, line_config={"color": c1t}).scale(0.35).next_to(bacteria, DOWN, buff=0.4).shift(6*RIGHT)

        t_structure = VGroup(t.get_horizontal_lines(), t.get_vertical_lines())
        cols = t.get_columns()

        g_tex = MathTex("g","(x)", "=", "2", "^x", color=c1t, font_size=fs2).next_to(t, DOWN, buff=0.2)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=False)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not it.
                Again, let's look at how many bacteria we have at each step.
                When we beginn, at x equals zero, there's one <bookmark mark="one"/> bacteria.
                After twenty minutes so at x equals one, the bacteria duplicates, so there are<bookmark mark="two"/> two bacteria.
                After another twenty minutes, so at x equals two,  each of the two bacteria duplicates, so there are <bookmark mark="four"/>four bacteria.
                And after another twenty minutes, meaning at x equals four, they each duplicate <bookmark mark="eight"/>again, and we get four more bacteria, to get us to eight.

                So you see, how at each of the timesteps, so every time that x increases by one, we get twice as many bacteria as in the previous timestep.<bookmark mark="step0"/>
                In the first timestep, we go from <bookmark mark="step1"/>one bacteria to two so we multiply the number of bacteria that we have by two.
                In the second timestep, we go from two <bookmark mark="step2"/> bacteria to four, so we double the number of bacteria again.
                and in the third timestep, we go from four <bookmark mark="step3"/> bacteria to eight, again multiplying the number of bacteria by two.

                This means, that at every time step, the number of bacteria is given by two to the power of x, because we need to multiply 2 x times by itself, to get the number of bacteria.
                This means, that the function describing the number of bacteria is<bookmark mark="exponential"/> g of <bookmark mark="gx"/>x equals <bookmark mark="gtwo"/>two to the power of <bookmark mark="gxx"/> x.
                """
         ) as tracker:
            
            self.wait_until_bookmark("one")
            self.play(bacteria.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("two")
            bacteria_2 = bacteria.copy()
            self.play(bacteria_2.animate.shift(1.2*bacteria.get_width()*RIGHT), run_time=0.5)

            self.wait_until_bookmark("four")
            bacteria_3 = bacteria.copy()
            bacteria_4 = bacteria_2.copy()
            self.play(bacteria_3.animate.shift(1.2*bacteria.get_height()*UP), bacteria_4.animate.shift(1.2*bacteria.get_height()*UP),
                      run_time=0.5)

            self.wait_until_bookmark("eight")
            bacteria_5 = bacteria.copy()
            bacteria_6 = bacteria_2.copy()
            bacteria_7 = bacteria_3.copy()
            bacteria_8 = bacteria_4.copy()
            self.play(bacteria_5.animate.shift(0.6*bacteria.get_height()*UP), bacteria_6.animate.shift(0.6*bacteria.get_height()*UP),
                      bacteria_7.animate.shift(0.6*bacteria.get_height()*UP), bacteria_8.animate.shift(0.6*bacteria.get_height()*UP),
                      run_time=0.5)

            self.wait_until_bookmark("step0")
            self.play(bacteria_2.animate.shift(5*RIGHT), bacteria_3.animate.shift(5*RIGHT), bacteria_4.animate.shift(5*RIGHT),
                      bacteria_5.animate.shift(5*RIGHT), bacteria_6.animate.shift(5*RIGHT), bacteria_7.animate.shift(5*RIGHT),
                      bacteria_8.animate.shift(5*RIGHT), Write(t_structure), Write(cols[0]), Write(cols[1]), run_time=0.5)

            self.wait_until_bookmark("step1")
            self.play(bacteria_2.animate.shift(5*LEFT), Write(cols[2]), run_time=0.5)

            self.wait_until_bookmark("step2")
            self.play(bacteria_3.animate.shift(5*LEFT), Write(cols[3]), bacteria_4.animate.shift(5*LEFT), run_time=0.5)

            self.wait_until_bookmark("step3")
            self.play(bacteria_5.animate.shift(5*LEFT), Write(cols[4]), bacteria_6.animate.shift(5*LEFT), bacteria_7.animate.shift(5*LEFT),
                      bacteria_8.animate.shift(5*LEFT), run_time=0.5)
            
            self.wait_until_bookmark("exponential")
            self.add(cursor)
            x,y,_ = g_tex[0].get_center()+0.4*DOWN
            self.play(Write(g_tex), CursorMoveTo(cursor,x,y), run_time=0.3)
        
            self.wait_until_bookmark("gx")
            cursor.blinking=False
            x,y,_ = g_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("gtwo")
            x,y,_ = g_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("gxx")
            x,y,_ = g_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)

class Func_6_1_I_6_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Exponential growth")

        bacteria = ImageMobject(assets_folder / "img" / "bacteria.png")
        bacteria = bacteria.scale(1.5/bacteria.get_width()).move_to([-6, -0.4, 0])

        t = MathTable(
            [["x", "0", "1", "2", "3", "..."],
            ["\\text{Bacteria}", "1", "2", "2\\cdot 2", "2\\cdot2\\cdot2", "..." ]], element_to_mobject_config={"color": c1t}, line_config={"color": c1t}).scale(0.35).next_to(bacteria, DOWN, buff=0.4).shift(6*RIGHT)

        t_structure = VGroup(t.get_horizontal_lines(), t.get_vertical_lines())
        cols = t.get_columns()

        g_tex = MathTex("g","(x)", "=", "2", "^x", color=c1t, font_size=fs2).next_to(t, DOWN, buff=0.2)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=False)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)

        # Action Sequence
        with self.voiceover(
                text="""
                That's correct, well done.
                Again, let's look at how many bacteria we have at each step.
                When we beginn, at x equals zero, there's one <bookmark mark="one"/> bacteria.
                After twenty minutes so at x equals one, the bacteria duplicates, so there are<bookmark mark="two"/> two bacteria.
                After another twenty minutes, so at x equals two,  each of the two bacteria duplicates, so there are <bookmark mark="four"/>four bacteria.
                And after another twenty minutes, meaning at x equals four, they each duplicate <bookmark mark="eight"/>again, and we get four more bacteria, to get us to eight.

                So you see, how at each of the timesteps, so every time that x increases by one, we get twice as many bacteria as in the previous timestep.<bookmark mark="step0"/>
                In the first timestep, we go from <bookmark mark="step1"/>one bacteria to two so we multiply the number of bacteria that we have by two.
                In the second timestep, we go from two <bookmark mark="step2"/> bacteria to four, so we double the number of bacteria again.
                and in the third timestep, we go from four <bookmark mark="step3"/> bacteria to eight, again multiplying the number of bacteria by two.

                This means, that at every time step, the number of bacteria is given by two to the power of x, because we need to multiply 2 x times by itself, to get the number of bacteria.
                This means, that the function describing the number of bacteria is<bookmark mark="exponential"/> g of <bookmark mark="gx"/>x equals <bookmark mark="gtwo"/>two to the power of <bookmark mark="gxx"/> x.
                """
         ) as tracker:
            
            self.wait_until_bookmark("one")
            self.play(bacteria.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("two")
            bacteria_2 = bacteria.copy()
            self.play(bacteria_2.animate.shift(1.2*bacteria.get_width()*RIGHT), run_time=0.5)

            self.wait_until_bookmark("four")
            bacteria_3 = bacteria.copy()
            bacteria_4 = bacteria_2.copy()
            self.play(bacteria_3.animate.shift(1.2*bacteria.get_height()*UP), bacteria_4.animate.shift(1.2*bacteria.get_height()*UP),
                      run_time=0.5)

            self.wait_until_bookmark("eight")
            bacteria_5 = bacteria.copy()
            bacteria_6 = bacteria_2.copy()
            bacteria_7 = bacteria_3.copy()
            bacteria_8 = bacteria_4.copy()
            self.play(bacteria_5.animate.shift(0.6*bacteria.get_height()*UP), bacteria_6.animate.shift(0.6*bacteria.get_height()*UP),
                      bacteria_7.animate.shift(0.6*bacteria.get_height()*UP), bacteria_8.animate.shift(0.6*bacteria.get_height()*UP),
                      run_time=0.5)

            self.wait_until_bookmark("step0")
            self.play(bacteria_2.animate.shift(5*RIGHT), bacteria_3.animate.shift(5*RIGHT), bacteria_4.animate.shift(5*RIGHT),
                      bacteria_5.animate.shift(5*RIGHT), bacteria_6.animate.shift(5*RIGHT), bacteria_7.animate.shift(5*RIGHT),
                      bacteria_8.animate.shift(5*RIGHT), Write(t_structure), Write(cols[0]), Write(cols[1]), run_time=0.5)

            self.wait_until_bookmark("step1")
            self.play(bacteria_2.animate.shift(5*LEFT), Write(cols[2]), run_time=0.5)

            self.wait_until_bookmark("step2")
            self.play(bacteria_3.animate.shift(5*LEFT), Write(cols[3]), bacteria_4.animate.shift(5*LEFT), run_time=0.5)

            self.wait_until_bookmark("step3")
            self.play(bacteria_5.animate.shift(5*LEFT), Write(cols[4]), bacteria_6.animate.shift(5*LEFT), bacteria_7.animate.shift(5*LEFT),
                      bacteria_8.animate.shift(5*LEFT), run_time=0.5)
            
            self.wait_until_bookmark("exponential")
            self.add(cursor)
            x,y,_ = g_tex[0].get_center()+0.4*DOWN
            self.play(Write(g_tex), CursorMoveTo(cursor,x,y), run_time=0.3)
        
            self.wait_until_bookmark("gx")
            cursor.blinking=False
            x,y,_ = g_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("gtwo")
            x,y,_ = g_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("gxx")
            x,y,_ = g_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)

class Func_6_1_I_6_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Exponential growth")

        bacteria = ImageMobject(assets_folder / "img" / "bacteria.png")
        bacteria = bacteria.scale(1.5/bacteria.get_width()).move_to([-6, -0.4, 0])

        t = MathTable(
            [["x", "0", "1", "2", "3", "..."],
            ["\\text{Bacteria}", "1", "2", "2\\cdot 2", "2\\cdot2\\cdot2", "..." ]], element_to_mobject_config={"color": c1t}, line_config={"color": c1t}).scale(0.35).next_to(bacteria, DOWN, buff=0.4).shift(6*RIGHT)

        t_structure = VGroup(t.get_horizontal_lines(), t.get_vertical_lines())
        cols = t.get_columns()

        g_tex = MathTex("g","(x)", "=", "2", "^x", color=c1t, font_size=fs2).next_to(t, DOWN, buff=0.2)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=False)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not it.
                Again, let's look at how many bacteria we have at each step.
                When we beginn, at x equals zero, there's one <bookmark mark="one"/> bacteria.
                After twenty minutes so at x equals one, the bacteria duplicates, so there are<bookmark mark="two"/> two bacteria.
                After another twenty minutes, so at x equals two,  each of the two bacteria duplicates, so there are <bookmark mark="four"/>four bacteria.
                And after another twenty minutes, meaning at x equals four, they each duplicate <bookmark mark="eight"/>again, and we get four more bacteria, to get us to eight.

                So you see, how at each of the timesteps, so every time that x increases by one, we get twice as many bacteria as in the previous timestep.<bookmark mark="step0"/>
                In the first timestep, we go from <bookmark mark="step1"/>one bacteria to two so we multiply the number of bacteria that we have by two.
                In the second timestep, we go from two <bookmark mark="step2"/> bacteria to four, so we double the number of bacteria again.
                and in the third timestep, we go from four <bookmark mark="step3"/> bacteria to eight, again multiplying the number of bacteria by two.

                This means, that at every time step, the number of bacteria is given by two to the power of x, because we need to multiply 2 x times by itself, to get the number of bacteria.
                This means, that the function describing the number of bacteria is<bookmark mark="exponential"/> g of <bookmark mark="gx"/>x equals <bookmark mark="gtwo"/>two to the power of <bookmark mark="gxx"/> x.
                """
         ) as tracker:
            
            self.wait_until_bookmark("one")
            self.play(bacteria.animate.shift(5*RIGHT), run_time=0.5)

            self.wait_until_bookmark("two")
            bacteria_2 = bacteria.copy()
            self.play(bacteria_2.animate.shift(1.2*bacteria.get_width()*RIGHT), run_time=0.5)

            self.wait_until_bookmark("four")
            bacteria_3 = bacteria.copy()
            bacteria_4 = bacteria_2.copy()
            self.play(bacteria_3.animate.shift(1.2*bacteria.get_height()*UP), bacteria_4.animate.shift(1.2*bacteria.get_height()*UP),
                      run_time=0.5)

            self.wait_until_bookmark("eight")
            bacteria_5 = bacteria.copy()
            bacteria_6 = bacteria_2.copy()
            bacteria_7 = bacteria_3.copy()
            bacteria_8 = bacteria_4.copy()
            self.play(bacteria_5.animate.shift(0.6*bacteria.get_height()*UP), bacteria_6.animate.shift(0.6*bacteria.get_height()*UP),
                      bacteria_7.animate.shift(0.6*bacteria.get_height()*UP), bacteria_8.animate.shift(0.6*bacteria.get_height()*UP),
                      run_time=0.5)

            self.wait_until_bookmark("step0")
            self.play(bacteria_2.animate.shift(5*RIGHT), bacteria_3.animate.shift(5*RIGHT), bacteria_4.animate.shift(5*RIGHT),
                      bacteria_5.animate.shift(5*RIGHT), bacteria_6.animate.shift(5*RIGHT), bacteria_7.animate.shift(5*RIGHT),
                      bacteria_8.animate.shift(5*RIGHT), Write(t_structure), Write(cols[0]), Write(cols[1]), run_time=0.5)

            self.wait_until_bookmark("step1")
            self.play(bacteria_2.animate.shift(5*LEFT), Write(cols[2]), run_time=0.5)

            self.wait_until_bookmark("step2")
            self.play(bacteria_3.animate.shift(5*LEFT), Write(cols[3]), bacteria_4.animate.shift(5*LEFT), run_time=0.5)

            self.wait_until_bookmark("step3")
            self.play(bacteria_5.animate.shift(5*LEFT), Write(cols[4]), bacteria_6.animate.shift(5*LEFT), bacteria_7.animate.shift(5*LEFT),
                      bacteria_8.animate.shift(5*LEFT), run_time=0.5)
            
            self.wait_until_bookmark("exponential")
            self.add(cursor)
            x,y,_ = g_tex[0].get_center()+0.4*DOWN
            self.play(Write(g_tex), CursorMoveTo(cursor,x,y), run_time=0.3)
        
            self.wait_until_bookmark("gx")
            cursor.blinking=False
            x,y,_ = g_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("gtwo")
            x,y,_ = g_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)

            self.wait_until_bookmark("gxx")
            x,y,_ = g_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
TASK_Func_6_1_I_7_q = SophiaTaskDefinition(
    answerOptions = ["The blue graph", "The green graph", "The purple graph"],
    correctAnswerIndex = 1,
    questionText = "Which of the graphs belongs to the function?"
)

class Func_6_1_I_7_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Exponential or Linear?")

        sarah = ImageMobject(assets_folder / "img" / "biologist.png")
        sarah = sarah.scale(2.5/sarah.get_width()).move_to([-5, 1.4, 0])

        bacteria = ImageMobject(assets_folder / "img" / "bacteria.png")
        bacteria = bacteria.scale(1.5/bacteria.get_width()).move_to([-6, -1, 0])
        bacteria_double = VGroup(Tex("$\\Uparrow$ Duplicate every", color=c1t, font_size=fs2), Tex("$20$ minutes", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.).next_to(bacteria, DOWN, buff=0.2).shift(RIGHT*5.8)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        cords = self.add_cords([0, 6, 1], [0, 64, 8], x_ticks=[2,4,6], y_ticks=[16,32,48,64])
        plane = cords[0]
        lin_growth = Tex("Linear Growth", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)

        g_tex = MathTex("g","(x)", "=", "2", "^x", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        
        f = lambda x:3*x
        g = lambda x:2**x
        h = lambda x:10*x**0.5

        f_plot = plane.plot(f, color=BLUE)
        g_plot = plane.plot(g, color=GREEN)
        h_plot = plane.plot(h, color=PURPLE)

        # Action Sequence
        with self.voiceover(
                text="""
                Look at the function<bookmark mark="g"/> g of <bookmark mark="gx"/>x equals <bookmark mark="gtwo"/>two to the power of <bookmark mark="gxx"/> x?
                Which of the following <bookmark mark="cords"/> graphs belongs to the function?
                The <bookmark mark="blue"/> blue graph? Or the <bookmark mark="green"/> green graph? Or is it the <bookmark mark="purple"/> purple graph?
                """
        ) as tracker:
            
            self.wait_until_bookmark("g")
            x,y,_ = g_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(g_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gx")
            x,y,_ = g_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gtwo")
            x,y,_ = g_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gxx")
            x,y,_ = g_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Write(cords), run_time=0.3)


            self.wait_until_bookmark("blue")
            x,y,_ = f_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(1).add_updater(lambda m: m.move_to(f_plot.get_end())))
            self.add_pencil_sound(.5)
            self.play(Create(f_plot), run_time=0.5)

            self.wait_until_bookmark("green")
            x,y,_ = g_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(1).add_updater(lambda m: m.move_to(g_plot.get_end())))
            self.add_pencil_sound(.5)
            self.play(Create(g_plot), run_time=0.5)

            self.wait_until_bookmark("purple")
            x,y,_ = h_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(1).add_updater(lambda m: m.move_to(h_plot.get_end())))
            self.add_pencil_sound(.5)
            self.play(Create(h_plot), run_time=0.5)

        self.wait(4)


class Func_6_1_I_7_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Exponential or Linear?")

        sarah = ImageMobject(assets_folder / "img" / "biologist.png")
        sarah = sarah.scale(2.5/sarah.get_width()).move_to([-5, 1.4, 0])

        bacteria = ImageMobject(assets_folder / "img" / "bacteria.png")
        bacteria = bacteria.scale(1.5/bacteria.get_width()).move_to([-6, -1, 0])
        bacteria_double = VGroup(Tex("$\\Uparrow$ Duplicate every", color=c1t, font_size=fs2), Tex("$20$ minutes", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.).next_to(bacteria, DOWN, buff=0.2).shift(RIGHT*5.8)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        cords = self.add_cords([0, 6, 1], [0, 64, 8], x_ticks=[2,4,6], y_ticks=[16,32,48,64])
        plane = cords[0]
        lin_growth = Tex("Linear Growth", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)

        g_tex = MathTex("g","(x)", "=", "2", "^x", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        
        f = lambda x:3*x
        g = lambda x:2**x
        h = lambda x:10*x**0.5

        f_plot = plane.plot(f, color=BLUE)
        g_plot = plane.plot(g, color=GREEN)
        h_plot = plane.plot(h, color=PURPLE)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                For the function <bookmark mark="g"/> g of <bookmark mark="gx"/>x equals <bookmark mark="gtwo"/>two to the power of <bookmark mark="gxx"/> x,
                the number of bacteria doubles every twenty minutes. So each timestep yields twice as many bacteria as the previous one.<bookmark mark="cords"/>
                The <bookmark mark="blue"/> blue graph has a constant slope, that means it always increases at the same rate, so it can't be the one we're
                looking for.
                The <bookmark mark="purple"/> purple graph increases at a decreasing rate, so it can't be right <bookmark mark="clear_cords"/> either.
                The <bookmark mark="green"/> green graph however, increases at an increasing rate so it must be the one we're looking for. Indeed,
                it doubles at every timestep, so it must be the right one.
                """
        ) as tracker:
            
            self.wait_until_bookmark("g")
            x,y,_ = g_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(g_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gx")
            x,y,_ = g_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gtwo")
            x,y,_ = g_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gxx")
            x,y,_ = g_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Write(cords), run_time=0.3)


            self.wait_until_bookmark("blue")
            x,y,_ = f_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(f_plot.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(f_plot))

            self.wait_until_bookmark("purple")
            x,y,_ = h_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(h_plot.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(h_plot))

            self.wait_until_bookmark("clear_cords")
            self.play(FadeOut(h_plot), FadeOut(f_plot), run_time=0.3)

            self.wait_until_bookmark("green")
            x,y,_ = g_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g_plot.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g_plot))

        self.wait(4)

class Func_6_1_I_7_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Exponential or Linear?")

        sarah = ImageMobject(assets_folder / "img" / "biologist.png")
        sarah = sarah.scale(2.5/sarah.get_width()).move_to([-5, 1.4, 0])

        bacteria = ImageMobject(assets_folder / "img" / "bacteria.png")
        bacteria = bacteria.scale(1.5/bacteria.get_width()).move_to([-6, -1, 0])
        bacteria_double = VGroup(Tex("$\\Uparrow$ Duplicate every", color=c1t, font_size=fs2), Tex("$20$ minutes", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.).next_to(bacteria, DOWN, buff=0.2).shift(RIGHT*5.8)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        cords = self.add_cords([0, 6, 1], [0, 64, 8], x_ticks=[2,4,6], y_ticks=[16,32,48,64])
        plane = cords[0]
        lin_growth = Tex("Linear Growth", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)

        g_tex = MathTex("g","(x)", "=", "2", "^x", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        
        f = lambda x:3*x
        g = lambda x:2**x
        h = lambda x:10*x**0.5

        f_plot = plane.plot(f, color=BLUE)
        g_plot = plane.plot(g, color=GREEN)
        h_plot = plane.plot(h, color=PURPLE)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's it!
                For the function <bookmark mark="g"/> g of <bookmark mark="gx"/>x equals <bookmark mark="gtwo"/>two to the power of <bookmark mark="gxx"/> x,
                the number of bacteria doubles every twenty minutes. So each timestep yields twice as many bacteria as the previous one.<bookmark mark="cords"/>
                The <bookmark mark="blue"/> blue graph has a constant slope, that means it always increases at the same rate, so it can't be the one we're
                looking for.
                The <bookmark mark="purple"/> purple graph increases at a decreasing rate, so it can't be right <bookmark mark="clear_cords"/> either.
                The <bookmark mark="green"/> green graph however, increases at an increasing rate so it must be the one we're looking for. Indeed,
                it doubles at every timestep, so it must be the right one.
                """
        ) as tracker:
            
            self.wait_until_bookmark("g")
            x,y,_ = g_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(g_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gx")
            x,y,_ = g_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gtwo")
            x,y,_ = g_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gxx")
            x,y,_ = g_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Write(cords), run_time=0.3)


            self.wait_until_bookmark("blue")
            x,y,_ = f_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(f_plot.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(f_plot))

            self.wait_until_bookmark("purple")
            x,y,_ = h_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(h_plot.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(h_plot))

            self.wait_until_bookmark("clear_cords")
            self.play(FadeOut(h_plot), FadeOut(f_plot), run_time=0.3)

            self.wait_until_bookmark("green")
            x,y,_ = g_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g_plot.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g_plot))

        self.wait(4)

class Func_6_1_I_7_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Exponential or Linear?")

        sarah = ImageMobject(assets_folder / "img" / "biologist.png")
        sarah = sarah.scale(2.5/sarah.get_width()).move_to([-5, 1.4, 0])

        bacteria = ImageMobject(assets_folder / "img" / "bacteria.png")
        bacteria = bacteria.scale(1.5/bacteria.get_width()).move_to([-6, -1, 0])
        bacteria_double = VGroup(Tex("$\\Uparrow$ Duplicate every", color=c1t, font_size=fs2), Tex("$20$ minutes", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.).next_to(bacteria, DOWN, buff=0.2).shift(RIGHT*5.8)
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        cords = self.add_cords([0, 6, 1], [0, 64, 8], x_ticks=[2,4,6], y_ticks=[16,32,48,64])
        plane = cords[0]
        lin_growth = Tex("Linear Growth", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)

        g_tex = MathTex("g","(x)", "=", "2", "^x", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        
        f = lambda x:3*x
        g = lambda x:2**x
        h = lambda x:10*x**0.5

        f_plot = plane.plot(f, color=BLUE)
        g_plot = plane.plot(g, color=GREEN)
        h_plot = plane.plot(h, color=PURPLE)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                For the function <bookmark mark="g"/> g of <bookmark mark="gx"/>x equals <bookmark mark="gtwo"/>two to the power of <bookmark mark="gxx"/> x,
                the number of bacteria doubles every twenty minutes. So each timestep yields twice as many bacteria as the previous one.<bookmark mark="cords"/>
                The <bookmark mark="blue"/> blue graph has a constant slope, that means it always increases at the same rate, so it can't be the one we're
                looking for.
                The <bookmark mark="purple"/> purple graph increases at a decreasing rate, so it can't be right <bookmark mark="clear_cords"/> either.
                The <bookmark mark="green"/> green graph however, increases at an increasing rate so it must be the one we're looking for. Indeed,
                it doubles at every timestep, so it must be the right one.
                """
        ) as tracker:
            
            self.wait_until_bookmark("g")
            x,y,_ = g_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(g_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gx")
            x,y,_ = g_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gtwo")
            x,y,_ = g_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("gxx")
            x,y,_ = g_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Write(cords), run_time=0.3)


            self.wait_until_bookmark("blue")
            x,y,_ = f_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(f_plot.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(f_plot))

            self.wait_until_bookmark("purple")
            x,y,_ = h_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(h_plot.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(h_plot))

            self.wait_until_bookmark("clear_cords")
            self.play(FadeOut(h_plot), FadeOut(f_plot), run_time=0.3)

            self.wait_until_bookmark("green")
            x,y,_ = g_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g_plot.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g_plot))

        self.wait(4)

PROTOTYPES=[
    PagePrototypeVideo.from_scene(Func_6_1_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_1_I_1_q, Func_6_1_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_1_I_1_a),
    PagePrototypeVideo.from_scene(Func_6_1_I_1_b),
    PagePrototypeVideo.from_scene(Func_6_1_I_2),
    PagePrototypeVideo.from_scene(Func_6_1_I_3),
    PagePrototypeVideo.from_scene(Func_6_1_I_4),
    PagePrototypeVideo.from_scene(Func_6_1_I_5_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_1_I_5_q, Func_6_1_I_5_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_1_I_5_a),
    PagePrototypeVideo.from_scene(Func_6_1_I_5_b),
    PagePrototypeVideo.from_scene(Func_6_1_I_6_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_1_I_6_q, Func_6_1_I_6_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_1_I_6_a),
    PagePrototypeVideo.from_scene(Func_6_1_I_6_b),
    PagePrototypeVideo.from_scene(Func_6_1_I_6_c),
    PagePrototypeVideo.from_scene(Func_6_1_I_7_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_1_I_7_q, Func_6_1_I_7_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_1_I_7_a),
    PagePrototypeVideo.from_scene(Func_6_1_I_7_b),
    PagePrototypeVideo.from_scene(Func_6_1_I_7_c)
]

scenes/Func/Func_6: Exponential Functions/Func_6_1.py
Sophia-Edu-Labs/sophia-math
# 6_2: Exponential Functions: Term & Graph

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition



#####################################
#####################################
class Func_6_2_I_1(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Exponential Function")

        cords = self.add_cords([0, 6, 1], [0, 64, 8], x_ticks=[2,4,6], y_ticks=[16,32,48,64])
        plane = cords[0]

        f_tex = MathTex("f","(x)", "=", "a", "^x", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)

        a_tex_g1 = MathTex("a>1", color=BLUE, font_size=fs2).next_to(f_tex, DOWN, buff=0.2)
        f = lambda x:2**x
        f_plot = plane.plot(f, color=BLUE)

        cords_2 = self.add_cords([0, 6, 1], [0, 1, 0.25], x_ticks=[2,4,6], y_ticks=[0,0.25,0.5,0.75,1])
        plane_2 = cords_2[0]

        a_tex_l1 = MathTex("0<a<1", color=GREEN, font_size=fs2).next_to(f_tex, DOWN, buff=0.2)
        g = lambda x:0.5**x
        g_plot = plane_2.plot(g, color=GREEN)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        # Action Sequence
        with self.voiceover(
                text="""
                Quick Overview of exponential functions.
                The term of an exponential function is <bookmark mark="f"/>f of <bookmark mark="fx"/>x
                equals <bookmark mark="fa"/>a to the power of <bookmark mark="fxx"/> x.

                The plot of the exponential function has two different shapes, depending on the value of <bookmark mark="a"/>a.

                If <bookmark mark="a_g1"/>a is greater than one, the function<bookmark mark="plot_1"/> increases at an increasing
                rate, so it gets steeper and steeper as x increases.

                If <bookmark mark="a_l1"/>a is between zero and one, the function<bookmark mark="plot_2"/> decreases at a decreasing
                rate, so its decreasing, and it gets flatter and flatter as x increases.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            x,y,_ = f_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(f_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fa")
            x,y,_ = f_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fxx")
            x,y,_ = f_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("a")
            cursor.blinking=False
            x,y,_ = f_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("a_g1")
            cursor.blinking=False
            x,y,_ = a_tex_g1.get_center()+0.4*DOWN
            self.play(Write(a_tex_g1), CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.play(Write(cords))
            cursor.blinking=True

            self.wait_until_bookmark("plot_1")
            cursor.blinking=False
            x,y,_ = f_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(f_plot.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(f_plot))
            cursor.blinking=True

            self.wait_until_bookmark("a_l1")
            cursor.blinking=False
            x,y,_ = a_tex_l1.get_center()+0.4*DOWN
            self.play(ReplacementTransform(a_tex_g1, a_tex_l1), CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.play(ReplacementTransform(cords, cords_2), Unwrite(f_plot), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("plot_2")
            cursor.blinking=False
            x,y,_ = g_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g_plot.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g_plot))
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
TASK_Func_6_2_I_2_q = SophiaTaskDefinition(
    answerOptions = ["$a=1$", "$a=-1$", "$a=\frac{1}{2}$", "$a=2$"],
    correctAnswerIndex = 2,
    questionText = "Given the exponential function $f(x)=a^x$, which value of $a$ describes the amount of pizza left after x minutes?"
)
class Func_6_2_I_2_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Exponential Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        full_pizza = ImageMobject(assets_folder / "img" / "full_pizza.png")
        full_pizza = full_pizza.scale(2.5/full_pizza.get_width()).move_to([-5, 1, 0])
        
        half_pizza = ImageMobject(assets_folder / "img" / "half_pizza.png")
        half_pizza = half_pizza.scale(2.5/half_pizza.get_width()).move_to([-5, 1, 0])

        quarter_pizza = ImageMobject(assets_folder / "img" / "quarter_pizza.png")
        quarter_pizza = quarter_pizza.scale(2.5/quarter_pizza.get_width()).move_to([-5, 1, 0])

        eigth_pizza = ImageMobject(assets_folder / "img" / "eigth_pizza.png")
        eigth_pizza = eigth_pizza.scale(2.5/eigth_pizza.get_width()).move_to([-5, 1, 0])

        all_pizza = Group(full_pizza, half_pizza, quarter_pizza, eigth_pizza)

        clock = ImageMobject(assets_folder / "img" / "clock.png")
        clock = clock.scale(2.5/clock.get_width()).move_to([-5, -2, 0])

        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(2.5/qmark.get_width()).move_to([-5, 1, 0])

        f_tex = MathTex("f","(x)", "=", "a", "^x", color=c1t, font_size=fs2).next_to(full_pizza, DOWN, buff=0.4).shift(RIGHT*5)
        x_minutes = Tex("$x$", ": \\# Minutes", color=c1t, font_size=fs2).next_to(f_tex, DOWN, buff=0.2)

        

        # Action Sequence
        with self.voiceover(
                text="""
                My friends cooked pizza <bookmark mark="full_pizza"/> for dinner, and I am running<bookmark mark="late"/> late!
                They hate it, when I'm late, so they decided to start eating without me.
                Every Minute, they will eat half of the remaining pizza.
                So after one minute, only <bookmark mark="full"/> half of the pizza is left.
                After two minutes, only <bookmark mark="half"/> one quarter of the pizza is left.
                After three minutes, only <bookmark mark="quarter"/> one eighth of the pizza is left, and so on...

                Now since they're already annoyed at me, I might as well annoy them a bit more, so I'll
                tell them how to describe the amount of pizza that is left for me using an exponential <bookmark mark="f"/>function
                <bookmark mark="fx"/>f of x <bookmark mark="fa"/>equals a to the <bookmark mark="fxx"/>power of  x.

                Now all I need to know is this: <bookmark mark="qmark"/>Which value do I plug in for a, <bookmark mark="x_minutes"/>
                if x is the number <bookmark mark="minutes"/>of minutes that have passed?
                """
        ) as tracker:
            
            self.wait_until_bookmark("full_pizza")
            self.play(all_pizza.animate.shift(RIGHT*5), run_time=0.5)

            self.wait_until_bookmark("late")
            self.play(clock.animate.shift(RIGHT*5), run_time=0.5)

            self.wait_until_bookmark("full")
            self.play(clock.animate.shift(RIGHT*5), FadeOut(full_pizza))

            self.wait_until_bookmark("half")
            self.play(FadeOut(half_pizza))

            self.wait_until_bookmark("quarter")
            self.play(FadeOut(quarter_pizza))

            self.wait_until_bookmark("f")
            x,y,_ = f_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(f_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fa")
            x,y,_ = f_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fxx")
            x,y,_ = f_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("qmark")
            self.play(qmark.animate.shift(RIGHT*5), run_time=0.5)

            self.wait_until_bookmark("x_minutes")
            cursor.blinking=False
            x,y,_ = x_minutes[0].get_center()+0.4*DOWN
            self.play(Write(x_minutes), CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("minutes")
            x,y,_ = x_minutes[1].get_center()+0.4*DOWN  
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

        self.wait(4)


class Func_6_2_I_2_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Exponential Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        full_pizza = ImageMobject(assets_folder / "img" / "full_pizza.png")
        full_pizza = full_pizza.scale(2.5/full_pizza.get_width()).move_to([0, 1, 0])
        
        half_pizza = ImageMobject(assets_folder / "img" / "half_pizza.png")
        half_pizza = half_pizza.scale(2.5/half_pizza.get_width()).move_to([0, 1, 0])

        quarter_pizza = ImageMobject(assets_folder / "img" / "quarter_pizza.png")
        quarter_pizza = quarter_pizza.scale(2.5/quarter_pizza.get_width()).move_to([0, 1, 0])

        eigth_pizza = ImageMobject(assets_folder / "img" / "eigth_pizza.png")
        eigth_pizza = eigth_pizza.scale(2.5/eigth_pizza.get_width()).move_to([0, 1, 0])

        all_pizza = Group(full_pizza, half_pizza, quarter_pizza, eigth_pizza)
        self.add(all_pizza)

        clock = ImageMobject(assets_folder / "img" / "clock.png")
        clock = clock.scale(2.5/clock.get_width()).move_to([-5, -2, 0])

        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(2.5/qmark.get_width()).move_to([0, 1, 0])

        f_tex = MathTex("f","(x)", "=", "\\frac12", "^x", color=c1t, font_size=fs2).next_to(full_pizza, DOWN, buff=0.4)
        sol_a = MathTex("\\Rightarrow","a","=", "\\frac12", color=c1t, font_size=fs2).next_to(f_tex, DOWN, buff=0.2)


        t = MathTable(
            [["x", "\\text{Remaining Pizza}"],
            ["1", "\\tfrac12"],
            ["2", "(\\tfrac12)^2"],
            ["3", "(\\tfrac12)^3"],
            ["...", "..."]], element_to_mobject_config={"color": c1t}, line_config={"color": c1t}).scale(0.35).next_to(full_pizza, DOWN, buff=0.4)
        
        rows = t.get_rows()
        t_structure = VGroup(t.get_horizontal_lines(), t.get_vertical_lines())
        

        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not correct.
                Every time a <bookmark mark="minute"/>minute passes, my friends eat <bookmark mark="half_1"/>half of the remaining pizza.
                That means every time x increases by one (which happens every minute), the amount of pizza left is <bookmark mark="half_2"/>
                multiplied by a half. This means, <bookmark mark="row_1"/>that after one minute, we multiply the original amount of pizza  by a half.
                <bookmark mark="row_2"/>After two minutes, we multiply the amount of pizza left by a half squared.
                <bookmark mark="row_3"/>After three minutes, we multiply the amount of pizza left by a half cubed, <bookmark mark="row_4"/>and so on...
                This means, that the amount of pizza left after x minutes is <bookmark mark="f"/>f of <bookmark mark="fx"/>x
                equals <bookmark mark="fa"/>one half to the power of <bookmark mark="fxx"/> x.
                <bookmark mark="sol_a"/>So a <bookmark mark="sol_half"/>is one half.
                """
        ) as tracker:
            
            self.wait_until_bookmark("minute")
            self.play(clock.animate.shift(RIGHT*5), run_time=0.5)

            self.wait_until_bookmark("half_1")
            self.play(clock.animate.shift(RIGHT*5), FadeOut(full_pizza))

            self.wait_until_bookmark("half_2")
            self.play(FadeOut(half_pizza))

            self.wait_until_bookmark("row_1")
            self.play(Write(t_structure), Write(rows[0]), run_time=0.5)
            x,y,_ = rows[1].get_right()+0.4*RIGHT
            cursor.blinking=False
            self.play(Write(rows[1]), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("row_2")
            x,y,_ = rows[2].get_right()+0.4*RIGHT
            self.play(Write(rows[2]), CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("row_3")
            x,y,_ = rows[3].get_right()+0.4*RIGHT
            self.play(Write(rows[3]), CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("row_4")
            x,y,_ = rows[4].get_right()+0.4*RIGHT
            self.play(Write(rows[4]), CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            x,y,_ = f_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(t.animate.shift(RIGHT*5), Write(f_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fa")
            x,y,_ = f_tex[3].get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fxx")
            x,y,_ = f_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_a")
            cursor.blinking=False
            x,y,_ = sol_a[1].get_center()+0.4*DOWN
            self.play(Write(sol_a), CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("sol_half")
            x,y,_ = sol_a[3].get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)

class Func_6_2_I_2_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Exponential Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        full_pizza = ImageMobject(assets_folder / "img" / "full_pizza.png")
        full_pizza = full_pizza.scale(2.5/full_pizza.get_width()).move_to([0, 1, 0])
        
        half_pizza = ImageMobject(assets_folder / "img" / "half_pizza.png")
        half_pizza = half_pizza.scale(2.5/half_pizza.get_width()).move_to([0, 1, 0])

        quarter_pizza = ImageMobject(assets_folder / "img" / "quarter_pizza.png")
        quarter_pizza = quarter_pizza.scale(2.5/quarter_pizza.get_width()).move_to([0, 1, 0])

        eigth_pizza = ImageMobject(assets_folder / "img" / "eigth_pizza.png")
        eigth_pizza = eigth_pizza.scale(2.5/eigth_pizza.get_width()).move_to([0, 1, 0])

        all_pizza = Group(full_pizza, half_pizza, quarter_pizza, eigth_pizza)
        self.add(all_pizza)

        clock = ImageMobject(assets_folder / "img" / "clock.png")
        clock = clock.scale(2.5/clock.get_width()).move_to([-5, -2, 0])

        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(2.5/qmark.get_width()).move_to([0, 1, 0])

        f_tex = MathTex("f","(x)", "=", "\\frac12", "^x", color=c1t, font_size=fs2).next_to(full_pizza, DOWN, buff=0.4)
        sol_a = MathTex("\\Rightarrow","a","=", "\\frac12", color=c1t, font_size=fs2).next_to(f_tex, DOWN, buff=0.2)


        t = MathTable(
            [["x", "\\text{Remaining Pizza}"],
            ["1", "\\tfrac12"],
            ["2", "(\\tfrac12)^2"],
            ["3", "(\\tfrac12)^3"],
            ["...", "..."]], element_to_mobject_config={"color": c1t}, line_config={"color": c1t}).scale(0.35).next_to(full_pizza, DOWN, buff=0.4)
        
        rows = t.get_rows()
        t_structure = VGroup(t.get_horizontal_lines(), t.get_vertical_lines())
        

        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not correct.
                Every time a <bookmark mark="minute"/>minute passes, my friends eat <bookmark mark="half_1"/>half of the remaining pizza.
                That means every time x increases by one (which happens every minute), the amount of pizza left is <bookmark mark="half_2"/>
                multiplied by a half. This means, <bookmark mark="row_1"/>that after one minute, we multiply the original amount of pizza  by a half.
                <bookmark mark="row_2"/>After two minutes, we multiply the amount of pizza left by a half squared.
                <bookmark mark="row_3"/>After three minutes, we multiply the amount of pizza left by a half cubed, <bookmark mark="row_4"/>and so on...
                This means, that the amount of pizza left after x minutes is <bookmark mark="f"/>f of <bookmark mark="fx"/>x
                equals <bookmark mark="fa"/>one half to the power of <bookmark mark="fxx"/> x.
                <bookmark mark="sol_a"/>So a <bookmark mark="sol_half"/>is one half.
                """
        ) as tracker:
            
            self.wait_until_bookmark("minute")
            self.play(clock.animate.shift(RIGHT*5), run_time=0.5)

            self.wait_until_bookmark("half_1")
            self.play(clock.animate.shift(RIGHT*5), FadeOut(full_pizza))

            self.wait_until_bookmark("half_2")
            self.play(FadeOut(half_pizza))

            self.wait_until_bookmark("row_1")
            self.play(Write(t_structure), Write(rows[0]), run_time=0.5)
            x,y,_ = rows[1].get_right()+0.4*RIGHT
            cursor.blinking=False
            self.play(Write(rows[1]), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("row_2")
            x,y,_ = rows[2].get_right()+0.4*RIGHT
            self.play(Write(rows[2]), CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("row_3")
            x,y,_ = rows[3].get_right()+0.4*RIGHT
            self.play(Write(rows[3]), CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("row_4")
            x,y,_ = rows[4].get_right()+0.4*RIGHT
            self.play(Write(rows[4]), CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            x,y,_ = f_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(t.animate.shift(RIGHT*5), Write(f_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fa")
            x,y,_ = f_tex[3].get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fxx")
            x,y,_ = f_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_a")
            cursor.blinking=False
            x,y,_ = sol_a[1].get_center()+0.4*DOWN
            self.play(Write(sol_a), CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("sol_half")
            x,y,_ = sol_a[3].get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)

class Func_6_2_I_2_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Exponential Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        full_pizza = ImageMobject(assets_folder / "img" / "full_pizza.png")
        full_pizza = full_pizza.scale(2.5/full_pizza.get_width()).move_to([0, 1, 0])
        
        half_pizza = ImageMobject(assets_folder / "img" / "half_pizza.png")
        half_pizza = half_pizza.scale(2.5/half_pizza.get_width()).move_to([0, 1, 0])

        quarter_pizza = ImageMobject(assets_folder / "img" / "quarter_pizza.png")
        quarter_pizza = quarter_pizza.scale(2.5/quarter_pizza.get_width()).move_to([0, 1, 0])

        eigth_pizza = ImageMobject(assets_folder / "img" / "eigth_pizza.png")
        eigth_pizza = eigth_pizza.scale(2.5/eigth_pizza.get_width()).move_to([0, 1, 0])

        all_pizza = Group(full_pizza, half_pizza, quarter_pizza, eigth_pizza)
        self.add(all_pizza)

        clock = ImageMobject(assets_folder / "img" / "clock.png")
        clock = clock.scale(2.5/clock.get_width()).move_to([-5, -2, 0])

        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(2.5/qmark.get_width()).move_to([0, 1, 0])

        f_tex = MathTex("f","(x)", "=", "\\frac12", "^x", color=c1t, font_size=fs2).next_to(full_pizza, DOWN, buff=0.4)
        sol_a = MathTex("\\Rightarrow","a","=", "\\frac12", color=c1t, font_size=fs2).next_to(f_tex, DOWN, buff=0.2)


        t = MathTable(
            [["x", "\\text{Remaining Pizza}"],
            ["1", "\\tfrac12"],
            ["2", "(\\tfrac12)^2"],
            ["3", "(\\tfrac12)^3"],
            ["...", "..."]], element_to_mobject_config={"color": c1t}, line_config={"color": c1t}).scale(0.35).next_to(full_pizza, DOWN, buff=0.4)
        
        rows = t.get_rows()
        t_structure = VGroup(t.get_horizontal_lines(), t.get_vertical_lines())
        

        

        # Action Sequence
        with self.voiceover(
                text="""
                Yes, that's right!
                Every time a <bookmark mark="minute"/>minute passes, my friends eat <bookmark mark="half_1"/>half of the remaining pizza.
                That means every time x increases by one (which happens every minute), the amount of pizza left is <bookmark mark="half_2"/>
                multiplied by a half. This means, <bookmark mark="row_1"/>that after one minute, we multiply the original amount of pizza  by a half.
                <bookmark mark="row_2"/>After two minutes, we multiply the amount of pizza left by a half squared.
                <bookmark mark="row_3"/>After three minutes, we multiply the amount of pizza left by a half cubed, <bookmark mark="row_4"/>and so on...
                This means, that the amount of pizza left after x minutes is <bookmark mark="f"/>f of <bookmark mark="fx"/>x
                equals <bookmark mark="fa"/>one half to the power of <bookmark mark="fxx"/> x.
                <bookmark mark="sol_a"/>So a <bookmark mark="sol_half"/>is one half.
                """
        ) as tracker:
            
            self.wait_until_bookmark("minute")
            self.play(clock.animate.shift(RIGHT*5), run_time=0.5)

            self.wait_until_bookmark("half_1")
            self.play(clock.animate.shift(RIGHT*5), FadeOut(full_pizza))

            self.wait_until_bookmark("half_2")
            self.play(FadeOut(half_pizza))

            self.wait_until_bookmark("row_1")
            self.play(Write(t_structure), Write(rows[0]), run_time=0.5)
            x,y,_ = rows[1].get_right()+0.4*RIGHT
            cursor.blinking=False
            self.play(Write(rows[1]), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("row_2")
            x,y,_ = rows[2].get_right()+0.4*RIGHT
            self.play(Write(rows[2]), CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("row_3")
            x,y,_ = rows[3].get_right()+0.4*RIGHT
            self.play(Write(rows[3]), CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("row_4")
            x,y,_ = rows[4].get_right()+0.4*RIGHT
            self.play(Write(rows[4]), CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            x,y,_ = f_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(t.animate.shift(RIGHT*5), Write(f_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fa")
            x,y,_ = f_tex[3].get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fxx")
            x,y,_ = f_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_a")
            cursor.blinking=False
            x,y,_ = sol_a[1].get_center()+0.4*DOWN
            self.play(Write(sol_a), CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("sol_half")
            x,y,_ = sol_a[3].get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)

class Func_6_2_I_2_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Exponential Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        full_pizza = ImageMobject(assets_folder / "img" / "full_pizza.png")
        full_pizza = full_pizza.scale(2.5/full_pizza.get_width()).move_to([0, 1, 0])
        
        half_pizza = ImageMobject(assets_folder / "img" / "half_pizza.png")
        half_pizza = half_pizza.scale(2.5/half_pizza.get_width()).move_to([0, 1, 0])

        quarter_pizza = ImageMobject(assets_folder / "img" / "quarter_pizza.png")
        quarter_pizza = quarter_pizza.scale(2.5/quarter_pizza.get_width()).move_to([0, 1, 0])

        eigth_pizza = ImageMobject(assets_folder / "img" / "eigth_pizza.png")
        eigth_pizza = eigth_pizza.scale(2.5/eigth_pizza.get_width()).move_to([0, 1, 0])

        all_pizza = Group(full_pizza, half_pizza, quarter_pizza, eigth_pizza)
        self.add(all_pizza)

        clock = ImageMobject(assets_folder / "img" / "clock.png")
        clock = clock.scale(2.5/clock.get_width()).move_to([-5, -2, 0])

        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(2.5/qmark.get_width()).move_to([0, 1, 0])

        f_tex = MathTex("f","(x)", "=", "\\frac12", "^x", color=c1t, font_size=fs2).next_to(full_pizza, DOWN, buff=0.4)
        sol_a = MathTex("\\Rightarrow","a","=", "\\frac12", color=c1t, font_size=fs2).next_to(f_tex, DOWN, buff=0.2)


        t = MathTable(
            [["x", "\\text{Remaining Pizza}"],
            ["1", "\\tfrac12"],
            ["2", "(\\tfrac12)^2"],
            ["3", "(\\tfrac12)^3"],
            ["...", "..."]], element_to_mobject_config={"color": c1t}, line_config={"color": c1t}).scale(0.35).next_to(full_pizza, DOWN, buff=0.4)
        
        rows = t.get_rows()
        t_structure = VGroup(t.get_horizontal_lines(), t.get_vertical_lines())
        

        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not correct.
                Every time a <bookmark mark="minute"/>minute passes, my friends eat <bookmark mark="half_1"/>half of the remaining pizza.
                That means every time x increases by one (which happens every minute), the amount of pizza left is <bookmark mark="half_2"/>
                multiplied by a half. This means, <bookmark mark="row_1"/>that after one minute, we multiply the original amount of pizza  by a half.
                <bookmark mark="row_2"/>After two minutes, we multiply the amount of pizza left by a half squared.
                <bookmark mark="row_3"/>After three minutes, we multiply the amount of pizza left by a half cubed, <bookmark mark="row_4"/>and so on...
                This means, that the amount of pizza left after x minutes is <bookmark mark="f"/>f of <bookmark mark="fx"/>x
                equals <bookmark mark="fa"/>one half to the power of <bookmark mark="fxx"/> x.
                <bookmark mark="sol_a"/>So a <bookmark mark="sol_half"/>is one half.
                """
        ) as tracker:
            
            self.wait_until_bookmark("minute")
            self.play(clock.animate.shift(RIGHT*5), run_time=0.5)

            self.wait_until_bookmark("half_1")
            self.play(clock.animate.shift(RIGHT*5), FadeOut(full_pizza))

            self.wait_until_bookmark("half_2")
            self.play(FadeOut(half_pizza))

            self.wait_until_bookmark("row_1")
            self.play(Write(t_structure), Write(rows[0]), run_time=0.5)
            x,y,_ = rows[1].get_right()+0.4*RIGHT
            cursor.blinking=False
            self.play(Write(rows[1]), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("row_2")
            x,y,_ = rows[2].get_right()+0.4*RIGHT
            self.play(Write(rows[2]), CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("row_3")
            x,y,_ = rows[3].get_right()+0.4*RIGHT
            self.play(Write(rows[3]), CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("row_4")
            x,y,_ = rows[4].get_right()+0.4*RIGHT
            self.play(Write(rows[4]), CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            x,y,_ = f_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(t.animate.shift(RIGHT*5), Write(f_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fa")
            x,y,_ = f_tex[3].get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fxx")
            x,y,_ = f_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_a")
            cursor.blinking=False
            x,y,_ = sol_a[1].get_center()+0.4*DOWN
            self.play(Write(sol_a), CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("sol_half")
            x,y,_ = sol_a[3].get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)

#####################################
#####################################
class Func_6_2_I_3(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        title = self.add_title("Growth factor")

        cords = self.add_cords([0, 6, 1], [0, 64, 8], x_ticks=[2,4,6], y_ticks=[16,32,48,64])
        plane = cords[0]

        f_tex = MathTex("f","(x)", "=", "a", "^x", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)

        a_tex_g1 = MathTex("a>1", color=BLUE, font_size=fs2).next_to(f_tex, DOWN, buff=0.2)
        f = lambda x:2**x
        f_plot = plane.plot(f, color=BLUE)

        cords_2 = self.add_cords([0, 6, 1], [0, 1, 0.25], x_ticks=[2,4,6], y_ticks=[0,0.25,0.5,0.75,1])
        plane_2 = cords_2[0]

        a_tex_l1 = MathTex("0<a<1", color=GREEN, font_size=fs2).next_to(f_tex, DOWN, buff=0.2)
        g = lambda x:0.5**x
        g_plot = plane_2.plot(g, color=GREEN)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = plane.c2p(0,0)
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        # Action Sequence
        with self.voiceover(
                text="""
                Another quick note on the function term of exponential functions.
                We know that the term of an exponential function is <bookmark mark="f"/>f of <bookmark mark="fx"/>x
                equals <bookmark mark="fa"/>a to the power of <bookmark mark="fxx"/> x.

                Now the value<bookmark mark="a"/>a is called <bookmark mark="growth"/>the <bookmark mark="factor"/>growth factor.
                It is called that, because it determines how fast the function grows, or decreases.

                If <bookmark mark="a_g1"/>"a" is greater than one, the function<bookmark mark="plot_1"/> increases by the factor of "a"
                at every timestep. If "a" is two, it doubles at every timestep, if "a" is three, it triples at every timestep, and so on.

                If a is between zero and one, the function<bookmark mark="plot_2"/> decreases by the factor of "a" at every timestep.
                If "a" is a half, it halves at every timestep, if "a" is a third, it reduces to a third at every timestep, and so on...
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            x,y,_ = f_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(f_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fa")
            x,y,_ = f_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fxx")
            x,y,_ = f_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("a")
            cursor.blinking=False
            x,y,_ = f_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("growth")
            cursor.blinking=False
            x,y,_ = title.get_left()+0.4*DOWN+RIGHT
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("factor")
            x,y,_ = title.get_right()+0.4*DOWN+0.7*LEFT
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("plot_1")
            cursor.blinking=False
            x,y,_ = f_plot.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), Write(cords), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(f_plot.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(f_plot))
            cursor.blinking=True

            self.wait_until_bookmark("plot_2")
            cursor.blinking=False
            x,y,_ = g_plot.get_start()
            self.play(ReplacementTransform(cords, cords_2), Unwrite(f_plot), CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g_plot.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g_plot))
            cursor.blinking=True

        self.wait(4)



#####################################
#####################################
######## Practice Part ##############
#####################################
#####################################




#####################################
#####################################
######## General Qs #################
#####################################
#####################################

#####################################
#####################################
class GraphToGrowthFactorQuestionScene(SophiaCursorScene, metaclass = ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Growth factor")

        plane = self.cords[0]

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(2.5/qmark.get_width()).move_to([-5, 1, 0])

        f_tex = MathTex("f","(x)", "=", "a", "^x", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.4)
        x_minutes = VGroup(Tex("$\\Rightarrow$", "What is the valuef of", color=c1t, font_size=fs3), Tex("the growth factor", " $a$?", color=c1t, font_size=fs3)).arrange(DOWN, buff=0.1, aligned_edge=RIGHT).next_to(f_tex, DOWN, buff=0.2)

        func = lambda x: self.a**x
        f = plane.plot(func, color=self.color)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro}<bookmark mark="plot"/> this plot, which belongs to an exponential <bookmark mark="function"/>function f 
                <bookmark mark="fx"/> of x <bookmark mark="fa"/> equals a to the <bookmark mark="xx"/>power of x.
                <bookmark mark="q"/>What is the value of the growth<bookmark mark="q_a"/> factor "a", that leads to this graph?
                """
        ) as tracker:
            
            self.play(Write(self.cords))
            
            self.wait_until_bookmark("plot")
            x, y, _ = f.get_start()
            self.play(CursorMoveToCurved(cursor, x, y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(f.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(f))
            cursor.blinking=True

            self.wait_until_bookmark("function")
            x,y,_ = f_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(f_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fa")
            x,y,_ = f_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("xx")
            x,y,_ = f_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("q")
            x,y,_ = x_minutes[1].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(x_minutes), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("q_a")
            x,y,_ = x_minutes[1][1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)


class GraphToGrowthFactorAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Growth factor")

        plane = self.cords[0]

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(2.5/qmark.get_width()).move_to([-5, 1, 0])

        f_tex = MathTex("f","(x)", "=", "a", "^x", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.4)
        sol = Tex("$\\Rightarrow$", f"a={self.a}", color=c1t, font_size=fs2).next_to(f_tex, DOWN, buff=0.2)
        func = lambda x: self.a**x
        f = plane.plot(func, color=self.color)

        verify = VGroup(Tex("$\\Rightarrow$", "Verify:", color=c1t, font_size=fs3), MathTex(f"f({self.x_max})", f"={self.a}^{self.x_max}", f"={self.a**self.x_max}", font_size=fs3, color=c1t))
        verify.arrange(DOWN, buff=0.2).next_to(sol, DOWN, buff=0.8)
        verify[0].shift(LEFT*0.6)

        self.add(f_tex)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro}
                If we look at the graph, we can see that <bookmark mark="x_one"/>at x equals one, it is <bookmark mark="f_x_one"/> at {self.a}.
                So that means that a to the power of one equals {self.a}.<bookmark mark="sol"/> So "a" must be {self.a}.

                We can also <bookmark mark="verify"/>verify this, by computing <bookmark mark="x_max"/>f of {self.x_max}.
                By looking at the graph, we can see that <bookmark mark="x_max_graph"/>
                it has to be {self.a**self.x_max}. So to verify, we compute "a" to the power of {self.x_max} for "a" equals {self.a}.
                <bookmark mark="verify_2"/>This is {self.a} to the power of {self.x_max}, <bookmark mark="verify_3"/>which equals {self.a**self.x_max}.
                This fits to the value on the graph.
                """
        ) as tracker:
            
            self.play(Write(self.cords))
            self.play(Write(f))

            self.wait_until_bookmark("x_one")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,0)
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("f_x_one")
            x,y,_ = plane.c2p(1,self.a)
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol")
            cursor.blinking=False
            x,y,_ = sol[1].get_center()+0.4*DOWN
            self.play(Write(sol), CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("verify")
            x,y,_ = verify[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(verify[0]), CursorMoveTo(cursor,x,y), run_time=0.5)
            cursor.blinking=False

            self.wait_until_bookmark("x_max")
            cursor.blinking=False
            x,y,_ = verify[1][0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(verify[1][0]), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("x_max_graph")
            cursor.blinking=False
            x,y,_ = plane.c2p(self.x_max,self.a**self.x_max)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("verify_2")
            cursor.blinking=False
            x,y,_ = verify[1][1].get_center()+0.4*DOWN
            self.play(Write(verify[1][1]), CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("verify_3")
            x,y,_ = verify[1][2].get_center()+0.4*DOWN
            self.play(Write(verify[1][2]), CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
class GrowthFactorToGraphQuestionScene(SophiaCursorScene, metaclass = ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Growth factor")

        plane = self.cords[0]

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        f_tex = MathTex("f","(x)", "=", str(self.a), "^x", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.4)
        x_minutes = VGroup(Tex("$\\Rightarrow$", "Which of the graphs", color=c1t, font_size=fs3), Tex("describes the function?", color=c1t, font_size=fs3)).arrange(DOWN, buff=0.1, aligned_edge=RIGHT).next_to(f_tex, DOWN, buff=0.6)
        x_minutes[1].shift(RIGHT*0.4)
        g_1 = plane.plot(self.f1, color=self.c1)
        g_2 = plane.plot(self.f2, color=self.c2)
        g_3 = plane.plot(self.f3, color=self.c3)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro}<bookmark mark="f"/> equal to f <bookmark mark="fx"/> of x <bookmark mark="fa"/> equals {self.a} to the <bookmark mark="xx"/>power of x.
                <bookmark mark="which"/>Which of the<bookmark mark="cords_in"/> following graphs describes the function?
                <bookmark mark="plot_1"/>
                Is it the {self.color_1_name} graph?

                Or <bookmark mark="plot_2"/> is it the {self.color_2_name} graph?

                Or <bookmark mark="plot_3"/> is it the {self.color_3_name} graph?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            x,y,_ = f_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(f_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = f_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fa")
            x,y,_ = f_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("xx")
            x,y,_ = f_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("which")
            x,y,_ = x_minutes[1].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(x_minutes), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("cords_in")
            self.play(Write(self.cords), run_time=0.3)

            self.wait_until_bookmark("plot_1")
            cursor.blinking=False
            x,y,_ = g_1.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g_1.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g_1))
            cursor.blinking=True

            self.wait_until_bookmark("plot_2")
            cursor.blinking=False
            x,y,_ = g_2.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g_2.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g_2))
            cursor.blinking=True

            self.wait_until_bookmark("plot_3")
            cursor.blinking=False
            x,y,_ = g_3.get_start()
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(g_3.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(g_3))
            cursor.blinking=True
            

        self.wait(4)


class GrowthFactorToGraphAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Growth factor")

        plane = self.cords[0]
        f_tex = MathTex("f","(x)", "=", str(self.a), "^x", color=c1t, font_size=fs2).next_to(plane, DOWN, buff=0.4)
        intro_auto = "Since the growth factor a is greater than one, the function increases by the factor of a at every timestep." if self.a>1 else "Since the growth factor a is between zero and one, the function decreases by the factor of a at every timestep."
        intro_auto_tex = Tex("$a>1$","$\\Rightarrow$exponential growth", color=c1t, font_size=fs3).next_to(f_tex, DOWN, buff=0.4) if self.a>1 else Tex("$0<a<1$","$\\Rightarrow$exponential decay", color=c1t, font_size=fs3).next_to(f_tex, DOWN, buff=0.4)
        
        g_1 = plane.plot(self.f1, color=self.c1)
        g_2 = plane.plot(self.f2, color=self.c2)
        g_3 = plane.plot(self.f3, color=self.c3)

        gs = [g_1,g_2,g_3]
        g_correct = gs[self.idx_correct]
        color_correct = self.color_1_name if self.idx_correct==0 else self.color_2_name if self.idx_correct==1 else self.color_3_name


        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro} <bookmark mark="intro_auto"/> {intro_auto} <bookmark mark="cords_in"/>
                This means that <bookmark mark="x_one"/>at x equals one, the graph has to be
                <bookmark mark="f_x_one"/> at {self.a}, because {self.a} to the power of one is {self.a}.
                Next, we can check other values, for example <bookmark mark="x_two"/>at x equals two,
                the value has to be equal to {self.a} to the power of two, <bookmark mark="f_x_two"/>which is {self.a**2},
                and <bookmark mark="x_max"/> at x equals {self.x_max}, the value has to be equal to {self.a} to the power of {self.x_max},
                <bookmark mark="f_x_max"/>which is {self.a**self.x_max}.

                If we <bookmark mark="plot"/> look at all three graphs, we can clearly see that it has to be <bookmark mark="erase"/>
                the {color_correct} graph.
                """
        ) as tracker:
            
            self.play(Write(f_tex))

            self.wait_until_bookmark("intro_auto")
            x,y,_ = intro_auto_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(intro_auto_tex), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("cords_in")
            self.play(Write(self.cords), run_time=0.3)

            self.wait_until_bookmark("x_one")
            cursor.blinking=False
            x,y,_ = plane.c2p(1,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("f_x_one")
            x,y,_ = plane.c2p(1,self.a)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            point_1 = cursor.copy().clear_updaters()
            self.add(point_1)

            self.wait_until_bookmark("x_two")
            x,y,_ = plane.c2p(2,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("f_x_two")
            x,y,_ = plane.c2p(2,self.a**2)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            point_2 = cursor.copy().clear_updaters()
            self.add(point_2)

            self.wait_until_bookmark("x_max")
            x,y,_ = plane.c2p(self.x_max,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            
            self.wait_until_bookmark("f_x_max")
            x,y,_ = plane.c2p(self.x_max,self.a**self.x_max)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            point_3 = cursor.copy().clear_updaters()
            self.add(point_3)

            self.wait_until_bookmark("plot")
            cursors = [cursor.copy() for _ in range(3)]
            locs = [g.get_start() for g in gs]
            x,y,_ = plane.c2p(0,0)
            self.play(*[CursorMoveTo(c,l[0], l[1]) for c,l in zip(cursors,locs)], CursorMoveTo(cursor,x,y), run_time=1)
            cursors[1]._start_fading(2).add_updater(lambda m: m.move_to(g_1.get_end()))
            cursors[2]._start_fading(2).add_updater(lambda m: m.move_to(g_2.get_end()))
            cursors[0]._start_fading(2).add_updater(lambda m: m.move_to(g_3.get_end()))
            self.add_pencil_sound(1.5)
            self.play(*[Create(g) for g in gs])
            cursor.blinking=True

            self.wait_until_bookmark("erase")
            self.add(g_correct.copy())
            self.play(Uncreate(g_1), Uncreate(g_2), Uncreate(g_3),  run_time=0.3)


        self.wait(4)


#####################################
#####################################
######## Specific Qs ################
#####################################
#####################################

#####################################
#####################################
TASK_Func_6_2_P_1_q = SophiaTaskDefinition(
    answerOptions = ["$a=3$", "$a=1$", "$a=\frac{1}{3}$", "$a=-2$"],
    correctAnswerIndex = 2,
    questionText = "Given the purple graph, what is the value of a?"
)

class Func_6_2_P_1_q(GraphToGrowthFactorQuestionScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 81, 9], x_ticks=[1,2,3,4], y_ticks=[27,54,81])
        self.a = 3
        self.color=PURPLE
        self.intro = "Look at"

        super().construct()

class Func_6_2_P_1_a(GraphToGrowthFactorAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 81, 9], x_ticks=[1,2,3,4], y_ticks=[27,54,81])
        self.a = 3
        self.x_max = 4
        self.color=PURPLE
        self.intro = "Yep, that is correct."

        super().construct()

class Func_6_2_P_1_b(GraphToGrowthFactorAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 81, 9], x_ticks=[1,2,3,4], y_ticks=[27,54,81])
        self.a = 3
        self.x_max = 4
        self.color=PURPLE
        self.intro = "No, that's not right."

        super().construct()

class Func_6_2_P_1_c(GraphToGrowthFactorAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 81, 9], x_ticks=[1,2,3,4], y_ticks=[27,54,81])
        self.a = 3
        self.x_max = 4
        self.color=PURPLE
        self.intro = "No, that's not right."

        super().construct()

class Func_6_2_P_1_d(GraphToGrowthFactorAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 81, 9], x_ticks=[1,2,3,4], y_ticks=[27,54,81])
        self.a = 3
        self.x_max = 4
        self.color=PURPLE
        self.intro = "No, that's not right."

        super().construct()


#####################################
#####################################
TASK_Func_6_2_P_2_q = SophiaTaskDefinition(
    answerOptions = ["The purple graph", "The blue graph", "The green graph"],
    correctAnswerIndex = 0,
    questionText = "Which of the graph corresponds to the function $f(x)=2^x$?"
)

class Func_6_2_P_2_q(GrowthFactorToGraphQuestionScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 81, 9], x_ticks=[1,2,3,4], y_ticks=[27,54,81])
        self.a = 2
        self.color=PURPLE
        self.intro = "Let's say we're considering a growth factor of a equals two,so your function is"

        self.f1 = lambda x: self.a**x
        self.f2 = lambda x: x**3
        self.f3 = lambda x: 50/(self.a**x)

        self.color_1_name = "purple"
        self.color_2_name = "blue"
        self.color_3_name = "green"

        self.c1 = PURPLE
        self.c2 = BLUE
        self.c3 = GREEN

        super().construct()

class Func_6_2_P_2_a(GrowthFactorToGraphAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 81, 9], x_ticks=[1,2,3,4], y_ticks=[27,54,81])
        self.x_max = 4
        self.a = 2
        self.color=PURPLE
        self.intro = "Yep, that is correct."

        self.f1 = lambda x: self.a**x
        self.f2 = lambda x: x**3
        self.f3 = lambda x: 50/(self.a**x)

        self.color_1_name = "purple"
        self.color_2_name = "blue"
        self.color_3_name = "green"

        self.c1 = PURPLE
        self.c2 = BLUE
        self.c3 = GREEN

        self.idx_correct = 0

        super().construct()

class Func_6_2_P_2_b(GrowthFactorToGraphAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 81, 9], x_ticks=[1,2,3,4], y_ticks=[27,54,81])
        self.x_max = 4
        self.a = 2
        self.color=PURPLE
        self.intro = "No, that's not right."

        self.f1 = lambda x: self.a**x
        self.f2 = lambda x: x**3
        self.f3 = lambda x: 50/(self.a**x)

        self.color_1_name = "purple"
        self.color_2_name = "blue"
        self.color_3_name = "green"

        self.c1 = PURPLE
        self.c2 = BLUE
        self.c3 = GREEN

        self.idx_correct = 0

        super().construct()

class Func_6_2_P_2_c(GrowthFactorToGraphAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 81, 9], x_ticks=[1,2,3,4], y_ticks=[27,54,81])
        self.x_max = 4
        self.a = 2
        self.color=PURPLE
        self.intro = "No, that's not right."

        self.f1 = lambda x: self.a**x
        self.f2 = lambda x: x**3
        self.f3 = lambda x: 50/(self.a**x)

        self.color_1_name = "purple"
        self.color_2_name = "blue"
        self.color_3_name = "green"

        self.c1 = PURPLE
        self.c2 = BLUE
        self.c3 = GREEN

        self.idx_correct = 0

        super().construct()


#####################################
#####################################
TASK_Func_6_2_P_3_q = SophiaTaskDefinition(
    answerOptions = ["$a=3$", "$a=2$", "$a=\frac{1}{2}$", "$a=-2$"],
    correctAnswerIndex = 1,
    questionText = "Given the GREEN graph, what is the value of a?"
)

class Func_6_2_P_3_q(GraphToGrowthFactorQuestionScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 16, 4], x_ticks=[1,2,3,4], y_ticks=[4,8,12,16])
        self.a = 2
        self.color=GREEN
        self.intro = "Check out"

        super().construct()

class Func_6_2_P_3_a(GraphToGrowthFactorAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 16, 4], x_ticks=[1,2,3,4], y_ticks=[4,8,12,16])
        self.a = 2
        self.x_max = 4
        self.color=GREEN
        self.intro = "No, that's not right."

        super().construct()

class Func_6_2_P_3_b(GraphToGrowthFactorAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 16, 4], x_ticks=[1,2,3,4], y_ticks=[4,8,12,16])
        self.a = 2
        self.x_max = 4
        self.color=GREEN
        self.intro = "Yes, that's it. Well done."

        super().construct()

class Func_6_2_P_3_c(GraphToGrowthFactorAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 16, 4], x_ticks=[1,2,3,4], y_ticks=[4,8,12,16])
        self.a = 2
        self.x_max = 4
        self.color=GREEN
        self.intro = "No, that's not right."

        super().construct()

class Func_6_2_P_3_d(GraphToGrowthFactorAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 16, 4], x_ticks=[1,2,3,4], y_ticks=[4,8,12,16])
        self.a = 2
        self.x_max = 4
        self.color=GREEN
        self.intro = "No, that's not right."

        super().construct()


#####################################
#####################################
TASK_Func_6_2_P_4_q = SophiaTaskDefinition(
    answerOptions = ["The blue graph", "The green graph", "The orange graph"],
    correctAnswerIndex = 2,
    questionText = "Which of the graph corresponds to the function $f(x)=\\frac{1}{2}^x$?"
)

class Func_6_2_P_4_q(GrowthFactorToGraphQuestionScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 1, 0.25], x_ticks=[1,2,3,4], y_ticks=[0.25,0.5,0.75,1])
        self.a = 1/2
        self.intro = "Let's say we're considering a growth factor of a equals one half,so your function is"

        self.f1 = lambda x: (4-self.a)**x
        self.f2 = lambda x: x/4
        self.f3 = lambda x: self.a**x

        self.color_1_name = "blue"
        self.color_2_name = "green"
        self.color_3_name = "orange"

        self.c1 = BLUE
        self.c2 = GREEN
        self.c3 = ORANGE

        super().construct()

class Func_6_2_P_4_a(GrowthFactorToGraphAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 1, 0.25], x_ticks=[1,2,3,4], y_ticks=[0.25,0.5,0.75,1])
        self.x_max = 4
        self.a = 1/2
        self.intro = "That's not right."

        self.f1 = lambda x: (4-self.a)**x
        self.f2 = lambda x: x/4
        self.f3 = lambda x: self.a**x

        self.color_1_name = "blue"
        self.color_2_name = "green"
        self.color_3_name = "orange"

        self.c1 = BLUE
        self.c2 = GREEN
        self.c3 = ORANGE

        self.idx_correct = 2

        super().construct()

class Func_6_2_P_4_b(GrowthFactorToGraphAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 1, 0.25], x_ticks=[1,2,3,4], y_ticks=[0.25,0.5,0.75,1])
        self.x_max = 4
        self.a = 1/2
        self.intro = "That's not right."

        self.f1 = lambda x: (4-self.a)**x
        self.f2 = lambda x: x/4
        self.f3 = lambda x: self.a**x

        self.color_1_name = "blue"
        self.color_2_name = "green"
        self.color_3_name = "orange"

        self.c1 = BLUE
        self.c2 = GREEN
        self.c3 = ORANGE

        self.idx_correct = 2

        super().construct()

class Func_6_2_P_4_c(GrowthFactorToGraphAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 1, 0.25], x_ticks=[1,2,3,4], y_ticks=[0.25,0.5,0.75,1])
        self.x_max = 4
        self.a = 1/2
        self.intro = "Yes! That's correct."

        self.f1 = lambda x: (4-self.a)**x
        self.f2 = lambda x: x/4
        self.f3 = lambda x: self.a**x

        self.color_1_name = "blue"
        self.color_2_name = "green"
        self.color_3_name = "orange"

        self.c1 = BLUE
        self.c2 = GREEN
        self.c3 = ORANGE

        self.idx_correct = 2

        super().construct()

#####################################
#####################################
TASK_Func_6_2_P_5_q = SophiaTaskDefinition(
    answerOptions = ["$a=4$", "$a=2$", "$a=3$", "$a=-2$"],
    correctAnswerIndex = 0,
    questionText = "Given the pink graph, what is the value of a?"
)

class Func_6_2_P_5_q(GraphToGrowthFactorQuestionScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 256, 64], x_ticks=[1,2,3,4], y_ticks=[64,128,192,256])
        self.a = 4
        self.color=PINK
        self.intro = "Have a look at"

        super().construct()

class Func_6_2_P_5_a(GraphToGrowthFactorAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 256, 64], x_ticks=[1,2,3,4], y_ticks=[64,128,192,256])
        self.a = 4
        self.x_max = 4
        self.color=PINK
        self.intro = "Yep, that is correct."

        super().construct()

class Func_6_2_P_5_b(GraphToGrowthFactorAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 256, 64], x_ticks=[1,2,3,4], y_ticks=[64,128,192,256])
        self.a = 4
        self.x_max = 4
        self.color=PINK
        self.intro = "No, that's not right."

        super().construct()

class Func_6_2_P_5_c(GraphToGrowthFactorAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 256, 64], x_ticks=[1,2,3,4], y_ticks=[64,128,192,256])
        self.a = 4
        self.x_max = 4
        self.color=PINK
        self.intro = "No, that's not right."

        super().construct()

class Func_6_2_P_5_d(GraphToGrowthFactorAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 256, 64], x_ticks=[1,2,3,4], y_ticks=[64,128,192,256])
        self.a = 4
        self.x_max = 4
        self.color=PINK
        self.intro = "No, that's not right."

        super().construct()


#####################################
#####################################
TASK_Func_6_2_P_6_q = SophiaTaskDefinition(
    answerOptions = ["The purple graph", "The blue graph", "The pink graph"],
    correctAnswerIndex = 1,
    questionText = "Which of the graph corresponds to the function $f(x)=3^x$?"
)

class Func_6_2_P_6_q(GrowthFactorToGraphQuestionScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 81, 9], x_ticks=[1,2,3,4], y_ticks=[27,54,81])
        self.a = 3
        self.intro = "Let's say we're considering a growth factor of a equals three,so your function is"

        self.f1 = lambda x: x**2
        self.f2 = lambda x: self.a**x
        self.f3 = lambda x: self.a**(4-x)

        self.color_1_name = "purple"
        self.color_2_name = "blue"
        self.color_3_name = "pink"

        self.c1 = PURPLE
        self.c2 = BLUE
        self.c3 = PINK

        super().construct()

class Func_6_2_P_6_a(GrowthFactorToGraphAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 81, 9], x_ticks=[1,2,3,4], y_ticks=[27,54,81])
        self.x_max = 4
        self.a = 3
        self.intro = "No, that's wrong."

        self.f1 = lambda x: x**2
        self.f2 = lambda x: self.a**x
        self.f3 = lambda x: self.a**(4-x)

        self.color_1_name = "purple"
        self.color_2_name = "blue"
        self.color_3_name = "pink"

        self.c1 = PURPLE
        self.c2 = BLUE
        self.c3 = PINK

        self.idx_correct = 1

        super().construct()

class Func_6_2_P_6_b(GrowthFactorToGraphAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 81, 9], x_ticks=[1,2,3,4], y_ticks=[27,54,81])
        self.x_max = 4
        self.a = 3
        self.intro = "Yep, that is right."

        self.f1 = lambda x: x**2
        self.f2 = lambda x: self.a**x
        self.f3 = lambda x: self.a**(4-x)

        self.color_1_name = "purple"
        self.color_2_name = "blue"
        self.color_3_name = "pink"

        self.c1 = PURPLE
        self.c2 = BLUE
        self.c3 = PINK

        self.idx_correct = 1

        super().construct()

class Func_6_2_P_6_c(GrowthFactorToGraphAnswerScene):

    def construct(self):

        self.cords = self.add_cords([0, 4, 1], [0, 81, 9], x_ticks=[1,2,3,4], y_ticks=[27,54,81])
        self.x_max = 4
        self.a = 3
        self.intro = "No, that's wrong."

        self.f1 = lambda x: x**2
        self.f2 = lambda x: self.a**x
        self.f3 = lambda x: self.a**(4-x)

        self.color_1_name = "purple"
        self.color_2_name = "blue"
        self.color_3_name = "pink"

        self.c1 = PURPLE
        self.c2 = BLUE
        self.c3 = PINK

        self.idx_correct = 1

        super().construct()



PROTOTYPES=[
    PagePrototypeVideo.from_scene(Func_6_2_I_1),
    PagePrototypeVideo.from_scene(Func_6_2_I_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_2_I_2_q, Func_6_2_I_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_2_I_2_a),
    PagePrototypeVideo.from_scene(Func_6_2_I_2_b),
    PagePrototypeVideo.from_scene(Func_6_2_I_2_c),
    PagePrototypeVideo.from_scene(Func_6_2_I_2_d),
    PagePrototypeVideo.from_scene(Func_6_2_I_3),
    PagePrototypeVideo.from_scene(Func_6_2_P_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_2_P_1_q, Func_6_2_P_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_2_P_1_a),
    PagePrototypeVideo.from_scene(Func_6_2_P_1_b),
    PagePrototypeVideo.from_scene(Func_6_2_P_1_c),
    PagePrototypeVideo.from_scene(Func_6_2_P_1_d),
    PagePrototypeVideo.from_scene(Func_6_2_P_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_2_P_2_q, Func_6_2_P_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_2_P_2_a),
    PagePrototypeVideo.from_scene(Func_6_2_P_2_b),
    PagePrototypeVideo.from_scene(Func_6_2_P_2_c),
    PagePrototypeVideo.from_scene(Func_6_2_P_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_2_P_3_q, Func_6_2_P_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_2_P_3_a),
    PagePrototypeVideo.from_scene(Func_6_2_P_3_b),
    PagePrototypeVideo.from_scene(Func_6_2_P_3_c),
    PagePrototypeVideo.from_scene(Func_6_2_P_3_d),
    PagePrototypeVideo.from_scene(Func_6_2_P_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_2_P_4_q, Func_6_2_P_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_2_P_4_a),
    PagePrototypeVideo.from_scene(Func_6_2_P_4_b),
    PagePrototypeVideo.from_scene(Func_6_2_P_4_c),
    PagePrototypeVideo.from_scene(Func_6_2_P_5_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_2_P_5_q, Func_6_2_P_5_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_2_P_5_a),
    PagePrototypeVideo.from_scene(Func_6_2_P_5_b),
    PagePrototypeVideo.from_scene(Func_6_2_P_5_c),
    PagePrototypeVideo.from_scene(Func_6_2_P_5_d),
    PagePrototypeVideo.from_scene(Func_6_2_P_6_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_2_P_6_q, Func_6_2_P_6_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_2_P_6_a),
    PagePrototypeVideo.from_scene(Func_6_2_P_6_b),
    PagePrototypeVideo.from_scene(Func_6_2_P_6_c),
]
scenes/Func/Func_6: Exponential Functions/Func_6_2.py
Sophia-Edu-Labs/sophia-math
# 6_2: Exponential Functions: Logarithm

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition



#####################################
#####################################
TASK_Func_6_3_I_1_q = SophiaTaskDefinition(
    answerOptions = ["Applying the square again $(\Box^2)^2$", "Taking the root $\sqrt{\Box^2}$", "Dividing by two $\Box/2$", "Multiplying by two $\Box\times 2$"],
    correctAnswerIndex = 1,
    questionText = "What operation can we apply to undo the squaring ($\Box^2$)?"
)
class Func_6_3_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Inverse Functions")

        two_add = MathTex("2", color=c1t, font_size=fs1).move_to([-1,1,0])
        four_add = MathTex("4", color=c1t, font_size=fs1).move_to([1,1,0])
        l = two_add.get_right()+0.2*RIGHT
        r = four_add.get_left()-0.2*RIGHT
        arrow_add = ArcBetweenPoints(l, r, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*UP)
        arrow_subtract = ArcBetweenPoints(r, l, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*DOWN)
        add_two = MathTex("+2", color=c1t, font_size=fs2).next_to(arrow_add, UP, buff=0.1)
        subtract_two = MathTex("-2", color=c1t, font_size=fs2).next_to(arrow_subtract, DOWN, buff=0.1)
        addition = VGroup(two_add, four_add, arrow_add, arrow_subtract, add_two, subtract_two)


        three_mul = MathTex("3", color=c1t, font_size=fs1).move_to([-1,1,0])
        nine_mul = MathTex("9", color=c1t, font_size=fs1).move_to([1,1,0])
        l = three_mul.get_right()+0.2*RIGHT
        r = nine_mul.get_left()-0.2*RIGHT
        arrow_mul = ArcBetweenPoints(l, r, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*UP)
        arrow_div = ArcBetweenPoints(r, l, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*DOWN)
        mul_three = MathTex("\\times 3", color=c1t, font_size=fs2).next_to(arrow_mul, UP, buff=0.1)
        div_three = MathTex("\\div 3", color=c1t, font_size=fs2).next_to(arrow_div, DOWN, buff=0.1)
        multiplication = VGroup(three_mul, nine_mul, arrow_mul, arrow_div, mul_three, div_three).shift(DOWN)


        four_pow = MathTex("4", color=c1t, font_size=fs1).move_to([-1,0,0])
        two_pow = MathTex("2", color=c1t, font_size=fs1).move_to([1,0,0])
        l = four_pow.get_right()+0.2*RIGHT
        r = two_pow.get_left()-0.2*RIGHT
        arrow_pow = ArcBetweenPoints(l, r, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*UP)
        arrow_root = ArcBetweenPoints(r, l, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*DOWN)
        pow_two = MathTex("\\Box^2", color=c1t, font_size=fs2).next_to(arrow_pow, UP, buff=0.1)
        root_two = MathTex("?", color=c1t, font_size=fs2).next_to(arrow_root, DOWN, buff=0.1)
        power = VGroup(four_pow, two_pow, arrow_pow, arrow_root, pow_two, root_two).shift(1.4*DOWN)

        

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        # Action Sequence
        with self.voiceover(
                text="""
                If we think about different mathematical operations, they always come in pairs, that can cancel each other out.
                For example, there's addition and subtraction. If you<bookmark mark="two_add_1"/>take a number, say two, and add something, say
                two <bookmark mark="two_add_2"/>to the original number,
                you can then <bookmark mark="two_add_3"/> subtract 2 from the result and get the original number back.
                
                <bookmark mark="clear_1"/>
                Another example is multiplication and division.
                Again, if you take a <bookmark mark="three_mul_1"/>number, like three, and multiply it by something, <bookmark mark="three_mul_2"/>say three,
                <bookmark mark="three_mul_3"/>you can then divide the result by three and get the original number back.

                <bookmark mark="clear_2"/>
                Do you know the inverse operation for raising something to a power?
                If we raise<bookmark mark="four_pow_1"/> a number, say four, to a power, like <bookmark mark="four_pow_2"/>two for example,
                <bookmark mark="four_pow_3"/>
                What operation do we need to apply to undo the squaring?
                """
        ) as tracker:
            
            self.wait_until_bookmark("two_add_1")
            x,y,_ = two_add.get_center()+0.6*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(two_add))

            self.wait_until_bookmark("two_add_2")
            x,y,_ = four_add.get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(four_add), Write(arrow_add), Write(add_two))

            self.wait_until_bookmark("two_add_3")
            x,y,_ = two_add.get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(arrow_subtract), Write(subtract_two))
            cursor.blinking=True

            self.wait_until_bookmark("clear_1")
            self.play(addition.animate.scale(0.5), run_time=0.3)
            self.play(addition.animate.shift(UP), run_time=0.3)

            self.wait_until_bookmark("three_mul_1")
            cursor.blinking=False
            x,y,_ = three_mul.get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(three_mul))

            self.wait_until_bookmark("three_mul_2")
            x,y,_ = nine_mul.get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(nine_mul), Write(arrow_mul), Write(mul_three))

            self.wait_until_bookmark("three_mul_3")
            x,y,_ = three_mul.get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(arrow_div), Write(div_three))
            cursor.blinking=True

            self.wait_until_bookmark("clear_2")
            self.play(multiplication.animate.scale(0.5), run_time=0.3)
            self.play(multiplication.animate.next_to(addition, DOWN, buff=0.4), run_time=0.3)

            self.wait_until_bookmark("four_pow_1")
            cursor.blinking=False
            x,y,_ = four_pow.get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(four_pow))

            self.wait_until_bookmark("four_pow_2")
            x,y,_ = two_pow.get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(two_pow), Write(arrow_pow), Write(pow_two))

            self.wait_until_bookmark("four_pow_3")
            x,y,_ = four_pow.get_center()+0.6*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(arrow_root), Write(root_two))
            cursor.blinking=True

        self.wait(4)

class Func_6_3_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Inverse Functions")

        four_pow = MathTex("2", color=c1t, font_size=fs1).move_to([-1,0,0])
        two_pow = MathTex("4", color=c1t, font_size=fs1).move_to([1,0,0])
        l = four_pow.get_right()+0.2*RIGHT
        r = two_pow.get_left()-0.2*RIGHT
        arrow_pow = ArcBetweenPoints(l, r, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*UP)
        arrow_root = ArcBetweenPoints(r, l, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*DOWN)
        pow_two = MathTex("\\Box^2", color=c1t, font_size=fs2).next_to(arrow_pow, UP, buff=0.1)
        root_two = MathTex("?", color=c1t, font_size=fs2).next_to(arrow_root, DOWN, buff=0.1)
        power = VGroup(four_pow, two_pow, arrow_pow, arrow_root, pow_two, root_two).shift(0.4*UP)
        self.add(power)

        pow_root = MathTex("\\Box ^2", "\\Leftrightarrow", "\\sqrt{\\Box}", color=c1t, font_size=fs2).move_to([0,-1,0])        

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        # Action Sequence
        with self.voiceover(
                text="""
                Unfortunately, that's not right.
                The inverse operation <bookmark mark="raise"/>for raising something to a power <bookmark mark="root"/>is taking the root.
                If we raise <bookmark mark="sol_raise"/>a number like four to the second power, we can undo that operation
                by <bookmark mark="sol_root"/>taking the second root of the result.

                So the inverse operation of raising a number to a power is taking the root.
                """
        ) as tracker:
            
            self.wait_until_bookmark("raise")
            x,y,_ = pow_root[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(pow_root[0]))

            self.wait_until_bookmark("root")
            x,y,_ = pow_root[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(pow_root[1]), Write(pow_root[2]))
            cursor.blinking=True

            self.wait_until_bookmark("sol_raise")
            cursor.blinking=False
            x,y,_ = pow_two.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y))

            self.wait_until_bookmark("sol_root")
            x,y,_ = root_two.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), ReplacementTransform(root_two, MathTex("\\sqrt{\\Box}", color=c1t, font_size=fs2).move_to(root_two)))
            cursor.blinking=True

        self.wait(4)


class Func_6_3_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Inverse Functions")

        four_pow = MathTex("2", color=c1t, font_size=fs1).move_to([-1,0,0])
        two_pow = MathTex("4", color=c1t, font_size=fs1).move_to([1,0,0])
        l = four_pow.get_right()+0.2*RIGHT
        r = two_pow.get_left()-0.2*RIGHT
        arrow_pow = ArcBetweenPoints(l, r, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*UP)
        arrow_root = ArcBetweenPoints(r, l, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*DOWN)
        pow_two = MathTex("\\Box^2", color=c1t, font_size=fs2).next_to(arrow_pow, UP, buff=0.1)
        root_two = MathTex("?", color=c1t, font_size=fs2).next_to(arrow_root, DOWN, buff=0.1)
        power = VGroup(four_pow, two_pow, arrow_pow, arrow_root, pow_two, root_two).shift(0.4*UP)
        self.add(power)

        pow_root = MathTex("\\Box ^2", "\\Leftrightarrow", "\\sqrt{\\Box}", color=c1t, font_size=fs2).move_to([0,-1,0])        

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        # Action Sequence
        with self.voiceover(
                text="""
                Yes, that is correct!
                The inverse operation <bookmark mark="raise"/>for raising something to a power <bookmark mark="root"/>is taking the root.
                If we raise <bookmark mark="sol_raise"/>a number like four to the second power, we can undo that operation
                by <bookmark mark="sol_root"/>taking the second root of the result.

                So the inverse operation of raising a number to a power is taking the root.
                """
        ) as tracker:
            
            self.wait_until_bookmark("raise")
            x,y,_ = pow_root[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(pow_root[0]))

            self.wait_until_bookmark("root")
            x,y,_ = pow_root[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(pow_root[1]), Write(pow_root[2]))
            cursor.blinking=True

            self.wait_until_bookmark("sol_raise")
            cursor.blinking=False
            x,y,_ = pow_two.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y))

            self.wait_until_bookmark("sol_root")
            x,y,_ = root_two.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), ReplacementTransform(root_two, MathTex("\\sqrt{\\Box}", color=c1t, font_size=fs2).move_to(root_two)))
            cursor.blinking=True

        self.wait(4)


class Func_6_3_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Inverse Functions")

        four_pow = MathTex("2", color=c1t, font_size=fs1).move_to([-1,0,0])
        two_pow = MathTex("4", color=c1t, font_size=fs1).move_to([1,0,0])
        l = four_pow.get_right()+0.2*RIGHT
        r = two_pow.get_left()-0.2*RIGHT
        arrow_pow = ArcBetweenPoints(l, r, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*UP)
        arrow_root = ArcBetweenPoints(r, l, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*DOWN)
        pow_two = MathTex("\\Box^2", color=c1t, font_size=fs2).next_to(arrow_pow, UP, buff=0.1)
        root_two = MathTex("?", color=c1t, font_size=fs2).next_to(arrow_root, DOWN, buff=0.1)
        power = VGroup(four_pow, two_pow, arrow_pow, arrow_root, pow_two, root_two).shift(0.4*UP)
        self.add(power)

        pow_root = MathTex("\\Box ^2", "\\Leftrightarrow", "\\sqrt{\\Box}", color=c1t, font_size=fs2).move_to([0,-1,0])        

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        # Action Sequence
        with self.voiceover(
                text="""
                Unfortunately, that's not right.
                The inverse operation <bookmark mark="raise"/>for raising something to a power <bookmark mark="root"/>is taking the root.
                If we raise <bookmark mark="sol_raise"/>a number like four to the second power, we can undo that operation
                by <bookmark mark="sol_root"/>taking the second root of the result.

                So the inverse operation of raising a number to a power is taking the root.
                """
        ) as tracker:
            
            self.wait_until_bookmark("raise")
            x,y,_ = pow_root[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(pow_root[0]))

            self.wait_until_bookmark("root")
            x,y,_ = pow_root[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(pow_root[1]), Write(pow_root[2]))
            cursor.blinking=True

            self.wait_until_bookmark("sol_raise")
            cursor.blinking=False
            x,y,_ = pow_two.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y))

            self.wait_until_bookmark("sol_root")
            x,y,_ = root_two.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), ReplacementTransform(root_two, MathTex("\\sqrt{\\Box}", color=c1t, font_size=fs2).move_to(root_two)))
            cursor.blinking=True

        self.wait(4)


class Func_6_3_I_1_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Inverse Functions")

        four_pow = MathTex("2", color=c1t, font_size=fs1).move_to([-1,0,0])
        two_pow = MathTex("4", color=c1t, font_size=fs1).move_to([1,0,0])
        l = four_pow.get_right()+0.2*RIGHT
        r = two_pow.get_left()-0.2*RIGHT
        arrow_pow = ArcBetweenPoints(l, r, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*UP)
        arrow_root = ArcBetweenPoints(r, l, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*DOWN)
        pow_two = MathTex("\\Box^2", color=c1t, font_size=fs2).next_to(arrow_pow, UP, buff=0.1)
        root_two = MathTex("?", color=c1t, font_size=fs2).next_to(arrow_root, DOWN, buff=0.1)
        power = VGroup(four_pow, two_pow, arrow_pow, arrow_root, pow_two, root_two).shift(0.4*UP)
        self.add(power)

        pow_root = MathTex("\\Box ^2", "\\Leftrightarrow", "\\sqrt{\\Box}", color=c1t, font_size=fs2).move_to([0,-1,0])        

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        # Action Sequence
        with self.voiceover(
                text="""
                Unfortunately, that's not right.
                The inverse operation <bookmark mark="raise"/>for raising something to a power <bookmark mark="root"/>is taking the root.
                If we raise <bookmark mark="sol_raise"/>a number like four to the second power, we can undo that operation
                by <bookmark mark="sol_root"/>taking the second root of the result.

                So the inverse operation of raising a number to a power is taking the root.
                """
        ) as tracker:
            
            self.wait_until_bookmark("raise")
            x,y,_ = pow_root[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(pow_root[0]))

            self.wait_until_bookmark("root")
            x,y,_ = pow_root[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(pow_root[1]), Write(pow_root[2]))
            cursor.blinking=True

            self.wait_until_bookmark("sol_raise")
            cursor.blinking=False
            x,y,_ = pow_two.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y))

            self.wait_until_bookmark("sol_root")
            x,y,_ = root_two.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), ReplacementTransform(root_two, MathTex("\\sqrt{\\Box}", color=c1t, font_size=fs2).move_to(root_two)))
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
class Func_6_3_I_2(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Logarithm")

        four_pow = MathTex("3", color=c1t, font_size=fs1).move_to([-1,0,0])
        two_pow = MathTex("64", color=c1t, font_size=fs1).move_to([1,0,0])
        l = four_pow.get_right()+0.2*RIGHT
        r = two_pow.get_left()-0.2*RIGHT
        arrow_pow = ArcBetweenPoints(l, r, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*UP)
        arrow_root = ArcBetweenPoints(r, l, color=c1t, angle=-PI/2).add_tip(tip_length=0.2, tip_width=0.1).shift(0.2*DOWN)
        exp_two = MathTex("4^\\Box", color=c1t, font_size=fs2).next_to(arrow_pow, UP, buff=0.1)
        log_two = MathTex("\\log_4{\\Box}", color=c1t, font_size=fs2).next_to(arrow_root, DOWN, buff=0.1)
        exp = VGroup(four_pow, two_pow, arrow_pow, arrow_root, exp_two, log_two).shift(0.4*UP)

        exp_log = MathTex("k^\\Box", "\\Leftrightarrow", "\\log_k{\\Box}", color=c1t, font_size=fs2).move_to([0,-2,0])        

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        # Action Sequence
        with self.voiceover(
                text="""
                Now similarly, you might ask yourself: What is the inverse operation for exponential functions?

                For example, I take <bookmark mark="take_number"/>a number, say three, and <bookmark mark="raise_4"/>raise four to the power of three.
                Then I will have 64. But what operation can I use, to get back to three? What is the inverse operation of raising something to a power?

                The answer is: <bookmark mark="take_log"/>Taking the logarithm. So if I raise four to the power of three I get 64.
                If I then take the base four logarithm of 64, I get three back. So <bookmark mark="inverse_raise"/>the inverse operation of raising a
                number k to a <bookmark mark="inverse_log"/>power is taking the base k logarithm.

                What exactly that means, we will see in the next video.
                """
        ) as tracker:
            
            self.wait_until_bookmark("take_number")
            x,y,_ = four_pow.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(four_pow))

            self.wait_until_bookmark("raise_4")
            x,y,_ = two_pow.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(two_pow), Write(arrow_pow), Write(exp_two))

            self.wait_until_bookmark("take_log")
            x,y,_ = four_pow.get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(arrow_root), Write(log_two))
            cursor.blinking=True

            self.wait_until_bookmark("inverse_raise")
            cursor.blinking=False
            x,y,_ = exp_log[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(exp_log[0]))

            self.wait_until_bookmark("inverse_log")
            x,y,_ = exp_log[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(exp_log[1]), Write(exp_log[2]))
            cursor.blinking=True

        self.wait(4)



#####################################
#####################################
class Func_6_3_I_3(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Logarithm")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        two_to_the_x = MathTex("2", "\\cdot2", "\\cdot2", "\\cdot2", "\\cdot2", "=", "2^5", "=", "32", color=c1t, font_size=fs2).move_to([0,0,0])
        thirtytwo = MathTex("32", "=", "2^?", color=c1t, font_size=fs2).next_to(two_to_the_x, DOWN, buff=0.4)
        logarithm = MathTex("\\log_2{32}", "=", "5", color=c1t, font_size=fs2).next_to(thirtytwo, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text="""
                So what does the logarithm actually do.

                We take a number,<bookmark mark="two_1"/> say two, and multiply it by itself one,
                <bookmark mark="two_2"/>two, <bookmark mark="two_3"/>three <bookmark mark="two_4"/>four,
                <bookmark mark="two_5"/>five times, to <bookmark mark="two_pow_5"/> get two to the power
                of five<bookmark mark="two_32"/>, which equals 32.

                But what if we want to go in the opposite direction?
                So say we <bookmark mark="thirtytwo_1"/> have 32, and we want to know
                how many times we have to multiply <bookmark mark="thirtytwo_2"/>two by itself to get 32.

                We can find this number by computing the<bookmark mark="sol_1"/> base two logarithm of 32.
                The base two logarithm of 32 is the number, to which we have to raise two
                to get 32. <bookmark mark="sol_2"/>And that number is five...
                """
        ) as tracker:
            
            self.wait_until_bookmark("two_1")
            x,y,_ = two_to_the_x[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(two_to_the_x[0]), run_time=0.3)

            self.wait_until_bookmark("two_2")
            x,y,_ = two_to_the_x[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(two_to_the_x[1]), run_time=0.3)

            self.wait_until_bookmark("two_3")
            x,y,_ = two_to_the_x[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(two_to_the_x[2]), run_time=0.3)

            self.wait_until_bookmark("two_4")
            x,y,_ = two_to_the_x[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(two_to_the_x[3]), run_time=0.3)
            
            self.wait_until_bookmark("two_5")
            x,y,_ = two_to_the_x[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(two_to_the_x[4]), run_time=0.3)

            self.wait_until_bookmark("two_pow_5")
            x,y,_ = two_to_the_x[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(two_to_the_x[5]), Write(two_to_the_x[6]), run_time=0.3)

            self.wait_until_bookmark("two_32")
            x,y,_ = two_to_the_x[8].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(two_to_the_x[7]), Write(two_to_the_x[8]), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("thirtytwo_1")
            x,y,_ = thirtytwo[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(thirtytwo[0]), run_time=0.3)

            self.wait_until_bookmark("thirtytwo_2")
            x,y,_ = thirtytwo[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(thirtytwo[1]), Write(thirtytwo[2]), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_1")
            x,y,_ = logarithm[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(logarithm[0]), run_time=0.3)

            self.wait_until_bookmark("sol_2")
            x,y,_ = logarithm[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(logarithm[1]), Write(logarithm[2]), run_time=0.3)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
TASK_Func_6_3_I_4_q = SophiaTaskDefinition(
    answerOptions = ["x=\sqrt[5]{625}", "x=\sqrt[625]{5}", "$x=\log_{625}{5}$", "$x=\log_5{625}$"],
    correctAnswerIndex = 3,
    questionText = "For what value of x does $5^x=625$ hold?"
)
class Func_6_3_I_4_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Logarithm")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        sixtwentyfive = MathTex("625", "=", "5^?", color=c1t, font_size=fs2).shift(UP*0.4)
        
        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(2/qmark.get_width()).move_to([-5, -1.4, 0])

        # Action Sequence
        with self.voiceover(
                text="""
                Let's try to use the logarithm ourself!
                We'll start with the <bookmark mark="sixtwofive_1"/>number 625.
                We want to know, to what power we have to raise <bookmark mark="sixtwofive_2"/>the number five to get 625.
                <bookmark mark="qmark"/>How do we find that number using the logarithm?
                """
        ) as tracker:
            
            self.wait_until_bookmark("sixtwofive_1")
            x,y,_ = sixtwentyfive[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(sixtwentyfive[0]), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sixtwofive_2")
            cursor.blinking=False
            x,y,_ = sixtwentyfive[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(sixtwentyfive[1]), Write(sixtwentyfive[2]), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("qmark")
            self.play(qmark.animate.shift(5*RIGHT), run_time=0.3)

        self.wait(4)


class Func_6_3_I_4_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Logarithm")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        sixtwentyfive = MathTex("625", "=", "5^?", color=c1t, font_size=fs2).shift(UP*0.4)
        sol_1 = MathTex("5^x", "=", "625", color=c1t, font_size=fs2).next_to(sixtwentyfive, DOWN, buff=0.4)
        sol_2 = MathTex("\\Rightarrow", "x=\\log_5{(625)}", color=c1t, font_size=fs2).next_to(sol_1, DOWN, buff=0.2)
        self.add(sixtwentyfive)


        # Action Sequence
        with self.voiceover(
                text="""
                That's not right.
                So we want to know to what power we have to raise five to get 625.
                We can reformulate this as the equation <bookmark mark="sol_1"/>five to the power of x <bookmark mark="sol_2"/>equals 625.
                This can then be solved as <bookmark mark="sol_3"/>x is equal to the base five logarithm of 625.
                The base of the logarithm is the number, which is the base of the power, in this case five.
                And the number which we take the logarithm of is the number we want to get, in this case 625.
                """
        ) as tracker:
            
            self.wait_until_bookmark("sol_1")
            x,y,_ = sol_1[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(sol_1[0]), run_time=0.3)

            self.wait_until_bookmark("sol_2")
            x,y,_ = sol_1[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(sol_1[1]), Write(sol_1[2]), run_time=0.3)

            self.wait_until_bookmark("sol_3")
            x,y,_ = sol_2[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(sol_2[0]), Write(sol_2[1]), run_time=0.3)
            cursor.blinking=True

        self.wait(4)

class Func_6_3_I_4_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Logarithm")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        sixtwentyfive = MathTex("625", "=", "5^?", color=c1t, font_size=fs2).shift(UP*0.4)
        sol_1 = MathTex("5^x", "=", "625", color=c1t, font_size=fs2).next_to(sixtwentyfive, DOWN, buff=0.4)
        sol_2 = MathTex("\\Rightarrow", "x=\\log_5{(625)}", color=c1t, font_size=fs2).next_to(sol_1, DOWN, buff=0.2)
        self.add(sixtwentyfive)


        # Action Sequence
        with self.voiceover(
                text="""
                That's not right.
                So we want to know to what power we have to raise five to get 625.
                We can reformulate this as the equation <bookmark mark="sol_1"/>five to the power of x <bookmark mark="sol_2"/>equals 625.
                This can then be solved as <bookmark mark="sol_3"/>x is equal to the base five logarithm of 625.
                The base of the logarithm is the number, which is the base of the power, in this case five.
                And the number which we take the logarithm of is the number we want to get, in this case 625.
                """
        ) as tracker:
            
            self.wait_until_bookmark("sol_1")
            x,y,_ = sol_1[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(sol_1[0]), run_time=0.3)

            self.wait_until_bookmark("sol_2")
            x,y,_ = sol_1[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(sol_1[1]), Write(sol_1[2]), run_time=0.3)

            self.wait_until_bookmark("sol_3")
            x,y,_ = sol_2[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(sol_2[0]), Write(sol_2[1]), run_time=0.3)
            cursor.blinking=True

        self.wait(4)

class Func_6_3_I_4_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Logarithm")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        sixtwentyfive = MathTex("625", "=", "5^?", color=c1t, font_size=fs2).shift(UP*0.4)
        sol_1 = MathTex("5^x", "=", "625", color=c1t, font_size=fs2).next_to(sixtwentyfive, DOWN, buff=0.4)
        sol_2 = MathTex("\\Rightarrow", "x=\\log_5{(625)}", color=c1t, font_size=fs2).next_to(sol_1, DOWN, buff=0.2)
        self.add(sixtwentyfive)


        # Action Sequence
        with self.voiceover(
                text="""
                That's not right.
                So we want to know to what power we have to raise five to get 625.
                We can reformulate this as the equation <bookmark mark="sol_1"/>five to the power of x <bookmark mark="sol_2"/>equals 625.
                This can then be solved as <bookmark mark="sol_3"/>x is equal to the base five logarithm of 625.
                The base of the logarithm is the number, which is the base of the power, in this case five.
                And the number which we take the logarithm of is the number we want to get, in this case 625.
                """
        ) as tracker:
            
            self.wait_until_bookmark("sol_1")
            x,y,_ = sol_1[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(sol_1[0]), run_time=0.3)

            self.wait_until_bookmark("sol_2")
            x,y,_ = sol_1[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(sol_1[1]), Write(sol_1[2]), run_time=0.3)

            self.wait_until_bookmark("sol_3")
            x,y,_ = sol_2[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(sol_2[0]), Write(sol_2[1]), run_time=0.3)
            cursor.blinking=True

        self.wait(4)

class Func_6_3_I_4_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Logarithm")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        sixtwentyfive = MathTex("625", "=", "5^?", color=c1t, font_size=fs2).shift(UP*0.4)
        sol_1 = MathTex("5^x", "=", "625", color=c1t, font_size=fs2).next_to(sixtwentyfive, DOWN, buff=0.4)
        sol_2 = MathTex("\\Rightarrow", "x=\\log_5{(625)}", color=c1t, font_size=fs2).next_to(sol_1, DOWN, buff=0.2)
        self.add(sixtwentyfive)


        # Action Sequence
        with self.voiceover(
                text="""
                Yes, that is correct!
                So we want to know to what power we have to raise five to get 625.
                We can reformulate this as the equation <bookmark mark="sol_1"/>five to the power of x <bookmark mark="sol_2"/>equals 625.
                This can then be solved as <bookmark mark="sol_3"/>x is equal to the base five logarithm of 625.
                The base of the logarithm is the number, which is the base of the power, in this case five.
                And the number which we take the logarithm of is the number we want to get, in this case 625.
                """
        ) as tracker:
            
            self.wait_until_bookmark("sol_1")
            x,y,_ = sol_1[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(sol_1[0]), run_time=0.3)

            self.wait_until_bookmark("sol_2")
            x,y,_ = sol_1[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(sol_1[1]), Write(sol_1[2]), run_time=0.3)

            self.wait_until_bookmark("sol_3")
            x,y,_ = sol_2[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(sol_2[0]), Write(sol_2[1]), run_time=0.3)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
class Func_6_3_I_5(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Logarithm")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        sol_1 = MathTex("a^x", "=", "b", color=c1t, font_size=fs2).move_to([0,1.5,0])
        sol_2 = MathTex("\\Rightarrow x=\\log_a{(b)}", color=c1t, font_size=fs2).move_to([0,-1,0])

        start_base = np.array([.4,-1.4,0])
        start_log = np.array([1,-0.7,0])
        base = Bubble(texts = ["a: Base of the logarithm"], center=np.array([0.4,-2.8, 0]), start_point=start_base, loc="t1", width=3, height=0.8)
        log = Bubble(texts = ["b: Number we want to get"], center=np.array([0,0.2, 0]), start_point=start_log, width=3, height=0.8)


        # Action Sequence
        with self.voiceover(
                text="""
                Now a bit more formally: Logarithms.
                We have a <bookmark mark="intro_1"/>base a, and we want to raise it to some power to get 
                <bookmark mark="intro_2"/>the number b as a result.
                Now that number x is what we're looking for.

                This is where the logarithm comes in. The <bookmark mark="sol_in"/>logarithm tells us, to what number we have to
                raise the base a, if we want to get the number b.

                The logarithm has two parts.
                <bookmark mark="base"/> The base "a", which is written as an index, which describes the base of the power,
                so the number that we want to raise to some power.
                <bookmark mark="log"/> And the number b, which is written in brackets, which is the number we want to get...
                """
        ) as tracker:
            
            self.wait_until_bookmark("intro_1")
            x,y,_ = sol_1[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(sol_1[0]), run_time=0.3)

            self.wait_until_bookmark("intro_2")
            x,y,_ = sol_1[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(sol_1[1]), Write(sol_1[2]), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_in")
            x,y,_ = sol_2.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(sol_2), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("base")
            x,y,_ = start_base
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(base.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(base), Create(base.text))
            cursor.blinking=True

            self.wait_until_bookmark("log")
            x,y,_ = start_log
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(log.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(log), Create(log.text))
            cursor.blinking=True



        self.wait(4)


#####################################
#####################################
######## Practice Part ##############
#####################################
#####################################




#####################################
#####################################
######## General Qs #################
#####################################
#####################################

#####################################
#####################################
class findLogExpressionQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Logarithm")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        sixtwentyfive = MathTex(f"{self.result}", "=", f"{self.base}^?", color=c1t, font_size=fs2).shift(UP*0.4)
        
        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(2/qmark.get_width()).move_to([-5, -1.4, 0])

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro}
                We'll start with the <bookmark mark="result_1"/>number {self.result}.
                We want to know, to what power we have to raise <bookmark mark="result_2"/>the number {self.base} to get {self.result}.
                <bookmark mark="qmark"/>How do we find that number using the logarithm?
                """
        ) as tracker:
            
            self.wait_until_bookmark("result_1")
            x,y,_ = sixtwentyfive[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(sixtwentyfive[0]), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("result_2")
            cursor.blinking=False
            x,y,_ = sixtwentyfive[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(sixtwentyfive[1]), Write(sixtwentyfive[2]), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("qmark")
            self.play(qmark.animate.shift(5*RIGHT), run_time=0.3)

        self.wait(4)



class findLogExpressionAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()

        self.add_title("Logarithm")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        x,y,_ = 0,0,0
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        sixtwentyfive = MathTex(f"{self.result}", "=", f"{self.base}^?", color=c1t, font_size=fs2).shift(UP*0.4)
        sol_1 = MathTex(f"{self.base}^x", "=", f"{self.result}", color=c1t, font_size=fs2).next_to(sixtwentyfive, DOWN, buff=0.4)
        sol_2 = MathTex("\\Rightarrow", f"x=\\log_{{{self.base}}}{({self.result})}", color=c1t, font_size=fs2).next_to(sol_1, DOWN, buff=0.2)
        self.add(sixtwentyfive)


        start_base = np.array([.4,-1.2,0])
        start_log = np.array([1,-0.5,0])

        base = Bubble(texts = [f"{self.base}: Base of the logarithm"], center=np.array([.6,-2.6, 0]), start_point=start_base, loc="t1", width=3, height=0.8)
        log = Bubble(texts = [f"{self.result}: Number we want to get"], center=np.array([0,0.2, 0]), start_point=start_log, width=3, height=0.8)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro}
                So we want to know to what power we have to raise {self.base} to get {self.result}.
                We can reformulate this as the equation <bookmark mark="sol_1"/>{self.base} to the power of x
                <bookmark mark="sol_2"/>equals {self.result}. This can then be solved as
                <bookmark mark="sol_3"/>x is equal to the base {self.base} logarithm of {self.result}. <bookmark mark="clean"/>
                The <bookmark mark="bubble_1"/>base of the logarithm is the number, which is the base of the power, in this case {self.base}.
                And the <bookmark mark="bubble_2"/>number which we take the logarithm of is the number we want to get, in this case {self.result}.
                """
        ) as tracker:
            
            self.wait_until_bookmark("sol_1")
            x,y,_ = sol_1[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(sol_1[0]), run_time=0.3)

            self.wait_until_bookmark("sol_2")
            x,y,_ = sol_1[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(sol_1[1]), Write(sol_1[2]), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_3")
            cursor.blinking=False
            x,y,_ = sol_2[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), Write(sol_2[0]), Write(sol_2[1]), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("clean")
            self.play(FadeOut(sol_1), FadeOut(sixtwentyfive), run_time=0.3)

            self.wait_until_bookmark("bubble_1")
            x,y,_ = start_base
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(base.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(base), Create(base.text))
            cursor.blinking=True

            self.wait_until_bookmark("bubble_2")
            x,y,_ = start_log
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(log.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(log), Create(log.text))
            cursor.blinking=True

        self.wait(4)

#####################################
#####################################
TASK_Func_6_3_P_1_q = SophiaTaskDefinition(
    answerOptions = ["$x=\log_{256}{4}$", "$x=\log_4{256}$", "x=\sqrt[4]{256}", "x=\sqrt[256]{4}"],
    correctAnswerIndex = 1,
    questionText = "For what value of x does $4^x=256$ hold?"
)

class Func_6_3_P_1_q(findLogExpressionQuestionScene):
    
        # Main method for constructing the animation
        def construct(self):

            self.result = 256
            self.base = 4
            self.intro = "Another example to practice:"

            super().construct()


class Func_6_3_P_1_a(findLogExpressionAnswerScene):

        # Main method for constructing the animation
        def construct(self):

            self.result = 256
            self.base = 4
            self.intro = "No, that's not right..."

            super().construct()

class Func_6_3_P_1_b(findLogExpressionAnswerScene):

        # Main method for constructing the animation
        def construct(self):

            self.result = 256
            self.base = 4
            self.intro = "Yes, you got it!"

            super().construct()

class Func_6_3_P_1_c(findLogExpressionAnswerScene):

        # Main method for constructing the animation
        def construct(self):

            self.result = 256
            self.base = 4
            self.intro = "No, that's not right..."

            super().construct()


class Func_6_3_P_1_d(findLogExpressionAnswerScene):

        # Main method for constructing the animation
        def construct(self):

            self.result = 256
            self.base = 4
            self.intro = "No, that's not right..."

            super().construct()


#####################################
#####################################
TASK_Func_6_3_P_2_q = SophiaTaskDefinition(
    answerOptions = ["$x=\log_\frac12{\\frac{1}{16}}$", "$x=\log_{\frac{1}{16}}{\frac12}$", "x=\sqrt[\frac12]{\frac{1}{16}}", "x=\sqrt[25\frac{1}{16}]{\frac12}"],
    correctAnswerIndex = 1,
    questionText = "For what value of x does $\frac12^x=\frac{1}{16}$ hold?"
)

class Func_6_3_P_2_q(findLogExpressionQuestionScene):
    
        # Main method for constructing the animation
        def construct(self):

            self.result = 1/16
            self.base = 1/2
            self.intro = "Another example to practice:"

            super().construct()


class Func_6_3_P_2_a(findLogExpressionAnswerScene):

        # Main method for constructing the animation
        def construct(self):

            self.result = 1/16
            self.base = 1/2
            self.intro = "Yes, you got it!"

            super().construct()

class Func_6_3_P_2_b(findLogExpressionAnswerScene):

        # Main method for constructing the animation
        def construct(self):

            self.result = 1/16
            self.base = 1/2
            self.intro = "No, that's not right..."

            super().construct()

class Func_6_3_P_2_c(findLogExpressionAnswerScene):

        # Main method for constructing the animation
        def construct(self):

            self.result = 1/16
            self.base = 1/2
            self.intro = "No, that's not right..."

            super().construct()


class Func_6_3_P_2_d(findLogExpressionAnswerScene):

        # Main method for constructing the animation
        def construct(self):

            self.result = 256
            self.base = 4
            self.intro = "No, that's not right..."

            super().construct()

PROTOTYPES=[
    PagePrototypeVideo.from_scene(Func_6_3_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_3_I_1_q, Func_6_3_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_3_I_1_a),
    PagePrototypeVideo.from_scene(Func_6_3_I_1_b),
    PagePrototypeVideo.from_scene(Func_6_3_I_1_c),
    PagePrototypeVideo.from_scene(Func_6_3_I_1_d),
    PagePrototypeVideo.from_scene(Func_6_3_I_2),
    PagePrototypeVideo.from_scene(Func_6_3_I_3),
    PagePrototypeVideo.from_scene(Func_6_3_I_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_3_I_4_q, Func_6_3_I_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_3_I_4_a),
    PagePrototypeVideo.from_scene(Func_6_3_I_4_b),
    PagePrototypeVideo.from_scene(Func_6_3_I_4_c),
    PagePrototypeVideo.from_scene(Func_6_3_I_4_d),
    PagePrototypeVideo.from_scene(Func_6_3_I_5),
    PagePrototypeVideo.from_scene(Func_6_3_P_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_3_P_1_q, Func_6_3_P_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_3_P_1_a),
    PagePrototypeVideo.from_scene(Func_6_3_P_1_b),
    PagePrototypeVideo.from_scene(Func_6_3_P_1_c),
    PagePrototypeVideo.from_scene(Func_6_3_P_1_d),
    PagePrototypeVideo.from_scene(Func_6_3_P_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_6_3_P_2_q, Func_6_3_P_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_6_3_P_2_a),
    PagePrototypeVideo.from_scene(Func_6_3_P_2_b),
    PagePrototypeVideo.from_scene(Func_6_3_P_2_c),
    PagePrototypeVideo.from_scene(Func_6_3_P_2_d),
]
scenes/Func/Func_6: Exponential Functions/Func_6_3.py
Sophia-Edu-Labs/sophia-math
# 7_1: Trigonometric Functions: Degrees and Radians

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition

#####################################
#####################################
TASK_Func_7_1_I_1_q = SophiaTaskDefinition(
    answerOptions = ["$90^\circ$", "$180^\circ$", "$270^\circ$", "$360^\circ$"],
    correctAnswerIndex = 2,
    questionText = "How many degrees does this $\\tfrac{3}{4}$ circle have?"
)
class Func_7_1_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Degrees")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0)

        get_arc = lambda: Arc(radius=1, angle=2*PI*a.get_value(), color=BLUE)
        line_start = Line(ORIGIN, get_arc().get_start(), color=BLUE)
        get_line_end = lambda: Line(ORIGIN, get_arc().get_end(), color=BLUE)

        arc = always_redraw(get_arc)
        line_end = always_redraw(get_line_end)
        self.add(arc, line_start, line_end)

        angle = DecimalNumber(0, num_decimal_places=0, color=c1t, font_size=fs2).add_updater(lambda m: m.set_value(a.get_value()*360)).shift(1.6*DOWN)
        deg = MathTex("{^\\circ}", color=c1t, font_size=fs2).next_to(angle, RIGHT, buff=0.4).shift(0.1*UP)
        self.add(angle, deg)

        # Action Sequence
        with self.voiceover(
                text="""
                Whenever two lines meet, we get an angle.
                And the most commonly known method to measure angles is by <bookmark mark="degrees"/>using degrees.

                <bookmark mark="full_circle"/>A full circle has 360 degrees.
                <bookmark mark="half_circle"/>A half circle has 180 degrees.
                <bookmark mark="quarter_circle"/>A quarter circle has 90 degrees.
                And so on...

                How many degrees does <bookmark mark="threequartercircle"/>this angle have,
                which reaches three quarters around the circle?
                """
        ) as tracker:

            # Display the arc initially
            self.play(a.animate.set_value(1))

            self.wait_until_bookmark("degrees")
            x,y,_ = angle.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("full_circle")
            x,y,_ = arc.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(MoveAlongPath(cursor, arc))

            self.wait_until_bookmark("half_circle")
            self.play(a.animate.set_value(0.5), run_time=0.5)
            self.play(MoveAlongPath(cursor, arc))
            x,y,_ = arc.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("quarter_circle")
            self.play(a.animate.set_value(0.25), run_time=0.5)
            self.play(MoveAlongPath(cursor, arc))
            self.play(CursorMoveTo(cursor,0,0))
            cursor.blinking=True

            self.wait_until_bookmark("threequartercircle")
            cursor.blinking=False
            self.play(a.animate.set_value(0.75), run_time=0.5)
            x,y,_ = arc.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(MoveAlongPath(cursor, arc))
            self.play(CursorMoveTo(cursor,0,0))
            cursor.blinking=True

        self.wait(4)


class Func_7_1_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Degrees")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0)

        get_arc = lambda: Arc(radius=1, angle=2*PI*a.get_value(), color=BLUE).shift(UP)
        line_start = Line(UP, get_arc().get_start(), color=BLUE)
        get_line_end = lambda: Line(UP, get_arc().get_end(), color=BLUE)

        arc = always_redraw(get_arc)
        line_end = always_redraw(get_line_end)
        self.add(arc, line_start, line_end)

        three_quarter = Tex("Here: $\\tfrac{3}{4}$ of a full circle", color=c1t, font_size=fs3)
        full_circle = Tex("Full circle: $360^\\circ$", color=c1t, font_size=fs3)
        explanations = VGroup(three_quarter, full_circle).arrange(DOWN, buff=0.2, aligned_edge=LEFT).shift(DOWN*1.2)

        equation = MathTex("\\tfrac{3}{4}", "\\cdot",  "360^\\circ", "=", "270^\\circ", color=c1t, font_size=fs2).shift(2.2*DOWN)

        
        # Action Sequence
        with self.voiceover(
                text="""
                That's wrong, unfortunately.

                We have <bookmark mark="three_quarter"/> three quarters of a circle here.
                And we know that <bookmark mark="full_circle"/>a full circle has 360 degrees.
                So the angle we're looking for is three quarters of 360 degrees.
                So our angle is <bookmark mark="equation_1"/> three quarters <bookmark mark="equation_2"/>
                times 360 degrees, which <bookmark mark="equation_3"/>is 270 degrees.
                """
        ) as tracker:

            # Display the arc initially
            self.play(a.animate.set_value(0.75))

            self.wait_until_bookmark("three_quarter")
            x,y,_ = three_quarter.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), Write(three_quarter), run_time=0.5)

            self.wait_until_bookmark("full_circle")
            x,y,_ = full_circle.get_center()+0.4*DOWN
            self.play(Write(full_circle), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("equation_1")
            x,y, _ = equation[0].get_center()+0.4*DOWN
            self.play(Write(equation[0]), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("equation_2")
            x,y, _ = equation[2].get_center()+0.4*DOWN
            self.play(Write(equation[1]), Write(equation[2]), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("equation_3")
            x,y, _ = equation[4].get_center()+0.4*DOWN
            self.play(Write(equation[3]), Write(equation[4]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)

class Func_7_1_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Degrees")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0)

        get_arc = lambda: Arc(radius=1, angle=2*PI*a.get_value(), color=BLUE).shift(UP)
        line_start = Line(UP, get_arc().get_start(), color=BLUE)
        get_line_end = lambda: Line(UP, get_arc().get_end(), color=BLUE)

        arc = always_redraw(get_arc)
        line_end = always_redraw(get_line_end)
        self.add(arc, line_start, line_end)

        three_quarter = Tex("Here: $\\tfrac{3}{4}$ of a full circle", color=c1t, font_size=fs3)
        full_circle = Tex("Full circle: $360^\\circ$", color=c1t, font_size=fs3)
        explanations = VGroup(three_quarter, full_circle).arrange(DOWN, buff=0.2, aligned_edge=LEFT).shift(DOWN*1.2)

        equation = MathTex("\\tfrac{3}{4}", "\\cdot",  "360^\\circ", "=", "270^\\circ", color=c1t, font_size=fs2).shift(2.2*DOWN)

        
        # Action Sequence
        with self.voiceover(
                text="""
                That's wrong, unfortunately.

                We have <bookmark mark="three_quarter"/> three quarters of a circle here.
                And we know that <bookmark mark="full_circle"/>a full circle has 360 degrees.
                So the angle we're looking for is three quarters of 360 degrees.
                So our angle is <bookmark mark="equation_1"/> three quarters <bookmark mark="equation_2"/>
                times 360 degrees, which <bookmark mark="equation_3"/>is 270 degrees.
                """
        ) as tracker:

            # Display the arc initially
            self.play(a.animate.set_value(0.75))

            self.wait_until_bookmark("three_quarter")
            x,y,_ = three_quarter.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), Write(three_quarter), run_time=0.5)

            self.wait_until_bookmark("full_circle")
            x,y,_ = full_circle.get_center()+0.4*DOWN
            self.play(Write(full_circle), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("equation_1")
            x,y, _ = equation[0].get_center()+0.4*DOWN
            self.play(Write(equation[0]), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("equation_2")
            x,y, _ = equation[2].get_center()+0.4*DOWN
            self.play(Write(equation[1]), Write(equation[2]), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("equation_3")
            x,y, _ = equation[4].get_center()+0.4*DOWN
            self.play(Write(equation[3]), Write(equation[4]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)

class Func_7_1_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Degrees")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0)

        get_arc = lambda: Arc(radius=1, angle=2*PI*a.get_value(), color=BLUE).shift(UP)
        line_start = Line(UP, get_arc().get_start(), color=BLUE)
        get_line_end = lambda: Line(UP, get_arc().get_end(), color=BLUE)

        arc = always_redraw(get_arc)
        line_end = always_redraw(get_line_end)
        self.add(arc, line_start, line_end)

        three_quarter = Tex("Here: $\\tfrac{3}{4}$ of a full circle", color=c1t, font_size=fs3)
        full_circle = Tex("Full circle: $360^\\circ$", color=c1t, font_size=fs3)
        explanations = VGroup(three_quarter, full_circle).arrange(DOWN, buff=0.2, aligned_edge=LEFT).shift(DOWN*1.2)

        equation = MathTex("\\tfrac{3}{4}", "\\cdot",  "360^\\circ", "=", "270^\\circ", color=c1t, font_size=fs2).shift(2.2*DOWN)

        
        # Action Sequence
        with self.voiceover(
                text="""
                That's right, congrats!

                We have <bookmark mark="three_quarter"/> three quarters of a circle here.
                And we know that <bookmark mark="full_circle"/>a full circle has 360 degrees.
                So the angle we're looking for is three quarters of 360 degrees.
                So our angle is <bookmark mark="equation_1"/> three quarters <bookmark mark="equation_2"/>
                times 360 degrees, which <bookmark mark="equation_3"/>is 270 degrees.
                """
        ) as tracker:

            # Display the arc initially
            self.play(a.animate.set_value(0.75))

            self.wait_until_bookmark("three_quarter")
            x,y,_ = three_quarter.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), Write(three_quarter), run_time=0.5)

            self.wait_until_bookmark("full_circle")
            x,y,_ = full_circle.get_center()+0.4*DOWN
            self.play(Write(full_circle), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("equation_1")
            x,y, _ = equation[0].get_center()+0.4*DOWN
            self.play(Write(equation[0]), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("equation_2")
            x,y, _ = equation[2].get_center()+0.4*DOWN
            self.play(Write(equation[1]), Write(equation[2]), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("equation_3")
            x,y, _ = equation[4].get_center()+0.4*DOWN
            self.play(Write(equation[3]), Write(equation[4]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)

class Func_7_1_I_1_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Degrees")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0)

        get_arc = lambda: Arc(radius=1, angle=2*PI*a.get_value(), color=BLUE).shift(UP)
        line_start = Line(UP, get_arc().get_start(), color=BLUE)
        get_line_end = lambda: Line(UP, get_arc().get_end(), color=BLUE)

        arc = always_redraw(get_arc)
        line_end = always_redraw(get_line_end)
        self.add(arc, line_start, line_end)

        three_quarter = Tex("Here: $\\tfrac{3}{4}$ of a full circle", color=c1t, font_size=fs3)
        full_circle = Tex("Full circle: $360^\\circ$", color=c1t, font_size=fs3)
        explanations = VGroup(three_quarter, full_circle).arrange(DOWN, buff=0.2, aligned_edge=LEFT).shift(DOWN*1.2)

        equation = MathTex("\\tfrac{3}{4}", "\\cdot",  "360^\\circ", "=", "270^\\circ", color=c1t, font_size=fs2).shift(2.2*DOWN)

        
        # Action Sequence
        with self.voiceover(
                text="""
                That's wrong, unfortunately.

                We have <bookmark mark="three_quarter"/> three quarters of a circle here.
                And we know that <bookmark mark="full_circle"/>a full circle has 360 degrees.
                So the angle we're looking for is three quarters of 360 degrees.
                So our angle is <bookmark mark="equation_1"/> three quarters <bookmark mark="equation_2"/>
                times 360 degrees, which <bookmark mark="equation_3"/>is 270 degrees.
                """
        ) as tracker:

            # Display the arc initially
            self.play(a.animate.set_value(0.75))

            self.wait_until_bookmark("three_quarter")
            x,y,_ = three_quarter.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), Write(three_quarter), run_time=0.5)

            self.wait_until_bookmark("full_circle")
            x,y,_ = full_circle.get_center()+0.4*DOWN
            self.play(Write(full_circle), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("equation_1")
            x,y, _ = equation[0].get_center()+0.4*DOWN
            self.play(Write(equation[0]), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("equation_2")
            x,y, _ = equation[2].get_center()+0.4*DOWN
            self.play(Write(equation[1]), Write(equation[2]), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("equation_3")
            x,y, _ = equation[4].get_center()+0.4*DOWN
            self.play(Write(equation[3]), Write(equation[4]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
TASK_Func_7_1_I_2_q = SophiaTaskDefinition(
    answerOptions = ["$90^\circ$", "$180^\circ$", "$270^\circ$", "$360^\circ$"],
    correctAnswerIndex = 3,
    questionText = "How many degrees does this $\\tfrac{3}{4}$ circle have?"
)
class Func_7_1_I_2_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Radians")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, y=0.6)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0)

        get_arc = lambda: Arc(radius=1, angle=2*PI*a.get_value(), color=BLUE, fill_color=BLUE).shift(0.6*UP)
        line_start = Line(0.6*UP, get_arc().get_start(), color=BLUE).add_updater(lambda m: m.set_stroke_width(0 if a.get_value() == 1 else 4))
        get_line_end = lambda: Line(0.6*UP, get_arc().get_end(), color=BLUE, stroke_width = 0 if a.get_value() == 1 else 4)

        arc = always_redraw(get_arc)
        line_end = always_redraw(get_line_end)
        self.add(arc, line_start, line_end)

        degrees = Tex("Degrees:", color=c1t, font_size=fs2)
        radians = Tex("Radians:", color=c1t, font_size=fs2)
        measures = VGroup(degrees, radians).arrange(DOWN, buff=0.4, aligned_edge=LEFT).shift(DOWN*1.8+LEFT)
        degrees_val_1 = MathTex("360^\\circ", color=c1t, font_size=fs2)
        radians_val_1 = MathTex("2\\Pi", color=c1t, font_size=fs2)
        values_1 = VGroup(degrees_val_1, radians_val_1).arrange(DOWN, buff=0.4, aligned_edge=LEFT).next_to(measures, RIGHT, buff=0.4)
        degrees_val_2 = MathTex("180^\\circ", color=c1t, font_size=fs2)
        radians_val_2 = MathTex("?", color=c1t, font_size=fs2)
        values_2 = VGroup(degrees_val_2, radians_val_2).arrange(DOWN, buff=0.4, aligned_edge=LEFT).next_to(values_1, RIGHT, buff=0.4)
        full = Tex("Full", color=c1t, font_size=fs2).next_to(degrees_val_1, UP, buff=0.4)
        half = Tex("Half", color=c1t, font_size=fs2).next_to(degrees_val_2, UP, buff=0.4)


        # Action Sequence
        with self.voiceover(
                text="""
                In addition to degrees, there is one more way to describe angles:
                Radians. And just like a full circle <bookmark mark="degrees"/>has 360 degrees,
                in radians the angle of a full circle<bookmark mark="radians"/> is 2 pi.

                Now, knowing that a full circle is 2 pi radians, how many radians
                <bookmark mark="half_circle"/>is a half circle?
                
                A little hint: As mentioned, a <bookmark mark="full_circle_fin"/> full circle has 360 degrees.
                And <bookmark mark="half_circle_fin"/>a half circle has 180 degrees.

                Now we also know that a full circle <bookmark mark="radians_fin"/>is 2 pi radians.
                So <bookmark mark="radians_fin_half"/>how many radians is a half circle?
                """
        ) as tracker:

            # Display the arc initially
            self.play(a.animate.set_value(1), run_time=3)

            self.wait_until_bookmark("degrees")
            x,y,_ = degrees_val_1.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(degrees), Write(degrees_val_1), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("radians")
            cursor.blinking=False
            x,y,_ = radians_val_1.get_center()+0.4*DOWN
            self.play(Write(radians), Write(radians_val_1), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("half_circle")
            cursor.blinking=False
            self.play(a.animate.set_value(0.5), run_time=0.5)
            x,y,_ = arc.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            self.play(MoveAlongPath(cursor, arc))
            self.play(CursorMoveTo(cursor, x, y), run_time=0.2)
            cursor.blinking=True

            self.wait_until_bookmark("full_circle_fin")
            cursor.blinking=False
            x,y,_ = degrees_val_1.get_center()+0.4*DOWN
            self.play(Write(full), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("half_circle_fin")
            cursor.blinking=False
            x,y,_ = degrees_val_2.get_center()+0.4*DOWN
            self.play(Write(half), Write(degrees_val_2), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("radians_fin")
            cursor.blinking=False
            x,y,_ = radians_val_1.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("radians_fin_half")
            cursor.blinking=False
            x,y,_ = radians_val_2.get_center()+0.4*DOWN
            self.play(Write(radians_val_2), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


class Func_7_1_I_2_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Radians")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0.6)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0)


        get_arc = lambda: Arc(radius=1, angle=2*PI*a.get_value(), color=BLUE, fill_color=BLUE).shift(0.6*UP)
        line_start = Line(0.6*UP, get_arc().get_start(), color=BLUE).add_updater(lambda m: m.set_stroke_width(0 if a.get_value() == 1 else 4))
        get_line_end = lambda: Line(0.6*UP, get_arc().get_end(), color=BLUE, stroke_width = 0 if a.get_value() == 1 else 4)

        arc = always_redraw(get_arc)
        line_end = always_redraw(get_line_end)
        self.add(arc, line_start, line_end)

        half = Tex("Here: $\\tfrac{1}{2}$ of a full circle", color=c1t, font_size=fs2)
        full_circle = Tex("Full circle: $2\\Pi$", color=c1t, font_size=fs2)
        explanations = VGroup(half, full_circle).arrange(DOWN, buff=0.2, aligned_edge=LEFT).shift(DOWN*1.2)

        equation = MathTex("\\tfrac{1}{2}", "\\cdot",  "2\\Pi", "=", "\\Pi", color=c1t, font_size=fs2).shift(2.2*DOWN)

        
        # Action Sequence
        with self.voiceover(
                text="""
                That's wrong, unfortunately.

                We're considering <bookmark mark="half"/> a half circle in this example.
                And we know that <bookmark mark="full_circle"/>a full circle has 2 Pi Radians.
                This means that our angle is <bookmark mark="equation_1"/> one half
                <bookmark mark="equation_2"/> times 2 Pi, which
                <bookmark mark="equation_3"/>equals Pi.
                """
        ) as tracker:

            # Display the arc initially
            self.play(a.animate.set_value(0.5))

            self.wait_until_bookmark("half")
            x,y,_ = half.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), Write(half), run_time=0.5)

            self.wait_until_bookmark("full_circle")
            x,y,_ = full_circle.get_center()+0.4*DOWN
            self.play(Write(full_circle), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("equation_1")
            cursor.blinking=False
            x,y, _ = equation[0].get_center()+0.4*DOWN
            self.play(Write(equation[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("equation_2")
            cursor.blinking=False
            x,y, _ = equation[2].get_center()+0.4*DOWN
            self.play(Write(equation[1]), Write(equation[2]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("equation_3")
            cursor.blinking=False
            x,y, _ = equation[4].get_center()+0.4*DOWN
            self.play(Write(equation[3]), Write(equation[4]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


class Func_7_1_I_2_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Radians")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0.6)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0)


        get_arc = lambda: Arc(radius=1, angle=2*PI*a.get_value(), color=BLUE, fill_color=BLUE).shift(0.6*UP)
        line_start = Line(0.6*UP, get_arc().get_start(), color=BLUE).add_updater(lambda m: m.set_stroke_width(0 if a.get_value() == 1 else 4))
        get_line_end = lambda: Line(0.6*UP, get_arc().get_end(), color=BLUE, stroke_width = 0 if a.get_value() == 1 else 4)

        arc = always_redraw(get_arc)
        line_end = always_redraw(get_line_end)
        self.add(arc, line_start, line_end)

        half = Tex("Here: $\\tfrac{1}{2}$ of a full circle", color=c1t, font_size=fs2)
        full_circle = Tex("Full circle: $2\\Pi$", color=c1t, font_size=fs2)
        explanations = VGroup(half, full_circle).arrange(DOWN, buff=0.2, aligned_edge=LEFT).shift(DOWN*1.2)

        equation = MathTex("\\tfrac{1}{2}", "\\cdot",  "2\\Pi", "=", "\\Pi", color=c1t, font_size=fs2).shift(2.2*DOWN)

        
        # Action Sequence
        with self.voiceover(
                text="""
                That's wrong, unfortunately.

                We're considering <bookmark mark="half"/> a half circle in this example.
                And we know that <bookmark mark="full_circle"/>a full circle has 2 Pi Radians.
                This means that our angle is <bookmark mark="equation_1"/> one half
                <bookmark mark="equation_2"/> times 2 Pi, which
                <bookmark mark="equation_3"/>equals Pi.
                """
        ) as tracker:

            # Display the arc initially
            self.play(a.animate.set_value(0.5))

            self.wait_until_bookmark("half")
            x,y,_ = half.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), Write(half), run_time=0.5)

            self.wait_until_bookmark("full_circle")
            x,y,_ = full_circle.get_center()+0.4*DOWN
            self.play(Write(full_circle), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("equation_1")
            cursor.blinking=False
            x,y, _ = equation[0].get_center()+0.4*DOWN
            self.play(Write(equation[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("equation_2")
            cursor.blinking=False
            x,y, _ = equation[2].get_center()+0.4*DOWN
            self.play(Write(equation[1]), Write(equation[2]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("equation_3")
            cursor.blinking=False
            x,y, _ = equation[4].get_center()+0.4*DOWN
            self.play(Write(equation[3]), Write(equation[4]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


class Func_7_1_I_2_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Radians")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0.6)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0)


        get_arc = lambda: Arc(radius=1, angle=2*PI*a.get_value(), color=BLUE, fill_color=BLUE).shift(0.6*UP)
        line_start = Line(0.6*UP, get_arc().get_start(), color=BLUE).add_updater(lambda m: m.set_stroke_width(0 if a.get_value() == 1 else 4))
        get_line_end = lambda: Line(0.6*UP, get_arc().get_end(), color=BLUE, stroke_width = 0 if a.get_value() == 1 else 4)

        arc = always_redraw(get_arc)
        line_end = always_redraw(get_line_end)
        self.add(arc, line_start, line_end)

        half = Tex("Here: $\\tfrac{1}{2}$ of a full circle", color=c1t, font_size=fs2)
        full_circle = Tex("Full circle: $2\\Pi$", color=c1t, font_size=fs2)
        explanations = VGroup(half, full_circle).arrange(DOWN, buff=0.2, aligned_edge=LEFT).shift(DOWN*1.2)

        equation = MathTex("\\tfrac{1}{2}", "\\cdot",  "2\\Pi", "=", "\\Pi", color=c1t, font_size=fs2).shift(2.2*DOWN)

        
        # Action Sequence
        with self.voiceover(
                text="""
                That's wrong, unfortunately.

                We're considering <bookmark mark="half"/> a half circle in this example.
                And we know that <bookmark mark="full_circle"/>a full circle has 2 Pi Radians.
                This means that our angle is <bookmark mark="equation_1"/> one half
                <bookmark mark="equation_2"/> times 2 Pi, which
                <bookmark mark="equation_3"/>equals Pi.
                """
        ) as tracker:

            # Display the arc initially
            self.play(a.animate.set_value(0.5))

            self.wait_until_bookmark("half")
            x,y,_ = half.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), Write(half), run_time=0.5)

            self.wait_until_bookmark("full_circle")
            x,y,_ = full_circle.get_center()+0.4*DOWN
            self.play(Write(full_circle), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("equation_1")
            cursor.blinking=False
            x,y, _ = equation[0].get_center()+0.4*DOWN
            self.play(Write(equation[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("equation_2")
            cursor.blinking=False
            x,y, _ = equation[2].get_center()+0.4*DOWN
            self.play(Write(equation[1]), Write(equation[2]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("equation_3")
            cursor.blinking=False
            x,y, _ = equation[4].get_center()+0.4*DOWN
            self.play(Write(equation[3]), Write(equation[4]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


class Func_7_1_I_2_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Radians")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0.6)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0)


        get_arc = lambda: Arc(radius=1, angle=2*PI*a.get_value(), color=BLUE, fill_color=BLUE).shift(0.6*UP)
        line_start = Line(0.6*UP, get_arc().get_start(), color=BLUE).add_updater(lambda m: m.set_stroke_width(0 if a.get_value() == 1 else 4))
        get_line_end = lambda: Line(0.6*UP, get_arc().get_end(), color=BLUE, stroke_width = 0 if a.get_value() == 1 else 4)

        arc = always_redraw(get_arc)
        line_end = always_redraw(get_line_end)
        self.add(arc, line_start, line_end)

        half = Tex("Here: $\\tfrac{1}{2}$ of a full circle", color=c1t, font_size=fs2)
        full_circle = Tex("Full circle: $2\\Pi$", color=c1t, font_size=fs2)
        explanations = VGroup(half, full_circle).arrange(DOWN, buff=0.2, aligned_edge=LEFT).shift(DOWN*1.2)

        equation = MathTex("\\tfrac{1}{2}", "\\cdot",  "2\\Pi", "=", "\\Pi", color=c1t, font_size=fs2).shift(2.2*DOWN)

        
        # Action Sequence
        with self.voiceover(
                text="""
                That is correct, well done!

                We're considering <bookmark mark="half"/> a half circle in this example.
                And we know that <bookmark mark="full_circle"/>a full circle has 2 Pi Radians.
                This means that our angle is <bookmark mark="equation_1"/> one half
                <bookmark mark="equation_2"/> times 2 Pi, which
                <bookmark mark="equation_3"/>equals Pi.
                """
        ) as tracker:

            # Display the arc initially
            self.play(a.animate.set_value(0.5))

            self.wait_until_bookmark("half")
            x,y,_ = half.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), Write(half), run_time=0.5)

            self.wait_until_bookmark("full_circle")
            x,y,_ = full_circle.get_center()+0.4*DOWN
            self.play(Write(full_circle), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("equation_1")
            cursor.blinking=False
            x,y, _ = equation[0].get_center()+0.4*DOWN
            self.play(Write(equation[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("equation_2")
            cursor.blinking=False
            x,y, _ = equation[2].get_center()+0.4*DOWN
            self.play(Write(equation[1]), Write(equation[2]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("equation_3")
            cursor.blinking=False
            x,y, _ = equation[4].get_center()+0.4*DOWN
            self.play(Write(equation[3]), Write(equation[4]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
class Func_7_1_I_3(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Measuring Angles")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, y=0.6)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0)

        get_arc = lambda: Arc(radius=1, angle=2*PI*a.get_value(), color=BLUE, fill_color=BLUE).shift(0.6*UP)
        line_start = Line(0.6*UP, get_arc().get_start(), color=BLUE).add_updater(lambda m: m.set_stroke_width(0 if a.get_value() == 1 else 4))
        get_line_end = lambda: Line(0.6*UP, get_arc().get_end(), color=BLUE, stroke_width = 0 if a.get_value() == 1 else 4)

        arc = always_redraw(get_arc)
        line_end = always_redraw(get_line_end)
        self.add(arc, line_start, line_end)

        temple = ImageMobject(assets_folder / "img" / "ancient_temple.png")
        temple = temple.scale(4/temple.get_width()).move_to([-5, -2.2, 0])


        # Action Sequence
        with self.voiceover(
                text="""
                Ever wondered why a full <bookmark mark="degrees"/>circle has 360 degrees?
                It seems to be such a random number, doesn't it? Why not 72? Or 420?

                Well, the reason that it is 360 is that it has always been that way.
                <bookmark mark="temple"/>The Babylonians, who lived in the area of today's Iraq,
                used a number system with <bookmark mark="base"/>a base of 60. This means that
                they counted in 60s instead of tens like we do today. And they used this number
                system to measure angles as well. So imagine, to them, 360 was kind of like
                100 is to us today. It was a nice round number that was easy to work with.
                <bookmark mark="degrees_switch"/> There is also a reason why <bookmark mark="rad"/>
                in Radians, a full circle is 2 Pi. And it's not historical, but mathematical.
                <bookmark mark="qmark"/>
                Take a moment and think: Why do we say that a full circle is 2 Pi Radians?
                If you want a hint: Think about the circumference of a circle.
                """
        ) as tracker:

            # Display the arc initially
            self.play(a.animate.set_value(1), run_time=1)

            self.wait_until_bookmark("degrees")
            threesixty = MathTex("360", color=c1t, font_size=fs1).move_to(arc)
            x,y,_ = threesixty.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(Write(threesixty), run_time=0.5)
            qmark = self.draw_qmark(cursor, [0,-2.2,0], run_time=4, apply_waves=0)
            for _ in range(2):
                self.play(ApplyWave(qmark), run_time=2)
            cursor.blinking=True

            self.wait_until_bookmark("temple")
            self.play(FadeOut(qmark), temple.animate.shift(5*RIGHT), run_time=1)

            self.wait_until_bookmark("base")
            x,y,_ = threesixty.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True
            for idx in range(6):
                threesixty_new = MathTex(str((1+idx)*60), color=c1t, font_size=fs1).move_to(threesixty)
                self.play(ReplacementTransform(threesixty, threesixty_new))
                self.wait(0.5 if idx!=0 else 3)
                threesixty = threesixty_new

            self.wait_until_bookmark("degrees_switch")
            self.play(temple.animate.shift(5*RIGHT))

            self.wait_until_bookmark("rad")
            rad = MathTex("2\\Pi", color=c1t, font_size=fs1).move_to(threesixty)
            self.play(ReplacementTransform(threesixty, rad))

            self.wait_until_bookmark("qmark")
            self.draw_qmark(cursor, [0,-2.2,0], run_time=4, apply_waves=0)
            for _ in range(2):
                self.play(ApplyWave(qmark), run_time=2)

        self.wait(4)


#####################################
#####################################
class Func_7_1_I_4(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Measuring Angles")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=False, y=0.6)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)

        get_arc = lambda: Arc(radius=1, angle=2*PI*a.get_value(), color=BLUE, fill_color=BLUE).shift(0.6*UP)
        line_start = Line(0.6*UP, get_arc().get_start(), color=BLUE).add_updater(lambda m: m.set_stroke_width(0 if a.get_value()%1==0 else 4))
        get_line_end = lambda: Line(0.6*UP, get_arc().get_end(), color=BLUE, stroke_width = 0 if a.get_value()%1==0 else 4)

        arc = always_redraw(get_arc)
        line_end = always_redraw(get_line_end)
        self.add(arc, line_start, line_end)

        b = ValueTracker(0)

        get_arc_2 = lambda: Arc(radius=1, angle=2*PI*b.get_value(), color=RED, fill_color=BLUE).shift(0.6*UP)
        line_start_2 = Line(0.6*UP, get_arc_2().get_start(), color=RED).add_updater(lambda m: m.set_stroke_width(0 if b.get_value()==1 else 4))
        get_line_end_2 = lambda: Line(0.6*UP, get_arc_2().get_end(), color=RED, stroke_width = 0 if b.get_value()==1 else 4)

        arc_2 = always_redraw(get_arc_2)
        line_end_2 = always_redraw(get_line_end_2)
        circ = MathTex("C", "=", "2", "\\cdot", "\\Pi", "\\cdot", "r", color=c1t, font_size=fs1).next_to(arc, DOWN, buff=0.6)

        unit_line = Line(0.6*UP, arc.get_end(), color=c1t, stroke_width=4)
        unit_label = MathTex("1", color=c1t, font_size=fs3).next_to(unit_line, DOWN, buff=0.2)

        # Action Sequence
        with self.voiceover(
                text="""
                Here it goes:
                Recall the formula <bookmark mark="around"/>for the circumference of a circle:
                The <bookmark mark="circ_1"/> circumference c of a circle is equal <bookmark mark="two"/>
                to 2 <bookmark mark="pi"/> times Pie times <bookmark mark="r"/>the radius r of the circle.

                If we look at the unit circle,<bookmark mark="unit"/> which is a circle with the radius
                of 1, we can see that the circumference of the unit circle is <bookmark mark="two_pi"/>
                simply equal to two times Pie.

                So in the unit circle, the angle in radians is <bookmark mark="rad_1"/> equal to
                the circumference of the unit circle.

                <bookmark mark="red_circle"/> And this holds true for other angles as well: A quarter
                of the unit circle has both a circumference and an angle of 0.5 Pie. <bookmark mark="half"/>
                And a half of the unit circle has both a circumference and an angle of Pie.
                """
        ) as tracker:

            self.wait_until_bookmark("around")
            x,y,_ = arc.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.play(MoveAlongPath(cursor, arc))
            cursor.blinking=True

            self.wait_until_bookmark("circ_1")
            x,y,_ = circ[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(circ[0]), Write(circ[1]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("two")
            cursor.blinking=False
            x,y,_ = circ[2].get_center()+0.4*DOWN
            self.play(Write(circ[2]), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("pi")
            x,y,_ = circ[4].get_center()+0.4*DOWN
            self.play(Write(circ[3]), Write(circ[4]), CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("r")
            x,y,_ = circ[6].get_center()+0.4*DOWN
            self.play(Write(circ[5]), Write(circ[6]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("unit")
            cursor.blinking=False
            x,y,_ = unit_line.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor_updater = lambda m: m.move_to(unit_line.get_end())
            cursor.add_updater(cursor_updater)
            self.play(Create(unit_line), Write(unit_label))
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("two_pi")
            cursor.blinking=False
            x,y,_ = circ[4].get_center()+0.4*DOWN
            self.play(circ.animate.shift(0.3*RIGHT), Unwrite(circ[5]), Unwrite(circ[6]), CursorMoveTo(cursor, x, y))
            cursor.blinking=True

            self.wait_until_bookmark("rad_1")
            dec = DecimalNumber(2, num_decimal_places=1, font_size=fs1).set_color(c1t).move_to(circ[2].get_right())
            pi_dec = MathTex("\\Pi", color=c1t, font_size=fs1).move_to(circ[4])
            self.play(ReplacementTransform(circ[2], dec), ReplacementTransform(circ[4], pi_dec), Unwrite(circ[0]), Unwrite(circ[1]), Unwrite(circ[3]))
            circumference = VGroup(dec, pi_dec)
            self.play(circumference.animate.shift(circumference.get_x()*LEFT), run_time=0.3)

            self.wait_until_bookmark("red_circle")
            self.add(arc_2, line_start_2, line_end_2)
            x,y,_ = arc_2.get_start()
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), Unwrite(unit_line), Unwrite(unit_label), run_time=0.5)
            cursor.add_updater(lambda m: m.move_to(arc_2.get_end()))
            dec.add_updater(lambda m: m.set_value(b.get_value()*2))
            self.play(b.animate.set_value(0.25))
            cursor.blinking=True

            self.wait_until_bookmark("half")
            cursor.blinking=False
            self.play(b.animate.set_value(0.5))
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
######## Practice Part ##############
#####################################
#####################################

#####################################
#####################################
######## General Qs #################
#####################################
#####################################
class DegToRadQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Measuring Angles")

        deg = int(self.angle_frac*360)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=False, y=0.6)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        circ =  Arc(radius=1, angle=2*PI, color=BLUE, fill_color=BLUE).shift(0.6*UP)
        self.add(circ)

        b = ValueTracker(0)

        get_arc_2 = lambda: Arc(radius=1, angle=2*PI*b.get_value(), color=self.color, fill_color=BLUE).shift(0.6*UP)
        line_start_2 = Line(0.6*UP, get_arc_2().get_start(), color=self.color).add_updater(lambda m: m.set_stroke_width(0 if b.get_value()==1 else 4))
        get_line_end_2 = lambda: Line(0.6*UP, get_arc_2().get_end(), color=self.color, stroke_width = 0 if b.get_value()==1 else 4)

        arc_2 = always_redraw(get_arc_2)
        line_end_2 = always_redraw(get_line_end_2)
        
        label_deg = Tex("Degrees: ", f"${deg}$", "$^\\circ$", color=c1t, font_size=fs1)
        label_rad = Tex("Radians: ", "  ?", color=c1t, font_size=fs1)
        labels = VGroup(label_deg, label_rad).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(circ, DOWN, buff=0.6)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro} <bookmark mark="red_circle"/> {self.color_string} circle. Measured in Degrees, it <bookmark mark="degrees"/>
                has an angle of {deg} degrees.
                What is the equivalent angle, when we <bookmark mark="rad"/>describe it in Radians, instead of Degrees?
                """
        ) as tracker:


            self.wait_until_bookmark("red_circle")
            self.add(arc_2, line_start_2, line_end_2)
            x,y,_ = arc_2.get_start()
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor_updater = lambda m: m.move_to(arc_2.get_end())
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(self.angle_frac))
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("degrees")
            x,y,_ = label_deg[1].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(label_deg), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("rad")
            x,y,_ = label_rad[1].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(label_rad), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

        self.wait(4)


class DegToRadAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Measuring Angles")

        deg = int(self.angle_frac*360)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=False, y=0.6)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        circ =  Arc(radius=1, angle=2*PI, color=BLUE, fill_color=BLUE).shift(0.6*UP)
        self.add(circ)

        b = ValueTracker(0)

        get_arc_2 = lambda: Arc(radius=1, angle=2*PI*b.get_value(), color=self.color, fill_color=BLUE).shift(0.6*UP)
        line_start_2 = Line(0.6*UP, get_arc_2().get_start(), color=self.color).add_updater(lambda m: m.set_stroke_width(0 if b.get_value()==1 else 4))
        get_line_end_2 = lambda: Line(0.6*UP, get_arc_2().get_end(), color=self.color, stroke_width = 0 if b.get_value()==1 else 4)

        arc_2 = always_redraw(get_arc_2)
        line_end_2 = always_redraw(get_line_end_2)
        
        label_deg = Tex("Degrees: ", f"${deg}$", "$^\\circ$", color=c1t, font_size=fs1).next_to(circ, DOWN, buff=0.6)
        eq = MathTex(f"{self.angle_frac_tex}", "\\cdot", "2\\Pi", "=", f"{2*self.angle_frac}\\Pi", color=c1t, font_size=fs1).next_to(label_deg, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro} The <bookmark mark="red_circle"/> angle of the {self.color_string} circle is <bookmark mark="degrees"/>
                {deg} degrees, which is {self.angle_frac_string} of a full circle.

                So the angle in Radians is also {self.angle_frac_string} of a full circle, which <bookmark mark="eq_1"/>
                is {self.angle_frac_string} <bookmark mark="eq_2"/> times 2 Pi, which <bookmark mark="eq_3"/> equals
                {self.angle_rad_string}Pi Radians.
                """
        ) as tracker:


            self.wait_until_bookmark("red_circle")
            self.add(arc_2, line_start_2, line_end_2)
            x,y,_ = arc_2.get_start()
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor_updater = lambda m: m.move_to(arc_2.get_end())
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(self.angle_frac))
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("degrees")
            x,y,_ = label_deg[1].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(label_deg), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("eq_1")
            cursor.blinking=False
            x,y,_ = eq[0].get_center()+0.4*DOWN
            self.play(Write(eq[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("eq_2")
            cursor.blinking=False
            x,y,_ = eq[2].get_center()+0.4*DOWN
            self.play(Write(eq[1]), Write(eq[2]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("eq_3")
            cursor.blinking=False
            x,y,_ = eq[4].get_center()+0.4*DOWN
            self.play(Write(eq[3]), Write(eq[4]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
class RadToDegQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Measuring Angles")

        deg = int(self.angle_frac*360)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=False, y=0.6)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        circ =  Arc(radius=1, angle=2*PI, color=BLUE, fill_color=BLUE).shift(0.6*UP)
        self.add(circ)

        b = ValueTracker(0)

        get_arc_2 = lambda: Arc(radius=1, angle=2*PI*b.get_value(), color=self.color, fill_color=BLUE).shift(0.6*UP)
        line_start_2 = Line(0.6*UP, get_arc_2().get_start(), color=self.color).add_updater(lambda m: m.set_stroke_width(0 if b.get_value()==1 else 4))
        get_line_end_2 = lambda: Line(0.6*UP, get_arc_2().get_end(), color=self.color, stroke_width = 0 if b.get_value()==1 else 4)

        arc_2 = always_redraw(get_arc_2)
        line_end_2 = always_redraw(get_line_end_2)
        
        label_rad = Tex("Radians: ", f"${2*self.angle_frac}\\Pi$", color=c1t, font_size=fs1)
        label_deg = Tex("Degrees: ", "$?^\\circ$", color=c1t, font_size=fs1)
        labels = VGroup(label_rad, label_deg).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(circ, DOWN, buff=0.6)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro} <bookmark mark="red_circle"/> {self.color_string} circle. Measured in Radians, it <bookmark mark="rad"/>
                has an angle of {self.angle_rad_string} Pi.
                What is the equivalent angle, when we <bookmark mark="degrees"/>describe it in Degrees, instead of Radians?
                """
        ) as tracker:


            self.wait_until_bookmark("red_circle")
            self.add(arc_2, line_start_2, line_end_2)
            x,y,_ = arc_2.get_start()
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor_updater = lambda m: m.move_to(arc_2.get_end())
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(self.angle_frac))
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("rad")
            x,y,_ = label_rad[1].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(label_rad), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("degrees")
            x,y,_ = label_deg[1].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(label_deg), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True

        self.wait(4)


class RadToDegAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    # Main method for constructing the animation
    @abstractmethod
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Measuring Angles")

        deg = int(self.angle_frac*360)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=False, y=0.6)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        circ =  Arc(radius=1, angle=2*PI, color=BLUE, fill_color=BLUE).shift(0.6*UP)
        self.add(circ)

        b = ValueTracker(0)

        get_arc_2 = lambda: Arc(radius=1, angle=2*PI*b.get_value(), color=self.color, fill_color=BLUE).shift(0.6*UP)
        line_start_2 = Line(0.6*UP, get_arc_2().get_start(), color=self.color).add_updater(lambda m: m.set_stroke_width(0 if b.get_value()==1 else 4))
        get_line_end_2 = lambda: Line(0.6*UP, get_arc_2().get_end(), color=self.color, stroke_width = 0 if b.get_value()==1 else 4)

        arc_2 = always_redraw(get_arc_2)
        line_end_2 = always_redraw(get_line_end_2)
        
        label_rad = Tex("Radians: ", f"${2*self.angle_frac}\\Pi$", color=c1t, font_size=fs1).next_to(circ, DOWN, buff=0.6)
        eq = MathTex(f"{self.angle_frac_tex}", "\\cdot", "360^\\circ", "=", f"{360*self.angle_frac}^\\circ", color=c1t, font_size=fs1).next_to(label_rad, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro} The <bookmark mark="red_circle"/> angle of the {self.color_string} circle is <bookmark mark="radians"/>
                {self.angle_rad_string} Pi, which is {self.angle_frac_string} of a full circle.

                So the angle in Degrees is also {self.angle_frac_string} of a full circle, which <bookmark mark="eq_1"/>
                is {self.angle_frac_string} <bookmark mark="eq_2"/> times 360 Degrees, which <bookmark mark="eq_3"/> equals
                {deg}degrees.
                """
        ) as tracker:


            self.wait_until_bookmark("red_circle")
            self.add(arc_2, line_start_2, line_end_2)
            x,y,_ = arc_2.get_start()
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor_updater = lambda m: m.move_to(arc_2.get_end())
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(self.angle_frac))
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("radians")
            x,y,_ = label_rad[1].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(label_rad), CursorMoveTo(cursor, x, y), run_time=1)
            cursor.blinking=True
            
            self.wait_until_bookmark("eq_1")
            cursor.blinking=False
            x,y,_ = eq[0].get_center()+0.4*DOWN
            self.play(Write(eq[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("eq_2")
            cursor.blinking=False
            x,y,_ = eq[2].get_center()+0.4*DOWN
            self.play(Write(eq[1]), Write(eq[2]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("eq_3")
            cursor.blinking=False
            x,y,_ = eq[4].get_center()+0.4*DOWN
            self.play(Write(eq[3]), Write(eq[4]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
######## Specific Qs ################
#####################################
#####################################
TASK_Func_7_1_P_1_q = SophiaTaskDefinition(
    answerOptions = ["$2\\Pi$", "$90\Pi$", "$\\frac{1}{2}\Pi$", "$\\frac{1}{4}\Pi$"],
    correctAnswerIndex = 2,
    questionText = f"What angle in Radians corresponds to $90^\circ$?"
)
class Func_7_1_P_1_q(DegToRadQuestionScene):

    def construct(self):
        
        self.intro = "Look at the"
        self.angle_frac = 1/4
        self.angle_frac_tex = "\\tfrac{1}{4}"
        self.angle_frac_string = "one quarter"
        self.angle_rad_string = "one half"
        self.color_string = "purple"
        self.color = PURPLE

        super().construct()


class Func_7_1_P_1_a(DegToRadAnswerScene):

    def construct(self):
        
        self.intro = "That's not it..."
        self.angle_frac = 1/4
        self.angle_frac_tex = "\\tfrac{1}{4}"
        self.angle_frac_string = "one quarter"
        self.angle_rad_string = "one half"
        self.color_string = "purple"
        self.color = PURPLE

        super().construct()


class Func_7_1_P_1_b(DegToRadAnswerScene):

    def construct(self):
        
        self.intro = "That's not it..."
        self.angle_frac = 1/4
        self.angle_frac_tex = "\\tfrac{1}{4}"
        self.angle_frac_string = "one quarter"
        self.angle_rad_string = "one half"
        self.color_string = "purple"
        self.color = PURPLE

        super().construct()


class Func_7_1_P_1_c(DegToRadAnswerScene):

    def construct(self):
        
        self.intro = "That's correct, well done."
        self.angle_frac = 1/4
        self.angle_frac_tex = "\\tfrac{1}{4}"
        self.angle_frac_string = "one quarter"
        self.angle_rad_string = "one half"
        self.color_string = "purple"
        self.color = PURPLE

        super().construct()


class Func_7_1_P_1_d(DegToRadAnswerScene):

    def construct(self):
        
        self.intro = "That's not it..."
        self.angle_frac = 1/4
        self.angle_frac_tex = "\\tfrac{1}{4}"
        self.angle_frac_string = "one quarter"
        self.angle_rad_string = "one half"
        self.color_string = "purple"
        self.color = PURPLE

        super().construct()
        

#####################################
#####################################
TASK_Func_7_1_P_2_q = SophiaTaskDefinition(
    answerOptions = ["$90^\circ$", "$180^\circ$", "$270^\circ$", "$360^\circ$"],
    correctAnswerIndex = 0,
    questionText = "What angle in degrees corresponds to $\tfrac{\Pi}{2}$?"
)
class Func_7_1_P_2_q(RadToDegQuestionScene):

    def construct(self):
        
        self.intro = "Look at the"
        self.angle_frac = 1/4
        self.angle_frac_tex = "\\tfrac{1}{4}"
        self.angle_frac_string = "one quarter"
        self.angle_rad_string = "one half"
        self.color_string = "green"
        self.color = GREEN

        super().construct()



class Func_7_1_P_2_a(RadToDegAnswerScene):

    def construct(self):

        self.intro = "That's correct, well done."
        self.angle_frac = 1/4
        self.angle_frac_tex = "\\tfrac{1}{4}"
        self.angle_frac_string = "one quarter"
        self.angle_rad_string = "one half"
        self.color_string = "green"
        self.color = GREEN

        super().construct()


class Func_7_1_P_2_b(RadToDegAnswerScene):

    def construct(self):

        self.intro = "No, that's not right."
        self.angle_frac = 1/4
        self.angle_frac_tex = "\\tfrac{1}{4}"
        self.angle_frac_string = "one quarter"
        self.angle_rad_string = "one half"
        self.color_string = "green"
        self.color = GREEN

        super().construct()


class Func_7_1_P_2_c(RadToDegAnswerScene):

    def construct(self):

        self.intro = "No, that's not right."
        self.angle_frac = 1/4
        self.angle_frac_tex = "\\tfrac{1}{4}"
        self.angle_frac_string = "one quarter"
        self.angle_rad_string = "one half"
        self.color_string = "green"
        self.color = GREEN

        super().construct()


class Func_7_1_P_2_d(RadToDegAnswerScene):

    def construct(self):

        self.intro = "No, that's not right."
        self.angle_frac = 1/4
        self.angle_frac_tex = "\\tfrac{1}{4}"
        self.angle_frac_string = "one quarter"
        self.angle_rad_string = "one half"
        self.color_string = "green"
        self.color = GREEN

        super().construct()


#####################################
#####################################
TASK_Func_7_1_P_3_q = SophiaTaskDefinition(
    answerOptions = ["$90^\circ$", "$180^\circ$", "$270^\circ$", "$360^\circ$"],
    correctAnswerIndex = 2,
    questionText = "What angle in degrees corresponds to $\tfrac{3\Pi}{2}$?"
)
class Func_7_1_P_3_q(RadToDegQuestionScene):

    def construct(self):
        
        self.intro = "Look at the"
        self.angle_frac = 3/4
        self.angle_frac_tex = "\\tfrac{3}{4}"
        self.angle_frac_string = "three quarter"
        self.angle_rad_string = "one and a half"
        self.color_string = "orange"
        self.color = ORANGE

        super().construct()



class Func_7_1_P_3_a(RadToDegAnswerScene):

    def construct(self):

        self.intro = "No, that's not it."
        self.angle_frac = 3/4
        self.angle_frac_tex = "\\tfrac{3}{4}"
        self.angle_frac_string = "three quarter"
        self.angle_rad_string = "one and a half"
        self.color_string = "orange"
        self.color = ORANGE

        super().construct()


class Func_7_1_P_3_b(RadToDegAnswerScene):

    def construct(self):

        self.intro = "No, that's not it."
        self.angle_frac = 3/4
        self.angle_frac_tex = "\\tfrac{3}{4}"
        self.angle_frac_string = "three quarter"
        self.angle_rad_string = "one and a half"
        self.color_string = "orange"
        self.color = ORANGE

        super().construct()


class Func_7_1_P_3_c(RadToDegAnswerScene):

    def construct(self):

        self.intro = "Yep, you got it."
        self.angle_frac = 3/4
        self.angle_frac_tex = "\\tfrac{3}{4}"
        self.angle_frac_string = "three quarter"
        self.angle_rad_string = "one and a half"
        self.color_string = "orange"
        self.color = ORANGE

        super().construct()


class Func_7_1_P_3_d(RadToDegAnswerScene):

    def construct(self):

        self.intro = "No, that's not it."
        self.angle_frac = 3/4
        self.angle_frac_tex = "\\tfrac{3}{4}"
        self.angle_frac_string = "three quarter"
        self.angle_rad_string = "one and a half"
        self.color_string = "orange"
        self.color = ORANGE

        super().construct()


#####################################
#####################################
TASK_Func_7_1_P_4_q = SophiaTaskDefinition(
    answerOptions = ["$2\Pi$", "$\\frac{1}{4}\Pi$", "$\\frac{1}{2}\Pi$", "$\Pi$"],
    correctAnswerIndex = 1,
    questionText = f"What angle in Radians corresponds to $45^\circ$?"
)
class Func_7_1_P_4_q(DegToRadQuestionScene):

    def construct(self):
        
        self.intro = "Check out the"
        self.angle_frac = 1/8
        self.angle_frac_tex = "\\tfrac{1}{8}"
        self.angle_frac_string = "one eigth"
        self.angle_rad_string = "one quarter"
        self.color_string = "pink"
        self.color = PINK

        super().construct()


class Func_7_1_P_4_a(DegToRadAnswerScene):

    def construct(self):
        
        self.intro = "Yes, that's right."
        self.angle_frac = 1/8
        self.angle_frac_tex = "\\tfrac{1}{8}"
        self.angle_frac_string = "one eigth"
        self.angle_rad_string = "one quarter"
        self.color_string = "pink"
        self.color = PINK


        super().construct()

class Func_7_1_P_4_b(DegToRadAnswerScene):

    def construct(self):
        
        self.intro = "No, that's not it."
        self.angle_frac = 1/8
        self.angle_frac_tex = "\\tfrac{1}{8}"
        self.angle_frac_string = "one eigth"
        self.angle_rad_string = "one quarter"
        self.color_string = "pink"
        self.color = PINK


        super().construct()

class Func_7_1_P_4_c(DegToRadAnswerScene):

    def construct(self):
        
        self.intro = "No, that's not it."
        self.angle_frac = 1/8
        self.angle_frac_tex = "\\tfrac{1}{8}"
        self.angle_frac_string = "one eigth"
        self.angle_rad_string = "one quarter"
        self.color_string = "pink"
        self.color = PINK


        super().construct()

class Func_7_1_P_4_d(DegToRadAnswerScene):

    def construct(self):
        
        self.intro = "No, that's not it."
        self.angle_frac = 1/8
        self.angle_frac_tex = "\\tfrac{1}{8}"
        self.angle_frac_string = "one eigth"
        self.angle_rad_string = "one quarter"
        self.color_string = "pink"
        self.color = PINK


        super().construct()

PROTOTYPES=[
    PagePrototypeVideo.from_scene(Func_7_1_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_1_I_1_q, Func_7_1_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_1_I_1_a),
    PagePrototypeVideo.from_scene(Func_7_1_I_1_b),
    PagePrototypeVideo.from_scene(Func_7_1_I_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_1_I_2_q, Func_7_1_I_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_1_I_2_a),
    PagePrototypeVideo.from_scene(Func_7_1_I_2_b),
    PagePrototypeVideo.from_scene(Func_7_1_I_2_c),
    PagePrototypeVideo.from_scene(Func_7_1_I_2_d),
    PagePrototypeVideo.from_scene(Func_7_1_I_3),
    PagePrototypeVideo.from_scene(Func_7_1_I_4),
    PagePrototypeVideo.from_scene(Func_7_1_P_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_1_P_1_q, Func_7_1_P_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_1_P_1_a),
    PagePrototypeVideo.from_scene(Func_7_1_P_1_b),
    PagePrototypeVideo.from_scene(Func_7_1_P_1_c),
    PagePrototypeVideo.from_scene(Func_7_1_P_1_d),
    PagePrototypeVideo.from_scene(Func_7_1_P_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_1_P_2_q, Func_7_1_P_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_1_P_2_a),
    PagePrototypeVideo.from_scene(Func_7_1_P_2_b),
    PagePrototypeVideo.from_scene(Func_7_1_P_2_c),
    PagePrototypeVideo.from_scene(Func_7_1_P_2_d),
    PagePrototypeVideo.from_scene(Func_7_1_P_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_1_P_3_q, Func_7_1_P_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_1_P_3_a),
    PagePrototypeVideo.from_scene(Func_7_1_P_3_b),
    PagePrototypeVideo.from_scene(Func_7_1_P_3_c),
    PagePrototypeVideo.from_scene(Func_7_1_P_3_d),
    PagePrototypeVideo.from_scene(Func_7_1_P_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_1_P_4_q, Func_7_1_P_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_1_P_4_a),
    PagePrototypeVideo.from_scene(Func_7_1_P_4_b),
    PagePrototypeVideo.from_scene(Func_7_1_P_4_c),
    PagePrototypeVideo.from_scene(Func_7_1_P_4_d),
]

scenes/Func/Func_7: Sine and Cosine Functions/Func_7_1.py
Sophia-Edu-Labs/sophia-math
# 7_2: Trigonometric Functions: Intro (Sine)

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition

#####################################
#####################################
TASK_Func_7_2_I_1_q = SophiaTaskDefinition(
    answerOptions = ["blue line / green line", "pink line / blue line", "pink line / green line", "green line / pink line"],
    correctAnswerIndex = 1,
    questionText = "Which of the lines do we have two divide by which to get the sine of the bottom left corner?"
)
class Func_7_2_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = lambda: Arc(radius=1, angle=2*PI, color=BLUE)
        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end).shift(0.7*LEFT+0.2*UP)
        

        # Action Sequence
        with self.voiceover(
                text="""
                Check out<bookmark mark="show_triangle"/> this beautiful triangle.

                You know what's just as beautiful? <bookmark mark="sine"/> The sine function. Well, at least
                once you really understand it.

                Let's start slowly though. Which line do we divide by which other line,
                to get the sine of the angle <bookmark mark="angle"/>in the bottom
                left corner?
                """
        ) as tracker:

            self.wait_until_bookmark("show_triangle")
            self.play(Create(triangle))

            self.wait_until_bookmark("sine")
            x,y,_ = title.get_center()-np.array([1.2,.4,0])
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("angle")
            cursor.blinking=False
            self.play(CursorMoveToCurved(cursor, -0.8, 0.1))
            cursor.blinking=True

        self.wait(4)


class Func_7_2_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = lambda: Arc(radius=1, angle=2*PI, color=BLUE)
        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end).shift(0.7*LEFT+0.2*UP)
        self.add(triangle)

        sine_formula = MathTex("\\sin(\\alpha) =", "\\frac{\\text{opposite}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(triangle, DOWN, buff=0.8)
        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                The sine is equal to <bookmark mark="opposite"/> the length of the opposite divided <bookmark mark="hypothenuse"/>
                by the length of the hypothenuse.

                The opposite is the side opposite to the angle. In this case,<bookmark mark="opposite_plot"/> it's the pink line.
                The hypothenuse is the longest side of a triangle. In this case,<bookmark mark="hypothenuse_plot"/> it's the blue line.
                This means, that we have to divide the pink line by the blue line to get the sine of the angle in the bottom left
                corner.
                """
        ) as tracker:
            
            x,y,_ = sine_formula[0].get_center()+0.4*DOWN+0.2*LEFT
            cursor.blinking=False
            self.play(Write(sine_formula[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("opposite")
            cursor.blinking=False
            x,y,_ = sine_formula[1].get_right()+0.2*RIGHT+0.2*UP
            self.play(Write(sine_formula[1]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse")
            cursor.blinking=False
            x,y,_ = sine_formula[1].get_right()+0.2*RIGHT+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("opposite_plot")
            cursor.blinking=False
            x,y,_ = line_sine.get_center()+0.2*RIGHT
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse_plot")
            cursor.blinking=False
            x,y,_ = line_end.get_center()+0.2*(LEFT+UP)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)

class Func_7_2_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = lambda: Arc(radius=1, angle=2*PI, color=BLUE)
        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end).shift(0.7*LEFT+0.2*UP)
        self.add(triangle)

        sine_formula = MathTex("\\sin(\\alpha) =", "\\frac{\\text{opposite}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(triangle, DOWN, buff=0.8)
        

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's correct.
                The sine is equal to <bookmark mark="opposite"/> the length of the opposite divided <bookmark mark="hypothenuse"/>
                by the length of the hypothenuse.

                The opposite is the side opposite to the angle. In this case,<bookmark mark="opposite_plot"/> it's the pink line.
                The hypothenuse is the longest side of a triangle. In this case,<bookmark mark="hypothenuse_plot"/> it's the blue line.
                This means, that we have to divide the pink line by the blue line to get the sine of the angle in the bottom left
                corner.
                """
        ) as tracker:
            
            x,y,_ = sine_formula[0].get_center()+0.4*DOWN+0.2*LEFT
            cursor.blinking=False
            self.play(Write(sine_formula[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("opposite")
            cursor.blinking=False
            x,y,_ = sine_formula[1].get_right()+0.2*RIGHT+0.2*UP
            self.play(Write(sine_formula[1]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse")
            cursor.blinking=False
            x,y,_ = sine_formula[1].get_right()+0.2*RIGHT+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("opposite_plot")
            cursor.blinking=False
            x,y,_ = line_sine.get_center()+0.2*RIGHT
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse_plot")
            cursor.blinking=False
            x,y,_ = line_end.get_center()+0.2*(LEFT+UP)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


class Func_7_2_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = lambda: Arc(radius=1, angle=2*PI, color=BLUE)
        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end).shift(0.7*LEFT+0.2*UP)
        self.add(triangle)

        sine_formula = MathTex("\\sin(\\alpha) =", "\\frac{\\text{opposite}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(triangle, DOWN, buff=0.8)
        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                The sine is equal to <bookmark mark="opposite"/> the length of the opposite divided <bookmark mark="hypothenuse"/>
                by the length of the hypothenuse.

                The opposite is the side opposite to the angle. In this case,<bookmark mark="opposite_plot"/> it's the pink line.
                The hypothenuse is the longest side of a triangle. In this case,<bookmark mark="hypothenuse_plot"/> it's the blue line.
                This means, that we have to divide the pink line by the blue line to get the sine of the angle in the bottom left
                corner.
                """
        ) as tracker:
            
            x,y,_ = sine_formula[0].get_center()+0.4*DOWN+0.2*LEFT
            cursor.blinking=False
            self.play(Write(sine_formula[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("opposite")
            cursor.blinking=False
            x,y,_ = sine_formula[1].get_right()+0.2*RIGHT+0.2*UP
            self.play(Write(sine_formula[1]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse")
            cursor.blinking=False
            x,y,_ = sine_formula[1].get_right()+0.2*RIGHT+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("opposite_plot")
            cursor.blinking=False
            x,y,_ = line_sine.get_center()+0.2*RIGHT
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse_plot")
            cursor.blinking=False
            x,y,_ = line_end.get_center()+0.2*(LEFT+UP)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


class Func_7_2_I_1_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = lambda: Arc(radius=1, angle=2*PI, color=BLUE)
        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end).shift(0.7*LEFT+0.2*UP)
        self.add(triangle)

        sine_formula = MathTex("\\sin(\\alpha) =", "\\frac{\\text{opposite}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(triangle, DOWN, buff=0.8)
        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                The sine is equal to <bookmark mark="opposite"/> the length of the opposite divided <bookmark mark="hypothenuse"/>
                by the length of the hypothenuse.

                The opposite is the side opposite to the angle. In this case,<bookmark mark="opposite_plot"/> it's the pink line.
                The hypothenuse is the longest side of a triangle. In this case,<bookmark mark="hypothenuse_plot"/> it's the blue line.
                This means, that we have to divide the pink line by the blue line to get the sine of the angle in the bottom left
                corner.
                """
        ) as tracker:
            
            x,y,_ = sine_formula[0].get_center()+0.4*DOWN+0.2*LEFT
            cursor.blinking=False
            self.play(Write(sine_formula[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("opposite")
            cursor.blinking=False
            x,y,_ = sine_formula[1].get_right()+0.2*RIGHT+0.2*UP
            self.play(Write(sine_formula[1]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse")
            cursor.blinking=False
            x,y,_ = sine_formula[1].get_right()+0.2*RIGHT+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("opposite_plot")
            cursor.blinking=False
            x,y,_ = line_sine.get_center()+0.2*RIGHT
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse_plot")
            cursor.blinking=False
            x,y,_ = line_end.get_center()+0.2*(LEFT+UP)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
TASK_Func_7_2_I_2_q = SophiaTaskDefinition(
    answerOptions = ["It has the length $\cos(1)$","It has length $\sin(1)$""It has length $\sqrt{2}$","It has length $1$"],
    correctAnswerIndex = 3,
    questionText = "What can we say about the hypothenuse (the blue line) for the inscribed triangle?"
)
class Func_7_2_I_2_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = lambda: Arc(radius=1.4, angle=2*PI, color=BLUE)
        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)
        triangle = VGroup(line_cos, line_sine, line_end).shift(0.7*LEFT+0.2*UP)
        self.add(triangle)

        sine_formula = MathTex("\\sin(\\alpha) =", "\\frac{\\text{opposite}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(triangle, DOWN, buff=0.8)
        self.add(sine_formula)

        # Action Sequence
        with self.voiceover(
                text="""
                Now what if we <bookmark mark="circle"/>inscribe the triangle into a circle, with the radius of one?
                If the top left corner is in the center of the circle, what can we say
                about <bookmark mark="hypothenuse"/> the hypothenuse, meaning the blue line?
                """
        ) as tracker:
            
            self.play(triangle.animate.shift(0.7*RIGHT+0.2*DOWN), sine_formula.animate.shift(DOWN))
            line_cos.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
            line_sine.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
            line_end.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))

            self.wait_until_bookmark("circle")
            self.play(Create(arc()))

            self.wait_until_bookmark("hypothenuse")
            x,y,_ = line_end.get_center()+0.1*(LEFT+UP)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


class Func_7_2_I_2_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = Arc(radius=1.4, angle=2*PI, color=BLUE)
        self.add(arc)

        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)
        triangle = VGroup(line_cos, line_sine, line_end)
        self.add(triangle)

        sine_formula = MathTex("\\sin(\\alpha) =", "\\frac{\\text{opposite}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(arc, DOWN, buff=0.6)
        self.add(sine_formula)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                The blue line goes <bookmark mark="center"/>from the center of the circle to the
                edge<bookmark mark="circle"/> of the circle. Since the radius of the circle is one, the length of the
                blue line is<bookmark mark="write_one"/> also one.

                Note that we can <bookmark mark="vary"/> vary the angle alpha and the length of the blue line will
                still be one, as long as it is inscribed into the unit circle
                """
        ) as tracker:
            
            self.wait_until_bookmark("center")
            cursor.blinking=False
            
            self.wait_until_bookmark("circle")
            x,y,_ = line_end.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("write_one")
            one = MathTex("1", color=c1t, font_size=fs3).move_to(line_end.get_center()+0.1*(LEFT+UP))
            self.play(Write(one))
            line_cos.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
            line_sine.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
            line_end.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))

            self.wait_until_bookmark("vary")
            cursor.blinking=False
            rotation_updater = lambda m: m.move_to(line_end.get_start())
            cursor.add_updater(rotation_updater)
            self.remove(one)
            self.play(a.animate.set_value(2*PI+0.5), run_time=6)
            cursor.blinking=True


        self.wait(4)


class Func_7_2_I_2_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = Arc(radius=1.4, angle=2*PI, color=BLUE)
        self.add(arc)

        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)
        triangle = VGroup(line_cos, line_sine, line_end)
        self.add(triangle)

        sine_formula = MathTex("\\sin(\\alpha) =", "\\frac{\\text{opposite}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(arc, DOWN, buff=0.6)
        self.add(sine_formula)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                The blue line goes <bookmark mark="center"/>from the center of the circle to the
                edge<bookmark mark="circle"/> of the circle. Since the radius of the circle is one, the length of the
                blue line is<bookmark mark="write_one"/> also one.

                Note that we can <bookmark mark="vary"/> vary the angle alpha and the length of the blue line will
                still be one, as long as it is inscribed into the unit circle
                """
        ) as tracker:
            
            self.wait_until_bookmark("center")
            cursor.blinking=False
            
            self.wait_until_bookmark("circle")
            x,y,_ = line_end.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("write_one")
            one = MathTex("1", color=c1t, font_size=fs3).move_to(line_end.get_center()+0.1*(LEFT+UP))
            self.play(Write(one))
            line_cos.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
            line_sine.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
            line_end.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))

            self.wait_until_bookmark("vary")
            cursor.blinking=False
            rotation_updater = lambda m: m.move_to(line_end.get_start())
            cursor.add_updater(rotation_updater)
            self.remove(one)
            self.play(a.animate.set_value(2*PI+0.5), run_time=6)
            cursor.blinking=True


        self.wait(4)


class Func_7_2_I_2_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = Arc(radius=1.4, angle=2*PI, color=BLUE)
        self.add(arc)

        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)
        triangle = VGroup(line_cos, line_sine, line_end)
        self.add(triangle)

        sine_formula = MathTex("\\sin(\\alpha) =", "\\frac{\\text{opposite}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(arc, DOWN, buff=0.6)
        self.add(sine_formula)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                The blue line goes <bookmark mark="center"/>from the center of the circle to the
                edge<bookmark mark="circle"/> of the circle. Since the radius of the circle is one, the length of the
                blue line is<bookmark mark="write_one"/> also one.

                Note that we can <bookmark mark="vary"/> vary the angle alpha and the length of the blue line will
                still be one, as long as it is inscribed into the unit circle
                """
        ) as tracker:
            
            self.wait_until_bookmark("center")
            cursor.blinking=False
            
            self.wait_until_bookmark("circle")
            x,y,_ = line_end.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("write_one")
            one = MathTex("1", color=c1t, font_size=fs3).move_to(line_end.get_center()+0.1*(LEFT+UP))
            self.play(Write(one))
            line_cos.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
            line_sine.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
            line_end.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))

            self.wait_until_bookmark("vary")
            cursor.blinking=False
            rotation_updater = lambda m: m.move_to(line_end.get_start())
            cursor.add_updater(rotation_updater)
            self.remove(one)
            self.play(a.animate.set_value(2*PI+0.5), run_time=6)
            cursor.blinking=True


        self.wait(4)


class Func_7_2_I_2_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = Arc(radius=1.4, angle=2*PI, color=BLUE)
        self.add(arc)

        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)
        triangle = VGroup(line_cos, line_sine, line_end)
        self.add(triangle)

        sine_formula = MathTex("\\sin(\\alpha) =", "\\frac{\\text{opposite}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(arc, DOWN, buff=0.6)
        self.add(sine_formula)

        # Action Sequence
        with self.voiceover(
                text="""
                Yes, that's right. Well done.
                The blue line goes <bookmark mark="center"/>from the center of the circle to the
                edge<bookmark mark="circle"/> of the circle. Since the radius of the circle is one, the length of the
                blue line is<bookmark mark="write_one"/> also one.

                Note that we can <bookmark mark="vary"/> vary the angle alpha and the length of the blue line will
                still be one, as long as it is inscribed into the unit circle
                """
        ) as tracker:
            
            self.wait_until_bookmark("center")
            cursor.blinking=False
            
            self.wait_until_bookmark("circle")
            x,y,_ = line_end.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("write_one")
            one = MathTex("1", color=c1t, font_size=fs3).move_to(line_end.get_center()+0.1*(LEFT+UP))
            self.play(Write(one))
            line_cos.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
            line_sine.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
            line_end.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))

            self.wait_until_bookmark("vary")
            cursor.blinking=False
            rotation_updater = lambda m: m.move_to(line_end.get_start())
            cursor.add_updater(rotation_updater)
            self.remove(one)
            self.play(a.animate.set_value(2*PI+0.5), run_time=6)
            cursor.blinking=True


        self.wait(4)


#####################################
#####################################
class Func_7_2_I_3(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = Arc(radius=1.4, angle=2*PI, color=BLUE, stroke_width=2)
        self.add(arc)

        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end)
        self.add(triangle)

        sine_formula = MathTex("\\sin(\\alpha) =", "\\frac{\\text{opposite}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(arc, DOWN, buff=0.6)
        sine_formula_2 = MathTex("\\sin(\\alpha) =", "\\text{opposite}", color=PINK, font_size=fs3).move_to(sine_formula)
        self.add(sine_formula)

        # Action Sequence
        with self.voiceover(
                text="""
                So <bookmark mark="sine"/> the sine of the angle alpha <bookmark mark="opposite"/>is the opposite divided 
                <bookmark mark="hypothenuse"/>by the hypothenuse.
                In our example, that means the <bookmark mark="pink_line"/>length of the pink line divided by the <bookmark mark="blue_line"/>
                length of the blue line. And we know that <bookmark mark="vary"/> the length of the blue line is always one, as long as it is
                inscribed into the unit circle. This means, that the sine of the angle alpha is <bookmark mark="sine_one"/> always equal to
                the length of the pink line,  <bookmark mark="hypothenuse_2"/>because the hypothenuse that we're dividing by is always one.

                So for the expression, that means that if we inscribe the triangle into the unit circle, the <bookmark mark="sine_term"/>
                sine of the inner angle is equal to the <bookmark mark="opposite_term"/>length of the opposite side.
                """
        ) as tracker:
            
            self.wait_until_bookmark("sine")
            cursor.blinking=False
            x,y,_ = sine_formula[0].get_center()+0.4*DOWN+0.2*LEFT
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)

            self.wait_until_bookmark("opposite")
            cursor.blinking=False
            x,y,_ = sine_formula[1].get_right()+0.2*RIGHT+0.2*UP
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse")
            cursor.blinking=False
            x,y,_ = sine_formula[1].get_right()+0.2*RIGHT+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("pink_line")
            cursor.blinking=False
            x,y,_ = line_sine.get_center()+0.2*RIGHT
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("blue_line")
            cursor.blinking=False
            x,y,_ = line_end.get_center()+0.2*(LEFT+UP)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True
            
            self.wait_until_bookmark("vary")
            cursor.blinking=False
            x,y,_ = line_end.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            rotation_updater = lambda m: m.move_to(line_end.get_start())
            cursor.add_updater(rotation_updater)
            self.play(a.animate.set_value(2*PI+0.5), run_time=6)
            cursor.remove_updater(rotation_updater)
            cursor.blinking=True

            self.wait_until_bookmark("sine_one")
            cursor.blinking=False
            x,y,_ = line_sine.get_center()+0.2*RIGHT
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse_2")
            cursor.blinking=False
            x,y,_ = sine_formula[1].get_right()+0.2*RIGHT+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("sine_term")
            cursor.blinking=False
            x,y,_ = sine_formula[0].get_center()+0.4*DOWN+0.2*LEFT
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("opposite_term")
            cursor.blinking=False
            x,y,_ = sine_formula_2[1].get_center()+0.4*DOWN
            self.play(ReplacementTransform(sine_formula, sine_formula_2), CursorMoveToCurved(cursor, x, y), run_time=0.5)

        self.wait(4)


#####################################
#####################################
class Func_7_2_I_4(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = Arc(radius=1.4, angle=2*PI, color=BLUE, stroke_width=2)
        self.add(arc)

        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end)
        self.add(triangle)

        angle_intro = Tex("Angle: ", color=c1t, font_size=fs2)
        angle_num = DecimalNumber(0, num_decimal_places=1, font_size=fs2).set_color(c1t).add_updater(lambda m: m.set_value(a.get_value()/np.pi))
        angle_label = MathTex("\\Pi", color=c1t, font_size=fs2)
        angle = VGroup(angle_intro, angle_num, angle_label).arrange(RIGHT, buff=0.1)

        sine_intro = Tex("Sine: ", color=c1t, font_size=fs2)
        sine_num = DecimalNumber(0, num_decimal_places=1, font_size=fs2).set_color(c1t).add_updater(lambda m: m.set_value(sine()))
        sine_group = VGroup(sine_intro, sine_num).arrange(RIGHT, buff=0.1)

        sine_angle = VGroup(angle, sine_group).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(arc, DOWN, buff=0.6)

        sine_num.shift((sine_num.get_left()-angle_num.get_left())[0]*LEFT)

        # Action Sequence
        with self.voiceover(
                text="""
                Now we can <bookmark mark="sine_function_title"/>use the sine-function to describe the relationship between
                the angle of the triangle and the sine of the angle, which in this case is equal to the length of the
                opposite side, so the pink line.

                When we change the angle, let us keep track<bookmark mark="track_angle"/> of the angle alpha and
                <bookmark mark="track_length"/>the length of the pink line, which is the sine of the angle.

                Now, <bookmark mark="vary"/>vary the angle alpha and observe how the length of the pink line changes.
                Also look at how the sine changes together with the angle.
                """
        ) as tracker:
            
            self.wait_until_bookmark("sine_function_title")
            cursor.blinking=False
            x,y,_ = title.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("track_angle")
            cursor.blinking=False
            x,y,_ = angle_num.get_center()+0.4*DOWN
            self.play(Write(angle), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("track_length")
            cursor.blinking=False
            x,y,_ = sine_num.get_center()+0.4*DOWN
            self.play(Write(sine_group), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True
            
            self.wait_until_bookmark("vary")
            cursor.blinking=False
            x,y,_ = line_end.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            rotation_updater = lambda m: m.move_to(line_end.get_start())
            cursor.add_updater(rotation_updater)
            self.play(a.animate.set_value(2*PI+0.5), run_time=6)
            cursor.remove_updater(rotation_updater)
            cursor.blinking=True


        self.wait(4)


#####################################
#####################################
class Func_7_2_I_5(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = Arc(radius=1, angle=2*PI, color=BLUE, stroke_width=2)
        self.add(arc)

        line_cos  = Line(ORIGIN, cosine()*RIGHT, color=GREEN, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, cosine()*RIGHT))
        line_sine = Line(cosine()*RIGHT, (cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(cosine()*RIGHT, (cosine()*RIGHT+sine()*UP)))
        line_end = Line((cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on((cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end)
        self.add(triangle)

        angle_intro = Tex("Angle: ", color=c1t, font_size=fs2)
        angle_num = DecimalNumber(0, num_decimal_places=1, font_size=fs2).set_color(c1t).add_updater(lambda m: m.set_value(a.get_value()/np.pi))
        angle_label = MathTex("\\Pi", color=c1t, font_size=fs2)
        angle = VGroup(angle_intro, angle_num, angle_label).arrange(RIGHT, buff=0.1)

        sine_intro = Tex("Sine: ", color=c1t, font_size=fs2)
        sine_num = DecimalNumber(0, num_decimal_places=1, font_size=fs2).set_color(c1t).add_updater(lambda m: m.set_value(sine()))
        sine_group = VGroup(sine_intro, sine_num).arrange(RIGHT, buff=0.1)

        sine_angle = VGroup(angle, sine_group).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(arc, DOWN, buff=0.6)

        sine_num.shift((sine_num.get_left()-angle_num.get_left())[0]*LEFT)

        cords = self.add_cords([0, 2*np.pi, np.pi/2], [-1, 1, 1], x_ticks=[0,np.pi/2, np.pi, 3*np.pi/2, 2*np.pi], x_labels=["0", "\\tfrac{1}{2}\\Pi" , "\\Pi", "\\tfrac{3}{2}\\Pi" , "2\\Pi"], y_ticks=[-1,1], height=2).shift(2.4*DOWN)
        plane = cords[0]

        upshift = UP
        perturb = np.array([0,0,1])

        get_fct = lambda: plane.plot(lambda x: np.sin(x), x_range=[0,a.get_value(),0.001], color=c1t, stroke_width=2)

        # Action Sequence
        with self.voiceover(
                text="""
                I already announced that we will use the sine function to describe the relationship between
                the angle of the triangle and the sine of the angle. <bookmark mark="reorder"/>

                Let's do that graphically.

                On this graph, <bookmark mark="x_axis"/>the x-axis describes the angle alpha,
                <bookmark mark="y_axis"/>and the y-axis describes the sine of the
                angle alpha. 

                Now let's <bookmark mark="reset"/>start at zero

                <bookmark mark="increase_1"/>and increase the angle alpha. See how the sine of the angle
                increases in parallel to the opposite side of the triangle?

                Anyway, this is the sine function... The value of the sine function at a certain angle alpha
                is equal to the length of the opposite side of the triangle. It also has this cool wave shape.
                """
        ) as tracker:
            
            self.wait_until_bookmark("reorder")
            x,y,_ = plane.c2p(0,0)
            self.play(arc.animate.shift(upshift), triangle.animate.shift(upshift), Write(cords), CursorMoveTo(cursor,x,y), run_time=2)
            line_cos.add_updater(lambda m: m.put_start_and_end_on(upshift, cosine()*RIGHT+upshift+perturb))
            line_sine.add_updater(lambda m: m.put_start_and_end_on(cosine()*RIGHT+upshift+perturb, (cosine()*RIGHT+sine()*UP)+upshift))
            line_end.add_updater(lambda m: m.put_start_and_end_on((cosine()*RIGHT+sine()*UP)+upshift, upshift))

            self.wait_until_bookmark("x_axis")
            cursor.blinking=False
            self.play(CursorMarkAxis(cursor, plane), run_time=0.5)

            self.wait_until_bookmark("y_axis")
            self.play(CursorMarkAxis(cursor, plane,  axis="y"), run_time=0.5)

            self.wait_until_bookmark("reset")
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveResize(cursor,x,y,0.2,0.2), a.animate.set_value(0))
            cursor_updater = lambda m: m.move_to(plane.c2p(a.get_value(), sine()))
            pink_line_2 = Line(plane.c2p(0,0), plane.c2p(0,1), color=PINK, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(plane.c2p(a.get_value(),0), plane.c2p(a.get_value(), sine())))
            cursor.add_updater(cursor_updater)
            self.add(pink_line_2, always_redraw(get_fct))

            self.wait_until_bookmark("increase_1")
            self.play(a.animate.set_value(2*np.pi), run_time=18)


        self.wait(4)

#####################################
#####################################
class Func_7_2_I_6(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        a = ValueTracker(0)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        upshift = UP
        perturb = np.array([0,0,1])

        one = ImageMobject(assets_folder / "img" / "one_baloony.png")
        one = one.scale(2.5/one.get_width()).move_to([-5, 1, 0])

        arc = Arc(radius=1, angle=2*PI, color=BLUE, stroke_width=2).shift(upshift)
        self.add(arc)

        line_cos  = Line(ORIGIN, cosine()*RIGHT, color=GREEN, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(upshift, cosine()*RIGHT+upshift+perturb))
        line_sine = Line(cosine()*RIGHT, (cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(cosine()*RIGHT+upshift+perturb, (cosine()*RIGHT+sine()*UP)+upshift))
        line_end = Line((cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on((cosine()*RIGHT+sine()*UP)+upshift, upshift))

        triangle = VGroup(line_cos, line_end, line_sine).shift(upshift)
        self.add(triangle)

        angle_intro = Tex("Angle: ", color=c1t, font_size=fs2)
        angle_num = DecimalNumber(0, num_decimal_places=1, font_size=fs2).set_color(c1t).add_updater(lambda m: m.set_value(a.get_value()/np.pi))
        angle_label = MathTex("\\Pi", color=c1t, font_size=fs2)
        angle = VGroup(angle_intro, angle_num, angle_label).arrange(RIGHT, buff=0.1)

        sine_intro = Tex("Sine: ", color=c1t, font_size=fs2)
        sine_num = DecimalNumber(0, num_decimal_places=1, font_size=fs2).set_color(c1t).add_updater(lambda m: m.set_value(sine()))
        sine_group = VGroup(sine_intro, sine_num).arrange(RIGHT, buff=0.1)

        sine_angle = VGroup(angle, sine_group).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(arc, DOWN, buff=0.6)

        sine_num.shift((sine_num.get_left()-angle_num.get_left())[0]*LEFT)

        cords = self.add_cords([0, 2*np.pi, np.pi/2], [-1, 1, 1], x_ticks=[0,np.pi/2, np.pi, 3*np.pi/2, 2*np.pi], x_labels=["0", "\\tfrac{1}{2}\\Pi" , "\\Pi", "\\tfrac{3}{2}\\Pi" , "2\\Pi"], y_ticks=[-1,1], height=2).shift(3.4*DOWN)
        plane = cords[0]
        x,y,_ = plane.c2p(0,0)
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        get_fct = plane.plot(lambda x: np.sin(x), color=c1t, stroke_width=2)
        self.add(get_fct)

        # Action Sequence
        with self.voiceover(
                text="""
                Here are three important facts about the sign function:

                <bookmark mark="one"/>FACT NUMBER ONE: The maximum value of the sign function is one.
                It is <bookmark mark="max"/> reached at the angle alpha equals half pi.
                Similarly, the minimum value of the sign function is negative one,
                <bookmark mark="min"/>and it is reached at the angle alpha equals
                three half pie.

                Look how in both cases<bookmark mark="switch"/>, the triangle is not really a triangle?
                It looks much more like a line.
                """
        ) as tracker:
            
            self.wait_until_bookmark("one")
            self.play(one.animate.shift(5*RIGHT), run_time=.5)
            self.wait(1)
            self.play(one.animate.shift(5*RIGHT), run_time=.5)
            
            self.wait_until_bookmark("max")
            cursor.blinking=False
            cursor_updater = lambda m: m.move_to(plane.c2p(a.get_value(), sine()))
            cursor.add_updater(cursor_updater)
            pink_line_2 = Line(plane.c2p(0,0), plane.c2p(0,1), color=PINK, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(plane.c2p(a.get_value(),0), plane.c2p(a.get_value(), sine())))
            self.add(pink_line_2)
            self.play(a.animate.set_value(np.pi/2), run_time=2)

            self.wait_until_bookmark("min")
            self.play(a.animate.set_value(3*np.pi/2), run_time=2)

            self.wait_until_bookmark("switch")
            self.play(a.animate.set_value(0.5*np.pi))
            self.wait(2)
            self.play(a.animate.set_value(1.5*np.pi))

        self.wait(4)


#####################################
#####################################
class Func_7_2_I_7(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        a = ValueTracker(0)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        upshift = UP
        perturb = np.array([0,0,1])

        two = ImageMobject(assets_folder / "img" / "two_baloony.png")
        two = two.scale(2.5/two.get_width()).move_to([-5, 1, 0])

        arc = Arc(radius=1, angle=2*PI, color=BLUE, stroke_width=2).shift(upshift)
        self.add(arc)

        line_cos  = Line(ORIGIN, cosine()*RIGHT, color=GREEN, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(upshift, cosine()*RIGHT+upshift+perturb))
        line_sine = Line(cosine()*RIGHT, (cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(cosine()*RIGHT+upshift+perturb, (cosine()*RIGHT+sine()*UP)+upshift))
        line_end = Line((cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on((cosine()*RIGHT+sine()*UP)+upshift, upshift))

        triangle = VGroup(line_cos, line_end, line_sine).shift(upshift)
        self.add(triangle)

        angle_intro = Tex("Angle: ", color=c1t, font_size=fs2)
        angle_num = DecimalNumber(0, num_decimal_places=1, font_size=fs2).set_color(c1t).add_updater(lambda m: m.set_value(a.get_value()/np.pi))
        angle_label = MathTex("\\Pi", color=c1t, font_size=fs2)
        angle = VGroup(angle_intro, angle_num, angle_label).arrange(RIGHT, buff=0.1)

        sine_intro = Tex("Sine: ", color=c1t, font_size=fs2)
        sine_num = DecimalNumber(0, num_decimal_places=1, font_size=fs2).set_color(c1t).add_updater(lambda m: m.set_value(sine()))
        sine_group = VGroup(sine_intro, sine_num).arrange(RIGHT, buff=0.1)

        sine_angle = VGroup(angle, sine_group).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(arc, DOWN, buff=0.6)

        sine_num.shift((sine_num.get_left()-angle_num.get_left())[0]*LEFT)

        cords = self.add_cords([0, 4*np.pi, np.pi], [-1, 1, 1], x_ticks=[0, np.pi, 2*np.pi, 3*np.pi, 4*np.pi], x_labels=["0" , "\\Pi", "2\\Pi", "3\\Pi", "4\\Pi"], y_ticks=[-1,1], height=2).shift(3.4*DOWN)
        plane = cords[0]
        x,y,_ = plane.c2p(0,0)
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        get_fct = lambda: plane.plot(lambda x: np.sin(x), x_range=[0,a.get_value(),0.001], color=c1t, stroke_width=2)
        self.add(always_redraw(get_fct))

        # Action Sequence
        with self.voiceover(
                text="""
                <bookmark mark="two"/>FACT NUMBER TWO: The sine function is periodic. This means, that it repeats itself
                every 2 pie.

                What does that mean?

                So we already know what the function looks <bookmark mark="zero_to_two_pi"/> like from zero to two pie.
                It starts at zero and then goes up to one, back to zero, down to negative one and back to zero.
                
                Now notice that this all happened while the triangle went around the circle fully, so after two pie,
                we're back at where we started.

                So naturally, the function will look exactly the way it does at x equals zero:
                <bookmark mark="continue_1"/> Up to one, back to zero, down to negative one, and back to zero again.

                And at four pie, it repeats itself again!
                """
        ) as tracker:
            
            self.wait_until_bookmark("two")
            self.play(two.animate.shift(5*RIGHT), run_time=.5)
            self.wait(1)
            self.play(two.animate.shift(5*RIGHT), run_time=.5)

            self.wait_until_bookmark("zero_to_two_pi")
            cursor.blinking=False
            cursor_updater = lambda m: m.move_to(plane.c2p(a.get_value(), sine()))
            cursor.add_updater(cursor_updater)
            pink_line_2 = Line(plane.c2p(0,0), plane.c2p(0,1), color=PINK, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(plane.c2p(a.get_value(),0), plane.c2p(a.get_value(), sine())))
            self.add(pink_line_2)
            self.play(a.animate.set_value(2*np.pi), run_time=10)
            cursor.blinking=True

            self.wait_until_bookmark("continue_1")
            cursor.blinking=False
            self.play(a.animate.set_value(4*np.pi), run_time=6)
            cursor.blinking=True


        self.wait(4)



#####################################
#####################################
class Func_7_2_I_8(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        a = ValueTracker(-2*np.pi)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        upshift = UP
        perturb = np.array([0,0,1])

        three = ImageMobject(assets_folder / "img" / "three_baloony.png")
        three = three.scale(2.5/three.get_width()).move_to([-5, 1, 0])

        arc = Arc(radius=1, angle=2*PI, color=BLUE, stroke_width=2).shift(upshift)
        self.add(arc)

        line_cos  = Line(ORIGIN, cosine()*RIGHT, color=GREEN, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(upshift, cosine()*RIGHT+upshift+perturb))
        line_sine = Line(cosine()*RIGHT, (cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(cosine()*RIGHT+upshift+perturb, (cosine()*RIGHT+sine()*UP)+upshift))
        line_end = Line((cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on((cosine()*RIGHT+sine()*UP)+upshift, upshift))

        triangle = VGroup(line_cos, line_end, line_sine).shift(upshift)
        self.add(triangle)

        cords = self.add_cords([-2*np.pi, 2*np.pi,  np.pi], [-1, 1, 1], x_ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi], x_labels=["-2\\Pi", "-\\Pi", "0" , "\\Pi", "2\\Pi"], y_ticks=[-1,1], height=2).shift(3.4*DOWN)
        plane = cords[0]
        x,y,_ = plane.c2p(-2*np.pi,0)
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        get_fct = lambda: plane.plot(lambda x: np.sin(x), x_range=[-2*np.pi,a.get_value(),0.001], color=c1t, stroke_width=2)
        self.add(always_redraw(get_fct))

        plot = plane.plot(lambda x: np.sin(x), color=c1t, stroke_width=2)

        # Action Sequence
        with self.voiceover(
                text="""
                <bookmark mark="three"/>FACT NUMBER THREE: The sine function is an odd function.

                What does that mean?

                Let's <bookmark mark="draw_1"/>first draw the function from negative two pi to zero.
                From fact number two, we know that the function looks exactly the same from negative two pie to zero
                as it does from zero to two pie.

                <bookmark mark="draw_2"/>
                Now let's draw the function from zero to two pie as well.

                Look <bookmark mark="y_axis"/> at the y-axis and compare the values of the function on
                the left and on the right side of the y-axis.

                See how the values are the same, but the sign is different? That's what it means to be an odd function.
                <bookmark mark="clean_circle"/> Specifically, <bookmark mark="odd_1_a"/>that f of negative x is
                <bookmark mark="odd_1_b"/>equal to negative f of x.

                You can easily check that this is true here. This means <bookmark mark="odd_2_a"/>that the sine of negative x
                <bookmark mark="odd_2_b"/>is equal to negative sine of  x.

                So the sine function is an odd function.
                """
        ) as tracker:
            
            self.wait_until_bookmark("three")
            self.play(three.animate.shift(5*RIGHT), run_time=.5)
            self.wait(1)
            self.play(three.animate.shift(5*RIGHT), run_time=.5)

            self.wait_until_bookmark("draw_1")
            cursor.blinking=False
            cursor_updater = lambda m: m.move_to(plane.c2p(a.get_value(), sine()))
            cursor.add_updater(cursor_updater)
            pink_line_2 = Line(plane.c2p(0,0), plane.c2p(0,1), color=PINK, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(plane.c2p(a.get_value(),0)+perturb, plane.c2p(a.get_value(), sine())))
            self.add(pink_line_2)
            self.play(a.animate.set_value(0), run_time=6)
            self.wait()

            self.wait_until_bookmark("draw_2")
            self.play(a.animate.set_value(2*np.pi), run_time=4)
            self.add(plot)
            self.remove(get_fct)
            cursor.blinking=True

            self.wait_until_bookmark("y_axis")
            cursor.blinking=False
            cursor.remove_updater(cursor_updater)
            self.play(CursorMarkAxis(cursor, plane,  axis="y"), run_time=0.5)
            self.wait(1)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveResize(cursor,x,y,0.2,0.2))
            cursor.blinking=True

            self.wait_until_bookmark("clean_circle")
            odd_1 = MathTex("f(-x)", "=", " -f(x)", color=c1t, font_size=fs2)
            odd_2 = MathTex("\\sin(x)", "=", "-\\sin(-x)", color=c1t, font_size=fs2)
            odd = VGroup(odd_1, odd_2).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(title, DOWN, buff=0.8)
            self.remove(arc, triangle)

            self.wait_until_bookmark("odd_1_a")
            cursor.blinking=False
            x,y,_ = odd_1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(odd_1), run_time=.5)

            self.wait_until_bookmark("odd_1_b")
            x,y,_ = odd_1[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("odd_2_a")
            cursor.blinking=False
            x,y,_ = odd_2[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(odd_2), run_time=.5)

            self.wait_until_bookmark("odd_2_b")
            x,y,_ = odd_2[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

        self.wait(4)



PROTOTYPES=[
    PagePrototypeVideo.from_scene(Func_7_2_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_2_I_1_q, Func_7_2_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_2_I_1_a),
    PagePrototypeVideo.from_scene(Func_7_2_I_1_b),
    PagePrototypeVideo.from_scene(Func_7_2_I_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_2_I_2_q, Func_7_2_I_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_2_I_2_a),
    PagePrototypeVideo.from_scene(Func_7_2_I_2_b),
    PagePrototypeVideo.from_scene(Func_7_2_I_2_c),
    PagePrototypeVideo.from_scene(Func_7_2_I_2_d),
    PagePrototypeVideo.from_scene(Func_7_2_I_3),
    PagePrototypeVideo.from_scene(Func_7_2_I_4),
    PagePrototypeVideo.from_scene(Func_7_2_I_5),
    PagePrototypeVideo.from_scene(Func_7_2_I_6),
    PagePrototypeVideo.from_scene(Func_7_2_I_7),
    PagePrototypeVideo.from_scene(Func_7_2_I_8),
]

scenes/Func/Func_7: Sine and Cosine Functions/Func_7_2.py
Sophia-Edu-Labs/sophia-math
# 7_3: Trigonometric Functions: Intro Cosine

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition

#####################################
#####################################
TASK_Func_7_3_I_1_q = SophiaTaskDefinition(
    answerOptions = ["blue line / green line", "pink line / blue line", "pink line / green line", "green line / blue line"],
    correctAnswerIndex = 3,
    questionText = "Which of the lines do we have two divide by which to get the sine of the bottom left corner?"
)
class Func_7_3_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Cosine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = lambda: Arc(radius=1, angle=2*PI, color=BLUE)
        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end).shift(0.7*LEFT+0.2*UP)
        

        # Action Sequence
        with self.voiceover(
                text="""
                Look at <bookmark mark="show_triangle"/> this triangle.

                From it, we now want to learn about<bookmark mark="cosine"/> the cosine function.

                Let's start with the definition of the cosine. Which line do we divide by which other line,
                to get the cosine of the angle <bookmark mark="angle"/>in the bottom
                left corner?
                """
        ) as tracker:

            self.wait_until_bookmark("show_triangle")
            self.play(Create(triangle))

            self.wait_until_bookmark("cosine")
            x,y,_ = title.get_center()-np.array([1.2,.4,0])
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("angle")
            cursor.blinking=False
            self.play(CursorMoveToCurved(cursor, -0.8, 0.1))
            cursor.blinking=True

        self.wait(4)


class Func_7_3_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Cosine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = lambda: Arc(radius=1, angle=2*PI, color=BLUE)
        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end).shift(0.7*LEFT+0.2*UP)
        self.add(triangle)

        cosine_formula = MathTex("\\cos(\\alpha) =", "\\frac{\\text{adjacent}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(triangle, DOWN, buff=0.8)
        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right. <bookmark mark="show_formula"/>
                The cosine is equal to <bookmark mark="adjacent"/> the length of the adjacent divided <bookmark mark="hypothenuse"/>
                by the length of the hypothenuse.

                The adjacent is the shorter side adjacent to the angle. In this case,<bookmark mark="adjacent_plot"/> it's the green line.
                The hypothenuse is the longest side of a triangle. In this case,<bookmark mark="hypothenuse_plot"/> it's the blue line.
                This means, that we have to divide the green line by the blue line to get the cosine of the angle in the bottom left
                corner.
                """
        ) as tracker:
            
            self.wait_until_bookmark("show_formula")
            x,y,_ = cosine_formula[0].get_center()+0.4*DOWN+0.2*LEFT
            cursor.blinking=False
            self.play(Write(cosine_formula[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("adjacent")
            cursor.blinking=False
            x,y,_ = cosine_formula[1].get_right()+0.2*RIGHT+0.2*UP
            self.play(Write(cosine_formula[1]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse")
            cursor.blinking=False
            x,y,_ = cosine_formula[1].get_right()+0.2*RIGHT+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("adjacent_plot")
            cursor.blinking=False
            x,y,_ = line_cos.get_center()+0.3*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse_plot")
            cursor.blinking=False
            x,y,_ = line_end.get_center()+0.2*(LEFT+UP)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)

class Func_7_3_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Cosine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = lambda: Arc(radius=1, angle=2*PI, color=BLUE)
        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end).shift(0.7*LEFT+0.2*UP)
        self.add(triangle)

        cosine_formula = MathTex("\\cos(\\alpha) =", "\\frac{\\text{adjacent}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(triangle, DOWN, buff=0.8)
        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right. <bookmark mark="show_formula"/>
                The cosine is equal to <bookmark mark="adjacent"/> the length of the adjacent divided <bookmark mark="hypothenuse"/>
                by the length of the hypothenuse.

                The adjacent is the shorter side adjacent to the angle. In this case,<bookmark mark="adjacent_plot"/> it's the green line.
                The hypothenuse is the longest side of a triangle. In this case,<bookmark mark="hypothenuse_plot"/> it's the blue line.
                This means, that we have to divide the green line by the blue line to get the cosine of the angle in the bottom left
                corner.
                """
        ) as tracker:
            
            self.wait_until_bookmark("show_formula")
            x,y,_ = cosine_formula[0].get_center()+0.4*DOWN+0.2*LEFT
            cursor.blinking=False
            self.play(Write(cosine_formula[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("adjacent")
            cursor.blinking=False
            x,y,_ = cosine_formula[1].get_right()+0.2*RIGHT+0.2*UP
            self.play(Write(cosine_formula[1]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse")
            cursor.blinking=False
            x,y,_ = cosine_formula[1].get_right()+0.2*RIGHT+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("adjacent_plot")
            cursor.blinking=False
            x,y,_ = line_cos.get_center()+0.3*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse_plot")
            cursor.blinking=False
            x,y,_ = line_end.get_center()+0.2*(LEFT+UP)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)

class Func_7_3_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Cosine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = lambda: Arc(radius=1, angle=2*PI, color=BLUE)
        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end).shift(0.7*LEFT+0.2*UP)
        self.add(triangle)

        cosine_formula = MathTex("\\cos(\\alpha) =", "\\frac{\\text{adjacent}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(triangle, DOWN, buff=0.8)
        

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right. <bookmark mark="show_formula"/>
                The cosine is equal to <bookmark mark="adjacent"/> the length of the adjacent divided <bookmark mark="hypothenuse"/>
                by the length of the hypothenuse.

                The adjacent is the shorter side adjacent to the angle. In this case,<bookmark mark="adjacent_plot"/> it's the green line.
                The hypothenuse is the longest side of a triangle. In this case,<bookmark mark="hypothenuse_plot"/> it's the blue line.
                This means, that we have to divide the green line by the blue line to get the cosine of the angle in the bottom left
                corner.
                """
        ) as tracker:
            
            self.wait_until_bookmark("show_formula")
            x,y,_ = cosine_formula[0].get_center()+0.4*DOWN+0.2*LEFT
            cursor.blinking=False
            self.play(Write(cosine_formula[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("adjacent")
            cursor.blinking=False
            x,y,_ = cosine_formula[1].get_right()+0.2*RIGHT+0.2*UP
            self.play(Write(cosine_formula[1]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse")
            cursor.blinking=False
            x,y,_ = cosine_formula[1].get_right()+0.2*RIGHT+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("adjacent_plot")
            cursor.blinking=False
            x,y,_ = line_cos.get_center()+0.3*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse_plot")
            cursor.blinking=False
            x,y,_ = line_end.get_center()+0.2*(LEFT+UP)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)

class Func_7_3_I_1_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Cosine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = lambda: Arc(radius=1, angle=2*PI, color=BLUE)
        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end).shift(0.7*LEFT+0.2*UP)
        self.add(triangle)

        cosine_formula = MathTex("\\cos(\\alpha) =", "\\frac{\\text{adjacent}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(triangle, DOWN, buff=0.8)
        

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's correct. Nice Job! <bookmark mark="show_formula"/>
                The cosine is equal to <bookmark mark="adjacent"/> the length of the adjacent divided <bookmark mark="hypothenuse"/>
                by the length of the hypothenuse.

                The adjacent is the shorter side adjacent to the angle. In this case,<bookmark mark="adjacent_plot"/> it's the green line.
                The hypothenuse is the longest side of a triangle. In this case,<bookmark mark="hypothenuse_plot"/> it's the blue line.
                This means, that we have to divide the green line by the blue line to get the cosine of the angle in the bottom left
                corner.
                """
        ) as tracker:
            
            self.wait_until_bookmark("show_formula")
            x,y,_ = cosine_formula[0].get_center()+0.4*DOWN+0.2*LEFT
            cursor.blinking=False
            self.play(Write(cosine_formula[0]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("adjacent")
            cursor.blinking=False
            x,y,_ = cosine_formula[1].get_right()+0.2*RIGHT+0.2*UP
            self.play(Write(cosine_formula[1]), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse")
            cursor.blinking=False
            x,y,_ = cosine_formula[1].get_right()+0.2*RIGHT+0.2*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("adjacent_plot")
            cursor.blinking=False
            x,y,_ = line_cos.get_center()+0.3*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("hypothenuse_plot")
            cursor.blinking=False
            x,y,_ = line_end.get_center()+0.2*(LEFT+UP)
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
#####################################
#####################################
class Func_7_3_I_3(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = lambda: Arc(radius=1.4, angle=2*PI, color=BLUE)
        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3)#.
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)
        triangle = VGroup(line_cos, line_sine, line_end).shift(0.7*LEFT+0.2*UP)
        self.add(triangle)

        cosine_formula = MathTex("\\cos(\\alpha) =", "\\frac{\\text{adjacent}}{\\text{hypothenuse}}", color=c1t, font_size=fs3).next_to(triangle, DOWN, buff=0.8)
        self.add(cosine_formula)

        # Action Sequence
        with self.voiceover(
                text="""
                Let's <bookmark mark="circle"/>inscribe the triangle into a circle, with the radius of one.
                If the top left corner is in the center of the circle, <bookmark mark="hypothenuse"/> the
                hypothenuse, meaning the blue line has the length one.

                We can <bookmark mark="vary"/> vary the angle alpha and the length of the blue line will
                still be one, as long as it is inscribed into the unit circle

                """
        ) as tracker:
            
            self.play(triangle.animate.shift(0.7*RIGHT+0.2*DOWN), cosine_formula.animate.shift(DOWN))
            line_cos.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
            line_sine.add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
            line_end.add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))

            self.wait_until_bookmark("circle")
            self.play(Create(arc()))

            self.wait_until_bookmark("hypothenuse")
            x,y,_ = line_end.get_center()+0.1*(LEFT+UP)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("vary")
            cursor.blinking=False
            rotation_updater = lambda m: m.move_to(line_end.get_start())
            cursor.add_updater(rotation_updater)
            self.play(a.animate.set_value(2*PI+0.5), run_time=6)
            cursor.blinking=True

        self.wait(4)


#####################################
#####################################
class Func_7_3_I_4(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Cosine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = Arc(radius=1.4, angle=2*PI, color=BLUE, stroke_width=2)
        self.add(arc)

        line_cos  = Line(ORIGIN, 1.4*cosine()*RIGHT, color=GREEN, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(ORIGIN, 1.4*cosine()*RIGHT))
        line_sine = Line(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(1.4*cosine()*RIGHT, 1.4*(cosine()*RIGHT+sine()*UP)))
        line_end = Line(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(1.4*(cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end)
        self.add(triangle)

        angle_intro = Tex("Angle: ", color=c1t, font_size=fs2)
        angle_num = DecimalNumber(0, num_decimal_places=1, font_size=fs2).set_color(c1t).add_updater(lambda m: m.set_value((a.get_value()/np.pi)%2))
        angle_label = MathTex("\\Pi", color=c1t, font_size=fs2)
        angle = VGroup(angle_intro, angle_num, angle_label).arrange(RIGHT, buff=0.3)

        cosine_intro = Tex("Cosine: ", color=c1t, font_size=fs2)
        cosine_num = DecimalNumber(0, num_decimal_places=1, font_size=fs2).set_color(c1t).add_updater(lambda m: m.set_value(cosine()))
        cosine_group = VGroup(cosine_intro, cosine_num).arrange(RIGHT, buff=0.3)

        sine_angle = VGroup(angle, cosine_group).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(arc, DOWN, buff=0.6)

        cosine_num.shift((cosine_num.get_left()-angle_num.get_left())[0]*LEFT)

        # Action Sequence
        with self.voiceover(
                text="""
                Now we can <bookmark mark="sine_function_title"/>use the cosine-function to describe the relationship between
                the angle of the triangle and the sine of the angle, which in this case is equal to the length of the
                adjacent side, so the green line.

                When we change the angle, let us keep track<bookmark mark="track_angle"/> of the angle alpha and
                <bookmark mark="track_length"/>the length of the green line, which is the cosine of the angle.

                Now, <bookmark mark="vary"/>vary the angle alpha and observe how the length of the green line changes.
                Also look at how the cosine changes together with the angle.
                """
        ) as tracker:
            
            self.wait_until_bookmark("sine_function_title")
            cursor.blinking=False
            x,y,_ = title.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("track_angle")
            cursor.blinking=False
            x,y,_ = angle_num.get_center()+0.4*DOWN
            self.play(Write(angle), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("track_length")
            cursor.blinking=False
            x,y,_ = cosine_num.get_center()+0.4*DOWN
            self.play(Write(cosine_group), CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True
            
            self.wait_until_bookmark("vary")
            cursor.blinking=False
            x,y,_ = line_end.get_start()
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            rotation_updater = lambda m: m.move_to(line_end.get_start())
            cursor.add_updater(rotation_updater)
            self.play(a.animate.set_value(2*PI+0.5), run_time=6)
            cursor.remove_updater(rotation_updater)
            cursor.blinking=True


        self.wait(4)


#####################################
#####################################
class Func_7_3_I_5(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Cosine Function")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(0.5)
        sine = lambda: np.sin(a.get_value())
        cosine = lambda: np.cos(a.get_value())

        arc = Arc(radius=1, angle=2*PI, color=BLUE, stroke_width=2)
        self.add(arc)

        line_cos  = Line(ORIGIN, cosine()*RIGHT, color=GREEN, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(ORIGIN, cosine()*RIGHT))
        line_sine = Line(cosine()*RIGHT, (cosine()*RIGHT+sine()*UP), color=PINK, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on(cosine()*RIGHT, (cosine()*RIGHT+sine()*UP)))
        line_end = Line((cosine()*RIGHT+sine()*UP), ORIGIN, color=PURE_BLUE, stroke_width=3)#.add_updater(lambda m: m.put_start_and_end_on((cosine()*RIGHT+sine()*UP), ORIGIN))
        triangle = VGroup(line_cos, line_sine, line_end)
        self.add(triangle)

        angle_intro = Tex("Angle: ", color=c1t, font_size=fs2)
        angle_num = DecimalNumber(0, num_decimal_places=1, font_size=fs2).set_color(c1t).add_updater(lambda m: m.set_value(a.get_value()/np.pi))
        angle_label = MathTex("\\Pi", color=c1t, font_size=fs2)
        angle = VGroup(angle_intro, angle_num, angle_label).arrange(RIGHT, buff=0.1)

        sine_intro = Tex("Cosine: ", color=c1t, font_size=fs2)
        sine_num = DecimalNumber(0, num_decimal_places=1, font_size=fs2).set_color(c1t).add_updater(lambda m: m.set_value(cosine()))
        sine_group = VGroup(sine_intro, sine_num).arrange(RIGHT, buff=0.1)

        sine_angle = VGroup(angle, sine_group).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(arc, DOWN, buff=0.6)

        sine_num.shift((sine_num.get_left()-angle_num.get_left())[0]*LEFT)

        cords = self.add_cords([0, 2*np.pi, np.pi/2], [-1, 1, 1], x_ticks=[0,np.pi/2, np.pi, 3*np.pi/2, 2*np.pi], x_labels=["0", "\\tfrac{1}{2}\\Pi" , "\\Pi", "\\tfrac{3}{2}\\Pi" , "2\\Pi"], y_ticks=[-1,1], height=2).shift(2.4*DOWN)
        plane = cords[0]

        upshift = UP
        perturb = np.array([0,0,1])

        get_fct = lambda: plane.plot(lambda x: np.cos(x), x_range=[0,a.get_value(),0.001], color=c1t, stroke_width=2)

        # Action Sequence
        with self.voiceover(
                text="""
                Let's describe the relationship between the cosine of an angle and the value of that angle
                <bookmark mark="reorder"/> using a function and its corresponding graph.

                The <bookmark mark="x_axis"/> x-axis describes the angle alpha,
                <bookmark mark="y_axis"/>and the y-axis describes the cosine of the
                angle alpha. 

                We'll <bookmark mark="reset"/>start at zero

                <bookmark mark="increase_1"/>and increase the angle alpha. As we increase the angle alpha,
                the length of the green line decreases. This means, that the cosine of the angle alpha
                decreases, until we reach negative one. Then, the cosine of the angle alpha starts to increase
                again, until it's back at one.

                """
        ) as tracker:
            
            self.wait_until_bookmark("reorder")
            x,y,_ = plane.c2p(0,0)
            self.play(arc.animate.shift(upshift), triangle.animate.shift(upshift), Write(cords), CursorMoveTo(cursor,x,y), run_time=2)
            line_cos.add_updater(lambda m: m.put_start_and_end_on(upshift, cosine()*RIGHT+upshift+perturb))
            line_sine.add_updater(lambda m: m.put_start_and_end_on(cosine()*RIGHT+upshift+perturb, (cosine()*RIGHT+sine()*UP)+upshift))
            line_end.add_updater(lambda m: m.put_start_and_end_on((cosine()*RIGHT+sine()*UP)+upshift, upshift))

            self.wait_until_bookmark("x_axis")
            cursor.blinking=False
            self.play(CursorMarkAxis(cursor, plane), run_time=0.5)

            self.wait_until_bookmark("y_axis")
            self.play(CursorMarkAxis(cursor, plane,  axis="y"), run_time=0.5)

            self.wait_until_bookmark("reset")
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveResize(cursor,x,y,0.2,0.2), a.animate.set_value(0))
            cursor_updater = lambda m: m.move_to(plane.c2p(a.get_value(), cosine()))
            green_line_2 = Line(plane.c2p(0,0), plane.c2p(0,1), color=GREEN, stroke_width=3).add_updater(lambda m: m.put_start_and_end_on(plane.c2p(a.get_value(),0), plane.c2p(a.get_value(), cosine())))
            cursor.add_updater(cursor_updater)
            self.add(green_line_2, always_redraw(get_fct))

            self.wait_until_bookmark("increase_1")
            self.play(a.animate.set_value(2*np.pi), run_time=25)


        self.wait(4)



#####################################
#####################################
######## Practice Part ##############
#####################################
#####################################
TASK_Func_7_3_P_1_q = SophiaTaskDefinition(
    answerOptions = ["blue: sine, pink: none", "blue: cosine, pink: sine", "blue: sine, pink: cosine", "blue: none, pink: sine"],
    correctAnswerIndex = 1,
    questionText = "Does one of the lines describe the sine function? Or the cosine function?"
)
class Func_7_3_P_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        cords = self.add_cords([0, 2*np.pi, np.pi/2], [-1, 1, 1], x_ticks=[0,np.pi/2, np.pi, 3*np.pi/2, 2*np.pi], x_labels=["0", "\\tfrac{1}{2}\\Pi" , "\\Pi", "\\tfrac{3}{2}\\Pi" , "2\\Pi"], y_ticks=[-1,1], height=2).shift(3*DOWN)
        plane = cords[0]

        graph_blue = plane.plot(lambda x: np.cos(x), x_range=[0,2*np.pi,0.001], color=PURE_BLUE, stroke_width=2)
        graph_pink = plane.plot(lambda x: np.sin(x), x_range=[0,2*np.pi,0.001], color=PINK)

        # Action Sequence
        with self.voiceover(
                text="""
                Look at <bookmark mark="cords"/> this coordinate system and <bookmark mark="blue"/> the blue as well
                as <bookmark mark="purple"/> the purple line.

                Does one of the lines describe the sine function?
                And does one of them describe the cosine function?
                """
        ) as tracker:
            
            self.wait_until_bookmark("cords")
            self.play(Write(cords))

            self.wait_until_bookmark("blue")
            self.play(Write(graph_blue))

            self.wait_until_bookmark("purple")
            self.play(Write(graph_pink))

        self.wait(4)


class Func_7_3_P_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        cords = self.add_cords([0, 2*np.pi, np.pi/2], [-1, 1, 1], x_ticks=[0,np.pi/2, np.pi, 3*np.pi/2, 2*np.pi], x_labels=["0", "\\tfrac{1}{2}\\Pi" , "\\Pi", "\\tfrac{3}{2}\\Pi" , "2\\Pi"], y_ticks=[-1,1], height=2).shift(3*DOWN)
        plane = cords[0]
        self.add(cords)

        graph_blue = plane.plot(lambda x: np.cos(x), x_range=[0,2*np.pi,0.001], color=PURE_BLUE, stroke_width=2)
        graph_pink = plane.plot(lambda x: np.sin(x), x_range=[0,2*np.pi,0.001], color=PURPLE)

        startpoint_blue = plane.c2p(0,1)+0.1*UP
        bubble_blue = Bubble(["$\\cos(0)=1$", "$\\Rightarrow$cosine"], start_point=startpoint_blue, center=0.8*LEFT+2*UP, loc="b2")
        blue_updater = lambda m: m.move_to(bubble_blue.get_end())

        startpoint_pink = plane.c2p(np.pi/2,1)+0.1*UP
        bubble_pink = Bubble(["$\\sin(\\tfrac{\\Pi}{2})=1$", "$\\Rightarrow$sine"], start_point = startpoint_pink, center=0.8*RIGHT+0.4*UP)
        pink_updater = lambda m: m.move_to(bubble_pink.get_end())

        self.add(cords)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right.

                <bookmark mark="blue"/> The blue line describes the cosine function One way to see this, is that
                at <bookmark mark="blue_0"/> x equals zero, the cosine is one. This is satisfied by the blue
                line.

                <bookmark mark="pink"/> The purple line describes the sine function. One way to see this, is that
                at <bookmark mark="pink_0"/> x equals pi over two, the sine is one. This is satisfied by the purple
                line.
                """
        ) as tracker:

            self.wait_until_bookmark("blue")
            self.play(Write(graph_blue))

            self.wait_until_bookmark("blue_0")
            x,y, _ = startpoint_blue
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(blue_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_blue), Write(bubble_blue.text), run_time=2)
            cursor.blinking=True

            self.wait_until_bookmark("pink")
            self.play(Write(graph_pink))
            
            self.wait_until_bookmark("pink_0")
            x,y, _ = startpoint_pink
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(pink_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_pink), Write(bubble_pink.text), run_time=2)
            cursor.blinking=True


        self.wait(4)



class Func_7_3_P_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        cords = self.add_cords([0, 2*np.pi, np.pi/2], [-1, 1, 1], x_ticks=[0,np.pi/2, np.pi, 3*np.pi/2, 2*np.pi], x_labels=["0", "\\tfrac{1}{2}\\Pi" , "\\Pi", "\\tfrac{3}{2}\\Pi" , "2\\Pi"], y_ticks=[-1,1], height=2).shift(3*DOWN)
        plane = cords[0]
        self.add(cords)

        graph_blue = plane.plot(lambda x: np.cos(x), x_range=[0,2*np.pi,0.001], color=PURE_BLUE, stroke_width=2)
        graph_pink = plane.plot(lambda x: np.sin(x), x_range=[0,2*np.pi,0.001], color=PURPLE)

        startpoint_blue = plane.c2p(0,1)+0.1*UP
        bubble_blue = Bubble(["$\\cos(0)=1$", "$\\Rightarrow$cosine"], start_point=startpoint_blue, center=0.8*LEFT+2*UP, loc="b2")
        blue_updater = lambda m: m.move_to(bubble_blue.get_end())

        startpoint_pink = plane.c2p(np.pi/2,1)+0.1*UP
        bubble_pink = Bubble(["$\\sin(\\tfrac{\\Pi}{2})=1$", "$\\Rightarrow$sine"], start_point = startpoint_pink, center=0.8*RIGHT+0.4*UP)
        pink_updater = lambda m: m.move_to(bubble_pink.get_end())

        self.add(cords)

        # Action Sequence
        with self.voiceover(
                text="""
                Yes, that's correct.

                <bookmark mark="blue"/> The blue line describes the cosine function One way to see this, is that
                at <bookmark mark="blue_0"/> x equals zero, the cosine is one. This is satisfied by the blue
                line.

                <bookmark mark="pink"/> The purple line describes the sine function. One way to see this, is that
                at <bookmark mark="pink_0"/> x equals pi over two, the sine is one. This is satisfied by the purple
                line.
                """
        ) as tracker:

            self.wait_until_bookmark("blue")
            self.play(Write(graph_blue))

            self.wait_until_bookmark("blue_0")
            x,y, _ = startpoint_blue
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(blue_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_blue), Write(bubble_blue.text), run_time=2)
            cursor.blinking=True

            self.wait_until_bookmark("pink")
            self.play(Write(graph_pink))
            
            self.wait_until_bookmark("pink_0")
            x,y, _ = startpoint_pink
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(pink_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_pink), Write(bubble_pink.text), run_time=2)
            cursor.blinking=True


        self.wait(4)


class Func_7_3_P_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        cords = self.add_cords([0, 2*np.pi, np.pi/2], [-1, 1, 1], x_ticks=[0,np.pi/2, np.pi, 3*np.pi/2, 2*np.pi], x_labels=["0", "\\tfrac{1}{2}\\Pi" , "\\Pi", "\\tfrac{3}{2}\\Pi" , "2\\Pi"], y_ticks=[-1,1], height=2).shift(3*DOWN)
        plane = cords[0]
        self.add(cords)

        graph_blue = plane.plot(lambda x: np.cos(x), x_range=[0,2*np.pi,0.001], color=PURE_BLUE, stroke_width=2)
        graph_pink = plane.plot(lambda x: np.sin(x), x_range=[0,2*np.pi,0.001], color=PURPLE)

        startpoint_blue = plane.c2p(0,1)+0.1*UP
        bubble_blue = Bubble(["$\\cos(0)=1$", "$\\Rightarrow$cosine"], start_point=startpoint_blue, center=0.8*LEFT+2*UP, loc="b2")
        blue_updater = lambda m: m.move_to(bubble_blue.get_end())

        startpoint_pink = plane.c2p(np.pi/2,1)+0.1*UP
        bubble_pink = Bubble(["$\\sin(\\tfrac{\\Pi}{2})=1$", "$\\Rightarrow$sine"], start_point = startpoint_pink, center=0.8*RIGHT+0.4*UP)
        pink_updater = lambda m: m.move_to(bubble_pink.get_end())

        self.add(cords)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right.

                <bookmark mark="blue"/> The blue line describes the cosine function One way to see this, is that
                at <bookmark mark="blue_0"/> x equals zero, the cosine is one. This is satisfied by the blue
                line.

                <bookmark mark="pink"/> The purple line describes the sine function. One way to see this, is that
                at <bookmark mark="pink_0"/> x equals pi over two, the sine is one. This is satisfied by the purple
                line.
                """
        ) as tracker:

            self.wait_until_bookmark("blue")
            self.play(Write(graph_blue))

            self.wait_until_bookmark("blue_0")
            x,y, _ = startpoint_blue
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(blue_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_blue), Write(bubble_blue.text), run_time=2)
            cursor.blinking=True

            self.wait_until_bookmark("pink")
            self.play(Write(graph_pink))
            
            self.wait_until_bookmark("pink_0")
            x,y, _ = startpoint_pink
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(pink_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_pink), Write(bubble_pink.text), run_time=2)
            cursor.blinking=True


        self.wait(4)


class Func_7_3_P_1_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine")

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        cords = self.add_cords([0, 2*np.pi, np.pi/2], [-1, 1, 1], x_ticks=[0,np.pi/2, np.pi, 3*np.pi/2, 2*np.pi], x_labels=["0", "\\tfrac{1}{2}\\Pi" , "\\Pi", "\\tfrac{3}{2}\\Pi" , "2\\Pi"], y_ticks=[-1,1], height=2).shift(3*DOWN)
        plane = cords[0]
        self.add(cords)

        graph_blue = plane.plot(lambda x: np.cos(x), x_range=[0,2*np.pi,0.001], color=PURE_BLUE, stroke_width=2)
        graph_pink = plane.plot(lambda x: np.sin(x), x_range=[0,2*np.pi,0.001], color=PURPLE)

        startpoint_blue = plane.c2p(0,1)+0.1*UP
        bubble_blue = Bubble(["$\\cos(0)=1$", "$\\Rightarrow$cosine"], start_point=startpoint_blue, center=0.8*LEFT+2*UP, loc="b2")
        blue_updater = lambda m: m.move_to(bubble_blue.get_end())

        startpoint_pink = plane.c2p(np.pi/2,1)+0.1*UP
        bubble_pink = Bubble(["$\\sin(\\tfrac{\\Pi}{2})=1$", "$\\Rightarrow$sine"], start_point = startpoint_pink, center=0.8*RIGHT+0.4*UP)
        pink_updater = lambda m: m.move_to(bubble_pink.get_end())

        self.add(cords)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right.

                <bookmark mark="blue"/> The blue line describes the cosine function One way to see this, is that
                at <bookmark mark="blue_0"/> x equals zero, the cosine is one. This is satisfied by the blue
                line.

                <bookmark mark="pink"/> The purple line describes the sine function. One way to see this, is that
                at <bookmark mark="pink_0"/> x equals pi over two, the sine is one. This is satisfied by the purple
                line.
                """
        ) as tracker:

            self.wait_until_bookmark("blue")
            self.play(Write(graph_blue))

            self.wait_until_bookmark("blue_0")
            x,y, _ = startpoint_blue
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(blue_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_blue), Write(bubble_blue.text), run_time=2)
            cursor.blinking=True

            self.wait_until_bookmark("pink")
            self.play(Write(graph_pink))
            
            self.wait_until_bookmark("pink_0")
            x,y, _ = startpoint_pink
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(pink_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_pink), Write(bubble_pink.text), run_time=2)
            cursor.blinking=True


        self.wait(4)




#####################################
#####################################
TASK_Func_7_3_P_2_q = SophiaTaskDefinition(
    answerOptions = ["Cosine: Even, Sine: Even", "Cosine: Even, Sine: Odd", "Cosine: Odd, Sine: Even", "Cosine: Odd, Sine: Odd"],
    correctAnswerIndex = 1,
    questionText = "Is the cosine function even or odd? What about the sine function?"
)
class Func_7_3_P_2_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine")

        cords = self.add_cords([-2*np.pi, 2*np.pi, np.pi], [-1, 1, 1], x_ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi], x_labels=["-2\\Pi", "-\\Pi", "0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        graph_blue = plane.plot(lambda x: np.cos(x), color=PURE_BLUE, stroke_width=2)
        graph_pink = plane.plot(lambda x: np.sin(x), color=PINK)

        # Action Sequence
        with self.voiceover(
                text="""
                The <bookmark mark="blue"/> blue graph corresponds to the cosine function and
                the<bookmark mark="purple"/> purple graph corresponds to the sine function. By
                looking at the two graphs, can you tell me if the sine function is an even or an odd function?

                And what about the cosine function?
                
                Is it even, or odd?
                """
        ) as tracker:
            
            self.wait_until_bookmark("blue")
            self.play(Write(graph_blue), run_time=3)

            self.wait_until_bookmark("purple")
            self.play(Write(graph_pink), run_time=3)

        self.wait(4)



class Func_7_3_P_2_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine")

        cords = self.add_cords([-2*np.pi, 2*np.pi, np.pi], [-1, 1, 1], x_ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi], x_labels=["-2\\Pi", "-\\Pi", "0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        graph_blue = plane.plot(lambda x: np.cos(x), color=PURE_BLUE, stroke_width=2)
        graph_pink = plane.plot(lambda x: np.sin(x), color=PINK)

        startpoint_odd = plane.c2p(0,0)+0.1*(LEFT+DOWN)
        bubble_odd = Bubble(["$\\sin(-x)=-\\sin(x)$", "$\\Rightarrow$Sine function is odd"], start_point=startpoint_odd, width = 2.6, center=0.4*RIGHT+2.6*DOWN, loc="t1")
        odd_updater = lambda m: m.move_to(bubble_odd.get_end())

        startpoint_even = plane.c2p(0,1) + 0.1*UP
        bubble_even = Bubble(["$\\cos(-x)=\\cos(x)$", "$\\Rightarrow$Cosine function is even"], start_point=startpoint_even, width = 2.6, center=0.8*LEFT+2*UP, loc="b1")
        even_updater = lambda m: m.move_to(bubble_even.get_end())

        # Action Sequence
        with self.voiceover(
                text="""
                That's correct, well done.
                The <bookmark mark="blue"/> cosine function is an even function, because it is <bookmark mark="y_axis"/> symmetric
                to the y-axis. <bookmark mark="bubble_cosine"/>Formally, a function is even if f of minus x is equal to f of x.
                This holds true for the cosine function.

                The<bookmark mark="purple"/> purple graph corresponds to the sine function. The sine function is an odd function,
                because it is <bookmark mark="origin"/> symmetric to the origin. <bookmark mark="bubble_sine"/>Formally, a
                function is odd if f of minus x is equal to minus f of x. This holds true for the sine function.

                So in summary, the sine function is an odd function and the cosine function is an even function.
                """
        ) as tracker:
            
            self.wait_until_bookmark("blue")
            self.play(Write(graph_blue), run_time=3)

            self.wait_until_bookmark("y_axis")
            cursor.blinking=False
            self.play(CursorMarkAxis(cursor, plane, "y"), run_time=0.5)


            self.wait_until_bookmark("bubble_cosine")
            x,y, _ = startpoint_even
            self.play(CursorMoveResize(cursor, x, y, 0.2, 0.2), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(even_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_even), Write(bubble_even.text), run_time=2)
            cursor.blinking=True

            self.wait_until_bookmark("purple")
            self.play(Write(graph_pink), run_time=3)

            self.wait_until_bookmark("origin")
            x,y,_ = plane.c2p(0,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("bubble_sine")
            x,y, _ = startpoint_odd
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(odd_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_odd), Write(bubble_odd.text), run_time=2)
            cursor.blinking=True

        self.wait(4)


class Func_7_3_P_2_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine")

        cords = self.add_cords([-2*np.pi, 2*np.pi, np.pi], [-1, 1, 1], x_ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi], x_labels=["-2\\Pi", "-\\Pi", "0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        graph_blue = plane.plot(lambda x: np.cos(x), color=PURE_BLUE, stroke_width=2)
        graph_pink = plane.plot(lambda x: np.sin(x), color=PINK)

        startpoint_odd = plane.c2p(0,0)+0.1*(LEFT+DOWN)
        bubble_odd = Bubble(["$\\sin(-x)=-\\sin(x)$", "$\\Rightarrow$Sine function is odd"], start_point=startpoint_odd, width = 2.6, center=0.4*RIGHT+2.6*DOWN, loc="t1")
        odd_updater = lambda m: m.move_to(bubble_odd.get_end())

        startpoint_even = plane.c2p(0,1) + 0.1*UP
        bubble_even = Bubble(["$\\cos(-x)=\\cos(x)$", "$\\Rightarrow$Cosine function is even"], start_point=startpoint_even, width = 2.6, center=0.8*LEFT+2*UP, loc="b1")
        even_updater = lambda m: m.move_to(bubble_even.get_end())

        # Action Sequence
        with self.voiceover(
                text="""
                That's correct, well done.
                The <bookmark mark="blue"/> cosine function is an even function, because it is <bookmark mark="y_axis"/> symmetric
                to the y-axis. <bookmark mark="bubble_cosine"/>Formally, a function is even if f of minus x is equal to f of x.
                This holds true for the cosine function.

                The<bookmark mark="purple"/> purple graph corresponds to the sine function. The sine function is an odd function,
                because it is <bookmark mark="origin"/> symmetric to the origin. <bookmark mark="bubble_sine"/>Formally, a
                function is odd if f of minus x is equal to minus f of x. This holds true for the sine function.

                So in summary, the sine function is an odd function and the cosine function is an even function.
                """
        ) as tracker:
            
            self.wait_until_bookmark("blue")
            self.play(Write(graph_blue), run_time=3)

            self.wait_until_bookmark("y_axis")
            cursor.blinking=False
            self.play(CursorMarkAxis(cursor, plane, "y"), run_time=0.5)


            self.wait_until_bookmark("bubble_cosine")
            x,y, _ = startpoint_even
            self.play(CursorMoveResize(cursor, x, y, 0.2, 0.2), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(even_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_even), Write(bubble_even.text), run_time=2)
            cursor.blinking=True

            self.wait_until_bookmark("purple")
            self.play(Write(graph_pink), run_time=3)

            self.wait_until_bookmark("origin")
            x,y,_ = plane.c2p(0,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("bubble_sine")
            x,y, _ = startpoint_odd
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(odd_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_odd), Write(bubble_odd.text), run_time=2)
            cursor.blinking=True

        self.wait(4)


class Func_7_3_P_2_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine")

        cords = self.add_cords([-2*np.pi, 2*np.pi, np.pi], [-1, 1, 1], x_ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi], x_labels=["-2\\Pi", "-\\Pi", "0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        graph_blue = plane.plot(lambda x: np.cos(x), color=PURE_BLUE, stroke_width=2)
        graph_pink = plane.plot(lambda x: np.sin(x), color=PINK)

        startpoint_odd = plane.c2p(0,0)+0.1*(LEFT+DOWN)
        bubble_odd = Bubble(["$\\sin(-x)=-\\sin(x)$", "$\\Rightarrow$Sine function is odd"], start_point=startpoint_odd, width = 2.6, center=0.4*RIGHT+2.6*DOWN, loc="t1")
        odd_updater = lambda m: m.move_to(bubble_odd.get_end())

        startpoint_even = plane.c2p(0,1) + 0.1*UP
        bubble_even = Bubble(["$\\cos(-x)=\\cos(x)$", "$\\Rightarrow$Cosine function is even"], start_point=startpoint_even, width = 2.6, center=0.8*LEFT+2*UP, loc="b1")
        even_updater = lambda m: m.move_to(bubble_even.get_end())

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right.
                The <bookmark mark="blue"/> cosine function is an even function, because it is <bookmark mark="y_axis"/> symmetric
                to the y-axis. <bookmark mark="bubble_cosine"/>Formally, a function is even if f of minus x is equal to f of x.
                This holds true for the cosine function.

                The<bookmark mark="purple"/> purple graph corresponds to the sine function. The sine function is an odd function,
                because it is <bookmark mark="origin"/> symmetric to the origin. <bookmark mark="bubble_sine"/>Formally, a
                function is odd if f of minus x is equal to minus f of x. This holds true for the sine function.

                So in summary, the sine function is an odd function and the cosine function is an even function.
                """
        ) as tracker:
            
            self.wait_until_bookmark("blue")
            self.play(Write(graph_blue), run_time=3)

            self.wait_until_bookmark("y_axis")
            cursor.blinking=False
            self.play(CursorMarkAxis(cursor, plane, "y"), run_time=0.5)


            self.wait_until_bookmark("bubble_cosine")
            x,y, _ = startpoint_even
            self.play(CursorMoveResize(cursor, x, y, 0.2, 0.2), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(even_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_even), Write(bubble_even.text), run_time=2)
            cursor.blinking=True

            self.wait_until_bookmark("purple")
            self.play(Write(graph_pink), run_time=3)

            self.wait_until_bookmark("origin")
            x,y,_ = plane.c2p(0,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("bubble_sine")
            x,y, _ = startpoint_odd
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(odd_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_odd), Write(bubble_odd.text), run_time=2)
            cursor.blinking=True

        self.wait(4)


class Func_7_3_P_2_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine")

        cords = self.add_cords([-2*np.pi, 2*np.pi, np.pi], [-1, 1, 1], x_ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi], x_labels=["-2\\Pi", "-\\Pi", "0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        graph_blue = plane.plot(lambda x: np.cos(x), color=PURE_BLUE, stroke_width=2)
        graph_pink = plane.plot(lambda x: np.sin(x), color=PINK)

        startpoint_odd = plane.c2p(0,0)+0.1*(LEFT+DOWN)
        bubble_odd = Bubble(["$\\sin(-x)=-\\sin(x)$", "$\\Rightarrow$Sine function is odd"], start_point=startpoint_odd, width = 2.6, center=0.4*RIGHT+2.6*DOWN, loc="t1")
        odd_updater = lambda m: m.move_to(bubble_odd.get_end())

        startpoint_even = plane.c2p(0,1) + 0.1*UP
        bubble_even = Bubble(["$\\cos(-x)=\\cos(x)$", "$\\Rightarrow$Cosine function is even"], start_point=startpoint_even, width = 2.6, center=0.8*LEFT+2*UP, loc="b1")
        even_updater = lambda m: m.move_to(bubble_even.get_end())

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right.
                The <bookmark mark="blue"/> cosine function is an even function, because it is <bookmark mark="y_axis"/> symmetric
                to the y-axis. <bookmark mark="bubble_cosine"/>Formally, a function is even if f of minus x is equal to f of x.
                This holds true for the cosine function.

                The<bookmark mark="purple"/> purple graph corresponds to the sine function. The sine function is an odd function,
                because it is <bookmark mark="origin"/> symmetric to the origin. <bookmark mark="bubble_sine"/>Formally, a
                function is odd if f of minus x is equal to minus f of x. This holds true for the sine function.

                So in summary, the sine function is an odd function and the cosine function is an even function.
                """
        ) as tracker:
            
            self.wait_until_bookmark("blue")
            self.play(Write(graph_blue), run_time=3)

            self.wait_until_bookmark("y_axis")
            cursor.blinking=False
            self.play(CursorMarkAxis(cursor, plane, "y"), run_time=0.5)


            self.wait_until_bookmark("bubble_cosine")
            x,y, _ = startpoint_even
            self.play(CursorMoveResize(cursor, x, y, 0.2, 0.2), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(even_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_even), Write(bubble_even.text), run_time=2)
            cursor.blinking=True

            self.wait_until_bookmark("purple")
            self.play(Write(graph_pink), run_time=3)

            self.wait_until_bookmark("origin")
            x,y,_ = plane.c2p(0,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            cursor.blinking=True

            self.wait_until_bookmark("bubble_sine")
            x,y, _ = startpoint_odd
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=0.5)
            self.add(cursor.copy()._start_fading(3).add_updater(odd_updater))
            self.add_pencil_sound(2)
            self.play(Create(bubble_odd), Write(bubble_odd.text), run_time=2)
            cursor.blinking=True

        self.wait(4)





PROTOTYPES=[
    PagePrototypeVideo.from_scene(Func_7_3_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_3_I_1_q, Func_7_3_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_3_I_1_a),
    PagePrototypeVideo.from_scene(Func_7_3_I_1_b),
    PagePrototypeVideo.from_scene(Func_7_3_I_3),
    PagePrototypeVideo.from_scene(Func_7_3_I_4),
    PagePrototypeVideo.from_scene(Func_7_3_I_5),
    PagePrototypeVideo.from_scene(Func_7_3_P_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_3_P_1_q, Func_7_3_P_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_3_P_1_a),
    PagePrototypeVideo.from_scene(Func_7_3_P_1_b),
    PagePrototypeVideo.from_scene(Func_7_3_P_1_c),
    PagePrototypeVideo.from_scene(Func_7_3_P_1_d),
    PagePrototypeVideo.from_scene(Func_7_3_P_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_3_P_2_q, Func_7_3_P_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_3_P_2_a),
    PagePrototypeVideo.from_scene(Func_7_3_P_2_b),
    PagePrototypeVideo.from_scene(Func_7_3_P_2_c),
    PagePrototypeVideo.from_scene(Func_7_3_P_2_d),
]

scenes/Func/Func_7: Sine and Cosine Functions/Func_7_3.py
Sophia-Edu-Labs/sophia-math
# 7_4: Trigonometric Functions: Scaling

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition

#####################################
#####################################
TASK_Func_7_4_I_1_q = SophiaTaskDefinition(
    answerOptions = ["Add $2$: $f(x)=\sin(x)+2$", "Multiply by $2$: $f(x)=2\sin(x)$", "Multiply by $\\tfrac{1}{2}$: $f(x)=\\tfrac{1}{2}\sin(x)$", "Add $\\tfrac{1}{2}$: $f(x)=\sin(x)+\\tfrac{1}{2}$"],
    correctAnswerIndex = 1,
    questionText = "How do we change the function $f(x)=\sin(x)$, so that its values reach from $-2$ to $2$?"
)
class Func_7_4_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-1.5, 1.5, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(-0.5,np.sin(-0.5))
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=False, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        graph_blue = plane.plot(lambda x: np.sin(x), color=BLUE)

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)

        # Action Sequence
        with self.voiceover(
                text="""
                This is a graph of the sine function.
                The values of the sine function range<bookmark mark="neg_1"/> from negative <bookmark mark="pos_1"/>one to one.

                Now we want to change the function, so that its values <bookmark mark="neg_2"/>range from negative
                <bookmark mark="pos_2"/>two to two.

                How do we change the <bookmark mark="f"/> term f <bookmark mark="fx"/> of x<bookmark mark="sin"/> equals sine
                <bookmark mark="x"/> of x, so that the values of the function range from negative
                two to two?
                """
        ) as tracker:
            
            
            self.add(cursor.copy().add_updater(lambda m: m.move_to(graph_blue.get_end()))._start_fading(2))
            self.add_pencil_sound(1.5)
            self.play(Create(graph_blue))
            cursor.blinking=True

            self.wait_until_bookmark("neg_1")
            x,y,_ = line_1.get_start()
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("pos_1")
            cursor.blinking=False
            self.add(cursor.copy().add_updater(lambda m: m.move_to(line_1.get_end()))._start_fading(2))
            self.play(Create(line_1), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("neg_2")
            x,y,_ = line_2.get_start()
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("pos_2")
            cursor.blinking=False
            self.add(cursor.copy().add_updater(lambda m: m.move_to(line_2.get_end()))._start_fading(2))
            self.play(Create(line_2), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            x,y,_ = functerm[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(functerm), CursorMoveTo(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("fx")
            x,y,_ = functerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("sin")
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("x")
            x,y,_ = functerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

        self.wait(4)


class Func_7_4_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-1.5, 1.5, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(-0.5,np.sin(-0.5))
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        graph_blue = plane.plot(lambda x: np.sin(x), color=BLUE)

        a = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(x), color=BLUE))

        ones = VGroup(MathTex("1", color=c1t, font_size=fs2), MathTex("-1", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
        arrows = VGroup(MathTex("\\Rightarrow", color=c1t, font_size=fs2), MathTex("\\Rightarrow", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=LEFT)
        twos = VGroup(MathTex("2", color=c1t, font_size=fs2), MathTex("-2", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
        ones_to_twos = VGroup(ones, arrows, twos).arrange(RIGHT, buff=0.4).next_to(title, DOWN, buff=0.4)
        row_one = VGroup(ones_to_twos[0][0], ones_to_twos[1][0], ones_to_twos[2][0])
        row_two = VGroup(ones_to_twos[0][1], ones_to_twos[1][1], ones_to_twos[2][1])

        functerm = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        functerm_2 = MathTex("f","(x)",  "=", "2", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)

        self.add(functerm, graph_blue)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right.
                We want the values of the function to range from negative two to two, instead of from negative one to one.
                This means, that wherever the function<bookmark mark="row_1_a"/> has a value of one, we want it
                <bookmark mark="row_1_b"/>to have a value of two instead.

                And wherever the function<bookmark mark="row_2_a"/> has a value of negative one, we want it <bookmark mark="row_2_b"/>
                to have a value of negative two instead.

                Clearly, we can achieve this by <bookmark mark="transform_term"/> multiplying the function by two.
                If we do that, <bookmark mark="stretch_func"/> the function will be stretched vertically by a factor of two.
                And that's exactly what we want.
                """
        ) as tracker:
            
            self.wait_until_bookmark("row_1_a")
            cursor.blinking=False
            x,y,_ = row_one[0].get_center()+0.4*DOWN
            self.play(Create(row_one), CursorMoveTo(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("row_1_b")
            x,y,_ = row_one[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("row_2_a")
            cursor.blinking=False
            x,y,_ = row_two[0].get_center()+0.4*DOWN
            self.play(Create(row_two), CursorMoveTo(cursor,x,y), run_time=.5)
            
            self.wait_until_bookmark("row_2_b")
            x,y,_ = row_two[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("transform_term")
            x,y,_ = functerm_2[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(TransformMatchingTex(functerm, functerm_2), CursorMoveTo(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("stretch_func")
            self.remove(graph_blue)
            self.add(graph_blue_updated)
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.add_updater(lambda m: m.move_to(plane.c2p(np.pi/2,a.get_value())))
            self.play(a.animate.set_value(2), run_time=2)
            cursor.blinking=True


        self.wait(4)


class Func_7_4_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-1.5, 1.5, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(-0.5,np.sin(-0.5))
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        graph_blue = plane.plot(lambda x: np.sin(x), color=BLUE)

        a = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(x), color=BLUE))

        ones = VGroup(MathTex("1", color=c1t, font_size=fs2), MathTex("-1", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
        arrows = VGroup(MathTex("\\Rightarrow", color=c1t, font_size=fs2), MathTex("\\Rightarrow", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=LEFT)
        twos = VGroup(MathTex("2", color=c1t, font_size=fs2), MathTex("-2", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
        ones_to_twos = VGroup(ones, arrows, twos).arrange(RIGHT, buff=0.4).next_to(title, DOWN, buff=0.4)
        row_one = VGroup(ones_to_twos[0][0], ones_to_twos[1][0], ones_to_twos[2][0])
        row_two = VGroup(ones_to_twos[0][1], ones_to_twos[1][1], ones_to_twos[2][1])

        functerm = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        functerm_2 = MathTex("f","(x)",  "=", "2", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)

        self.add(functerm, graph_blue)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's it!
                We want the values of the function to range from negative two to two, instead of from negative one to one.
                This means, that wherever the function<bookmark mark="row_1_a"/> has a value of one, we want it
                <bookmark mark="row_1_b"/>to have a value of two instead.

                And wherever the function<bookmark mark="row_2_a"/> has a value of negative one, we want it <bookmark mark="row_2_b"/>
                to have a value of negative two instead.

                Clearly, we can achieve this by <bookmark mark="transform_term"/> multiplying the function by two.
                If we do that, <bookmark mark="stretch_func"/> the function will be stretched vertically by a factor of two.
                And that's exactly what we want.
                """
        ) as tracker:
            
            self.wait_until_bookmark("row_1_a")
            cursor.blinking=False
            x,y,_ = row_one[0].get_center()+0.4*DOWN
            self.play(Create(row_one), CursorMoveTo(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("row_1_b")
            x,y,_ = row_one[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("row_2_a")
            cursor.blinking=False
            x,y,_ = row_two[0].get_center()+0.4*DOWN
            self.play(Create(row_two), CursorMoveTo(cursor,x,y), run_time=.5)
            
            self.wait_until_bookmark("row_2_b")
            x,y,_ = row_two[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("transform_term")
            x,y,_ = functerm_2[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(TransformMatchingTex(functerm, functerm_2), CursorMoveTo(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("stretch_func")
            self.remove(graph_blue)
            self.add(graph_blue_updated)
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.add_updater(lambda m: m.move_to(plane.c2p(np.pi/2,a.get_value())))
            self.play(a.animate.set_value(2), run_time=2)
            cursor.blinking=True


        self.wait(4)


class Func_7_4_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-1.5, 1.5, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(-0.5,np.sin(-0.5))
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        graph_blue = plane.plot(lambda x: np.sin(x), color=BLUE)

        a = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(x), color=BLUE))

        ones = VGroup(MathTex("1", color=c1t, font_size=fs2), MathTex("-1", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
        arrows = VGroup(MathTex("\\Rightarrow", color=c1t, font_size=fs2), MathTex("\\Rightarrow", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=LEFT)
        twos = VGroup(MathTex("2", color=c1t, font_size=fs2), MathTex("-2", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
        ones_to_twos = VGroup(ones, arrows, twos).arrange(RIGHT, buff=0.4).next_to(title, DOWN, buff=0.4)
        row_one = VGroup(ones_to_twos[0][0], ones_to_twos[1][0], ones_to_twos[2][0])
        row_two = VGroup(ones_to_twos[0][1], ones_to_twos[1][1], ones_to_twos[2][1])

        functerm = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        functerm_2 = MathTex("f","(x)",  "=", "2", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)

        self.add(functerm, graph_blue)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right.
                We want the values of the function to range from negative two to two, instead of from negative one to one.
                This means, that wherever the function<bookmark mark="row_1_a"/> has a value of one, we want it
                <bookmark mark="row_1_b"/>to have a value of two instead.

                And wherever the function<bookmark mark="row_2_a"/> has a value of negative one, we want it <bookmark mark="row_2_b"/>
                to have a value of negative two instead.

                Clearly, we can achieve this by <bookmark mark="transform_term"/> multiplying the function by two.
                If we do that, <bookmark mark="stretch_func"/> the function will be stretched vertically by a factor of two.
                And that's exactly what we want.
                """
        ) as tracker:
            
            self.wait_until_bookmark("row_1_a")
            cursor.blinking=False
            x,y,_ = row_one[0].get_center()+0.4*DOWN
            self.play(Create(row_one), CursorMoveTo(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("row_1_b")
            x,y,_ = row_one[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("row_2_a")
            cursor.blinking=False
            x,y,_ = row_two[0].get_center()+0.4*DOWN
            self.play(Create(row_two), CursorMoveTo(cursor,x,y), run_time=.5)
            
            self.wait_until_bookmark("row_2_b")
            x,y,_ = row_two[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("transform_term")
            x,y,_ = functerm_2[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(TransformMatchingTex(functerm, functerm_2), CursorMoveTo(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("stretch_func")
            self.remove(graph_blue)
            self.add(graph_blue_updated)
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.add_updater(lambda m: m.move_to(plane.c2p(np.pi/2,a.get_value())))
            self.play(a.animate.set_value(2), run_time=2)
            cursor.blinking=True


        self.wait(4)


class Func_7_4_I_1_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-1.5, 1.5, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(-0.5,np.sin(-0.5))
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        graph_blue = plane.plot(lambda x: np.sin(x), color=BLUE)

        a = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(x), color=BLUE))

        ones = VGroup(MathTex("1", color=c1t, font_size=fs2), MathTex("-1", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
        arrows = VGroup(MathTex("\\Rightarrow", color=c1t, font_size=fs2), MathTex("\\Rightarrow", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=LEFT)
        twos = VGroup(MathTex("2", color=c1t, font_size=fs2), MathTex("-2", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
        ones_to_twos = VGroup(ones, arrows, twos).arrange(RIGHT, buff=0.4).next_to(title, DOWN, buff=0.4)
        row_one = VGroup(ones_to_twos[0][0], ones_to_twos[1][0], ones_to_twos[2][0])
        row_two = VGroup(ones_to_twos[0][1], ones_to_twos[1][1], ones_to_twos[2][1])

        functerm = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        functerm_2 = MathTex("f","(x)",  "=", "2", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)

        self.add(functerm, graph_blue)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right.
                We want the values of the function to range from negative two to two, instead of from negative one to one.
                This means, that wherever the function<bookmark mark="row_1_a"/> has a value of one, we want it
                <bookmark mark="row_1_b"/>to have a value of two instead.

                And wherever the function<bookmark mark="row_2_a"/> has a value of negative one, we want it <bookmark mark="row_2_b"/>
                to have a value of negative two instead.

                Clearly, we can achieve this by <bookmark mark="transform_term"/> multiplying the function by two.
                If we do that, <bookmark mark="stretch_func"/> the function will be stretched vertically by a factor of two.
                And that's exactly what we want.
                """
        ) as tracker:
            
            self.wait_until_bookmark("row_1_a")
            cursor.blinking=False
            x,y,_ = row_one[0].get_center()+0.4*DOWN
            self.play(Create(row_one), CursorMoveTo(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("row_1_b")
            x,y,_ = row_one[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("row_2_a")
            cursor.blinking=False
            x,y,_ = row_two[0].get_center()+0.4*DOWN
            self.play(Create(row_two), CursorMoveTo(cursor,x,y), run_time=.5)
            
            self.wait_until_bookmark("row_2_b")
            x,y,_ = row_two[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("transform_term")
            x,y,_ = functerm_2[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(TransformMatchingTex(functerm, functerm_2), CursorMoveTo(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("stretch_func")
            self.remove(graph_blue)
            self.add(graph_blue_updated)
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.add_updater(lambda m: m.move_to(plane.c2p(np.pi/2,a.get_value())))
            self.play(a.animate.set_value(2), run_time=2)
            cursor.blinking=True


        self.wait(4)



#####################################
#####################################
class Func_7_4_I_2(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm = MathTex("f","(x)",  "=", "a", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        a_val = VGroup(MathTex("a=", color=c1t, font_size=fs1), DecimalNumber(1).scale(.9).set_color(c1t).add_updater(lambda m: m.set_value(a.get_value()))).arrange(RIGHT, buff=0.2).next_to(functerm, DOWN, buff=0.4)
        a_val[1].shift((a_val[0].get_bottom()-a_val[1].get_bottom())[1]*UP)
        self.add(graph_blue_updated, functerm, a_val)

        # Action Sequence
        with self.voiceover(
                text="""
                In general, we can scale the sine function <bookmark mark="y_axis"/> in y-direction by simply
                multiplying the entire function <bookmark mark="scale_a"/> by a constant factor a.<bookmark mark="move_cursor"/>
                If <bookmark mark="a_1"/>a is greater than one, the function will be stretched vertically.
                And if <bookmark mark="a_2"/>a is less than one, the function will be compressed vertically.
                We can also reflect the function at the x-axis by <bookmark mark="a_3"/>choosing a negative value for a.
                """
        ) as tracker:
            
            self.wait_until_bookmark("y_axis")
            cursor.blinking = False
            self.play(CursorMarkAxis(cursor, plane, "y"), run_time=.5)

            self.wait_until_bookmark("scale_a")
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveResize(cursor,x,y, 0.2, 0.2), run_time=.5)
            cursor.blinking = True

            self.wait_until_bookmark("move_cursor")
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.add_updater(lambda m: m.move_to(plane.c2p(np.pi/2,a.get_value())))

            self.wait_until_bookmark("a_1")
            self.play(a.animate.set_value(2.5), run_time=2.5)
            cursor.blinking=True

            self.wait_until_bookmark("a_2")
            cursor.blinking=False
            self.play(a.animate.set_value(0.3), run_time=4)
            cursor.blinking=True

            self.wait_until_bookmark("a_3")
            cursor.blinking=False
            self.play(a.animate.set_value(-1), run_time=1)
            cursor.blinking=True


        self.wait(4)


#####################################
#####################################
TASK_Func_7_4_P_1_q = SophiaTaskDefinition(
    answerOptions = ["$a=2$", "$a=\\tfrac{1}{2}$", "$a=-2$", "$a=-\\tfrac{1}{2}$"],
    correctAnswerIndex = 2,
    questionText = "What value do we choose for $a$, to stretch the function vertically by a factor of two and reflect it at the x-axis?",
)
class Func_7_4_P_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm = MathTex("f","(x)",  "=", "a", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm)

        # Action Sequence
        with self.voiceover(
                text="""
                Here's the sine <bookmark mark="f"/> function f <bookmark mark="fx"/> of x <bookmark mark="a"/>
                equals a <bookmark mark="sin"/> times sine <bookmark mark="x"/> of x.
                Now <bookmark mark="move_cursor"/>say we want to stretch the function <bookmark mark="a_1"/>by a factor of two,
                and <bookmark mark="a_2"/>reflect it at the x-axis.

                What <bookmark mark="a_mark"/>value of a do we need to choose, to make this happen?
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking = False
            x,y,_ = functerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=.5)

            self.wait_until_bookmark("fx")
            x,y,_ = functerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("a")
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("sin")
            x,y,_ = functerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

            self.wait_until_bookmark("x")
            x,y,_ = functerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)
            cursor.blinking=True

            self.wait_until_bookmark("move_cursor")
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/2,a.get_value()))
            cursor.add_updater(cursor_updater)

            self.wait_until_bookmark("a_1")
            self.play(a.animate.set_value(2))

            self.wait_until_bookmark("a_2")
            self.play(a.animate.set_value(-2), run_time=.3)
            cursor.blinking=True

            self.wait_until_bookmark("a_mark")
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            cursor.blinking=False
            cursor.remove_updater(cursor_updater)
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)
            cursor.blinking=True

        self.wait(4)



class Func_7_4_P_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm = MathTex("f","(x)",  "=", "a", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it. So we start with the <bookmark mark="f"/> function f
                <bookmark mark="fx"/> of x <bookmark mark="a"/> equals a <bookmark mark="sin"/>
                times sine <bookmark mark="x"/> of x.
                Now to <bookmark mark="move_cursor_1"/>stretch the function <bookmark mark="a_1"/>by a factor of two,
                we <bookmark mark="a_term_1"/>multiply the function by a factor of a equals two.

                <bookmark mark="move_cursor_2"/>Next, to <bookmark mark="a_2"/>reflect the function at the x-axis,
                we multiply the entire function by negative one, which means <bookmark mark="a_term_2"/>choosing
                a value of "a" equals negative two.

                So the answer is "a" equals negative two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking = False
            x,y,_ = functerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=.5)

            self.wait_until_bookmark("fx")
            x,y,_ = functerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("a")
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("sin")
            x,y,_ = functerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

            self.wait_until_bookmark("x")
            x,y,_ = functerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)
            cursor.blinking=True

            self.wait_until_bookmark("move_cursor_1")
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/2,a.get_value()))
            cursor.add_updater(cursor_updater)

            self.wait_until_bookmark("a_1")
            self.play(a.animate.set_value(2))

            self.wait_until_bookmark("a_term_1")
            cursor.remove_updater(cursor_updater)
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)
            cursor.blinking=True
            self.play(ReplacementTransform(functerm[3], MathTex("2", color=c1t, font_size=fs1).move_to(functerm[3])))

            self.wait_until_bookmark("move_cursor_2")
            x,y,_ = plane.c2p(np.pi/2,2)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.add_updater(cursor_updater)

            self.wait_until_bookmark("a_2")
            self.play(a.animate.set_value(-2), run_time=.3)
            cursor.blinking=True

            self.wait_until_bookmark("a_term_2")
            cursor.remove_updater(cursor_updater)
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)
            cursor.blinking=True
            self.play(functerm[-2].animate.shift(0.3*RIGHT), functerm[-1].animate.shift(0.3*RIGHT), ReplacementTransform(functerm[3], MathTex("-2", color=c1t, font_size=fs1).move_to(functerm[3]).shift(0.1*RIGHT)))

        self.wait(4)


class Func_7_4_P_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm = MathTex("f","(x)",  "=", "a", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it. So we start with the <bookmark mark="f"/> function f
                <bookmark mark="fx"/> of x <bookmark mark="a"/> equals a <bookmark mark="sin"/>
                times sine <bookmark mark="x"/> of x.
                Now to <bookmark mark="move_cursor_1"/>stretch the function <bookmark mark="a_1"/>by a factor of two,
                we <bookmark mark="a_term_1"/>multiply the function by a factor of a equals two.

                <bookmark mark="move_cursor_2"/>Next, to <bookmark mark="a_2"/>reflect the function at the x-axis,
                we multiply the entire function by negative one, which means <bookmark mark="a_term_2"/>choosing
                a value of "a" equals negative two.

                So the answer is "a" equals negative two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking = False
            x,y,_ = functerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=.5)

            self.wait_until_bookmark("fx")
            x,y,_ = functerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("a")
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("sin")
            x,y,_ = functerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

            self.wait_until_bookmark("x")
            x,y,_ = functerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)
            cursor.blinking=True

            self.wait_until_bookmark("move_cursor_1")
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/2,a.get_value()))
            cursor.add_updater(cursor_updater)

            self.wait_until_bookmark("a_1")
            self.play(a.animate.set_value(2))

            self.wait_until_bookmark("a_term_1")
            cursor.remove_updater(cursor_updater)
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)
            cursor.blinking=True
            self.play(ReplacementTransform(functerm[3], MathTex("2", color=c1t, font_size=fs1).move_to(functerm[3])))

            self.wait_until_bookmark("move_cursor_2")
            x,y,_ = plane.c2p(np.pi/2,2)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.add_updater(cursor_updater)

            self.wait_until_bookmark("a_2")
            self.play(a.animate.set_value(-2), run_time=.3)
            cursor.blinking=True

            self.wait_until_bookmark("a_term_2")
            cursor.remove_updater(cursor_updater)
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)
            cursor.blinking=True
            self.play(functerm[-2].animate.shift(0.3*RIGHT), functerm[-1].animate.shift(0.3*RIGHT), ReplacementTransform(functerm[3], MathTex("-2", color=c1t, font_size=fs1).move_to(functerm[3]).shift(0.1*RIGHT)))

        self.wait(4)


class Func_7_4_P_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm = MathTex("f","(x)",  "=", "a", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's right. So we start with the <bookmark mark="f"/> function f
                <bookmark mark="fx"/> of x <bookmark mark="a"/> equals a <bookmark mark="sin"/>
                times sine <bookmark mark="x"/> of x.
                Now to <bookmark mark="move_cursor_1"/>stretch the function <bookmark mark="a_1"/>by a factor of two,
                we <bookmark mark="a_term_1"/>multiply the function by a factor of a equals two.

                <bookmark mark="move_cursor_2"/>Next, to <bookmark mark="a_2"/>reflect the function at the x-axis,
                we multiply the entire function by negative one, which means <bookmark mark="a_term_2"/>choosing
                a value of "a" equals negative two.

                So the answer is "a" equals negative two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking = False
            x,y,_ = functerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=.5)

            self.wait_until_bookmark("fx")
            x,y,_ = functerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("a")
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("sin")
            x,y,_ = functerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

            self.wait_until_bookmark("x")
            x,y,_ = functerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)
            cursor.blinking=True

            self.wait_until_bookmark("move_cursor_1")
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/2,a.get_value()))
            cursor.add_updater(cursor_updater)

            self.wait_until_bookmark("a_1")
            self.play(a.animate.set_value(2))

            self.wait_until_bookmark("a_term_1")
            cursor.remove_updater(cursor_updater)
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)
            cursor.blinking=True
            self.play(ReplacementTransform(functerm[3], MathTex("2", color=c1t, font_size=fs1).move_to(functerm[3])))

            self.wait_until_bookmark("move_cursor_2")
            x,y,_ = plane.c2p(np.pi/2,2)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.add_updater(cursor_updater)

            self.wait_until_bookmark("a_2")
            self.play(a.animate.set_value(-2), run_time=.3)
            cursor.blinking=True

            self.wait_until_bookmark("a_term_2")
            cursor.remove_updater(cursor_updater)
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)
            cursor.blinking=True
            self.play(functerm[-2].animate.shift(0.3*RIGHT), functerm[-1].animate.shift(0.3*RIGHT), ReplacementTransform(functerm[3], MathTex("-2", color=c1t, font_size=fs1).move_to(functerm[3]).shift(0.1*RIGHT)))

        self.wait(4)


class Func_7_4_P_1_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm = MathTex("f","(x)",  "=", "a", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not it. So we start with the <bookmark mark="f"/> function f
                <bookmark mark="fx"/> of x <bookmark mark="a"/> equals a <bookmark mark="sin"/>
                times sine <bookmark mark="x"/> of x.
                Now to <bookmark mark="move_cursor_1"/>stretch the function <bookmark mark="a_1"/>by a factor of two,
                we <bookmark mark="a_term_1"/>multiply the function by a factor of a equals two.

                <bookmark mark="move_cursor_2"/>Next, to <bookmark mark="a_2"/>reflect the function at the x-axis,
                we multiply the entire function by negative one, which means <bookmark mark="a_term_2"/>choosing
                a value of "a" equals negative two.

                So the answer is "a" equals negative two.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f")
            cursor.blinking = False
            x,y,_ = functerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=.5)

            self.wait_until_bookmark("fx")
            x,y,_ = functerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("a")
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("sin")
            x,y,_ = functerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

            self.wait_until_bookmark("x")
            x,y,_ = functerm[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)
            cursor.blinking=True

            self.wait_until_bookmark("move_cursor_1")
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/2,a.get_value()))
            cursor.add_updater(cursor_updater)

            self.wait_until_bookmark("a_1")
            self.play(a.animate.set_value(2))

            self.wait_until_bookmark("a_term_1")
            cursor.remove_updater(cursor_updater)
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)
            cursor.blinking=True
            self.play(ReplacementTransform(functerm[3], MathTex("2", color=c1t, font_size=fs1).move_to(functerm[3])))

            self.wait_until_bookmark("move_cursor_2")
            x,y,_ = plane.c2p(np.pi/2,2)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.add_updater(cursor_updater)

            self.wait_until_bookmark("a_2")
            self.play(a.animate.set_value(-2), run_time=.3)
            cursor.blinking=True

            self.wait_until_bookmark("a_term_2")
            cursor.remove_updater(cursor_updater)
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor, x, y), run_time=.3)
            cursor.blinking=True
            self.play(functerm[-2].animate.shift(0.3*RIGHT), functerm[-1].animate.shift(0.3*RIGHT), ReplacementTransform(functerm[3], MathTex("-2", color=c1t, font_size=fs1).move_to(functerm[3]).shift(0.1*RIGHT)))

        self.wait(4)


#####################################
#####################################
TASK_Func_7_4_I_3_q = SophiaTaskDefinition(
    answerOptions = ["Add $b$ to $x$: $f(x)=\sin(x+b)$", "Multiply $f$ by $b$: $f(x)=b\sin(x)$", "Add $b$ to $f$: $f(x)=\sin(x)+b$", "Multiply x by $b$: $f(x)=\sin(bx)$"],
    correctAnswerIndex = 3,
    questionText = "How do we change the function $f(x)=\sin(x)$, so that it is scaled in x-Direction?"
)
class Func_7_4_I_3_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm = MathTex("f","(x)",  "=", "a", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        functerm_2 = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm)

        # Action Sequence
        with self.voiceover(
                text="""
                <bookmark mark="start"/>
                We can scale the sine function <bookmark mark="y_axis"/> in y-direction by simply
                multiplying the entire function by a <bookmark mark="scale_a"/>constant factor a.
                <bookmark mark="move_cursor"/>


                Now, what if we want to scale the <bookmark mark="x_axis"/> function in x-direction?
                How do we change the <bookmark mark="f"/> function term f <bookmark mark="fx"/> of x <bookmark mark="sin"/>equals
                sine <bookmark mark="x"/> of x, so that <bookmark mark="scale_b"/>f is scaled in x-direction?
                
                """
        ) as tracker:
            
            self.wait_until_bookmark("start")
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/2,a.get_value()))
            cursor.add_updater(cursor_updater)
            self.play(a.animate.set_value(2.5), run_time=.8)
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True
            
            self.wait_until_bookmark("y_axis")
            cursor.blinking = False
            self.play(CursorMarkAxis(cursor, plane, "y"), run_time=.5)
            self.wait(1)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveResize(cursor,x,y,0.2,0.2), run_time=.3)
            cursor.blinking=True

            self.wait_until_bookmark("scale_a")
            cursor.blinking = False
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveResize(cursor,x,y, 0.2, 0.2), run_time=.5)
            cursor.blinking = True


            self.wait_until_bookmark("x_axis")
            cursor.blinking = False
            self.play(a.animate(run_time=.4).set_value(1), CursorMarkAxis(cursor, plane, "x"), run_time=1)

            self.wait_until_bookmark("f")
            cursor.blinking = False
            x,y,_ = functerm[0].get_center()+0.4*DOWN
            self.play(TransformMatchingTex(functerm, functerm_2), CursorMoveResize(cursor, x, y, 0.2, 0.2), run_time=.5)

            self.wait_until_bookmark("fx")
            x,y,_ = functerm_2[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("sin")
            x,y,_ = functerm_2[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

            self.wait_until_bookmark("x")
            x,y,_ = functerm_2[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)
            cursor.blinking=True

            self.wait_until_bookmark("scale_b")
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/(2*b.get_value()),1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(2.5), run_time=2.5)
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

        self.wait(4)


class Func_7_4_I_3_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm_1 = MathTex("f","(x)",  "=",  "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        functerm_2 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm_1)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not correct.
                
                <bookmark mark="scale_b"/>We can scale the sine function in x-direction by simply
                multiplying the value of x by a <bookmark mark="term_1"/>constant factor b.

                This way we scale all the values we plug in for x, which means we scale the entire
                <bookmark mark="x_axis"/>function in x-direction.
                """
        ) as tracker:

            self.wait_until_bookmark("scale_b")
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/(2*b.get_value()),1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(2.5), run_time=1)
            self.play(b.animate.set_value(0.4), run_time=2)
            self.play(b.animate.set_value(1), run_time=1)
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("term_1")
            cursor.blinking = False
            x,y,_ = functerm_2[5].get_center()+0.4*DOWN
            self.play(TransformMatchingTex(functerm_1, functerm_2), CursorMoveTo(cursor, x, y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("x_axis")
            cursor.blinking = False
            self.play(CursorMarkAxis(cursor, plane, "x"), run_time=.5)
            x,y,_ = plane.c2p(0,0)
            self.wait(2)
            self.play(CursorMoveResize(cursor,x,y,0.2,0.2), run_time=.3)
            cursor.blinking=True

        self.wait(4)



class Func_7_4_I_3_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm_1 = MathTex("f","(x)",  "=",  "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        functerm_2 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm_1)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not correct.
                
                <bookmark mark="scale_b"/>We can scale the sine function in x-direction by simply
                multiplying the value of x by a <bookmark mark="term_1"/>constant factor b.

                This way we scale all the values we plug in for x, which means we scale the entire
                <bookmark mark="x_axis"/>function in x-direction.
                """
        ) as tracker:

            self.wait_until_bookmark("scale_b")
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/(2*b.get_value()),1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(2.5), run_time=1)
            self.play(b.animate.set_value(0.4), run_time=2)
            self.play(b.animate.set_value(1), run_time=1)
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("term_1")
            cursor.blinking = False
            x,y,_ = functerm_2[5].get_center()+0.4*DOWN
            self.play(TransformMatchingTex(functerm_1, functerm_2), CursorMoveTo(cursor, x, y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("x_axis")
            cursor.blinking = False
            self.play(CursorMarkAxis(cursor, plane, "x"), run_time=.5)
            x,y,_ = plane.c2p(0,0)
            self.wait(2)
            self.play(CursorMoveResize(cursor,x,y,0.2,0.2), run_time=.3)
            cursor.blinking=True

        self.wait(4)



class Func_7_4_I_3_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm_1 = MathTex("f","(x)",  "=",  "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        functerm_2 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm_1)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not correct.
                
                <bookmark mark="scale_b"/>We can scale the sine function in x-direction by simply
                multiplying the value of x by a <bookmark mark="term_1"/>constant factor b.

                This way we scale all the values we plug in for x, which means we scale the entire
                <bookmark mark="x_axis"/>function in x-direction.
                """
        ) as tracker:

            self.wait_until_bookmark("scale_b")
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/(2*b.get_value()),1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(2.5), run_time=1)
            self.play(b.animate.set_value(0.4), run_time=2)
            self.play(b.animate.set_value(1), run_time=1)
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("term_1")
            cursor.blinking = False
            x,y,_ = functerm_2[5].get_center()+0.4*DOWN
            self.play(TransformMatchingTex(functerm_1, functerm_2), CursorMoveTo(cursor, x, y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("x_axis")
            cursor.blinking = False
            self.play(CursorMarkAxis(cursor, plane, "x"), run_time=.5)
            x,y,_ = plane.c2p(0,0)
            self.wait(2)
            self.play(CursorMoveResize(cursor,x,y,0.2,0.2), run_time=.3)
            cursor.blinking=True

        self.wait(4)



class Func_7_4_I_3_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm_1 = MathTex("f","(x)",  "=",  "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        functerm_2 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm_1)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's right. Nice job.
                
                <bookmark mark="scale_b"/>We can scale the sine function in x-direction by simply
                multiplying the value of x by a <bookmark mark="term_1"/>constant factor b.

                This way we scale all the values we plug in for x, which means we scale the entire
                <bookmark mark="x_axis"/>function in x-direction.
                """
        ) as tracker:

            self.wait_until_bookmark("scale_b")
            x,y,_ = plane.c2p(np.pi/2,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/(2*b.get_value()),1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(2.5), run_time=1)
            self.play(b.animate.set_value(0.4), run_time=2)
            self.play(b.animate.set_value(1), run_time=1)
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("term_1")
            cursor.blinking = False
            x,y,_ = functerm_2[5].get_center()+0.4*DOWN
            self.play(TransformMatchingTex(functerm_1, functerm_2), CursorMoveTo(cursor, x, y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("x_axis")
            cursor.blinking = False
            self.play(CursorMarkAxis(cursor, plane, "x"), run_time=.5)
            x,y,_ = plane.c2p(0,0)
            self.wait(2)
            self.play(CursorMoveResize(cursor,x,y,0.2,0.2), run_time=.3)
            cursor.blinking=True

        self.wait(4)





#####################################
#####################################
TASK_Func_7_4_I_4_q = SophiaTaskDefinition(
    answerOptions = ["$b<1$: squash, $b>1$: stretch", "$b<1$: stretch, $b>1$: squash", "$b<0$: squash, $b>0$: stretch", "$b<0$: squash, $b>0$: stretch"],
    correctAnswerIndex = 1,
    questionText = "Which values of $b$ would stretch the function, and which values would squash it?"
)
class Func_7_4_I_4_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm_1 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm_1)

        # Action Sequence
        with self.voiceover(
                text="""
                Looking at the function <bookmark mark="f"/> term f <bookmark mark="fx"/> of x <bookmark mark="sin"/>equals
                sine <bookmark mark="b_1"/> of <bookmark mark="x"/> b times x, what values of
                b <bookmark mark="stretch"/>would  stretch the function in x-direction?

                And: which values of <bookmark mark ="compress"/>b would squash the function
                in x direction?
                """
        ) as tracker:

            self.wait_until_bookmark("f")
            cursor.blinking = False
            x,y,_ = functerm_1[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor, x, y), run_time=.5)

            self.wait_until_bookmark("fx")
            x,y,_ = functerm_1[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

            self.wait_until_bookmark("sin")
            x,y,_ = functerm_1[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

            self.wait_until_bookmark("b_1")
            x,y,_ = functerm_1[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

            self.wait_until_bookmark("x")
            x,y,_ = functerm_1[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)
            cursor.blinking=True

            self.wait_until_bookmark("stretch")
            cursor.blinking = False
            x,y,_ = plane.c2p(np.pi/2,1)
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/(2*b.get_value()),1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(0.4), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("compress")
            cursor.blinking = False
            self.play(b.animate.set_value(2.5), run_time=1)
            cursor.blinking=True

        cursor.remove_updater(cursor_updater)
        x,y,_ = plane.c2p(0,0)
        self.play(CursorMoveResize(cursor,x,y,0.2,0.2), b.animate.set_value(1), run_time=1)            

        self.wait(4)


class Func_7_4_I_4_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm_1 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm_1)

        line_1 = Line(plane.c2p(0,-1), plane.c2p(1.5*np.pi,-1), color=PURPLE)
        text_1 = MathTex("1.5\\Pi", color=PURPLE, font_size=fs3).next_to(line_1, DOWN, buff=0.1)
        line_2 = Line(plane.c2p(0,-1), plane.c2p(.5*np.pi,-1), color=GREEN)
        text_2 = MathTex("0.5\\Pi", color=GREEN, font_size=fs3).next_to(line_2, DOWN, buff=0.1)
        line_3 = Line(plane.c2p(0,1), plane.c2p(.5*np.pi,1), color=PURPLE)
        text_3 = MathTex("0.5\\Pi", color=PURPLE, font_size=fs3).next_to(line_3, UP, buff=0.1)
        line_4 = Line(plane.c2p(0,1), plane.c2p(np.pi,1), color=GREEN)
        text_4 = MathTex("\\Pi", color=GREEN, font_size=fs3).next_to(line_4, UP, buff=.1).shift(RIGHT*0.4)


        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                To understand these dynamics, let's look at the <bookmark mark="point"/> point x equals 1.5 pie.
                Here, the sine function <bookmark mark="line_1"/>has the value negative one.

                Now if we want to <bookmark mark="squash"/>squash the function in x-direction, for example by a factor of three, we need
                the point where the function has the value negative one to <bookmark mark="line_2"/>be at x equals 0.5 pie, instead of 1.5 pie.
                To achieve this, we multiply x by three, so b equals three. This way, x equals 0.5 pi achieves the same value as x equals 1.5
                pi did before.This means that for b greater than one, we squash the function in x-direction. <bookmark mark="clean"/>

                <bookmark mark="point_2"/>Now let's look at the point x <bookmark mark="line_3"/>equals 0.5 pie. Here, the sine function
                has the value one. If we want<bookmark mark="stretch"/> to stretch the function in x-direction, for example by a factor of two,
                we need the point where the function has the value one to be <bookmark mark="line_4"/>at x equals pie, instead of 0.5 pie.
                To achieve this, we divide x by two, so b equals 0.5. This means that for b smaller than one, we stretch the function in x-direction.
                <bookmark mark="clean_final"/>

                So in summary, for b greater <bookmark mark="squash_final"/>than one, we SQUASH the function in x-direction,
                and for b smaller than one, we <bookmark mark="stretch_final"/>STRETCH the function in x-direction.
                """
        ) as tracker:

            self.wait_until_bookmark("point")
            x,y,_ = plane.c2p(1.5*np.pi,-1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("line_1")
            self.play(Create(line_1), Write(text_1), run_time=1)

            self.wait_until_bookmark("squash")
            cursor.blinking = False
            cursor_updater = lambda m: m.move_to(plane.c2p(3*np.pi/(2*b.get_value()),-1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(3), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("line_2")
            self.play(Create(line_2), Write(text_2), run_time=1)

            self.wait_until_bookmark("clean")
            cursor.blinking=False
            self.play(FadeOut(line_1), FadeOut(line_2), FadeOut(text_1), FadeOut(text_2), b.animate.set_value(1), run_time=1)
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("point_2")
            x,y,_ = plane.c2p(.5*np.pi,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("line_3")
            self.play(Create(line_3), Write(text_3), run_time=1)

            self.wait_until_bookmark("stretch")
            cursor.blinking = False
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/(2*b.get_value()),1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(0.5), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("line_4")
            self.play(Create(line_4), Write(text_4), run_time=1)
            self.bring_to_front(line_3)

            self.wait_until_bookmark("clean_final")
            cursor.blinking=False
            self.play(FadeOut(line_3), FadeOut(line_4), FadeOut(text_3), FadeOut(text_4), b.animate.set_value(1), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("squash_final")
            cursor.blinking = False
            self.play(b.animate.set_value(3), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("stretch_final")
            cursor.blinking = False
            self.play(b.animate.set_value(0.5), run_time=1)
            cursor.blinking=True

        cursor.remove_updater(cursor_updater)
        x,y,_ = plane.c2p(0,0)
        cursor.blinking=False
        self.play(CursorMoveResize(cursor,x,y,0.2,0.2), b.animate.set_value(1), run_time=1)         
        cursor.blinking=True   

        self.wait(4)



class Func_7_4_I_4_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm_1 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm_1)

        line_1 = Line(plane.c2p(0,-1), plane.c2p(1.5*np.pi,-1), color=PURPLE)
        text_1 = MathTex("1.5\\Pi", color=PURPLE, font_size=fs3).next_to(line_1, DOWN, buff=0.1)
        line_2 = Line(plane.c2p(0,-1), plane.c2p(.5*np.pi,-1), color=GREEN)
        text_2 = MathTex("0.5\\Pi", color=GREEN, font_size=fs3).next_to(line_2, DOWN, buff=0.1)
        line_3 = Line(plane.c2p(0,1), plane.c2p(.5*np.pi,1), color=PURPLE)
        text_3 = MathTex("0.5\\Pi", color=PURPLE, font_size=fs3).next_to(line_3, UP, buff=0.1)
        line_4 = Line(plane.c2p(0,1), plane.c2p(np.pi,1), color=GREEN)
        text_4 = MathTex("\\Pi", color=GREEN, font_size=fs3).next_to(line_4, UP, buff=.1).shift(RIGHT*0.4)


        # Action Sequence
        with self.voiceover(
                text="""
                Yes, that's correct.
                To understand these dynamics, let's look at the <bookmark mark="point"/> point x equals 1.5 pie.
                Here, the sine function <bookmark mark="line_1"/>has the value negative one.

                Now if we want to <bookmark mark="squash"/>squash the function in x-direction, for example by a factor of three, we need
                the point where the function has the value negative one to <bookmark mark="line_2"/>be at x equals 0.5 pie, instead of 1.5 pie.
                To achieve this, we multiply x by three, so b equals three. This way, x equals 0.5 pi achieves the same value as x equals 1.5
                pi did before.This means that for b greater than one, we squash the function in x-direction. <bookmark mark="clean"/>

                <bookmark mark="point_2"/>Now let's look at the point x <bookmark mark="line_3"/>equals 0.5 pie. Here, the sine function
                has the value one. If we want<bookmark mark="stretch"/> to stretch the function in x-direction, for example by a factor of two,
                we need the point where the function has the value one to be <bookmark mark="line_4"/>at x equals pie, instead of 0.5 pie.
                To achieve this, we divide x by two, so b equals 0.5. This means that for b smaller than one, we stretch the function in x-direction.
                <bookmark mark="clean_final"/>

                So in summary, for b greater <bookmark mark="squash_final"/>than one, we SQUASH the function in x-direction,
                and for b smaller than one, we <bookmark mark="stretch_final"/>STRETCH the function in x-direction.
                """
        ) as tracker:

            self.wait_until_bookmark("point")
            x,y,_ = plane.c2p(1.5*np.pi,-1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("line_1")
            self.play(Create(line_1), Write(text_1), run_time=1)

            self.wait_until_bookmark("squash")
            cursor.blinking = False
            cursor_updater = lambda m: m.move_to(plane.c2p(3*np.pi/(2*b.get_value()),-1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(3), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("line_2")
            self.play(Create(line_2), Write(text_2), run_time=1)

            self.wait_until_bookmark("clean")
            cursor.blinking=False
            self.play(FadeOut(line_1), FadeOut(line_2), FadeOut(text_1), FadeOut(text_2), b.animate.set_value(1), run_time=1)
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("point_2")
            x,y,_ = plane.c2p(.5*np.pi,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("line_3")
            self.play(Create(line_3), Write(text_3), run_time=1)

            self.wait_until_bookmark("stretch")
            cursor.blinking = False
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/(2*b.get_value()),1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(0.5), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("line_4")
            self.play(Create(line_4), Write(text_4), run_time=1)
            self.bring_to_front(line_3)

            self.wait_until_bookmark("clean_final")
            cursor.blinking=False
            self.play(FadeOut(line_3), FadeOut(line_4), FadeOut(text_3), FadeOut(text_4), b.animate.set_value(1), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("squash_final")
            cursor.blinking = False
            self.play(b.animate.set_value(3), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("stretch_final")
            cursor.blinking = False
            self.play(b.animate.set_value(0.5), run_time=1)
            cursor.blinking=True

        cursor.remove_updater(cursor_updater)
        x,y,_ = plane.c2p(0,0)
        cursor.blinking=False
        self.play(CursorMoveResize(cursor,x,y,0.2,0.2), b.animate.set_value(1), run_time=1)         
        cursor.blinking=True   

        self.wait(4)


class Func_7_4_I_4_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm_1 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm_1)

        line_1 = Line(plane.c2p(0,-1), plane.c2p(1.5*np.pi,-1), color=PURPLE)
        text_1 = MathTex("1.5\\Pi", color=PURPLE, font_size=fs3).next_to(line_1, DOWN, buff=0.1)
        line_2 = Line(plane.c2p(0,-1), plane.c2p(.5*np.pi,-1), color=GREEN)
        text_2 = MathTex("0.5\\Pi", color=GREEN, font_size=fs3).next_to(line_2, DOWN, buff=0.1)
        line_3 = Line(plane.c2p(0,1), plane.c2p(.5*np.pi,1), color=PURPLE)
        text_3 = MathTex("0.5\\Pi", color=PURPLE, font_size=fs3).next_to(line_3, UP, buff=0.1)
        line_4 = Line(plane.c2p(0,1), plane.c2p(np.pi,1), color=GREEN)
        text_4 = MathTex("\\Pi", color=GREEN, font_size=fs3).next_to(line_4, UP, buff=.1).shift(RIGHT*0.4)


        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                To understand these dynamics, let's look at the <bookmark mark="point"/> point x equals 1.5 pie.
                Here, the sine function <bookmark mark="line_1"/>has the value negative one.

                Now if we want to <bookmark mark="squash"/>squash the function in x-direction, for example by a factor of three, we need
                the point where the function has the value negative one to <bookmark mark="line_2"/>be at x equals 0.5 pie, instead of 1.5 pie.
                To achieve this, we multiply x by three, so b equals three. This way, x equals 0.5 pi achieves the same value as x equals 1.5
                pi did before.This means that for b greater than one, we squash the function in x-direction. <bookmark mark="clean"/>

                <bookmark mark="point_2"/>Now let's look at the point x <bookmark mark="line_3"/>equals 0.5 pie. Here, the sine function
                has the value one. If we want<bookmark mark="stretch"/> to stretch the function in x-direction, for example by a factor of two,
                we need the point where the function has the value one to be <bookmark mark="line_4"/>at x equals pie, instead of 0.5 pie.
                To achieve this, we divide x by two, so b equals 0.5. This means that for b smaller than one, we stretch the function in x-direction.
                <bookmark mark="clean_final"/>

                So in summary, for b greater <bookmark mark="squash_final"/>than one, we SQUASH the function in x-direction,
                and for b smaller than one, we <bookmark mark="stretch_final"/>STRETCH the function in x-direction.
                """
        ) as tracker:

            self.wait_until_bookmark("point")
            x,y,_ = plane.c2p(1.5*np.pi,-1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("line_1")
            self.play(Create(line_1), Write(text_1), run_time=1)

            self.wait_until_bookmark("squash")
            cursor.blinking = False
            cursor_updater = lambda m: m.move_to(plane.c2p(3*np.pi/(2*b.get_value()),-1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(3), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("line_2")
            self.play(Create(line_2), Write(text_2), run_time=1)

            self.wait_until_bookmark("clean")
            cursor.blinking=False
            self.play(FadeOut(line_1), FadeOut(line_2), FadeOut(text_1), FadeOut(text_2), b.animate.set_value(1), run_time=1)
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("point_2")
            x,y,_ = plane.c2p(.5*np.pi,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("line_3")
            self.play(Create(line_3), Write(text_3), run_time=1)

            self.wait_until_bookmark("stretch")
            cursor.blinking = False
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/(2*b.get_value()),1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(0.5), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("line_4")
            self.play(Create(line_4), Write(text_4), run_time=1)
            self.bring_to_front(line_3)

            self.wait_until_bookmark("clean_final")
            cursor.blinking=False
            self.play(FadeOut(line_3), FadeOut(line_4), FadeOut(text_3), FadeOut(text_4), b.animate.set_value(1), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("squash_final")
            cursor.blinking = False
            self.play(b.animate.set_value(3), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("stretch_final")
            cursor.blinking = False
            self.play(b.animate.set_value(0.5), run_time=1)
            cursor.blinking=True

        cursor.remove_updater(cursor_updater)
        x,y,_ = plane.c2p(0,0)
        cursor.blinking=False
        self.play(CursorMoveResize(cursor,x,y,0.2,0.2), b.animate.set_value(1), run_time=1)         
        cursor.blinking=True   

        self.wait(4)


class Func_7_4_I_4_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))

        line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
        line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

        functerm_1 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        self.add(graph_blue_updated, functerm_1)

        line_1 = Line(plane.c2p(0,-1), plane.c2p(1.5*np.pi,-1), color=PURPLE)
        text_1 = MathTex("1.5\\Pi", color=PURPLE, font_size=fs3).next_to(line_1, DOWN, buff=0.1)
        line_2 = Line(plane.c2p(0,-1), plane.c2p(.5*np.pi,-1), color=GREEN)
        text_2 = MathTex("0.5\\Pi", color=GREEN, font_size=fs3).next_to(line_2, DOWN, buff=0.1)
        line_3 = Line(plane.c2p(0,1), plane.c2p(.5*np.pi,1), color=PURPLE)
        text_3 = MathTex("0.5\\Pi", color=PURPLE, font_size=fs3).next_to(line_3, UP, buff=0.1)
        line_4 = Line(plane.c2p(0,1), plane.c2p(np.pi,1), color=GREEN)
        text_4 = MathTex("\\Pi", color=GREEN, font_size=fs3).next_to(line_4, UP, buff=.1).shift(RIGHT*0.4)


        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not right.
                To understand these dynamics, let's look at the <bookmark mark="point"/> point x equals 1.5 pie.
                Here, the sine function <bookmark mark="line_1"/>has the value negative one.

                Now if we want to <bookmark mark="squash"/>squash the function in x-direction, for example by a factor of three, we need
                the point where the function has the value negative one to <bookmark mark="line_2"/>be at x equals 0.5 pie, instead of 1.5 pie.
                To achieve this, we multiply x by three, so b equals three. This way, x equals 0.5 pi achieves the same value as x equals 1.5
                pi did before.This means that for b greater than one, we squash the function in x-direction. <bookmark mark="clean"/>

                <bookmark mark="point_2"/>Now let's look at the point x <bookmark mark="line_3"/>equals 0.5 pie. Here, the sine function
                has the value one. If we want<bookmark mark="stretch"/> to stretch the function in x-direction, for example by a factor of two,
                we need the point where the function has the value one to be <bookmark mark="line_4"/>at x equals pie, instead of 0.5 pie.
                To achieve this, we divide x by two, so b equals 0.5. This means that for b smaller than one, we stretch the function in x-direction.
                <bookmark mark="clean_final"/>

                So in summary, for b greater <bookmark mark="squash_final"/>than one, we SQUASH the function in x-direction,
                and for b smaller than one, we <bookmark mark="stretch_final"/>STRETCH the function in x-direction.
                """
        ) as tracker:

            self.wait_until_bookmark("point")
            x,y,_ = plane.c2p(1.5*np.pi,-1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)

            self.wait_until_bookmark("line_1")
            self.play(Create(line_1), Write(text_1), run_time=1)

            self.wait_until_bookmark("squash")
            cursor.blinking = False
            cursor_updater = lambda m: m.move_to(plane.c2p(3*np.pi/(2*b.get_value()),-1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(3), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("line_2")
            self.play(Create(line_2), Write(text_2), run_time=1)

            self.wait_until_bookmark("clean")
            cursor.blinking=False
            self.play(FadeOut(line_1), FadeOut(line_2), FadeOut(text_1), FadeOut(text_2), b.animate.set_value(1), run_time=1)
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("point_2")
            x,y,_ = plane.c2p(.5*np.pi,1)
            cursor.blinking = False
            self.play(CursorMoveTo(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("line_3")
            self.play(Create(line_3), Write(text_3), run_time=1)

            self.wait_until_bookmark("stretch")
            cursor.blinking = False
            cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/(2*b.get_value()),1))
            cursor.add_updater(cursor_updater)
            self.play(b.animate.set_value(0.5), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("line_4")
            self.play(Create(line_4), Write(text_4), run_time=1)
            self.bring_to_front(line_3)

            self.wait_until_bookmark("clean_final")
            cursor.blinking=False
            self.play(FadeOut(line_3), FadeOut(line_4), FadeOut(text_3), FadeOut(text_4), b.animate.set_value(1), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("squash_final")
            cursor.blinking = False
            self.play(b.animate.set_value(3), run_time=1)
            cursor.blinking=True

            self.wait_until_bookmark("stretch_final")
            cursor.blinking = False
            self.play(b.animate.set_value(0.5), run_time=1)
            cursor.blinking=True

        cursor.remove_updater(cursor_updater)
        x,y,_ = plane.c2p(0,0)
        cursor.blinking=False
        self.play(CursorMoveResize(cursor,x,y,0.2,0.2), b.animate.set_value(1), run_time=1)         
        cursor.blinking=True   

        self.wait(4)


#####################################
#####################################
TASK_Func_7_4_I_5_q = SophiaTaskDefinition(
    answerOptions = ["The function is stretched in $x$-direction", "The function is stretched in $y$-direction", "The function is reflected at the $x$-axis", "The function is reflected at the $y$-axis"],
    correctAnswerIndex = 3,
    questionText = "What happens if we plug in $b=-1$?"
)
class Func_7_4_I_5_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))

        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(3.2/qmark.get_width()).move_to([-5, 1, 0])

        functerm_1 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        beq = MathTex("b", "=", "-1", color=c1t, font_size=fs1).next_to(functerm_1, DOWN, buff=0.5)
        self.add(graph_blue_updated, functerm_1)

        # Action Sequence
        with self.voiceover(
                text="""
                Now, we know what happens for b greater than one and for b smaller than one.
                But <bookmark mark="qmark"/>what about negative values of b?
                
                What happens if we <bookmark mark="b"/>plug in b equals<bookmark mark="neg_one"/> negative one?
                """
        ) as tracker:

            self.wait_until_bookmark("qmark")
            self.play(qmark.animate.shift(5*RIGHT), run_time=.5)
            self.wait(1)
            self.play(qmark.animate.shift(5*RIGHT))

            self.wait_until_bookmark("b")
            cursor.blinking=False
            x,y,_ = beq[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(beq), run_time=.5)

            self.wait_until_bookmark("neg_one")
            x,y,_ = beq[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True
            
        self.wait(4)


class Func_7_4_I_5_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-2*np.pi, 2*np.pi, np.pi], [-1.2, 1.2, 1], x_ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi], x_labels=["-2\\Pi", "-\\Pi", "0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))
        
        functerm_1 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        beq = MathTex("b", "=", "-1", color=c1t, font_size=fs1).next_to(functerm_1, DOWN, buff=0.5)
        self.add(graph_blue_updated, functerm_1)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right. If we plug in <bookmark mark="b"/>b equals <bookmark mark="neg_one"/>negative one, we
                basically switch negative values with positive values, which amounts <bookmark mark="reflect"/> to reflecting the
                function at the y-axis.
                """
        ) as tracker:

            self.wait_until_bookmark("b")
            cursor.blinking=False
            x,y,_ = beq[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(beq), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("neg_one")
            cursor.blinking = False
            x,y,_ = beq[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("reflect")
            cursor.blinking = False
            self.play(CursorMarkAxis(cursor, plane, axis="y"), run_time=.3)
            self.play(b.animate.set_value(-1), run_time=1)
            self.wait(0.2)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveResize(cursor,x,y,0.2,0.2), run_time=0.4)
            cursor.blinking=True
            
        self.wait(4)


class Func_7_4_I_5_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-2*np.pi, 2*np.pi, np.pi], [-1.2, 1.2, 1], x_ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi], x_labels=["-2\\Pi", "-\\Pi", "0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))
        
        functerm_1 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        beq = MathTex("b", "=", "-1", color=c1t, font_size=fs1).next_to(functerm_1, DOWN, buff=0.5)
        self.add(graph_blue_updated, functerm_1)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right. If we plug in <bookmark mark="b"/>b equals <bookmark mark="neg_one"/>negative one, we
                basically switch negative values with positive values, which amounts <bookmark mark="reflect"/> to reflecting the
                function at the y-axis.
                """
        ) as tracker:

            self.wait_until_bookmark("b")
            cursor.blinking=False
            x,y,_ = beq[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(beq), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("neg_one")
            cursor.blinking = False
            x,y,_ = beq[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("reflect")
            cursor.blinking = False
            self.play(CursorMarkAxis(cursor, plane, axis="y"), run_time=.3)
            self.play(b.animate.set_value(-1), run_time=1)
            self.wait(0.2)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveResize(cursor,x,y,0.2,0.2), run_time=0.4)
            cursor.blinking=True
            
        self.wait(4)


class Func_7_4_I_5_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-2*np.pi, 2*np.pi, np.pi], [-1.2, 1.2, 1], x_ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi], x_labels=["-2\\Pi", "-\\Pi", "0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))
        
        functerm_1 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        beq = MathTex("b", "=", "-1", color=c1t, font_size=fs1).next_to(functerm_1, DOWN, buff=0.5)
        self.add(graph_blue_updated, functerm_1)

        # Action Sequence
        with self.voiceover(
                text="""
                No, that's not quite right. If we plug in <bookmark mark="b"/>b equals <bookmark mark="neg_one"/>negative one, we
                basically switch negative values with positive values, which amounts <bookmark mark="reflect"/> to reflecting the
                function at the y-axis.
                """
        ) as tracker:

            self.wait_until_bookmark("b")
            cursor.blinking=False
            x,y,_ = beq[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(beq), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("neg_one")
            cursor.blinking = False
            x,y,_ = beq[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("reflect")
            cursor.blinking = False
            self.play(CursorMarkAxis(cursor, plane, axis="y"), run_time=.3)
            self.play(b.animate.set_value(-1), run_time=1)
            self.wait(0.2)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveResize(cursor,x,y,0.2,0.2), run_time=0.4)
            cursor.blinking=True
            
        self.wait(4)


class Func_7_4_I_5_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine \& Cosine: Scaling")

        cords = self.add_cords([-2*np.pi, 2*np.pi, np.pi], [-1.2, 1.2, 1], x_ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi], x_labels=["-2\\Pi", "-\\Pi", "0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()*np.sin(b.get_value()*x), color=BLUE))
        
        functerm_1 = MathTex("f","(x)",  "=", "\\sin", "(", "b", "\\cdot x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        beq = MathTex("b", "=", "-1", color=c1t, font_size=fs1).next_to(functerm_1, DOWN, buff=0.5)
        self.add(graph_blue_updated, functerm_1)

        # Action Sequence
        with self.voiceover(
                text="""
                Yep, that's right. If we plug in <bookmark mark="b"/>b equals <bookmark mark="neg_one"/>negative one, we
                basically switch negative values with positive values, which amounts <bookmark mark="reflect"/> to reflecting the
                function at the y-axis.
                """
        ) as tracker:

            self.wait_until_bookmark("b")
            cursor.blinking=False
            x,y,_ = beq[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(beq), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("neg_one")
            cursor.blinking = False
            x,y,_ = beq[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
            cursor.blinking=True

            self.wait_until_bookmark("reflect")
            cursor.blinking = False
            self.play(CursorMarkAxis(cursor, plane, axis="y"), run_time=.3)
            self.play(b.animate.set_value(-1), run_time=1)
            self.wait(0.2)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveResize(cursor,x,y,0.2,0.2), run_time=0.4)
            cursor.blinking=True
            
        self.wait(4)


#####################################
#####################################
####### Practice Part ###############
#####################################
#####################################


#####################################
#####################################
######## General Qs #################
#####################################
#####################################

class SineCosineScalingQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

    @abstractmethod
    def construct(self):

        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine-function: Scaling" if self.use_sine else "Cosine-function: Scaling")

        cords = self.add_cords([-2*np.pi, 2*np.pi, np.pi], [-1.2, 1.2, 1], x_ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi], x_labels=["-2\\Pi", "-\\Pi", "0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        
        
        func_tex_string = "\\sin" if self.use_sine else "\\cos"
        func_speech_string = "sign" if self.use_sine else "cosine"
        func = lambda x: a.get_value()*np.sin(b.get_value()*x) if self.use_sine else a.get_value()*np.cos(b.get_value()*x)


        functerm = MathTex("f","(x)",  "=", func_tex_string, "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
        graph_blue_updated = always_redraw(lambda: plane.plot(func, color=BLUE))
        self.add(graph_blue_updated)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro}<bookmark mark="f_intro"/>
                f <bookmark mark="fx_intro"/>of x<bookmark mark="sin_cos_intro"/> equals {func_speech_string} <bookmark mark="x_intro"/>of x.
                {self.a_text}
                {self.b_text}
                {self.q_text}
                """
        ) as tracker:
            
            self.wait_until_bookmark("f_intro")
            x,y,_ = functerm[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), Write(functerm), run_time=.3)

            self.wait_until_bookmark("fx_intro")
            x,y,_ = functerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.4)

            self.wait_until_bookmark("sin_cos_intro")
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.6)

            self.wait_until_bookmark("x_intro")
            x,y,_ = functerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
            cursor.blinking=True

            if self.a_factor !=1:
                self.wait_until_bookmark("a")
                cursor.blinking=False
                x,y,_ = plane.c2p(self.x_start, func(self.x_start))
                self.play(CursorMoveTo(cursor,x,y), run_time=.5)
                cursor_updater = lambda m: m.move_to(plane.c2p(self.x_start, func(self.x_start)))
                cursor.add_updater(cursor_updater)
                self.add_scale_sound("up" if self.a_factor>1 else "down", duration=1)
                self.play(a.animate.set_value(self.a_factor), run_time=1)
                cursor.blinking=True
                cursor.remove_updater(cursor_updater)

            if self.b_factor !=1:
                self.wait_until_bookmark("b")
                cursor.blinking=False
                if self.a_factor==1:
                    x,y,_ = plane.c2p(self.x_start, func(self.x_start))
                    self.play(CursorMoveTo(cursor,x,y), run_time=.5)
                cursor_updater = lambda m: m.move_to(plane.c2p(self.x_start/b.get_value(), func(self.x_start/b.get_value())))
                cursor.add_updater(cursor_updater)
                self.add_scale_sound("up" if self.b_factor<1 else "down", duration=1)
                self.play(b.animate.set_value(self.b_factor), run_time=1)
                cursor.blinking=True
                cursor.remove_updater(cursor_updater)



class SineCosineScalingAnswerScene(SophiaCursorScene, metaclass=ABCMeta):

    @abstractmethod
    def construct(self):

        self.a_xplain = f"""This means we have to multiply the <bookmark mark="a_explained"/>entire function by {self.a_factor}.""" if self.a_factor!=1 else ""
        self.b_xplain = f"""This means we have to multiply the <bookmark mark="b_explained"/>argument x by {self.b_factor}.""" if self.b_factor!=1 else ""
        
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Sine-function: Scaling" if self.use_sine else "Cosine-function: Scaling")

        cords = self.add_cords([-2*np.pi, 2*np.pi, np.pi], [-1.2, 1.2, 1], x_ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi], x_labels=["-2\\Pi", "-\\Pi", "0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)

        a = ValueTracker(1)
        b = ValueTracker(1)
        
        
        func_tex_string = "\\sin" if self.use_sine else "\\cos"
        func_speech_string = "sign" if self.use_sine else "cosine"
        func = lambda x: a.get_value()*np.sin(b.get_value()*x) if self.use_sine else a.get_value()*np.cos(b.get_value()*x)


        functerm = MathTex("f","(x)",  "=", "a", func_tex_string, "(", "b", "\\cdot x)", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        functerm_shifted_a = MathTex("f","(x)",  "=", str(self.a_factor), func_tex_string, "(", "b", "\\cdot x)", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        functerm_shifted_b = MathTex("f","(x)",  "=", str(self.a_factor), func_tex_string, "(", str(self.b_factor), "\\cdot x)", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=1)
        graph_blue_updated = always_redraw(lambda: plane.plot(func, color=BLUE))
        self.add(graph_blue_updated, functerm)

        # Action Sequence
        with self.voiceover(
                text=f"""
                {self.intro}. We're working with the<bookmark mark="f_intro"/> function
                f <bookmark mark="fx_intro"/>of x <bookmark mark="a_intro"/>equals "a"<bookmark mark="sincos_intro"/>
                times <bookmark mark="b_intro"/>{func_speech_string} of b <bookmark mark="x_intro"/>times x.
                {self.a_text}. {self.a_xplain}
                {self.b_text}. {self.b_xplain}.
                So, the term of the shifted <bookmark mark="f"/> function is f <bookmark mark="fx"/> of x
                <bookmark mark="a_term"/> equals {self.a_factor} <bookmark mark="sine_cosine"/>times {func_speech_string}
                <bookmark mark="b_term"/> of {self.b_factor} <bookmark mark="x"/>times x.
                """
        ) as tracker:
            
            self.wait_until_bookmark("f_intro")
            cursor.blinking=False
            x,y,_ = functerm[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=.3)

            self.wait_until_bookmark("fx_intro")
            x,y,_ = functerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
            
            self.wait_until_bookmark("a_intro")
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)

            self.wait_until_bookmark("sincos_intro")
            x,y,_ = functerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)

            self.wait_until_bookmark("b_intro")
            x,y,_ = functerm[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
            
            self.wait_until_bookmark("x_intro")
            x,y,_ = functerm[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
            cursor.blinking=True

            if self.a_factor !=1:
                self.wait_until_bookmark("a")
                cursor.blinking=False
                x,y,_ = plane.c2p(self.x_start, func(self.x_start))
                self.play(CursorMoveTo(cursor,x,y), run_time=.5)
                cursor_updater = lambda m: m.move_to(plane.c2p(self.x_start, func(self.x_start)))
                cursor.add_updater(cursor_updater)
                self.add_scale_sound("up" if self.a_factor>1 else "down", duration=1)
                self.play(a.animate.set_value(self.a_factor), run_time=1)
                cursor.blinking=True
                cursor.remove_updater(cursor_updater)

                self.wait_until_bookmark("a_explained")
                cursor.blinking=False
                x,y,_ = functerm[3].get_center()+0.4*DOWN
                self.play(ReplacementTransform(functerm, functerm_shifted_a), CursorMoveTo(cursor,x,y), run_time=1)
                functerm = functerm_shifted_a
                cursor.blinking=True

            if self.b_factor !=1:

                self.wait_until_bookmark("b")
                cursor.blinking=False
                x,y,_ = plane.c2p(self.x_start, func(self.x_start))
                self.play(CursorMoveTo(cursor,x,y), run_time=.5)
                cursor_updater = lambda m: m.move_to(plane.c2p(self.x_start/b.get_value(), func(self.x_start/b.get_value())))
                cursor.add_updater(cursor_updater)
                self.add_scale_sound("up" if self.b_factor<1 else "down", duration=1)
                self.play(b.animate.set_value(self.b_factor), run_time=1)
                cursor.blinking=True
                cursor.remove_updater(cursor_updater)

                self.wait_until_bookmark("b_explained")
                cursor.blinking=False
                x,y,_ = functerm[6].get_center()+0.4*DOWN
                self.play(ReplacementTransform(functerm, functerm_shifted_b), CursorMoveTo(cursor,x,y), run_time=1)
                functerm = functerm_shifted_b
                cursor.blinking=True

            self.wait_until_bookmark("f")
            cursor.blinking=False
            x,y,_ = functerm[0].get_center()+0.4*DOWN
            if self.b_factor==1:
                self.play(ReplacementTransform(functerm, functerm_shifted_b), CursorMoveTo(cursor,x,y), run_time=.3)
            else:
                self.play(CursorMoveTo(cursor,x,y), run_time=.3)

            self.wait_until_bookmark("fx")
            x,y,_ = functerm[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)

            self.wait_until_bookmark("a_term")
            x,y,_ = functerm[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
            
            self.wait_until_bookmark("sine_cosine")
            x,y,_ = functerm[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)

            self.wait_until_bookmark("b_term")
            x,y,_ = functerm[6].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)

            self.wait_until_bookmark("x")
            x,y,_ = functerm[7].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
            cursor.blinking=True


#####################################
#####################################
######## Specific Qs ################
#####################################
#####################################
TASK_Func_7_4_P_2_q = SophiaTaskDefinition(
    answerOptions = ["$f(x)=2\sin(\\frac{1}{3}x)$", "$f(x)=\\frac{1}{2}\sin(3x)$", "$f(x)=2\sin(3x)$", "$f(x)=\\frac{1}{2}\sin(\\frac{1}{3}x)$"],
    correctAnswerIndex = 1,
    questionText = "What is the term of the sine function, if we stretch it by 2 in y direction and squash it by 3 in x direction?"
)
class Func_7_4_P_2_q(SineCosineScalingQuestionScene):

    def construct(self):
    
        self.intro = "Let's practice scaling now. Consider the function"
        self.use_sine = True

        self.a_factor = 2
        self.b_factor = 3

        self.x_start = (-3/2)*np.pi

        self.a_text = """We want to <bookmark mark="a"/>stretch the function in y-direction by a factor of 2."""
        self.b_text = """and want to <bookmark mark="b"/>squash the function in x-direction by a factor of 3."""
        self.q_text = """What is the term of the scaled function?"""

        super().construct()


class Func_7_4_P_2_a(SineCosineScalingAnswerScene):

    def construct(self):
    
        self.intro = "No, that's not right."
        self.use_sine = True

        self.a_factor = 2
        self.b_factor = 3

        self.x_start = (-3/2)*np.pi

        self.a_text = """We want to <bookmark mark="a"/>stretch the function in y-direction by a factor of 2."""
        self.b_text = """We also want to <bookmark mark="b"/>squash the function in x-direction by a factor of 3."""
        
        super().construct()


class Func_7_4_P_2_b(SineCosineScalingAnswerScene):

    def construct(self):
    
        self.intro = "No, that's not right."
        self.use_sine = True

        self.a_factor = 2
        self.b_factor = 3

        self.x_start = (-3/2)*np.pi

        self.a_text = """We want to <bookmark mark="a"/>stretch the function in y-direction by a factor of 2."""
        self.b_text = """We also want to <bookmark mark="b"/>squash the function in x-direction by a factor of 3."""
        
        super().construct()


class Func_7_4_P_2_c(SineCosineScalingAnswerScene):

    def construct(self):
    
        self.intro = "That is correct, great job."
        self.use_sine = True

        self.a_factor = 2
        self.b_factor = 3

        self.x_start = (-3/2)*np.pi

        self.a_text = """We want to <bookmark mark="a"/>stretch the function in y-direction by a factor of 2."""
        self.b_text = """We also want to <bookmark mark="b"/>squash the function in x-direction by a factor of 3."""
        
        super().construct()


class Func_7_4_P_2_d(SineCosineScalingAnswerScene):

    def construct(self):
    
        self.intro = "No, that's not right."
        self.use_sine = True

        self.a_factor = 2
        self.b_factor = 3

        self.x_start = (-3/2)*np.pi

        self.a_text = """We want to <bookmark mark="a"/>stretch the function in y-direction by a factor of 2."""
        self.b_text = """We also want to <bookmark mark="b"/>squash the function in x-direction by a factor of 3."""
        
        super().construct()


#####################################
#####################################
TASK_Func_7_4_P_3_q = SophiaTaskDefinition(
    answerOptions = ["$f(x)=2\cos(x)$", "$f(x)=\\frac{1}{2}\cos(x)$", "$f(x)=\cos(2x)$", "$f(x)=\cos(\\frac{1}{2}x)$"],
    correctAnswerIndex = 3,
    questionText = "What is the term of the cosine function, if we stretch it by 2 in x direction?"
)
class Func_7_4_P_3_q(SineCosineScalingQuestionScene):

    def construct(self):
    
        self.intro = "Ok, now consider the function"
        self.use_sine = False

        self.a_factor = 1
        self.b_factor = 1/2

        self.x_start = np.pi

        self.a_text = """"""
        self.b_text = """We now want to <bookmark mark="b"/>stretch the function in x-direction by a factor of 2."""
        self.q_text = """What is the term of the function, after we scale it?"""

        super().construct()


class Func_7_4_P_3_a(SineCosineScalingAnswerScene):

    def construct(self):
    
        self.intro = "No, that's not right."
        self.use_sine = True

        self.a_factor = 1
        self.b_factor = 1/2

        self.x_start = np.pi

        self.a_text = ""
        self.b_text = """We want to <bookmark mark="b"/>stretch the function in x-direction by a factor of 2."""
        
        super().construct()

class Func_7_4_P_3_b(SineCosineScalingAnswerScene):

    def construct(self):
    
        self.intro = "No, that's not right."
        self.use_sine = True

        self.a_factor = 1
        self.b_factor = 1/2

        self.x_start = np.pi

        self.a_text = ""
        self.b_text = """We want to <bookmark mark="b"/>stretch the function in x-direction by a factor of 2."""
        
        super().construct()

class Func_7_4_P_3_c(SineCosineScalingAnswerScene):

    def construct(self):
    
        self.intro = "No, that's not right."
        self.use_sine = True

        self.a_factor = 1
        self.b_factor = 1/2

        self.x_start = np.pi

        self.a_text = ""
        self.b_text = """We want to <bookmark mark="b"/>stretch the function in x-direction by a factor of 2."""
        
        super().construct()

class Func_7_4_P_3_d(SineCosineScalingAnswerScene):

    def construct(self):
    
        self.intro = "Yep, that's correct. Well done"
        self.use_sine = True

        self.a_factor = 1
        self.b_factor = 1/2

        self.x_start = np.pi

        self.a_text = ""
        self.b_text = """We want to <bookmark mark="b"/>stretch the function in x-direction by a factor of 2."""
        
        super().construct()



#####################################
#####################################
TASK_Func_7_4_P_4_q = SophiaTaskDefinition(
    answerOptions = ["$f(x)=\\frac{1}{2}\sin(x)", "$f(x)=2\sin(x)$", "$f(x)=\sin(2x)$", "$f(x)=\sin(\\frac{1}{2}x)$"],
    correctAnswerIndex = 0,
    questionText = "What is the term of the sine function, if we squash it by 0.5 in y direction?"
)
class Func_7_4_P_4_q(SineCosineScalingQuestionScene):

    def construct(self):
    
        self.intro = "Next exercise. Look at the function"
        self.use_sine = True

        self.a_factor = 0.5
        self.b_factor = 1

        self.x_start = (-3/2)*np.pi

        self.a_text = """We want to <bookmark mark="a"/>squash the function in y-direction by a factor of one half."""
        self.b_text = """"""
        self.q_text = """What is the term of the scaled function?"""

        super().construct()


class Func_7_4_P_4_a(SineCosineScalingAnswerScene):

    def construct(self):
    
        self.intro = "Correct! Well done."
        self.use_sine = True

        self.a_factor = 0.5
        self.b_factor = 1

        self.x_start = (-3/2)*np.pi

        self.a_text = """So we want to <bookmark mark="a"/>stretch the function in y-direction by a factor of one half."""
        self.b_text = ""

        super().construct()

class Func_7_4_P_4_b(SineCosineScalingAnswerScene):

    def construct(self):
    
        self.intro = "No, that's incorrect."
        self.use_sine = True

        self.a_factor = 0.5
        self.b_factor = 1

        self.x_start = (-3/2)*np.pi

        self.a_text = """So we want to <bookmark mark="a"/>stretch the function in y-direction by a factor of one half."""
        self.b_text = ""

        super().construct()

class Func_7_4_P_4_c(SineCosineScalingAnswerScene):

    def construct(self):
    
        self.intro = "No, that's incorrect."
        self.use_sine = True

        self.a_factor = 0.5
        self.b_factor = 1

        self.x_start = (-3/2)*np.pi

        self.a_text = """So we want to <bookmark mark="a"/>stretch the function in y-direction by a factor of one half."""
        self.b_text = ""

        super().construct()

class Func_7_4_P_4_d(SineCosineScalingAnswerScene):

    def construct(self):
    
        self.intro = "No, that's incorrect."
        self.use_sine = True

        self.a_factor = 0.5
        self.b_factor = 1

        self.x_start = (-3/2)*np.pi

        self.a_text = """So we want to <bookmark mark="a"/>stretch the function in y-direction by a factor of one half."""
        self.b_text = ""

        super().construct()

PROTOTYPES=[
    PagePrototypeVideo.from_scene(Func_7_4_I_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_4_I_1_q, Func_7_4_I_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_4_I_1_a),
    PagePrototypeVideo.from_scene(Func_7_4_I_1_b),
    PagePrototypeVideo.from_scene(Func_7_4_I_1_c),
    PagePrototypeVideo.from_scene(Func_7_4_I_1_d),
    PagePrototypeVideo.from_scene(Func_7_4_I_2),
    PagePrototypeVideo.from_scene(Func_7_4_P_1_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_4_P_1_q, Func_7_4_P_1_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_4_P_1_a),
    PagePrototypeVideo.from_scene(Func_7_4_P_1_b),
    PagePrototypeVideo.from_scene(Func_7_4_P_1_c),
    PagePrototypeVideo.from_scene(Func_7_4_P_1_d),
    PagePrototypeVideo.from_scene(Func_7_4_I_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_4_I_3_q, Func_7_4_I_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_4_I_3_a),
    PagePrototypeVideo.from_scene(Func_7_4_I_3_b),
    PagePrototypeVideo.from_scene(Func_7_4_I_3_c),
    PagePrototypeVideo.from_scene(Func_7_4_I_3_d),
    PagePrototypeVideo.from_scene(Func_7_4_I_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_4_I_4_q, Func_7_4_I_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_4_I_4_a),
    PagePrototypeVideo.from_scene(Func_7_4_I_4_b),
    PagePrototypeVideo.from_scene(Func_7_4_I_4_c),
    PagePrototypeVideo.from_scene(Func_7_4_I_4_d),
    PagePrototypeVideo.from_scene(Func_7_4_I_5_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_4_I_5_q, Func_7_4_I_5_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_4_I_5_a),
    PagePrototypeVideo.from_scene(Func_7_4_I_5_b),
    PagePrototypeVideo.from_scene(Func_7_4_I_5_c),
    PagePrototypeVideo.from_scene(Func_7_4_I_5_d),
    PagePrototypeVideo.from_scene(Func_7_4_P_2_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_4_P_2_q, Func_7_4_P_2_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_4_P_2_a),
    PagePrototypeVideo.from_scene(Func_7_4_P_2_b),
    PagePrototypeVideo.from_scene(Func_7_4_P_2_c),
    PagePrototypeVideo.from_scene(Func_7_4_P_2_d),
    PagePrototypeVideo.from_scene(Func_7_4_P_3_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_4_P_3_q, Func_7_4_P_3_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_4_P_3_a),
    PagePrototypeVideo.from_scene(Func_7_4_P_3_b),
    PagePrototypeVideo.from_scene(Func_7_4_P_3_c),
    PagePrototypeVideo.from_scene(Func_7_4_P_3_d),
    PagePrototypeVideo.from_scene(Func_7_4_P_4_q),
    PagePrototypeQuestion.from_task_definition(TASK_Func_7_4_P_4_q, Func_7_4_P_4_q.__name__),
    PagePrototypeVideo.from_scene(Func_7_4_P_4_a),
    PagePrototypeVideo.from_scene(Func_7_4_P_4_b),
    PagePrototypeVideo.from_scene(Func_7_4_P_4_c),
    PagePrototypeVideo.from_scene(Func_7_4_P_4_d),
]

scenes/Func/Func_7: Sine and Cosine Functions/Func_7_4.py
Sophia-Edu-Labs/sophia-math
# # 7_5: Trigonometric Functions: Shifting

# # Import necessary libraries and modules
# from abc import ABCMeta, abstractmethod
# from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
# from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
#                                           CursorPositionTracking,
#                                           CursorResizeDefault, SophiaScene,
#                                           assets_folder, avatars_folder,
#                                           generated_avatars_folder, AltCursor,
#                                           SophiaCursorScene, CursorMoveTo,
#                                           CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
# from sophialib.styles.styleconstants import *
# from sophialib.styles.sophiaobjects import *
# from manim import *
# from PIL import Image
# import numpy as np
# from pathlib import Path
# from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition

# #####################################
# #####################################
# TASK_Func_7_5_I_1_q = SophiaTaskDefinition(
#     answerOptions = ["Add $1$: $f(x)=\sin(x)+1$", "Multiply by $2$: $f(x)=2\sin(x)$", "Multiply by $\tfrac{1}{2}$: $f(x)=\tfrac{1}{2}\sin(x)$", "Subtract $\tfrac{1}{2}$: $f(x)=\sin(x)-\tfrac{1}{2}$"],
#     correctAnswerIndex = 1,
#     questionText = "How do we change the function $f(x)=\sin(x)$, so that its values reach from $0$ to $2$?"
# )
# class Func_7_5_I_1_q(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-1.5, 1.5, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(-0.5,np.cos(-0.5))
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=False, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         graph_blue = plane.plot(lambda x: np.cos(x), color=BLUE)

#         line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
#         line_2 = Line(plane.c2p(0,0), plane.c2p(0,2), color=GREEN)

#         functerm = MathTex("f","(x)",  "=", "\\cos", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Look at this graph of a cosine function.
#                 The values of the cosine function range<bookmark mark="neg_1"/> from negative <bookmark mark="pos_1"/>one to one.

#                 Now we want to change the function, so that its values <bookmark mark="neg_2"/>range from zero
#                 <bookmark mark="pos_2"/> to two.

#                 How do we change the <bookmark mark="f"/> term f <bookmark mark="fx"/> of x<bookmark mark="cos"/> equals cosine
#                 <bookmark mark="x"/> of x, so that the values of the function range from negative
#                 two to two?
#                 """
#         ) as tracker:
            
            
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(graph_blue.get_end()))._start_fading(2))
#             self.add_pencil_sound(1.5)
#             self.play(Create(graph_blue))
#             cursor.blinking=True

#             self.wait_until_bookmark("neg_1")
#             x,y,_ = line_1.get_start()
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("pos_1")
#             cursor.blinking=False
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(line_1.get_end()))._start_fading(2))
#             self.play(Create(line_1), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("neg_2")
#             x,y,_ = line_2.get_start()
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("pos_2")
#             cursor.blinking=False
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(line_2.get_end()))._start_fading(2))
#             self.play(Create(line_2), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("f")
#             x,y,_ = functerm[0].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(functerm), CursorMoveTo(cursor,x,y), run_time=.5)

#             self.wait_until_bookmark("fx")
#             x,y,_ = functerm[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)

#             self.wait_until_bookmark("cos")
#             x,y,_ = functerm[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)

#             self.wait_until_bookmark("x")
#             x,y,_ = functerm[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
#             cursor.blinking=True

#         self.wait(4)



# class Func_7_5_I_1_a(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-1.5, 1.5, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         graph_blue = plane.plot(lambda x: np.cos(x), color=BLUE)

#         a = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.cos(x), color=BLUE))

#         ones = VGroup(MathTex("1", color=c1t, font_size=fs2), MathTex("-1", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
#         arrows = VGroup(MathTex("\\Rightarrow", color=c1t, font_size=fs2), MathTex("\\Rightarrow", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=LEFT)
#         twos = VGroup(MathTex("2", color=c1t, font_size=fs2), MathTex("0", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
#         ones_to_twos = VGroup(ones, arrows, twos).arrange(RIGHT, buff=0.4).next_to(title, DOWN, buff=0.4)
#         row_one = VGroup(ones_to_twos[0][0], ones_to_twos[1][0], ones_to_twos[2][0])
#         row_two = VGroup(ones_to_twos[0][1], ones_to_twos[1][1], ones_to_twos[2][1])

#         functerm = MathTex("f","(x)",  "=", "\\cos", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_2 = MathTex("f","(x)",  "=", "\\cos", "(x)", "+", "1", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)

#         self.add(functerm, graph_blue)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 That's not right.
#                 We want the values of the function to range from zero to two, instead of from negative one to one.
#                 This means, that wherever the function<bookmark mark="row_1_a"/> has a value of one, we want it
#                 <bookmark mark="row_1_b"/>to have a value of two instead.

#                 And wherever the function<bookmark mark="row_2_a"/> has a value of negative one, we want it <bookmark mark="row_2_b"/>
#                 to have a value of zero instead.

#                 Clearly, we can achieve this by <bookmark mark="transform_term"/> adding one to the function.
#                 If we do that, <bookmark mark="stretch_func"/> the function will be shifted vertically up by one.
#                 And that's exactly what we want.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("row_1_a")
#             cursor.blinking=False
#             x,y,_ = row_one[0].get_center()+0.4*DOWN
#             self.play(Create(row_one), CursorMoveTo(cursor,x,y), run_time=.5)

#             self.wait_until_bookmark("row_1_b")
#             x,y,_ = row_one[2].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("row_2_a")
#             cursor.blinking=False
#             x,y,_ = row_two[0].get_center()+0.4*DOWN
#             self.play(Create(row_two), CursorMoveTo(cursor,x,y), run_time=.5)
            
#             self.wait_until_bookmark("row_2_b")
#             x,y,_ = row_two[2].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("transform_term")
#             x,y,_ = functerm_2[6].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(TransformMatchingTex(functerm, functerm_2), CursorMoveTo(cursor,x,y), run_time=.5)

#             self.wait_until_bookmark("stretch_func")
#             x,y,_ = plane.c2p(0,1)
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#             start = plane.c2p(0,1)+OUT
#             self.add(Updown_Arrow(start, vert=True).add_updater(lambda m: m.put_start_and_end_on(start, plane.c2p(0,a.get_value()+1))))
#             cursor.add_updater(lambda m: m.move_to(plane.c2p(0,a.get_value()+1)))
#             self.remove(graph_blue)
#             self.add(graph_blue_updated)
#             self.add_move_sound(direction="forward", duration=1)
#             self.play(a.animate.set_value(1), run_time=2)
#             cursor.blinking=True


#         self.wait(4)


# class Func_7_5_I_1_b(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-1.5, 1.5, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         graph_blue = plane.plot(lambda x: np.cos(x), color=BLUE)

#         a = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.cos(x), color=BLUE))

#         ones = VGroup(MathTex("1", color=c1t, font_size=fs2), MathTex("-1", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
#         arrows = VGroup(MathTex("\\Rightarrow", color=c1t, font_size=fs2), MathTex("\\Rightarrow", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=LEFT)
#         twos = VGroup(MathTex("2", color=c1t, font_size=fs2), MathTex("0", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
#         ones_to_twos = VGroup(ones, arrows, twos).arrange(RIGHT, buff=0.4).next_to(title, DOWN, buff=0.4)
#         row_one = VGroup(ones_to_twos[0][0], ones_to_twos[1][0], ones_to_twos[2][0])
#         row_two = VGroup(ones_to_twos[0][1], ones_to_twos[1][1], ones_to_twos[2][1])

#         functerm = MathTex("f","(x)",  "=", "\\cos", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_2 = MathTex("f","(x)",  "=", "\\cos", "(x)", "+", "1", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)

#         self.add(functerm, graph_blue)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 That's correct. Great job.
#                 We want the values of the function to range from zero to two, instead of from negative one to one.
#                 This means, that wherever the function<bookmark mark="row_1_a"/> has a value of one, we want it
#                 <bookmark mark="row_1_b"/>to have a value of two instead.

#                 And wherever the function<bookmark mark="row_2_a"/> has a value of negative one, we want it <bookmark mark="row_2_b"/>
#                 to have a value of zero instead.

#                 Clearly, we can achieve this by <bookmark mark="transform_term"/> adding one to the function.
#                 If we do that, <bookmark mark="stretch_func"/> the function will be shifted vertically up by one.
#                 And that's exactly what we want.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("row_1_a")
#             cursor.blinking=False
#             x,y,_ = row_one[0].get_center()+0.4*DOWN
#             self.play(Create(row_one), CursorMoveTo(cursor,x,y), run_time=.5)

#             self.wait_until_bookmark("row_1_b")
#             x,y,_ = row_one[2].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("row_2_a")
#             cursor.blinking=False
#             x,y,_ = row_two[0].get_center()+0.4*DOWN
#             self.play(Create(row_two), CursorMoveTo(cursor,x,y), run_time=.5)
            
#             self.wait_until_bookmark("row_2_b")
#             x,y,_ = row_two[2].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("transform_term")
#             x,y,_ = functerm_2[6].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(TransformMatchingTex(functerm, functerm_2), CursorMoveTo(cursor,x,y), run_time=.5)

#             self.wait_until_bookmark("stretch_func")
#             x,y,_ = plane.c2p(0,1)
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#             start = plane.c2p(0,1)+OUT
#             self.add(Updown_Arrow(start, vert=True).add_updater(lambda m: m.put_start_and_end_on(start, plane.c2p(0,a.get_value()+1))))
#             cursor.add_updater(lambda m: m.move_to(plane.c2p(0,a.get_value()+1)))
#             self.remove(graph_blue)
#             self.add(graph_blue_updated)
#             self.add_move_sound(direction="forward", duration=1)
#             self.play(a.animate.set_value(1), run_time=2)
#             cursor.blinking=True


#         self.wait(4)


# class Func_7_5_I_1_a(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-1.5, 1.5, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         graph_blue = plane.plot(lambda x: np.cos(x), color=BLUE)

#         a = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.cos(x), color=BLUE))

#         ones = VGroup(MathTex("1", color=c1t, font_size=fs2), MathTex("-1", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
#         arrows = VGroup(MathTex("\\Rightarrow", color=c1t, font_size=fs2), MathTex("\\Rightarrow", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=LEFT)
#         twos = VGroup(MathTex("2", color=c1t, font_size=fs2), MathTex("0", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
#         ones_to_twos = VGroup(ones, arrows, twos).arrange(RIGHT, buff=0.4).next_to(title, DOWN, buff=0.4)
#         row_one = VGroup(ones_to_twos[0][0], ones_to_twos[1][0], ones_to_twos[2][0])
#         row_two = VGroup(ones_to_twos[0][1], ones_to_twos[1][1], ones_to_twos[2][1])

#         functerm = MathTex("f","(x)",  "=", "\\cos", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_2 = MathTex("f","(x)",  "=", "\\cos", "(x)", "+", "1", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)

#         self.add(functerm, graph_blue)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not right.
#                 We want the values of the function to range from zero to two, instead of from negative one to one.
#                 This means, that wherever the function<bookmark mark="row_1_a"/> has a value of one, we want it
#                 <bookmark mark="row_1_b"/>to have a value of two instead.

#                 And wherever the function<bookmark mark="row_2_a"/> has a value of negative one, we want it <bookmark mark="row_2_b"/>
#                 to have a value of zero instead.

#                 Clearly, we can achieve this by <bookmark mark="transform_term"/> adding one to the function.
#                 If we do that, <bookmark mark="stretch_func"/> the function will be shifted vertically up by one.
#                 And that's exactly what we want.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("row_1_a")
#             cursor.blinking=False
#             x,y,_ = row_one[0].get_center()+0.4*DOWN
#             self.play(Create(row_one), CursorMoveTo(cursor,x,y), run_time=.5)

#             self.wait_until_bookmark("row_1_b")
#             x,y,_ = row_one[2].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("row_2_a")
#             cursor.blinking=False
#             x,y,_ = row_two[0].get_center()+0.4*DOWN
#             self.play(Create(row_two), CursorMoveTo(cursor,x,y), run_time=.5)
            
#             self.wait_until_bookmark("row_2_b")
#             x,y,_ = row_two[2].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("transform_term")
#             x,y,_ = functerm_2[6].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(TransformMatchingTex(functerm, functerm_2), CursorMoveTo(cursor,x,y), run_time=.5)

#             self.wait_until_bookmark("stretch_func")
#             x,y,_ = plane.c2p(0,1)
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#             start = plane.c2p(0,1)+OUT
#             self.add(Updown_Arrow(start, vert=True).add_updater(lambda m: m.put_start_and_end_on(start, plane.c2p(0,a.get_value()+1))))
#             cursor.add_updater(lambda m: m.move_to(plane.c2p(0,a.get_value()+1)))
#             self.remove(graph_blue)
#             self.add(graph_blue_updated)
#             self.add_move_sound(direction="forward", duration=1)
#             self.play(a.animate.set_value(1), run_time=2)
#             cursor.blinking=True


#         self.wait(4)


# class Func_7_5_I_1_a(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-1.5, 1.5, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-1,1]).shift(1.6*DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         graph_blue = plane.plot(lambda x: np.cos(x), color=BLUE)

#         a = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.cos(x), color=BLUE))

#         ones = VGroup(MathTex("1", color=c1t, font_size=fs2), MathTex("-1", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
#         arrows = VGroup(MathTex("\\Rightarrow", color=c1t, font_size=fs2), MathTex("\\Rightarrow", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=LEFT)
#         twos = VGroup(MathTex("2", color=c1t, font_size=fs2), MathTex("0", color=c1t, font_size=fs2)).arrange(DOWN, buff=0.2, aligned_edge=RIGHT)
#         ones_to_twos = VGroup(ones, arrows, twos).arrange(RIGHT, buff=0.4).next_to(title, DOWN, buff=0.4)
#         row_one = VGroup(ones_to_twos[0][0], ones_to_twos[1][0], ones_to_twos[2][0])
#         row_two = VGroup(ones_to_twos[0][1], ones_to_twos[1][1], ones_to_twos[2][1])

#         functerm = MathTex("f","(x)",  "=", "\\cos", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_2 = MathTex("f","(x)",  "=", "\\cos", "(x)", "+", "1", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)

#         self.add(functerm, graph_blue)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not right.
#                 We want the values of the function to range from zero to two, instead of from negative one to one.
#                 This means, that wherever the function<bookmark mark="row_1_a"/> has a value of one, we want it
#                 <bookmark mark="row_1_b"/>to have a value of two instead.

#                 And wherever the function<bookmark mark="row_2_a"/> has a value of negative one, we want it <bookmark mark="row_2_b"/>
#                 to have a value of zero instead.

#                 Clearly, we can achieve this by <bookmark mark="transform_term"/> adding one to the function.
#                 If we do that, <bookmark mark="stretch_func"/> the function will be shifted vertically up by one.
#                 And that's exactly what we want.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("row_1_a")
#             cursor.blinking=False
#             x,y,_ = row_one[0].get_center()+0.4*DOWN
#             self.play(Create(row_one), CursorMoveTo(cursor,x,y), run_time=.5)

#             self.wait_until_bookmark("row_1_b")
#             x,y,_ = row_one[2].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("row_2_a")
#             cursor.blinking=False
#             x,y,_ = row_two[0].get_center()+0.4*DOWN
#             self.play(Create(row_two), CursorMoveTo(cursor,x,y), run_time=.5)
            
#             self.wait_until_bookmark("row_2_b")
#             x,y,_ = row_two[2].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("transform_term")
#             x,y,_ = functerm_2[6].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(TransformMatchingTex(functerm, functerm_2), CursorMoveTo(cursor,x,y), run_time=.5)

#             self.wait_until_bookmark("stretch_func")
#             x,y,_ = plane.c2p(0,1)
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#             start = plane.c2p(0,1)+OUT
#             self.add(Updown_Arrow(start, vert=True).add_updater(lambda m: m.put_start_and_end_on(start, plane.c2p(0,a.get_value()+1))))
#             cursor.add_updater(lambda m: m.move_to(plane.c2p(0,a.get_value()+1)))
#             self.remove(graph_blue)
#             self.add(graph_blue_updated)
#             self.add_move_sound(direction="forward", duration=1)
#             self.play(a.animate.set_value(1), run_time=2)
#             cursor.blinking=True


#         self.wait(4)


# #####################################
# #####################################
# class Func_7_5_I_2(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.cos(x), color=BLUE))

#         line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
#         line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

#         functerm = MathTex("f","(x)",  "=", "\\sin", "(x)", "+","a", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         a_val = VGroup(MathTex("a=", color=c1t, font_size=fs1), DecimalNumber(1).scale(.9).set_color(c1t).add_updater(lambda m: m.set_value(a.get_value()))).arrange(RIGHT, buff=0.2).next_to(functerm, DOWN, buff=0.4)
#         a_val[1].shift((a_val[0].get_bottom()-a_val[1].get_bottom())[1]*UP)
#         self.add(graph_blue_updated, functerm, a_val)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 In general, we can shift the cosine function <bookmark mark="y_axis"/> in y-direction by simply
#                 adding  <bookmark mark="scale_a"/> a constant factor a.<bookmark mark="move_cursor"/>.
#                 If <bookmark mark="a_1"/>a is positive, the function will be shifted up.
#                 And if <bookmark mark="a_2"/>a is negative, the function will be shifted down.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("y_axis")
#             cursor.blinking = False
#             self.play(CursorMarkAxis(cursor, plane, "y"), run_time=.5)

#             self.wait_until_bookmark("scale_a")
#             x,y,_ = functerm[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveResize(cursor,x,y, 0.2, 0.2), run_time=.5)
#             cursor.blinking = True

#             self.wait_until_bookmark("move_cursor")
#             x,y,_ = plane.c2p(np.pi/2,0)
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#             cursor.add_updater(lambda m: m.move_to(plane.c2p(np.pi/2,a.get_value())))

#             self.wait_until_bookmark("a_1")
#             self.add_move_sound(direction="forward", duration=1.5)
#             start = plane.c2p(np.pi/2,0)+OUT
#             self.add(Updown_Arrow(start, vert=True).add_updater(lambda m: m.put_start_and_end_on(start, plane.c2p(np.pi/2,a.get_value()))))
#             self.play(a.animate.set_value(1))
#             cursor.blinking=True

#             self.wait_until_bookmark("a_2")
#             cursor.blinking=False
#             self.add_move_sound(direction="backward", duration=1.5)
#             self.play(a.animate.set_value(-1))
#             cursor.blinking=True


#         self.wait(4)


# #####################################
# #####################################
# TASK_Func_7_5_P_1_q = SophiaTaskDefinition(
#     answerOptions = ["$a=2$", "$a=\tfrac{1}{2}$", "$a=-2$", "$a=-\tfrac{1}{2}$"],
#     correctAnswerIndex = 2,
#     questionText = "What value do we choose for $a$, to stretch the function vertically by a factor of two and reflect it at the x-axis?",
# )
# class Func_7_5_P_1_q(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.sin(x), color=BLUE))

#         qmark = ImageMobject(assets_folder / "img" / "qmark.png")
#         qmark = qmark.scale(3.2/qmark.get_width()).move_to([-5, 1, 0])

#         functerm = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         self.add(graph_blue_updated, functerm)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Consider the <bookmark mark="f"/> function f <bookmark mark="fx"/> of x <bookmark mark="sin"/>equals
#                 sine <bookmark mark="x"/> of x.

#                 Now we want to shift the <bookmark mark="shift_down"/>function down by two.

#                 <bookmark mark="qmark"/>What does the term of the shifted function look like?
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("f")
#             cursor.blinking = False
#             x,y,_ = functerm[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("fx")
#             x,y,_ = functerm[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin")
#             x,y,_ = functerm[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("x")
#             x,y,_ = functerm[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("shift_down")
#             x,y,_ = plane.c2p(np.pi,0)
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor, x, y), run_time=.5)
#             start = plane.c2p(np.pi,0)+OUT
#             cursor.add_updater(lambda m: m.move_to(plane.c2p(np.pi,a.get_value())))
#             self.add(Updown_Arrow(start, vert=True).add_updater(lambda m: m.put_start_and_end_on(start, plane.c2p(np.pi,a.get_value()))))
#             self.add_move_sound(direction="backward", duration=.5)
#             self.play(a.animate.set_value(-2), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("qmark")
#             self.play(qmark.animate.shift(5*RIGHT), run_time=.5)
#             self.wait(1)
#             self.play(qmark.animate.shift(5*RIGHT), run_time=.5)


#         self.wait(4)


# class Func_7_5_P_1_a(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.sin(x), color=BLUE))

#         qmark = ImageMobject(assets_folder / "img" / "qmark.png")
#         qmark = qmark.scale(3.2/qmark.get_width()).move_to([-5, 1, 0])

#         functerm = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_shifted = MathTex("f","(x)",  "=", "\\sin", "(x)", "-","2", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         self.add(graph_blue_updated, functerm)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Yep, that's right.
#                 We're starting with the function <bookmark mark="f"/> f <bookmark mark="fx"/> of x <bookmark mark="sin"/>equals
#                 sine <bookmark mark="x"/> of x and we want to <bookmark mark="shift_down"/>shift it down by two.

#                 This means, that we want to decrease every value by two, so <bookmark mark="subtract_two"/> we subtract
#                 two from the entire function.

#                 So, the new term will <bookmark mark="f_final"/> be f <bookmark mark="fx_final"/> of x
#                 <bookmark mark="sin_final"/>equals sine <bookmark mark="x_final"/> of x <bookmark mark="minus_two"/> minus two.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("f")
#             cursor.blinking = False
#             x,y,_ = functerm[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("fx")
#             x,y,_ = functerm[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin")
#             x,y,_ = functerm[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("x")
#             x,y,_ = functerm[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("shift_down")
#             x,y,_ = plane.c2p(np.pi,0)
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor, x, y), run_time=.5)
#             start = plane.c2p(np.pi,0)+OUT
#             cursor_updater = lambda m: m.move_to(plane.c2p(np.pi,a.get_value()))
#             cursor.add_updater(cursor_updater)
#             self.add(Updown_Arrow(start, vert=True).add_updater(lambda m: m.put_start_and_end_on(start, plane.c2p(np.pi,a.get_value()))))
#             self.add_move_sound(direction="backward", duration=.5)
#             self.play(a.animate.set_value(-2), run_time=.5)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("subtract_two")
#             x,y,_ = functerm_shifted[-1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(TransformMatchingTex(functerm, functerm_shifted), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("f_final")
#             cursor.blinking=False
#             x,y,_ = functerm_shifted[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("fx_final")
#             x,y,_ = functerm_shifted[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin_final")
#             x,y,_ = functerm_shifted[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("x_final")
#             x,y,_ = functerm_shifted[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("minus_two")
#             x,y,_ = functerm_shifted[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)
#             cursor.blinking=True


#         self.wait(4)

# class Func_7_5_P_1_b(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.sin(x), color=BLUE))

#         qmark = ImageMobject(assets_folder / "img" / "qmark.png")
#         qmark = qmark.scale(3.2/qmark.get_width()).move_to([-5, 1, 0])

#         functerm = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_shifted = MathTex("f","(x)",  "=", "\\sin", "(x)", "-","2", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         self.add(graph_blue_updated, functerm)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not correct.
#                 We're starting with the function <bookmark mark="f"/> f <bookmark mark="fx"/> of x <bookmark mark="sin"/>equals
#                 sine <bookmark mark="x"/> of x and we want to <bookmark mark="shift_down"/>shift it down by two.

#                 This means, that we want to decrease every value by two, so <bookmark mark="subtract_two"/> we subtract
#                 two from the entire function.

#                 So, the new term will <bookmark mark="f_final"/> be f <bookmark mark="fx_final"/> of x
#                 <bookmark mark="sin_final"/>equals sine <bookmark mark="x_final"/> of x <bookmark mark="minus_two"/> minus two.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("f")
#             cursor.blinking = False
#             x,y,_ = functerm[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("fx")
#             x,y,_ = functerm[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin")
#             x,y,_ = functerm[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("x")
#             x,y,_ = functerm[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("shift_down")
#             x,y,_ = plane.c2p(np.pi,0)
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor, x, y), run_time=.5)
#             start = plane.c2p(np.pi,0)+OUT
#             cursor_updater = lambda m: m.move_to(plane.c2p(np.pi,a.get_value()))
#             cursor.add_updater(cursor_updater)
#             self.add(Updown_Arrow(start, vert=True).add_updater(lambda m: m.put_start_and_end_on(start, plane.c2p(np.pi,a.get_value()))))
#             self.add_move_sound(direction="backward", duration=.5)
#             self.play(a.animate.set_value(-2), run_time=.5)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("subtract_two")
#             x,y,_ = functerm_shifted[-1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(TransformMatchingTex(functerm, functerm_shifted), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("f_final")
#             cursor.blinking=False
#             x,y,_ = functerm_shifted[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("fx_final")
#             x,y,_ = functerm_shifted[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin_final")
#             x,y,_ = functerm_shifted[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("x_final")
#             x,y,_ = functerm_shifted[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("minus_two")
#             x,y,_ = functerm_shifted[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)
#             cursor.blinking=True


#         self.wait(4)


# class Func_7_5_P_1_c(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.sin(x), color=BLUE))

#         qmark = ImageMobject(assets_folder / "img" / "qmark.png")
#         qmark = qmark.scale(3.2/qmark.get_width()).move_to([-5, 1, 0])

#         functerm = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_shifted = MathTex("f","(x)",  "=", "\\sin", "(x)", "-","2", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         self.add(graph_blue_updated, functerm)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not correct.
#                 We're starting with the function <bookmark mark="f"/> f <bookmark mark="fx"/> of x <bookmark mark="sin"/>equals
#                 sine <bookmark mark="x"/> of x and we want to <bookmark mark="shift_down"/>shift it down by two.

#                 This means, that we want to decrease every value by two, so <bookmark mark="subtract_two"/> we subtract
#                 two from the entire function.

#                 So, the new term will <bookmark mark="f_final"/> be f <bookmark mark="fx_final"/> of x
#                 <bookmark mark="sin_final"/>equals sine <bookmark mark="x_final"/> of x <bookmark mark="minus_two"/> minus two.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("f")
#             cursor.blinking = False
#             x,y,_ = functerm[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("fx")
#             x,y,_ = functerm[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin")
#             x,y,_ = functerm[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("x")
#             x,y,_ = functerm[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("shift_down")
#             x,y,_ = plane.c2p(np.pi,0)
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor, x, y), run_time=.5)
#             start = plane.c2p(np.pi,0)+OUT
#             cursor_updater = lambda m: m.move_to(plane.c2p(np.pi,a.get_value()))
#             cursor.add_updater(cursor_updater)
#             self.add(Updown_Arrow(start, vert=True).add_updater(lambda m: m.put_start_and_end_on(start, plane.c2p(np.pi,a.get_value()))))
#             self.add_move_sound(direction="backward", duration=.5)
#             self.play(a.animate.set_value(-2), run_time=.5)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("subtract_two")
#             x,y,_ = functerm_shifted[-1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(TransformMatchingTex(functerm, functerm_shifted), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("f_final")
#             cursor.blinking=False
#             x,y,_ = functerm_shifted[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("fx_final")
#             x,y,_ = functerm_shifted[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin_final")
#             x,y,_ = functerm_shifted[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("x_final")
#             x,y,_ = functerm_shifted[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("minus_two")
#             x,y,_ = functerm_shifted[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)
#             cursor.blinking=True


#         self.wait(4)



# class Func_7_5_P_1_d(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.sin(x), color=BLUE))

#         qmark = ImageMobject(assets_folder / "img" / "qmark.png")
#         qmark = qmark.scale(3.2/qmark.get_width()).move_to([-5, 1, 0])

#         functerm = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_shifted = MathTex("f","(x)",  "=", "\\sin", "(x)", "-","2", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         self.add(graph_blue_updated, functerm)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not correct.
#                 We're starting with the function <bookmark mark="f"/> f <bookmark mark="fx"/> of x <bookmark mark="sin"/>equals
#                 sine <bookmark mark="x"/> of x and we want to <bookmark mark="shift_down"/>shift it down by two.

#                 This means, that we want to decrease every value by two, so <bookmark mark="subtract_two"/> we subtract
#                 two from the entire function.

#                 So, the new term will <bookmark mark="f_final"/> be f <bookmark mark="fx_final"/> of x
#                 <bookmark mark="sin_final"/>equals sine <bookmark mark="x_final"/> of x <bookmark mark="minus_two"/> minus two.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("f")
#             cursor.blinking = False
#             x,y,_ = functerm[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("fx")
#             x,y,_ = functerm[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin")
#             x,y,_ = functerm[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("x")
#             x,y,_ = functerm[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("shift_down")
#             x,y,_ = plane.c2p(np.pi,0)
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor, x, y), run_time=.5)
#             start = plane.c2p(np.pi,0)+OUT
#             cursor_updater = lambda m: m.move_to(plane.c2p(np.pi,a.get_value()))
#             cursor.add_updater(cursor_updater)
#             self.add(Updown_Arrow(start, vert=True).add_updater(lambda m: m.put_start_and_end_on(start, plane.c2p(np.pi,a.get_value()))))
#             self.add_move_sound(direction="backward", duration=.5)
#             self.play(a.animate.set_value(-2), run_time=.5)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("subtract_two")
#             x,y,_ = functerm_shifted[-1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(TransformMatchingTex(functerm, functerm_shifted), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("f_final")
#             cursor.blinking=False
#             x,y,_ = functerm_shifted[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("fx_final")
#             x,y,_ = functerm_shifted[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin_final")
#             x,y,_ = functerm_shifted[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("x_final")
#             x,y,_ = functerm_shifted[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("minus_two")
#             x,y,_ = functerm_shifted[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)
#             cursor.blinking=True


#         self.wait(4)



# #####################################
# #####################################
# TASK_Func_7_5_I_3_q = SophiaTaskDefinition(
#     answerOptions = ["$f(x)=\sin(x+b), b>0$", "$f(x)=\sin(x+b), b<0$", "$f(x)=\sin(x\cdot b), b<0$", "$f(x)=\sin(x\cdot b), b>0$", ],
#     correctAnswerIndex = 0,
#     questionText = "What does the function $f(x)=\sin(x)$ look like, after it was shifted to the left?"
# )
# class Func_7_5_I_3_q(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a = ValueTracker(0)
#         b = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.sin(b.get_value()+x), color=BLUE))

#         line_1 = Line(plane.c2p(0,-1), plane.c2p(0,1), color=GREY)
#         line_2 = Line(plane.c2p(0,-2), plane.c2p(0,2), color=GREEN)

#         functerm = MathTex("f","(x)",  "=", "\\sin", "(x)", "+", "a", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_2 = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         self.add(graph_blue_updated, functerm)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 <bookmark mark="start"/>
#                 We can shift the sine function <bookmark mark="y_axis"/> in y-direction by simply
#                 adding a <bookmark mark="shift_a"/>constant factor a to the entire function.

#                 Now, what if we want to shift the <bookmark mark="x_axis"/> function in x-direction?
#                 For example: How do we change the <bookmark mark="f"/> function term f <bookmark mark="fx"/>of x <bookmark mark="sin"/>equals
#                 sine <bookmark mark="x"/> of x, so that <bookmark mark="shift_b"/>f is shifted to the left?
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("start")
#             x,y,_ = plane.c2p(np.pi/2,1)
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/2,1+a.get_value()))
#             cursor.add_updater(cursor_updater)
#             ud_1 = Updown_Arrow(plane.c2p(np.pi/2,1), vert=True).add_updater(lambda m: m.put_start_and_end_on(plane.c2p(np.pi/2,1), plane.c2p(np.pi/2,1+a.get_value())))
#             self.add(ud_1)
#             self.add_move_sound(direction="forward", duration=.8)
#             self.play(a.animate.set_value(2), run_time=.8)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True
            
#             self.wait_until_bookmark("y_axis")
#             cursor.blinking = False
#             self.play(CursorMarkAxis(cursor, plane, "y"), run_time=.5)
#             self.wait(1)
#             x,y,_ = plane.c2p(0,0)
#             self.play(CursorMoveResize(cursor,x,y,0.2,0.2), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("shift_a")
#             cursor.blinking = False
#             x,y,_ = functerm[-1].get_center()+0.4*DOWN
#             self.play(CursorMoveResize(cursor,x,y, 0.2, 0.2), run_time=.5)
#             cursor.blinking = True


#             self.wait_until_bookmark("x_axis")
#             cursor.blinking = False
#             self.play(a.animate(run_time=.4).set_value(0), CursorMarkAxis(cursor, plane, "x"), run_time=1)
#             self.remove(ud_1)

#             self.wait_until_bookmark("f")
#             cursor.blinking = False
#             x,y,_ = functerm_2[0].get_center()+0.4*DOWN
#             self.play(TransformMatchingTex(functerm, functerm_2), CursorMoveResize(cursor, x, y, 0.2, 0.2), run_time=.5)

#             self.wait_until_bookmark("fx")
#             x,y,_ = functerm_2[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin")
#             x,y,_ = functerm_2[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

#             self.wait_until_bookmark("x")
#             x,y,_ = functerm_2[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("shift_b")
#             x,y,_ = plane.c2p(np.pi,0)
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#             cursor_updater = lambda m: m.move_to(plane.c2p(np.pi-b.get_value(),0))
#             cursor.add_updater(cursor_updater)
#             ud_2 = Updown_Arrow(plane.c2p(np.pi,0), vert=False).add_updater(lambda m: m.put_start_and_end_on(plane.c2p(np.pi,0), plane.c2p(np.pi-b.get_value(),0)))
#             self.add(ud_2)
#             self.add_move_sound(direction="forward", duration=2.5)
#             self.play(b.animate.set_value(2.5), run_time=2.5)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#         self.wait(4)



# class Func_7_5_I_3_a(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a = ValueTracker(0)
#         b = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.sin(b.get_value()+x), color=BLUE))
#         graph_grey = plane.plot(lambda x: np.sin(x), color=GREY, stroke_width=1)

#         arrow_1 = Line(plane.c2p(2*np.pi,0), plane.c2p(np.pi,0), color=ORANGE)
#         arrow_2 = Line(plane.c2p(3/2*np.pi,-1), plane.c2p(np.pi/2,-1), color=ORANGE)

#         functerm = MathTex("f","(x)",  "=", "\\sin", "(x+", "\\pi",")", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_general = MathTex("f","(x)",  "=", "\\sin", "(x+", "b",")", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_general_neg = MathTex("b>0", color=c1t, font_size=fs1).next_to(functerm_general, DOWN, buff=.2)
#         functerm_2 = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         self.add(graph_grey, graph_blue_updated, functerm_2)


#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Yep, that is correct...

#                 We want to shift the<bookmark mark="f"/> function f <bookmark mark="fx"/>of x <bookmark mark="sin"/>equals
#                 sine <bookmark mark="x"/> of x <bookmark mark="shift_b"/>to the left...
                
#                 This means, for example, that the point that used to be <bookmark mark="two_pi"/>at two pi will now
#                 <bookmark mark="pi"/>be at x equals pi, and that the point that used to be <bookmark mark="onepfive"/>
#                 at one and a half pi will now be<bookmark mark="half_pi"/> at half pi.

#                 So  we need the value of pi to be what the value of two pi used to be, and the value of half pi to be
#                 what the value of one and a half pi used to be.
#                 We can achiev this by <bookmark mark="add_b"/>adding pi to x.

#                 This means that the term of the shifted <bookmark mark="f_final"/>function will be f
#                 <bookmark mark="fx_final"/>of x <bookmark mark="sin_final"/>equals sine <bookmark mark="x_final"/>of open
#                 bracket x <bookmark mark="plus_pi"/>plus pi close bracket.

#                 So if we just want to shift it to the left, the general term will be f of x equals sine of
#                 <bookmark mark="x_plus_b"/>x plus b, <bookmark mark="b_pos"/> where b is a positive number.
#                 """
#         ) as tracker:
            

#             self.wait_until_bookmark("f")
#             cursor.blinking = False
#             x,y,_ = functerm_2[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.5)

#             self.wait_until_bookmark("fx")
#             x,y,_ = functerm_2[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin")
#             x,y,_ = functerm_2[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

#             self.wait_until_bookmark("x")
#             x,y,_ = functerm_2[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("shift_b")
#             x,y,_ = plane.c2p(np.pi,0)
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#             cursor_updater = lambda m: m.move_to(plane.c2p(np.pi-b.get_value(),0))
#             cursor.add_updater(cursor_updater)
#             ud_2 = Updown_Arrow(plane.c2p(np.pi,0), vert=False).add_updater(lambda m: m.put_start_and_end_on(plane.c2p(np.pi,0), plane.c2p(np.pi-b.get_value(),0)))
#             self.add(ud_2)
#             self.add_move_sound(direction="forward", duration=2.5)
#             self.play(b.animate.set_value(np.pi), run_time=2.5)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("two_pi")
#             cursor.blinking = False
#             x,y,_ = plane.c2p(2*np.pi,0)
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("pi")
#             cursor.blinking = False
#             cursor_updater = lambda m: m.move_to(arrow_1.get_end())
#             cursor.add_updater(cursor_updater)
#             self.play(Create(arrow_1), run_time=.3)
#             arrow_1.add_tip(tip_length=0.2)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("onepfive")
#             cursor.blinking = False
#             x,y,_ = plane.c2p(3/2*np.pi,-1)
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("half_pi")
#             cursor.blinking = False
#             cursor_updater = lambda m: m.move_to(arrow_2.get_end())
#             cursor.add_updater(cursor_updater)
#             self.play(Create(arrow_2), run_time=.3)
#             arrow_2.add_tip(tip_length=0.2)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("add_b")
#             cursor.blinking = False
#             x,y,_ = functerm[-2].get_center()+0.4*DOWN
#             self.play(TransformMatchingTex(functerm_2, functerm), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True


#             self.wait_until_bookmark("f_final")
#             cursor.blinking = False
#             x,y,_ = functerm[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("fx_final")
#             x,y,_ = functerm[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin_final")
#             x,y,_ = functerm[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

#             self.wait_until_bookmark("x_final")
#             x,y,_ = functerm[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

#             self.wait_until_bookmark("plus_pi")
#             x,y,_ = functerm[-2].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("x_plus_b")
#             cursor.blinking = False
#             x,y,_ = functerm_general[4].get_center()+0.4*DOWN
#             self.play(TransformMatchingTex(functerm, functerm_general), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("b_pos")
#             cursor.blinking = False
#             x,y,_ = functerm_general_neg.get_center()+0.4*DOWN
#             self.play(Write(functerm_general_neg), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True

#         self.wait(4)


# class Func_7_5_I_3_b(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a = ValueTracker(0)
#         b = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.sin(b.get_value()+x), color=BLUE))
#         graph_grey = plane.plot(lambda x: np.sin(x), color=GREY, stroke_width=1)

#         arrow_1 = Line(plane.c2p(2*np.pi,0), plane.c2p(np.pi,0), color=ORANGE)
#         arrow_2 = Line(plane.c2p(3/2*np.pi,-1), plane.c2p(np.pi/2,-1), color=ORANGE)

#         functerm = MathTex("f","(x)",  "=", "\\sin", "(x+", "\\pi",")", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_general = MathTex("f","(x)",  "=", "\\sin", "(x+", "b",")", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_general_neg = MathTex("b>0", color=c1t, font_size=fs1).next_to(functerm_general, DOWN, buff=.2)
#         functerm_2 = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         self.add(graph_grey, graph_blue_updated, functerm_2)


#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's right.

#                 We want to shift the<bookmark mark="f"/> function f <bookmark mark="fx"/>of x <bookmark mark="sin"/>equals
#                 sine <bookmark mark="x"/> of x <bookmark mark="shift_b"/>to the left...
                
#                 This means, for example, that the point that used to be <bookmark mark="two_pi"/>at two pi will now
#                 <bookmark mark="pi"/>be at x equals pi, and that the point that used to be <bookmark mark="onepfive"/>
#                 at one and a half pi will now be<bookmark mark="half_pi"/> at half pi.

#                 So  we need the value of pi to be what the value of two pi used to be, and the value of half pi to be
#                 what the value of one and a half pi used to be.
#                 We can achiev this by <bookmark mark="add_b"/>adding pi to x.

#                 This means that the term of the shifted <bookmark mark="f_final"/>function will be f
#                 <bookmark mark="fx_final"/>of x <bookmark mark="sin_final"/>equals sine <bookmark mark="x_final"/>of open
#                 bracket x <bookmark mark="plus_pi"/>plus pi close bracket.

#                 So if we just want to shift it to the left, the general term will be f of x equals sine of
#                 <bookmark mark="x_plus_b"/>x plus b, <bookmark mark="b_pos"/> where b is a positive number.
#                 """
#         ) as tracker:
            

#             self.wait_until_bookmark("f")
#             cursor.blinking = False
#             x,y,_ = functerm_2[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.5)

#             self.wait_until_bookmark("fx")
#             x,y,_ = functerm_2[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin")
#             x,y,_ = functerm_2[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

#             self.wait_until_bookmark("x")
#             x,y,_ = functerm_2[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("shift_b")
#             x,y,_ = plane.c2p(np.pi,0)
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#             cursor_updater = lambda m: m.move_to(plane.c2p(np.pi-b.get_value(),0))
#             cursor.add_updater(cursor_updater)
#             ud_2 = Updown_Arrow(plane.c2p(np.pi,0), vert=False).add_updater(lambda m: m.put_start_and_end_on(plane.c2p(np.pi,0), plane.c2p(np.pi-b.get_value(),0)))
#             self.add(ud_2)
#             self.add_move_sound(direction="forward", duration=2.5)
#             self.play(b.animate.set_value(np.pi), run_time=2.5)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("two_pi")
#             cursor.blinking = False
#             x,y,_ = plane.c2p(2*np.pi,0)
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("pi")
#             cursor.blinking = False
#             cursor_updater = lambda m: m.move_to(arrow_1.get_end())
#             cursor.add_updater(cursor_updater)
#             self.play(Create(arrow_1), run_time=.3)
#             arrow_1.add_tip(tip_length=0.2)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("onepfive")
#             cursor.blinking = False
#             x,y,_ = plane.c2p(3/2*np.pi,-1)
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("half_pi")
#             cursor.blinking = False
#             cursor_updater = lambda m: m.move_to(arrow_2.get_end())
#             cursor.add_updater(cursor_updater)
#             self.play(Create(arrow_2), run_time=.3)
#             arrow_2.add_tip(tip_length=0.2)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("add_b")
#             cursor.blinking = False
#             x,y,_ = functerm[-2].get_center()+0.4*DOWN
#             self.play(TransformMatchingTex(functerm_2, functerm), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True


#             self.wait_until_bookmark("f_final")
#             cursor.blinking = False
#             x,y,_ = functerm[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("fx_final")
#             x,y,_ = functerm[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin_final")
#             x,y,_ = functerm[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

#             self.wait_until_bookmark("x_final")
#             x,y,_ = functerm[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

#             self.wait_until_bookmark("plus_pi")
#             x,y,_ = functerm[-2].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("x_plus_b")
#             cursor.blinking = False
#             x,y,_ = functerm_general[4].get_center()+0.4*DOWN
#             self.play(TransformMatchingTex(functerm, functerm_general), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("b_pos")
#             cursor.blinking = False
#             x,y,_ = functerm_general_neg.get_center()+0.4*DOWN
#             self.play(Write(functerm_general_neg), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True

#         self.wait(4)


# class Func_7_5_I_3_c(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a = ValueTracker(0)
#         b = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.sin(b.get_value()+x), color=BLUE))
#         graph_grey = plane.plot(lambda x: np.sin(x), color=GREY, stroke_width=1)

#         arrow_1 = Line(plane.c2p(2*np.pi,0), plane.c2p(np.pi,0), color=ORANGE)
#         arrow_2 = Line(plane.c2p(3/2*np.pi,-1), plane.c2p(np.pi/2,-1), color=ORANGE)

#         functerm = MathTex("f","(x)",  "=", "\\sin", "(x+", "\\pi",")", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_general = MathTex("f","(x)",  "=", "\\sin", "(x+", "b",")", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_general_neg = MathTex("b>0", color=c1t, font_size=fs1).next_to(functerm_general, DOWN, buff=.2)
#         functerm_2 = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         self.add(graph_grey, graph_blue_updated, functerm_2)


#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's right.

#                 We want to shift the<bookmark mark="f"/> function f <bookmark mark="fx"/>of x <bookmark mark="sin"/>equals
#                 sine <bookmark mark="x"/> of x <bookmark mark="shift_b"/>to the left...
                
#                 This means, for example, that the point that used to be <bookmark mark="two_pi"/>at two pi will now
#                 <bookmark mark="pi"/>be at x equals pi, and that the point that used to be <bookmark mark="onepfive"/>
#                 at one and a half pi will now be<bookmark mark="half_pi"/> at half pi.

#                 So  we need the value of pi to be what the value of two pi used to be, and the value of half pi to be
#                 what the value of one and a half pi used to be.
#                 We can achiev this by <bookmark mark="add_b"/>adding pi to x.

#                 This means that the term of the shifted <bookmark mark="f_final"/>function will be f
#                 <bookmark mark="fx_final"/>of x <bookmark mark="sin_final"/>equals sine <bookmark mark="x_final"/>of open
#                 bracket x <bookmark mark="plus_pi"/>plus pi close bracket.

#                 So if we just want to shift it to the left, the general term will be f of x equals sine of
#                 <bookmark mark="x_plus_b"/>x plus b, <bookmark mark="b_pos"/> where b is a positive number.
#                 """
#         ) as tracker:
            

#             self.wait_until_bookmark("f")
#             cursor.blinking = False
#             x,y,_ = functerm_2[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.5)

#             self.wait_until_bookmark("fx")
#             x,y,_ = functerm_2[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin")
#             x,y,_ = functerm_2[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

#             self.wait_until_bookmark("x")
#             x,y,_ = functerm_2[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("shift_b")
#             x,y,_ = plane.c2p(np.pi,0)
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#             cursor_updater = lambda m: m.move_to(plane.c2p(np.pi-b.get_value(),0))
#             cursor.add_updater(cursor_updater)
#             ud_2 = Updown_Arrow(plane.c2p(np.pi,0), vert=False).add_updater(lambda m: m.put_start_and_end_on(plane.c2p(np.pi,0), plane.c2p(np.pi-b.get_value(),0)))
#             self.add(ud_2)
#             self.add_move_sound(direction="forward", duration=2.5)
#             self.play(b.animate.set_value(np.pi), run_time=2.5)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("two_pi")
#             cursor.blinking = False
#             x,y,_ = plane.c2p(2*np.pi,0)
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("pi")
#             cursor.blinking = False
#             cursor_updater = lambda m: m.move_to(arrow_1.get_end())
#             cursor.add_updater(cursor_updater)
#             self.play(Create(arrow_1), run_time=.3)
#             arrow_1.add_tip(tip_length=0.2)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("onepfive")
#             cursor.blinking = False
#             x,y,_ = plane.c2p(3/2*np.pi,-1)
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("half_pi")
#             cursor.blinking = False
#             cursor_updater = lambda m: m.move_to(arrow_2.get_end())
#             cursor.add_updater(cursor_updater)
#             self.play(Create(arrow_2), run_time=.3)
#             arrow_2.add_tip(tip_length=0.2)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("add_b")
#             cursor.blinking = False
#             x,y,_ = functerm[-2].get_center()+0.4*DOWN
#             self.play(TransformMatchingTex(functerm_2, functerm), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True


#             self.wait_until_bookmark("f_final")
#             cursor.blinking = False
#             x,y,_ = functerm[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("fx_final")
#             x,y,_ = functerm[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin_final")
#             x,y,_ = functerm[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

#             self.wait_until_bookmark("x_final")
#             x,y,_ = functerm[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

#             self.wait_until_bookmark("plus_pi")
#             x,y,_ = functerm[-2].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("x_plus_b")
#             cursor.blinking = False
#             x,y,_ = functerm_general[4].get_center()+0.4*DOWN
#             self.play(TransformMatchingTex(functerm, functerm_general), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("b_pos")
#             cursor.blinking = False
#             x,y,_ = functerm_general_neg.get_center()+0.4*DOWN
#             self.play(Write(functerm_general_neg), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True

#         self.wait(4)


# class Func_7_5_I_3_d(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Sine \& Cosine: Shifting")

#         cords = self.add_cords([-.5, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[0, np.pi, 2*np.pi], x_labels=["0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a = ValueTracker(0)
#         b = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.sin(b.get_value()+x), color=BLUE))
#         graph_grey = plane.plot(lambda x: np.sin(x), color=GREY, stroke_width=1)

#         arrow_1 = Line(plane.c2p(2*np.pi,0), plane.c2p(np.pi,0), color=ORANGE)
#         arrow_2 = Line(plane.c2p(3/2*np.pi,-1), plane.c2p(np.pi/2,-1), color=ORANGE)

#         functerm = MathTex("f","(x)",  "=", "\\sin", "(x+", "\\pi",")", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_general = MathTex("f","(x)",  "=", "\\sin", "(x+", "b",")", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         functerm_general_neg = MathTex("b>0", color=c1t, font_size=fs1).next_to(functerm_general, DOWN, buff=.2)
#         functerm_2 = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=1)
#         self.add(graph_grey, graph_blue_updated, functerm_2)


#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's right.

#                 We want to shift the<bookmark mark="f"/> function f <bookmark mark="fx"/>of x <bookmark mark="sin"/>equals
#                 sine <bookmark mark="x"/> of x <bookmark mark="shift_b"/>to the left...
                
#                 This means, for example, that the point that used to be <bookmark mark="two_pi"/>at two pi will now
#                 <bookmark mark="pi"/>be at x equals pi, and that the point that used to be <bookmark mark="onepfive"/>
#                 at one and a half pi will now be<bookmark mark="half_pi"/> at half pi.

#                 So  we need the value of pi to be what the value of two pi used to be, and the value of half pi to be
#                 what the value of one and a half pi used to be.
#                 We can achiev this by <bookmark mark="add_b"/>adding pi to x.

#                 This means that the term of the shifted <bookmark mark="f_final"/>function will be f
#                 <bookmark mark="fx_final"/>of x <bookmark mark="sin_final"/>equals sine <bookmark mark="x_final"/>of open
#                 bracket x <bookmark mark="plus_pi"/>plus pi close bracket.

#                 So if we just want to shift it to the left, the general term will be f of x equals sine of
#                 <bookmark mark="x_plus_b"/>x plus b, <bookmark mark="b_pos"/> where b is a positive number.
#                 """
#         ) as tracker:
            

#             self.wait_until_bookmark("f")
#             cursor.blinking = False
#             x,y,_ = functerm_2[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.5)

#             self.wait_until_bookmark("fx")
#             x,y,_ = functerm_2[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin")
#             x,y,_ = functerm_2[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

#             self.wait_until_bookmark("x")
#             x,y,_ = functerm_2[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)
#             cursor.blinking=True

#             self.wait_until_bookmark("shift_b")
#             x,y,_ = plane.c2p(np.pi,0)
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#             cursor_updater = lambda m: m.move_to(plane.c2p(np.pi-b.get_value(),0))
#             cursor.add_updater(cursor_updater)
#             ud_2 = Updown_Arrow(plane.c2p(np.pi,0), vert=False).add_updater(lambda m: m.put_start_and_end_on(plane.c2p(np.pi,0), plane.c2p(np.pi-b.get_value(),0)))
#             self.add(ud_2)
#             self.add_move_sound(direction="forward", duration=2.5)
#             self.play(b.animate.set_value(np.pi), run_time=2.5)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("two_pi")
#             cursor.blinking = False
#             x,y,_ = plane.c2p(2*np.pi,0)
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("pi")
#             cursor.blinking = False
#             cursor_updater = lambda m: m.move_to(arrow_1.get_end())
#             cursor.add_updater(cursor_updater)
#             self.play(Create(arrow_1), run_time=.3)
#             arrow_1.add_tip(tip_length=0.2)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("onepfive")
#             cursor.blinking = False
#             x,y,_ = plane.c2p(3/2*np.pi,-1)
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("half_pi")
#             cursor.blinking = False
#             cursor_updater = lambda m: m.move_to(arrow_2.get_end())
#             cursor.add_updater(cursor_updater)
#             self.play(Create(arrow_2), run_time=.3)
#             arrow_2.add_tip(tip_length=0.2)
#             cursor.remove_updater(cursor_updater)
#             cursor.blinking=True

#             self.wait_until_bookmark("add_b")
#             cursor.blinking = False
#             x,y,_ = functerm[-2].get_center()+0.4*DOWN
#             self.play(TransformMatchingTex(functerm_2, functerm), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True


#             self.wait_until_bookmark("f_final")
#             cursor.blinking = False
#             x,y,_ = functerm[0].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("fx_final")
#             x,y,_ = functerm[1].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.3)

#             self.wait_until_bookmark("sin_final")
#             x,y,_ = functerm[3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

#             self.wait_until_bookmark("x_final")
#             x,y,_ = functerm[4].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor, x, y), run_time=.2)

#             self.wait_until_bookmark("plus_pi")
#             x,y,_ = functerm[-2].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor, x, y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("x_plus_b")
#             cursor.blinking = False
#             x,y,_ = functerm_general[4].get_center()+0.4*DOWN
#             self.play(TransformMatchingTex(functerm, functerm_general), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("b_pos")
#             cursor.blinking = False
#             x,y,_ = functerm_general_neg.get_center()+0.4*DOWN
#             self.play(Write(functerm_general_neg), CursorMoveTo(cursor, x, y), run_time=.5)
#             cursor.blinking=True

#         self.wait(4)


# #####################################
# #####################################
# class Func_7_5_I_4(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Shifting Sideways")

#         cords = self.add_cords([-2*np.pi, 2*np.pi, np.pi], [-2, 2, 1], x_ticks=[-2*np.pi, -np.pi, 0, np.pi, 2*np.pi], x_labels=["-2\\Pi", "-\\Pi","0", "\\Pi", "2\\Pi"], y_ticks=[-2,-1,1,2]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)
#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a = ValueTracker(0)
#         b = ValueTracker(0)
#         graph_blue_updated = always_redraw(lambda: plane.plot(lambda x: a.get_value()+np.sin(b.get_value()+x), color=BLUE))
#         graph_grey = plane.plot(lambda x: np.sin(x), color=GREY, stroke_width=1)

#         arrow_1 = Line(plane.c2p(2*np.pi,0), plane.c2p(np.pi,0), color=ORANGE)
#         arrow_2 = Line(plane.c2p(3/2*np.pi,-1), plane.c2p(np.pi/2,-1), color=ORANGE)
#         arrow_3 = Line(plane.c2p(0,0), plane.c2p(np.pi,0), color=ORANGE)
#         arrow_4 = Line(plane.c2p(np.pi/2,1), plane.c2p(3*np.pi/2,1), color=ORANGE)

#         functerm_add = MathTex("f","(x)",  "=", "\\sin", "(x-", "b",")", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=.6)
#         functerm_subtract = MathTex("f","(x)",  "=", "\\sin", "(x+", "b",")", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=.6)
#         functerm = MathTex("f","(x)",  "=", "\\sin", "(x)", color=c1t, font_size=fs1).next_to(cords, DOWN, buff=.6)
#         self.add(graph_grey, graph_blue_updated, functerm)


#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Quick summary: Shifting sine and cosine functions along<bookmark mark="x_axis"/> the x-axis,
#                 so shifting them left, or right.         

#                 If we want to shift <bookmark mark="shift_left"/> the function to the left,
#                 we have <bookmark mark="add"/>to add the amount we want to shift by from x.

#                 Why is that?
#                 For example, let's say we want to shift the sine function to the left by pi.
#                 This means, that the point that used to<bookmark mark="two_pi"/> be at two pi will
#                 <bookmark mark="pi"/>now be at pi. And the point that used to be <bookmark mark="onepfive"/>
#                 at one and a half pi will now <bookmark mark="half_pi"/>be at half pi.

#                 To make the value of pi equal to that of two pi, or the value of half pi equal to that of one and a half pi,
#                 we have to add pi to x. So to shift the function left, we subtract from x.
#                 <bookmark mark="reset"/>
#                 If we want to <bookmark mark="shift_right"/>shift the function to the right, we have to subtract the amount we want to shift by from x.
                
#                 Again, why is that the case?
#                 Let's say we want to shift the sine function to the right by pi.
#                 This means, that the point that used to<bookmark mark="zero_right"/> be at zero will
#                 now be <bookmark mark="pi_right"/> pi. And the point that used to <bookmark mark="pihalf_right"/>be
#                 at half pi will now <bookmark mark="onepfive_right"/>be at one point five pi.
#                 """
#         ) as tracker:            
                
#                 self.wait_until_bookmark("x_axis")
#                 cursor.blinking = False
#                 self.play(CursorMarkAxis(cursor,plane), run_time=.5)
#                 self.wait(1)
#                 self.play(CursorMoveResize(cursor,x,y,0.2,0.2), run_time=.5)
#                 cursor.blinking=True

#                 self.wait_until_bookmark("shift_left")
#                 cursor.blinking = False
#                 x,y,_ = plane.c2p(np.pi/2,1)
#                 self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#                 cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/2-b.get_value(),1))
#                 cursor.add_updater(cursor_updater)
#                 self.play(b.animate.set_value(np.pi))
#                 cursor.remove_updater(cursor_updater)
#                 cursor.blinking=True

#                 self.wait_until_bookmark("add")
#                 cursor.blinking = False
#                 x,y,_ = functerm_subtract[-2].get_center()+0.4*DOWN
#                 self.play(TransformMatchingTex(functerm, functerm_subtract), CursorMoveTo(cursor, x, y), run_time=.5)
#                 cursor.blinking=True

#                 self.wait_until_bookmark("two_pi")
#                 cursor.blinking = False
#                 x,y,_ = plane.c2p(2*np.pi,0)
#                 self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#                 cursor.blinking=True

#                 self.wait_until_bookmark("pi")
#                 cursor.blinking = False
#                 cursor_updater = lambda m: m.move_to(arrow_1.get_end())
#                 cursor.add_updater(cursor_updater)
#                 self.play(Create(arrow_1), run_time=.3)
#                 arrow_1.add_tip(tip_length=0.2)
#                 cursor.remove_updater(cursor_updater)
#                 cursor.blinking=True

#                 self.wait_until_bookmark("onepfive")
#                 cursor.blinking = False
#                 x,y,_ = plane.c2p(3/2*np.pi,-1)
#                 self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#                 cursor.blinking=True

#                 self.wait_until_bookmark("half_pi")
#                 cursor.blinking = False
#                 cursor_updater = lambda m: m.move_to(arrow_2.get_end())
#                 cursor.add_updater(cursor_updater)
#                 self.play(Create(arrow_2), run_time=.3)
#                 arrow_2.add_tip(tip_length=0.2)
#                 cursor.remove_updater(cursor_updater)
#                 cursor.blinking=True

#                 self.wait_until_bookmark("reset")
#                 cursor.blinking = False
#                 x,y,_ = plane.c2p(0,0)
#                 self.play(TransformMatchingTex(functerm_subtract, functerm), CursorMoveTo(cursor, x, y), b.animate.set_value(0), Unwrite(arrow_1), Unwrite(arrow_2), run_time=.5)
#                 cursor.blinking=True

#                 self.wait_until_bookmark("shift_right")
#                 cursor.blinking = False
#                 x,y,_ = plane.c2p(np.pi/2,1)
#                 self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#                 cursor_updater = lambda m: m.move_to(plane.c2p(np.pi/2-b.get_value(),1))
#                 cursor.add_updater(cursor_updater)
#                 self.play(b.animate.set_value(-np.pi))
#                 cursor.remove_updater(cursor_updater)
#                 cursor.blinking=True

#                 self.wait_until_bookmark("zero_right")
#                 cursor.blinking = False
#                 x,y,_ = plane.c2p(0,0)
#                 self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#                 cursor.blinking=True

#                 self.wait_until_bookmark("pi_right")
#                 cursor.blinking = False
#                 cursor_updater = lambda m: m.move_to(arrow_3.get_end())
#                 cursor.add_updater(cursor_updater)
#                 self.play(Create(arrow_3), run_time=.3)
#                 arrow_3.add_tip(tip_length=0.2)
#                 cursor.remove_updater(cursor_updater)
#                 cursor.blinking=True

#                 self.wait_until_bookmark("pihalf_right")
#                 cursor.blinking = False
#                 x,y,_ = plane.c2p(np.pi/2,1)
#                 self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#                 cursor.blinking=True

#                 self.wait_until_bookmark("onepfive_right")
#                 cursor.blinking = False
#                 cursor_updater = lambda m: m.move_to(arrow_4.get_end())
#                 cursor.add_updater(cursor_updater)
#                 self.play(Create(arrow_4), run_time=.3)
#                 arrow_4.add_tip(tip_length=0.2)
#                 cursor.remove_updater(cursor_updater)
#                 cursor.blinking=True

#         self.wait(4)






# # PROTOTYPES=[
# #     PagePrototypeVideo.from_scene(Func_7_3_I_1_q),
# #     PagePrototypeQuestion.from_task_definition(TASK_Func_7_3_I_1_q, Func_7_3_I_1_q.__name__),
# #     PagePrototypeVideo.from_scene(Func_7_3_I_1_a),
# #     PagePrototypeVideo.from_scene(Func_7_3_I_1_b),
# #     PagePrototypeVideo.from_scene(Func_7_3_I_2_q),
# #     PagePrototypeQuestion.from_task_definition(TASK_Func_7_3_I_2_q, Func_7_3_I_2_q.__name__),
# #     PagePrototypeVideo.from_scene(Func_7_3_I_2_a),
# #     PagePrototypeVideo.from_scene(Func_7_3_I_2_b),
# #     PagePrototypeVideo.from_scene(Func_7_3_I_2_c),
# #     PagePrototypeVideo.from_scene(Func_7_3_I_2_d),
# #     PagePrototypeVideo.from_scene(Func_7_3_I_3),
# #     PagePrototypeVideo.from_scene(Func_7_3_I_4),
# #     PagePrototypeVideo.from_scene(Func_7_3_I_4),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_1_q),
# #     PagePrototypeQuestion.from_task_definition(TASK_Func_7_3_P_1_q, Func_7_3_P_1_q.__name__),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_1_a),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_1_b),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_1_c),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_1_d),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_2_q),
# #     PagePrototypeQuestion.from_task_definition(TASK_Func_7_3_P_2_q, Func_7_3_P_2_q.__name__),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_2_a),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_2_b),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_2_c),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_2_d),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_3_q),
# #     PagePrototypeQuestion.from_task_definition(TASK_Func_7_3_P_3_q, Func_7_3_P_3_q.__name__),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_3_a),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_3_b),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_3_c),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_3_d),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_4_q),
# #     PagePrototypeQuestion.from_task_definition(TASK_Func_7_3_P_4_q, Func_7_3_P_4_q.__name__),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_4_a),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_4_b),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_4_c),
# #     PagePrototypeVideo.from_scene(Func_7_3_P_4_d),
# # ]

scenes/Func/Func_7: Sine and Cosine Functions/Func_7_5.py
Sophia-Edu-Labs/sophia-math
# # 8_1: Polynomial Functions: Degree and Coefficients

# # Import necessary libraries and modules
# from abc import ABCMeta, abstractmethod
# from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
# from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
#                                           CursorPositionTracking,
#                                           CursorResizeDefault, SophiaScene,
#                                           assets_folder, avatars_folder,
#                                           generated_avatars_folder, AltCursor,
#                                           SophiaCursorScene, CursorMoveTo,
#                                           CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
# from sophialib.styles.styleconstants import *
# from sophialib.styles.sophiaobjects import *
# from manim import *
# from PIL import Image
# import numpy as np
# from pathlib import Path
# from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition


# #####################################
# #####################################
# TASK_Func_8_1_I_1_q = SophiaTaskDefinition(
#     answerOptions = ["$f(x)=\sin(x)", "$f(x)=\cos(x)", "$f(x)=\\frac{1}{2}x$", "$f(x)=x^2$"],
#     correctAnswerIndex = 2,
#     questionText = "What is a linear function we could use to model a roller coaster?"
# )
# class Func_8_1_I_1_q(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-2,2, 1], x_ticks=[-2,0,2], y_ticks=[-1,1])
#         plane = cords[0]

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         gero = ImageMobject(assets_folder / "img" / "gero.png")
#         gero = gero.scale(2.5/gero.get_width()).move_to([-5, 1.4, 0])
#         phone = ImageMobject(assets_folder / "img" / "phone.png")
#         phone = phone.scale(2.5/phone.get_width()).move_to([-5, 1.4, 0])
#         rollercoaster = ImageMobject(assets_folder / "img" / "rollercoaster.png")
#         rollercoaster = rollercoaster.scale(2.5/rollercoaster.get_width()).move_to([-5, -1.4, 0])

#         func = plane.plot(lambda x: x/2, color=BLUE)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 We're now combining the knowledge of functions that we've obtained so far, to cover a new
#                 topic: Polynomial Functions.

#                 We'll start with an example. <bookmark mark="gero_in"/>
#                 Meet Gero. Gero loves nothing more <bookmark mark="rollercoaster_in"/> than rollercoasters,
#                 so he decides to build one for his friends.
#                 <bookmark mark="phone_gero"/>
#                 He talked to a rollercoaster construction company, and they told him, that all he needs to
#                 do is tell them the term of a function, and they'll build a rollercoaster that follows that
#                 <bookmark mark="phone_out"/>function.

#                 Gero hasn't been using the sophia math app enough, so he only knows about
#                 linear functions. <bookmark mark="linear_func"/>What is a linear function he could use
#                 to model a rollercoaster?
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("gero_in")
#             self.play(gero.animate.shift(RIGHT*5))

#             self.wait_until_bookmark("rollercoaster_in")
#             self.play(rollercoaster.animate.shift(RIGHT*5))

#             self.wait_until_bookmark("phone_gero")
#             self.play(gero.animate.shift(RIGHT*5), phone.animate(run_time=0.5).shift(RIGHT*5))

#             self.wait_until_bookmark("phone_out")
#             self.play(phone.animate.shift(RIGHT*5))

#             self.wait_until_bookmark("linear_func")
#             x,y,_ = func.get_start()
#             cursor.blinking=False
#             self.play(Create(cords), CursorMoveTo(cursor,x,y))
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func.get_end()))._start_fading(2))
#             self.add_pencil_sound(1.5)
#             self.play(Create(func))
#             cursor.blinking=True

#         self.wait(4)


# class Func_8_1_I_1_a(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-2,2, 1], x_ticks=[-2,0,2], y_ticks=[-1,1])
#         plane = cords[0]

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: x/2, color=BLUE)

#         lin = MathTex("ax", "+", "b", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.6)
#         sin = MathTex("\\sin(x),", "\\,\\cos(x)", font_size=fs2, color=c1t).next_to(lin, DOWN, buff=.4)
#         l,t,_ = sin.get_critical_point(UP+LEFT)
#         r,b,_ = sin.get_critical_point(DOWN+RIGHT)
#         cross_trigon = VGroup(Line([l,t,0], [r,b,0], color=RED, stroke_width=2), Line([l,b,0], [r,t,0], color=RED, stroke_width=2))
#         square = MathTex("x^2", font_size=fs2, color=c1t).next_to(sin, DOWN, buff=.4)
#         l,t, _ = square.get_critical_point(UP+LEFT)
#         r,b, _ = square.get_critical_point(DOWN+RIGHT)
#         cross_square = VGroup(Line([l,t,0], [r,b,0], color=RED, stroke_width=2), Line([l,b,0], [r,t,0], color=RED, stroke_width=2))
#         correct = MathTex("\\tfrac{1}{2}x", font_size=fs2, color=c1t).next_to(square, DOWN, buff=.4)

#         check = ImageMobject(assets_folder / "img" / "green_checkmark.png")
#         check = check.scale(1/check.get_width()).next_to(correct, RIGHT, buff=.4)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not a linear function.
#                 <bookmark mark="linear_func"/>
#                 A linear function is a function that has a constant slope. This means, it
#                 can only contain terms of the <bookmark mark="ax"/> form a
#                 times x <bookmark mark="b"/>plus b, where a and b are constants.
#                 <bookmark mark="sine"/>So the sine and the<bookmark mark="not_sine"/> cosine
#                 aren't linear, <bookmark mark="x_squared"/>and x squared <bookmark mark="not_x_squared"/>
#                 isn't linear either.
#                 <bookmark mark="sol"/> one half times x on the other hand, is linear,
#                 <bookmark mark="checkmark"/> so that is the correct answer.
#                 """
#         ) as tracker:
            
#             self.play(Create(cords))

#             self.wait_until_bookmark("linear_func")
#             x,y,_ = func.get_start()
#             cursor.blinking=False
#             self.play(Create(cords), CursorMoveTo(cursor,x,y))
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func.get_end()))._start_fading(2))
#             self.add_pencil_sound(1.5)
#             self.play(Create(func))
#             cursor.blinking=True

#             self.wait_until_bookmark("ax")
#             x,y,_ = lin[0].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(lin), CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("b")
#             x,y,_ = lin[2].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("sine")
#             x,y,_ = sin.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(sin), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("not_sine")
#             self.play(Create(cross_trigon))

#             self.wait_until_bookmark("x_squared")
#             x,y,_ = square.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(square), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("not_x_squared")
#             self.play(Create(cross_square))

#             self.wait_until_bookmark("sol")
#             x,y,_ = correct.get_center()+0.5*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(correct), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("checkmark")
#             self.play(FadeIn(check), run_time=.5)

#         self.wait(4)


# class Func_8_1_I_1_b(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-2,2, 1], x_ticks=[-2,0,2], y_ticks=[-1,1])
#         plane = cords[0]

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: x/2, color=BLUE)

#         lin = MathTex("ax", "+", "b", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.6)
#         sin = MathTex("\\sin(x),", "\\,\\cos(x)", font_size=fs2, color=c1t).next_to(lin, DOWN, buff=.4)
#         l,t,_ = sin.get_critical_point(UP+LEFT)
#         r,b,_ = sin.get_critical_point(DOWN+RIGHT)
#         cross_trigon = VGroup(Line([l,t,0], [r,b,0], color=RED, stroke_width=2), Line([l,b,0], [r,t,0], color=RED, stroke_width=2))
#         square = MathTex("x^2", font_size=fs2, color=c1t).next_to(sin, DOWN, buff=.4)
#         l,t, _ = square.get_critical_point(UP+LEFT)
#         r,b, _ = square.get_critical_point(DOWN+RIGHT)
#         cross_square = VGroup(Line([l,t,0], [r,b,0], color=RED, stroke_width=2), Line([l,b,0], [r,t,0], color=RED, stroke_width=2))
#         correct = MathTex("\\tfrac{1}{2}x", font_size=fs2, color=c1t).next_to(square, DOWN, buff=.4)

#         check = ImageMobject(assets_folder / "img" / "green_checkmark.png")
#         check = check.scale(1/check.get_width()).next_to(correct, RIGHT, buff=.4)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not a linear function.
#                 <bookmark mark="linear_func"/>
#                 A linear function is a function that has a constant slope. This means, it
#                 can only contain terms of the <bookmark mark="ax"/> form a
#                 times x <bookmark mark="b"/>plus b, where a and b are constants.
#                 <bookmark mark="sine"/>So the sine and the<bookmark mark="not_sine"/> cosine
#                 aren't linear, <bookmark mark="x_squared"/>and x squared <bookmark mark="not_x_squared"/>
#                 isn't linear either.
#                 <bookmark mark="sol"/> one half times x on the other hand, is linear,
#                 <bookmark mark="checkmark"/> so that is the correct answer.
#                 """
#         ) as tracker:
            
#             self.play(Create(cords))

#             self.wait_until_bookmark("linear_func")
#             x,y,_ = func.get_start()
#             cursor.blinking=False
#             self.play(Create(cords), CursorMoveTo(cursor,x,y))
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func.get_end()))._start_fading(2))
#             self.add_pencil_sound(1.5)
#             self.play(Create(func))
#             cursor.blinking=True

#             self.wait_until_bookmark("ax")
#             x,y,_ = lin[0].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(lin), CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("b")
#             x,y,_ = lin[2].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("sine")
#             x,y,_ = sin.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(sin), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("not_sine")
#             self.play(Create(cross_trigon))

#             self.wait_until_bookmark("x_squared")
#             x,y,_ = square.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(square), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("not_x_squared")
#             self.play(Create(cross_square))

#             self.wait_until_bookmark("sol")
#             x,y,_ = correct.get_center()+0.5*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(correct), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("checkmark")
#             self.play(FadeIn(check), run_time=.5)

#         self.wait(4)


# class Func_8_1_I_1_c(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-2,2, 1], x_ticks=[-2,0,2], y_ticks=[-1,1])
#         plane = cords[0]

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: x/2, color=BLUE)

#         lin = MathTex("ax", "+", "b", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.6)
#         sin = MathTex("\\sin(x),", "\\,\\cos(x)", font_size=fs2, color=c1t).next_to(lin, DOWN, buff=.4)
#         l,t,_ = sin.get_critical_point(UP+LEFT)
#         r,b,_ = sin.get_critical_point(DOWN+RIGHT)
#         cross_trigon = VGroup(Line([l,t,0], [r,b,0], color=RED, stroke_width=2), Line([l,b,0], [r,t,0], color=RED, stroke_width=2))
#         square = MathTex("x^2", font_size=fs2, color=c1t).next_to(sin, DOWN, buff=.4)
#         l,t, _ = square.get_critical_point(UP+LEFT)
#         r,b, _ = square.get_critical_point(DOWN+RIGHT)
#         cross_square = VGroup(Line([l,t,0], [r,b,0], color=RED, stroke_width=2), Line([l,b,0], [r,t,0], color=RED, stroke_width=2))
#         correct = MathTex("\\tfrac{1}{2}x", font_size=fs2, color=c1t).next_to(square, DOWN, buff=.4)

#         check = ImageMobject(assets_folder / "img" / "green_checkmark.png")
#         check = check.scale(1/check.get_width()).next_to(correct, RIGHT, buff=.4)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Yep, that's right.
#                 <bookmark mark="linear_func"/>
#                 A linear function is a function that has a constant slope. This means, it
#                 can only contain terms of the <bookmark mark="ax"/> form a
#                 times x <bookmark mark="b"/>plus b, where a and b are constants.
#                 <bookmark mark="sine"/>So the sine and the<bookmark mark="not_sine"/> cosine
#                 aren't linear, <bookmark mark="x_squared"/>and x squared <bookmark mark="not_x_squared"/>
#                 isn't linear either.
#                 <bookmark mark="sol"/> one half times x on the other hand, is linear,
#                 <bookmark mark="checkmark"/> so that is the correct answer.
#                 """
#         ) as tracker:
            
#             self.play(Create(cords))

#             self.wait_until_bookmark("linear_func")
#             x,y,_ = func.get_start()
#             cursor.blinking=False
#             self.play(Create(cords), CursorMoveTo(cursor,x,y))
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func.get_end()))._start_fading(2))
#             self.add_pencil_sound(1.5)
#             self.play(Create(func))
#             cursor.blinking=True

#             self.wait_until_bookmark("ax")
#             x,y,_ = lin[0].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(lin), CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("b")
#             x,y,_ = lin[2].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("sine")
#             x,y,_ = sin.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(sin), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("not_sine")
#             self.play(Create(cross_trigon))

#             self.wait_until_bookmark("x_squared")
#             x,y,_ = square.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(square), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("not_x_squared")
#             self.play(Create(cross_square))

#             self.wait_until_bookmark("sol")
#             x,y,_ = correct.get_center()+0.5*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(correct), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("checkmark")
#             self.play(FadeIn(check), run_time=.5)

#         self.wait(4)


# class Func_8_1_I_1_d(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-2,2, 1], x_ticks=[-2,0,2], y_ticks=[-1,1])
#         plane = cords[0]

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: x/2, color=BLUE)

#         lin = MathTex("ax", "+", "b", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.6)
#         sin = MathTex("\\sin(x),", "\\,\\cos(x)", font_size=fs2, color=c1t).next_to(lin, DOWN, buff=.4)
#         l,t,_ = sin.get_critical_point(UP+LEFT)
#         r,b,_ = sin.get_critical_point(DOWN+RIGHT)
#         cross_trigon = VGroup(Line([l,t,0], [r,b,0], color=RED, stroke_width=2), Line([l,b,0], [r,t,0], color=RED, stroke_width=2))
#         square = MathTex("x^2", font_size=fs2, color=c1t).next_to(sin, DOWN, buff=.4)
#         l,t, _ = square.get_critical_point(UP+LEFT)
#         r,b, _ = square.get_critical_point(DOWN+RIGHT)
#         cross_square = VGroup(Line([l,t,0], [r,b,0], color=RED, stroke_width=2), Line([l,b,0], [r,t,0], color=RED, stroke_width=2))
#         correct = MathTex("\\tfrac{1}{2}x", font_size=fs2, color=c1t).next_to(square, DOWN, buff=.4)

#         check = ImageMobject(assets_folder / "img" / "green_checkmark.png")
#         check = check.scale(1/check.get_width()).next_to(correct, RIGHT, buff=.4)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not a linear function.
#                 <bookmark mark="linear_func"/>
#                 A linear function is a function that has a constant slope. This means, it
#                 can only contain terms of the <bookmark mark="ax"/> form a
#                 times x <bookmark mark="b"/>plus b, where a and b are constants.
#                 <bookmark mark="sine"/>So the sine and the<bookmark mark="not_sine"/> cosine
#                 aren't linear, <bookmark mark="x_squared"/>and x squared <bookmark mark="not_x_squared"/>
#                 isn't linear either.
#                 <bookmark mark="sol"/> one half times x on the other hand, is linear,
#                 <bookmark mark="checkmark"/> so that is the correct answer.
#                 """
#         ) as tracker:
            
#             self.play(Create(cords))

#             self.wait_until_bookmark("linear_func")
#             x,y,_ = func.get_start()
#             cursor.blinking=False
#             self.play(Create(cords), CursorMoveTo(cursor,x,y))
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func.get_end()))._start_fading(2))
#             self.add_pencil_sound(1.5)
#             self.play(Create(func))
#             cursor.blinking=True

#             self.wait_until_bookmark("ax")
#             x,y,_ = lin[0].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(lin), CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("b")
#             x,y,_ = lin[2].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("sine")
#             x,y,_ = sin.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(sin), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("not_sine")
#             self.play(Create(cross_trigon))

#             self.wait_until_bookmark("x_squared")
#             x,y,_ = square.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(square), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("not_x_squared")
#             self.play(Create(cross_square))

#             self.wait_until_bookmark("sol")
#             x,y,_ = correct.get_center()+0.5*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(correct), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("checkmark")
#             self.play(FadeIn(check), run_time=.5)

#         self.wait(4)


# #####################################
# #####################################
# TASK_Func_8_1_I_2_q = SophiaTaskDefinition(
#     answerOptions = ["Multiply $f$ with $a>0$", "Remove the $\\tfrac{1}{2}x$ term from $f$", "Add a constant $c$ to $f$", "Add terms like $x^3, x^4$,... to $f$"],
#     correctAnswerIndex = 3,
#     questionText = "How can we add more curves to the rollercoaster?"
# )
# class Func_8_1_I_2_q(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-5,5, 2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4])
#         plane = cords[0]

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=False)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: x/2, color=BLUE)
#         func_squared = plane.plot(lambda x: x**2+x/2, color=PURPLE)

#         functerm_linear = MathTex("f(x)=", "\\tfrac{1}{2}", "x", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.6)
#         functerm_squared = MathTex("f(x)=", "x^2", "+\\tfrac{1}{2}x", font_size=fs2, color=c1t).move_to(functerm_linear)

#         qmark = ImageMobject(assets_folder / "img" / "qmark.png")
#         qmark = qmark.scale(2/qmark.get_width()).move_to([-5, 0, 0])

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Ok, now admittedly, that's a pretty boring rollercoaster.

#                 To make it more fun, we could <bookmark mark="add_square"/> add an
#                 x squared to the function. The function would then be of degree two,
#                 and contain a nice curve.

#                 Now that's a little better, but not much better. <bookmark mark="qmark"/>
#                 How could we add more curves to the rollercoaster? More ups and downs,
#                 to make it more fun?
#                 """
#         ) as tracker:
            
#             x,y,_ = func.get_start()
#             self.play(Create(cords), CursorMoveTo(cursor, x, y), run_time=.5)
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func.get_end()))._start_fading(2))
#             self.add_pencil_sound(1.5)
#             self.play(Create(func), Write(functerm_linear), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("add_square")
#             self.play(Transform(func, func_squared), Transform(functerm_linear, functerm_squared))

#             self.wait_until_bookmark("qmark")
#             self.play(qmark.animate.shift(RIGHT*5), run_time=.5)
#             self.wait(1)
#             self.play(qmark.animate.shift(RIGHT*5)) 

#         self.wait(4)



# class Func_8_1_I_2_a(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-5,5, 2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a_0, a_1, a_2, a_3, a_4, a_5, a_6 = ValueTracker(0), ValueTracker(0.5), ValueTracker(1), ValueTracker(0), ValueTracker(0), ValueTracker(0), ValueTracker(0)
#         a,b = ValueTracker(-2), ValueTracker(2)
#         f = lambda x: a_0.get_value()+a_1.get_value()*x+a_2.get_value()*x**2+a_3.get_value()*x**3+a_4.get_value()*x**4+a_5.get_value()*x**5+a_6.get_value()*x**6
#         func_squared = always_redraw(lambda: plane.plot(f, color=PURPLE,x_range=[a.get_value(),b.get_value(), 0.001]))
#         self.add(func_squared)


#         qmark = ImageMobject(assets_folder / "img" / "qmark.png")
#         qmark = qmark.scale(2/qmark.get_width()).move_to([-5, 0, 0])

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not the right solution.

#                 If we <bookmark mark="square_only"/>remove the x term from the function,
#                 it barely changes.<bookmark mark="reset_1"/>
#                 So that's not the right solution.

#                 If <bookmark mark="add"/> we add a constant to the function, or
#                 <bookmark mark="multiply"/> if we multiply the function with a constant,
#                 the function will only move up or down, or get stretched or compressed.
#                 But <bookmark mark="reset_2"/> we want to add more curves to the rollercoaster,
#                 so that's not the right solution either.

#                 What we can do however is add terms containing<bookmark mark="add_terms"/> x cubed
#                 or x to the power of four to the function. That way, the function will have
#                 more ups and downs, and the rollercoaster will be more fun.
#                 So the right solution is to add terms like x cubed or x to the power of four
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("square_only")
#             self.play(a_1.animate.set_value(0))

#             self.wait_until_bookmark("reset_1")
#             self.play(a_1.animate.set_value(0.5), run_time=.5)

#             self.wait_until_bookmark("add")
#             self.play(a_0.animate.set_value(2), run_time=.5)

#             self.wait_until_bookmark("multiply")
#             self.play(a_0.animate.set_value(0), a_1.animate.set_value(1/4), a_2.animate.set_value(0.5), run_time=2.5)

#             self.wait_until_bookmark("reset_2")
#             self.play(a_1.animate.set_value(0.5), a_2.animate.set_value(1), run_time=.5)

#             self.wait_until_bookmark("add_terms")
#             self.play(a.animate(run_time=1.5).set_value(-1.55), b.animate(run_time=1.5).set_value(1.45), a_6.animate.set_value(-2), a_4.animate.set_value(3), a_3.animate.set_value(-2),a_1.animate.set_value(3), run_time=3.5)

#         self.wait(4)


# class Func_8_1_I_2_b(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-5,5, 2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a_0, a_1, a_2, a_3, a_4, a_5, a_6 = ValueTracker(0), ValueTracker(0.5), ValueTracker(1), ValueTracker(0), ValueTracker(0), ValueTracker(0), ValueTracker(0)
#         a,b = ValueTracker(-2), ValueTracker(2)
#         f = lambda x: a_0.get_value()+a_1.get_value()*x+a_2.get_value()*x**2+a_3.get_value()*x**3+a_4.get_value()*x**4+a_5.get_value()*x**5+a_6.get_value()*x**6
#         func_squared = always_redraw(lambda: plane.plot(f, color=PURPLE,x_range=[a.get_value(),b.get_value(), 0.001]))
#         self.add(func_squared)


#         qmark = ImageMobject(assets_folder / "img" / "qmark.png")
#         qmark = qmark.scale(2/qmark.get_width()).move_to([-5, 0, 0])

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not the right solution.

#                 If we <bookmark mark="square_only"/>remove the x term from the function,
#                 it barely changes.<bookmark mark="reset_1"/>
#                 So that's not the right solution.

#                 If <bookmark mark="add"/> we add a constant to the function, or
#                 <bookmark mark="multiply"/> if we multiply the function with a constant,
#                 the function will only move up or down, or get stretched or compressed.
#                 But <bookmark mark="reset_2"/> we want to add more curves to the rollercoaster,
#                 so that's not the right solution either.

#                 What we can do however is add terms containing<bookmark mark="add_terms"/> x cubed
#                 or x to the power of four to the function. That way, the function will have
#                 more ups and downs, and the rollercoaster will be more fun.
#                 So the right solution is to add terms like x cubed or x to the power of four
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("square_only")
#             self.play(a_1.animate.set_value(0))

#             self.wait_until_bookmark("reset_1")
#             self.play(a_1.animate.set_value(0.5), run_time=.5)

#             self.wait_until_bookmark("add")
#             self.play(a_0.animate.set_value(2), run_time=.5)

#             self.wait_until_bookmark("multiply")
#             self.play(a_0.animate.set_value(0), a_1.animate.set_value(1/4), a_2.animate.set_value(0.5), run_time=2.5)

#             self.wait_until_bookmark("reset_2")
#             self.play(a_1.animate.set_value(0.5), a_2.animate.set_value(1), run_time=.5)

#             self.wait_until_bookmark("add_terms")
#             self.play(a.animate(run_time=1.5).set_value(-1.55), b.animate(run_time=1.5).set_value(1.45), a_6.animate.set_value(-2), a_4.animate.set_value(3), a_3.animate.set_value(-2),a_1.animate.set_value(3), run_time=3.5)

#         self.wait(4)


# class Func_8_1_I_2_c(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-5,5, 2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a_0, a_1, a_2, a_3, a_4, a_5, a_6 = ValueTracker(0), ValueTracker(0.5), ValueTracker(1), ValueTracker(0), ValueTracker(0), ValueTracker(0), ValueTracker(0)
#         a,b = ValueTracker(-2), ValueTracker(2)
#         f = lambda x: a_0.get_value()+a_1.get_value()*x+a_2.get_value()*x**2+a_3.get_value()*x**3+a_4.get_value()*x**4+a_5.get_value()*x**5+a_6.get_value()*x**6
#         func_squared = always_redraw(lambda: plane.plot(f, color=PURPLE,x_range=[a.get_value(),b.get_value(), 0.001]))
#         self.add(func_squared)


#         qmark = ImageMobject(assets_folder / "img" / "qmark.png")
#         qmark = qmark.scale(2/qmark.get_width()).move_to([-5, 0, 0])

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not the right solution.

#                 If we <bookmark mark="square_only"/>remove the x term from the function,
#                 it barely changes.<bookmark mark="reset_1"/>
#                 So that's not the right solution.

#                 If <bookmark mark="add"/> we add a constant to the function, or
#                 <bookmark mark="multiply"/> if we multiply the function with a constant,
#                 the function will only move up or down, or get stretched or compressed.
#                 But <bookmark mark="reset_2"/> we want to add more curves to the rollercoaster,
#                 so that's not the right solution either.

#                 What we can do however is add terms containing<bookmark mark="add_terms"/> x cubed
#                 or x to the power of four to the function. That way, the function will have
#                 more ups and downs, and the rollercoaster will be more fun.
#                 So the right solution is to add terms like x cubed or x to the power of four
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("square_only")
#             self.play(a_1.animate.set_value(0))

#             self.wait_until_bookmark("reset_1")
#             self.play(a_1.animate.set_value(0.5), run_time=.5)

#             self.wait_until_bookmark("add")
#             self.play(a_0.animate.set_value(2), run_time=.5)

#             self.wait_until_bookmark("multiply")
#             self.play(a_0.animate.set_value(0), a_1.animate.set_value(1/4), a_2.animate.set_value(0.5), run_time=2.5)

#             self.wait_until_bookmark("reset_2")
#             self.play(a_1.animate.set_value(0.5), a_2.animate.set_value(1), run_time=.5)

#             self.wait_until_bookmark("add_terms")
#             self.play(a.animate(run_time=1.5).set_value(-1.55), b.animate(run_time=1.5).set_value(1.45), a_6.animate.set_value(-2), a_4.animate.set_value(3), a_3.animate.set_value(-2),a_1.animate.set_value(3), run_time=3.5)

#         self.wait(4)


# class Func_8_1_I_2_d(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-5,5, 2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN)
#         plane = cords[0]
#         self.add(cords)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         a_0, a_1, a_2, a_3, a_4, a_5, a_6 = ValueTracker(0), ValueTracker(0.5), ValueTracker(1), ValueTracker(0), ValueTracker(0), ValueTracker(0), ValueTracker(0)
#         a,b = ValueTracker(-2), ValueTracker(2)
#         f = lambda x: a_0.get_value()+a_1.get_value()*x+a_2.get_value()*x**2+a_3.get_value()*x**3+a_4.get_value()*x**4+a_5.get_value()*x**5+a_6.get_value()*x**6
#         func_squared = always_redraw(lambda: plane.plot(f, color=PURPLE,x_range=[a.get_value(),b.get_value(), 0.001]))
#         self.add(func_squared)


#         qmark = ImageMobject(assets_folder / "img" / "qmark.png")
#         qmark = qmark.scale(2/qmark.get_width()).move_to([-5, 0, 0])

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Yes! That's right...

#                 If we <bookmark mark="square_only"/>remove the x term from the function,
#                 it barely changes.<bookmark mark="reset_1"/>
#                 So that's not the right solution.

#                 If <bookmark mark="add"/> we add a constant to the function, or
#                 <bookmark mark="multiply"/> if we multiply the function with a constant,
#                 the function will only move up or down, or get stretched or compressed.
#                 But <bookmark mark="reset_2"/> we want to add more curves to the rollercoaster,
#                 so that's not the right solution either.

#                 What we can do however is add terms containing<bookmark mark="add_terms"/> x cubed
#                 or x to the power of four to the function. That way, the function will have
#                 more ups and downs, and the rollercoaster will be more fun.
#                 So the right solution is to add terms like x cubed or x to the power of four
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("square_only")
#             self.play(a_1.animate.set_value(0))

#             self.wait_until_bookmark("reset_1")
#             self.play(a_1.animate.set_value(0.5), run_time=.5)

#             self.wait_until_bookmark("add")
#             self.play(a_0.animate.set_value(2), run_time=.5)

#             self.wait_until_bookmark("multiply")
#             self.play(a_0.animate.set_value(0), a_1.animate.set_value(1/4), a_2.animate.set_value(0.5), run_time=2.5)

#             self.wait_until_bookmark("reset_2")
#             self.play(a_1.animate.set_value(0.5), a_2.animate.set_value(1), run_time=.5)

#             self.wait_until_bookmark("add_terms")
#             self.play(a.animate(run_time=1.5).set_value(-1.55), b.animate(run_time=1.5).set_value(1.45), a_6.animate.set_value(-2), a_4.animate.set_value(3), a_3.animate.set_value(-2),a_1.animate.set_value(3), run_time=3.5)

#         self.wait(4)


# #####################################
# #####################################
# TASK_Func_8_1_I_3_q = SophiaTaskDefinition(
#     answerOptions = ["$6$", "$1$", "$-6$", "It doesn't have a degree"],
#     correctAnswerIndex = 0,
#     questionText = "What is the degree of the function $f(x)=-2x^6+3x^4-2x^3+x^2+3x$?"
# )
# class Func_8_1_I_3_q(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-5,5, 2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: -2*x**6+3*x**4-2*x**3+x**2+3*x, x_range=[-1.55,1.45,0.01], color=PURPLE)
#         func_tex = VGroup(MathTex("f(x)=", font_size=(fs2+fs3)/2, color=c1t), MathTex("-", "2x^6", "+", "3x^4", "-", "2x^3", "+", "x^2", "+", "3x", font_size=(fs2+fs3)/2, color=c1t)).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(cords, DOWN, buff=.8)

#         qmark = ImageMobject(assets_folder / "img" / "qmark.png")
#         qmark = qmark.scale(2/qmark.get_width()).move_to([-5, 0, 0])

#         deg_text = VGroup(Tex("Degree:", color=c1t, font_size=fs3), Tex("Highest power of x", color=c1t, font_size=fs3)).arrange(DOWN, aligned_edge=LEFT,buff=0.2).next_to(func_tex, DOWN, buff=.8)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 The function we have here
#                 is described by the <bookmark mark="term_in"/> term f of x equals
#                 <bookmark mark="sixth_degree"/>negative two times x to the power
#                 of six<bookmark mark="fourth_degree"/>  plus three times x to the power
#                 of four<bookmark mark="third_degree"/>  minus two times x to the power
#                 of three<bookmark mark="second_degree"/> plus x squared
#                 <bookmark mark="first_degree"/>plus three times x.

#                 This is a polynomial function. Let's take a closer look at the term.

#                 We'll start with the degree.
#                 <bookmark mark="degree"/>the degree of a polynomial function is the highest power of x,
#                 that appears in the function.
#                 <bookmark mark="qmark"/>
#                 What is the degree of the function that is shown here?
#                 """
#         ) as tracker:
            
#             x,y,_ = func.get_start()
#             self.play(CursorMoveTo(cursor, x, y), run_time=.5)
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func.get_end()))._start_fading(2))
#             self.add_pencil_sound(1.5)
#             self.play(Create(func))
#             cursor.blinking=True
            
#             self.wait_until_bookmark("term_in")
#             self.play(Write(func_tex), run_time=.8)

#             self.wait_until_bookmark("sixth_degree")
#             x,y,_ = func_tex[1][1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("fourth_degree")
#             x,y,_ = func_tex[1][3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("third_degree")
#             x,y,_ = func_tex[1][5].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("second_degree")
#             x,y,_ = func_tex[1][7].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("first_degree")
#             x,y,_ = func_tex[1][9].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("degree")
#             x,y,_ = deg_text[0].get_left()+0.2*LEFT
#             cursor.blinking = False
#             self.play(Write(deg_text), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("qmark")
#             self.play(qmark.animate.shift(RIGHT*5), run_time=.5)
#             self.wait(1)
#             self.play(qmark.animate.shift(RIGHT*5))


#         self.wait(4)


# class Func_8_1_I_3_a(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-5,5, 2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: -2*x**6+3*x**4-2*x**3+x**2+3*x, x_range=[-1.55,1.45,0.01], color=PURPLE)
#         func_tex = VGroup(MathTex("f(x)=", font_size=(fs2+fs3)/2, color=c1t), MathTex("-", "2x^6", "+", "3x^4", "-", "2x^3", "+", "x^2", "+", "3x", font_size=(fs2+fs3)/2, color=c1t)).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(cords, DOWN, buff=.8)

#         deg_text = VGroup(Tex("Degree:", color=c1t, font_size=fs3), Tex("Highest power of x", color=c1t, font_size=fs3)).arrange(DOWN, aligned_edge=LEFT,buff=0.2).next_to(func_tex, DOWN, buff=.8)

#         self.add(func_tex, deg_text)


#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Yep, that's it...

#                 We're looking for <bookmark mark="degree"/> the degree of the function,
#                 so we need to <bookmark mark="highest"/>find the highest power of x that appears in the function.

#                 So let's go through the parts of the function one by one.


#                 The first part is<bookmark mark="sixth_degree"/> negative two times x to the power
#                 of six, which is the power of six.
#                 We then have<bookmark mark="fourth_degree"/> three times x to the power
#                 of four, which is the power of four.
#                 Next, we have <bookmark mark="third_degree"/>  minus two times x to the power
#                 of three, which is third degree, <bookmark mark="second_degree"/> x squared,
#                 so the power of two and <bookmark mark="first_degree"/>lastly three times x,
#                 which is the power of one.

#                 So the highest power of x that appears in the function is
#                 <bookmark mark="final"/> six, because we have the component negative two times x to the power
#                 of six.
#                 """
#         ) as tracker:

#             self.wait_until_bookmark("degree")
#             x,y,_ = deg_text[0].get_left()+0.2*LEFT
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("highest")
#             x,y,_ = deg_text[1].get_left()+0.2*LEFT
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("sixth_degree")
#             x,y,_ = func_tex[1][1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("fourth_degree")
#             x,y,_ = func_tex[1][3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("third_degree")
#             x,y,_ = func_tex[1][5].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("second_degree")
#             x,y,_ = func_tex[1][7].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("first_degree")
#             x,y,_ = func_tex[1][9].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("final")
#             x,y,_ = func_tex[1][1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#         self.wait(4)


# class Func_8_1_I_3_b(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-5,5, 2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: -2*x**6+3*x**4-2*x**3+x**2+3*x, x_range=[-1.55,1.45,0.01], color=PURPLE)
#         func_tex = VGroup(MathTex("f(x)=", font_size=(fs2+fs3)/2, color=c1t), MathTex("-", "2x^6", "+", "3x^4", "-", "2x^3", "+", "x^2", "+", "3x", font_size=(fs2+fs3)/2, color=c1t)).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(cords, DOWN, buff=.8)

#         deg_text = VGroup(Tex("Degree:", color=c1t, font_size=fs3), Tex("Highest power of x", color=c1t, font_size=fs3)).arrange(DOWN, aligned_edge=LEFT,buff=0.2).next_to(func_tex, DOWN, buff=.8)

#         self.add(func_tex, deg_text)


#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's wrong.

#                 We're looking for <bookmark mark="degree"/> the degree of the function,
#                 so we need to <bookmark mark="highest"/>find the highest power of x that appears in the function.

#                 So let's go through the parts of the function one by one.


#                 The first part is<bookmark mark="sixth_degree"/> negative two times x to the power
#                 of six, which is the power of six.
#                 We then have<bookmark mark="fourth_degree"/> three times x to the power
#                 of four, which is the power of four.
#                 Next, we have <bookmark mark="third_degree"/>  minus two times x to the power
#                 of three, which is third degree, <bookmark mark="second_degree"/> x squared,
#                 so the power of two and <bookmark mark="first_degree"/>lastly three times x,
#                 which is the power of one.

#                 So the highest power of x that appears in the function is
#                 <bookmark mark="final"/> six, because we have the component negative two times x to the power
#                 of six.
#                 """
#         ) as tracker:

#             self.wait_until_bookmark("degree")
#             x,y,_ = deg_text[0].get_left()+0.2*LEFT
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("highest")
#             x,y,_ = deg_text[1].get_left()+0.2*LEFT
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("sixth_degree")
#             x,y,_ = func_tex[1][1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("fourth_degree")
#             x,y,_ = func_tex[1][3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("third_degree")
#             x,y,_ = func_tex[1][5].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("second_degree")
#             x,y,_ = func_tex[1][7].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("first_degree")
#             x,y,_ = func_tex[1][9].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("final")
#             x,y,_ = func_tex[1][1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#         self.wait(4)


# class Func_8_1_I_3_c(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-5,5, 2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: -2*x**6+3*x**4-2*x**3+x**2+3*x, x_range=[-1.55,1.45,0.01], color=PURPLE)
#         func_tex = VGroup(MathTex("f(x)=", font_size=(fs2+fs3)/2, color=c1t), MathTex("-", "2x^6", "+", "3x^4", "-", "2x^3", "+", "x^2", "+", "3x", font_size=(fs2+fs3)/2, color=c1t)).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(cords, DOWN, buff=.8)

#         deg_text = VGroup(Tex("Degree:", color=c1t, font_size=fs3), Tex("Highest power of x", color=c1t, font_size=fs3)).arrange(DOWN, aligned_edge=LEFT,buff=0.2).next_to(func_tex, DOWN, buff=.8)

#         self.add(func_tex, deg_text)


#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's wrong.

#                 We're looking for <bookmark mark="degree"/> the degree of the function,
#                 so we need to <bookmark mark="highest"/>find the highest power of x that appears in the function.

#                 So let's go through the parts of the function one by one.


#                 The first part is<bookmark mark="sixth_degree"/> negative two times x to the power
#                 of six, which is the power of six.
#                 We then have<bookmark mark="fourth_degree"/> three times x to the power
#                 of four, which is the power of four.
#                 Next, we have <bookmark mark="third_degree"/>  minus two times x to the power
#                 of three, which is third degree, <bookmark mark="second_degree"/> x squared,
#                 so the power of two and <bookmark mark="first_degree"/>lastly three times x,
#                 which is the power of one.

#                 So the highest power of x that appears in the function is
#                 <bookmark mark="final"/> six, because we have the component negative two times x to the power
#                 of six.
#                 """
#         ) as tracker:

#             self.wait_until_bookmark("degree")
#             x,y,_ = deg_text[0].get_left()+0.2*LEFT
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("highest")
#             x,y,_ = deg_text[1].get_left()+0.2*LEFT
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("sixth_degree")
#             x,y,_ = func_tex[1][1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("fourth_degree")
#             x,y,_ = func_tex[1][3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("third_degree")
#             x,y,_ = func_tex[1][5].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("second_degree")
#             x,y,_ = func_tex[1][7].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("first_degree")
#             x,y,_ = func_tex[1][9].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("final")
#             x,y,_ = func_tex[1][1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#         self.wait(4)


# class Func_8_1_I_3_d(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         cords = self.add_cords([-2,2,1], [-5,5, 2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: -2*x**6+3*x**4-2*x**3+x**2+3*x, x_range=[-1.55,1.45,0.01], color=PURPLE)
#         func_tex = VGroup(MathTex("f(x)=", font_size=(fs2+fs3)/2, color=c1t), MathTex("-", "2x^6", "+", "3x^4", "-", "2x^3", "+", "x^2", "+", "3x", font_size=(fs2+fs3)/2, color=c1t)).arrange(DOWN, buff=0.2, aligned_edge=LEFT).next_to(cords, DOWN, buff=.8)

#         deg_text = VGroup(Tex("Degree:", color=c1t, font_size=fs3), Tex("Highest power of x", color=c1t, font_size=fs3)).arrange(DOWN, aligned_edge=LEFT,buff=0.2).next_to(func_tex, DOWN, buff=.8)

#         self.add(func_tex, deg_text)


#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's wrong.

#                 We're looking for <bookmark mark="degree"/> the degree of the function,
#                 so we need to <bookmark mark="highest"/>find the highest power of x that appears in the function.

#                 So let's go through the parts of the function one by one.


#                 The first part is<bookmark mark="sixth_degree"/> negative two times x to the power
#                 of six, which is the power of six.
#                 We then have<bookmark mark="fourth_degree"/> three times x to the power
#                 of four, which is the power of four.
#                 Next, we have <bookmark mark="third_degree"/>  minus two times x to the power
#                 of three, which is third degree, <bookmark mark="second_degree"/> x squared,
#                 so the power of two and <bookmark mark="first_degree"/>lastly three times x,
#                 which is the power of one.

#                 So the highest power of x that appears in the function is
#                 <bookmark mark="final"/> six, because we have the component negative two times x to the power
#                 of six.
#                 """
#         ) as tracker:

#             self.wait_until_bookmark("degree")
#             x,y,_ = deg_text[0].get_left()+0.2*LEFT
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("highest")
#             x,y,_ = deg_text[1].get_left()+0.2*LEFT
#             cursor.blinking = False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("sixth_degree")
#             x,y,_ = func_tex[1][1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("fourth_degree")
#             x,y,_ = func_tex[1][3].get_center()+0.4*DOWN
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("third_degree")
#             x,y,_ = func_tex[1][5].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("second_degree")
#             x,y,_ = func_tex[1][7].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("first_degree")
#             x,y,_ = func_tex[1][9].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("final")
#             x,y,_ = func_tex[1][1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#         self.wait(4)



# #####################################
# #####################################
# TASK_Func_8_1_I_4_q = SophiaTaskDefinition(
#     answerOptions = ["$x^3:1$, $x:1$", "$x^3:1$, $x:-1$", "$x^3:-1$, $x:1$", "$x^3:-1$, $x:-1"],
#     correctAnswerIndex = 1,
#     questionText = "What are the coefficients of $x^3$ and $x$??"
# )
# class Func_8_1_I_4_q(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Coefficients")

#         cords = self.add_cords([-2,2,1], [-10,10,4], x_ticks=[-2,0,2], y_ticks=[-8,-4,4,8]).shift(DOWN*0.4)
#         plane = cords[0]

#         x,y,_ = plane.c2p(0,0)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: 2*x**2-x, color=PINK)
#         func_2 = plane.plot(lambda x: x**3-x, color=GREEN_E)
#         func_tex = MathTex("f", "(x)", "=", "2", "x^2", "-", "x", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.8)
#         func_tex_2 = MathTex("f", "(x)", "=", "x^3", "-", "x", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.8)
#         da1 = MathTex("\\Downarrow", color=BLUE).next_to(func_tex[4], DOWN, buff=.2)
#         da2 = MathTex("\\Downarrow", color=GREEN).next_to(func_tex[6], DOWN, buff=.2)
#         c1 = MathTex("2", color=BLUE).next_to(da1, DOWN, buff=.2)
#         c2 = MathTex("-1", color=GREEN).next_to(da2, DOWN, buff=.2)


#         qmark = ImageMobject(assets_folder / "img" / "qmark.png")
#         qmark = qmark.scale(2.5/qmark.get_width()).move_to([-5, 1.4, 0])

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Moving on <bookmark mark="title"/>to: Coefficients:

#                 Each polynomial contains different expressions, like the ones, the exes, the x squareds and so on.

#                 Each of these expressions is multiplied by a number, which is called the coefficient of the expression.
#                 <bookmark mark="example"/>
#                 For example, for the <bookmark mark="function"/> function f <bookmark mark="fx"/> of x equals two
#                 <bookmark mark="x_sq"/>times x squared <bookmark mark="minus_x"/> minus x, the
#                 coefficient of the expression x squared <bookmark mark="x_sq_c"/>is two,
#                 and the coefficient of the expression x <bookmark mark="minus_x_c"/>is negative one.
#                 <bookmark mark="clean"/>
#                 Now consider<bookmark mark="example_2"/> the function f <bookmark mark="fx_2"/> of x equals
#                 <bookmark mark="x_cubed"/>x cubed <bookmark mark="minus_x_2"/>minus x.
#                 <bookmark mark="qmark"/>What is the coefficient of the <bookmark mark="c1_final"/>
#                 expression x cubed? And what is the <bookmark mark="c2_final"/>coefficient of x?
#                 """
#         ) as tracker:

#             self.wait_until_bookmark("title")
#             x,y,_ = title.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.5)
#             cursor.blinking=True

#             self.wait_until_bookmark("example")
#             x,y,_ = func.get_start()
#             cursor.blinking=False
#             self.play(Create(cords), CursorMoveTo(cursor,x,y), run_time=.4)
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func.get_end()))._start_fading(2))
#             self.add_pencil_sound(1.5)
#             self.play(Create(func), Write(func_tex))
#             cursor.blinking=True

#             self.wait_until_bookmark("function")
#             x,y,_ = func_tex[0].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("fx")
#             x,y,_ = func_tex[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("x_sq")
#             x,y,_ = func_tex[4].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("minus_x")
#             x,y,_ = func_tex[6].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("x_sq_c")
#             x,y,_ = c1.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da1), Write(c1), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("minus_x_c")
#             x,y,_ = c2.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da2), Write(c2), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("clean")
#             self.play(FadeOut(func), FadeOut(func_tex), FadeOut(da1), FadeOut(da2), FadeOut(c1), FadeOut(c2))

#             self.wait_until_bookmark("example_2")
#             x,y,_ = func_2.get_start()
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(func_tex_2), run_time=.3)
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func_2.get_end()))._start_fading(1.5))
#             self.add_pencil_sound(1)
#             self.play(Create(func_2), run_time=1)
#             cursor.blinking=True

#             self.wait_until_bookmark("fx_2")
#             x,y,_ = func_tex_2[1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("x_cubed")
#             x,y,_ = func_tex_2[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("minus_x_2")
#             x,y,_ = func_tex_2[5].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("qmark")
#             self.play(qmark.animate.shift(RIGHT*5), run_time=.5)
#             self.wait(1)
#             self.play(qmark.animate.shift(RIGHT*5))

#             self.wait_until_bookmark("c1_final")
#             x,y,_ = func_tex_2[3].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("c2_final")
#             x,y,_ = func_tex_2[5].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#         self.wait(4)


# class Func_8_1_I_4_a(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Coefficients")

#         cords = self.add_cords([-2,2,1], [-10,10,4], x_ticks=[-2,0,2], y_ticks=[-8,-4,4,8]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: 2*x**2-x, color=PINK)
#         func_2 = plane.plot(lambda x: x**3-x, color=GREEN_E)
#         func_tex = MathTex("f", "(x)", "=", "x^3", "-", "x", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.8)
#         da1 = MathTex("\\Downarrow", color=BLUE).next_to(func_tex[3], DOWN, buff=.2)
#         da2 = MathTex("\\Downarrow", color=MAROON_D).next_to(func_tex[5], DOWN, buff=.2)
#         c1 = MathTex("1", color=BLUE).next_to(da1, DOWN, buff=.2)
#         c2 = MathTex("-1", color=MAROON_D).next_to(da2, DOWN, buff=.2)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not right.

#                 We're looking at<bookmark mark="example_2"/> the function f <bookmark mark="fx_2"/> of x equals
#                 <bookmark mark="x_cubed"/>x cubed <bookmark mark="minus_x_2"/>minus x.
                
#                 The coefficient of the expression x cubed is <bookmark mark="c1_final"/>one,
#                 because we have the component x cubed and don't multiply it with anything, which
#                 is the same as multiplying it with one.

#                 The coefficient of the expression x is <bookmark mark="c2_final"/>negative one,
#                 because we simply have the component x, but we subtract it, and don't add it.
#                 This is the same as adding negative one times x.
#                 """
#         ) as tracker:

#             x,y,_ = func_2.get_start()
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(func_tex), run_time=.3)
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func_2.get_end()))._start_fading(1.5))
#             self.add_pencil_sound(1)
#             self.play(Create(func_2), run_time=1)
#             cursor.blinking=True

#             self.wait_until_bookmark("fx_2")
#             x,y,_ = func_tex[1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("x_cubed")
#             x,y,_ = func_tex[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("minus_x_2")
#             x,y,_ = func_tex[5].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("c1_final")
#             x,y,_ = c1.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da1), Write(c1), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("c2_final")
#             x,y,_ = c2.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da2), Write(c2), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#         self.wait(4)

# class Func_8_1_I_4_b(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Coefficients")

#         cords = self.add_cords([-2,2,1], [-10,10,4], x_ticks=[-2,0,2], y_ticks=[-8,-4,4,8]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: 2*x**2-x, color=PINK)
#         func_2 = plane.plot(lambda x: x**3-x, color=GREEN_E)
#         func_tex = MathTex("f", "(x)", "=", "x^3", "-", "x", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.8)
#         da1 = MathTex("\\Downarrow", color=BLUE).next_to(func_tex[3], DOWN, buff=.2)
#         da2 = MathTex("\\Downarrow", color=MAROON_D).next_to(func_tex[5], DOWN, buff=.2)
#         c1 = MathTex("1", color=BLUE).next_to(da1, DOWN, buff=.2)
#         c2 = MathTex("-1", color=MAROON_D).next_to(da2, DOWN, buff=.2)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Oui! Excuse my french. Yes, that's correct.

#                 We're looking at<bookmark mark="example_2"/> the function f <bookmark mark="fx_2"/> of x equals
#                 <bookmark mark="x_cubed"/>x cubed <bookmark mark="minus_x_2"/>minus x.
                
#                 The coefficient of the expression x cubed is <bookmark mark="c1_final"/>one,
#                 because we have the component x cubed and don't multiply it with anything, which
#                 is the same as multiplying it with one.

#                 The coefficient of the expression x is <bookmark mark="c2_final"/>negative one,
#                 because we simply have the component x, but we subtract it, and don't add it.
#                 This is the same as adding negative one times x.
#                 """
#         ) as tracker:

#             x,y,_ = func_2.get_start()
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(func_tex), run_time=.3)
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func_2.get_end()))._start_fading(1.5))
#             self.add_pencil_sound(1)
#             self.play(Create(func_2), run_time=1)
#             cursor.blinking=True

#             self.wait_until_bookmark("fx_2")
#             x,y,_ = func_tex[1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("x_cubed")
#             x,y,_ = func_tex[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("minus_x_2")
#             x,y,_ = func_tex[5].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("c1_final")
#             x,y,_ = c1.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da1), Write(c1), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("c2_final")
#             x,y,_ = c2.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da2), Write(c2), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#         self.wait(4)

# class Func_8_1_I_4_c(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Coefficients")

#         cords = self.add_cords([-2,2,1], [-10,10,4], x_ticks=[-2,0,2], y_ticks=[-8,-4,4,8]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: 2*x**2-x, color=PINK)
#         func_2 = plane.plot(lambda x: x**3-x, color=GREEN_E)
#         func_tex = MathTex("f", "(x)", "=", "x^3", "-", "x", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.8)
#         da1 = MathTex("\\Downarrow", color=BLUE).next_to(func_tex[3], DOWN, buff=.2)
#         da2 = MathTex("\\Downarrow", color=MAROON_D).next_to(func_tex[5], DOWN, buff=.2)
#         c1 = MathTex("1", color=BLUE).next_to(da1, DOWN, buff=.2)
#         c2 = MathTex("-1", color=MAROON_D).next_to(da2, DOWN, buff=.2)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not right.

#                 We're looking at<bookmark mark="example_2"/> the function f <bookmark mark="fx_2"/> of x equals
#                 <bookmark mark="x_cubed"/>x cubed <bookmark mark="minus_x_2"/>minus x.
                
#                 The coefficient of the expression x cubed is <bookmark mark="c1_final"/>one,
#                 because we have the component x cubed and don't multiply it with anything, which
#                 is the same as multiplying it with one.

#                 The coefficient of the expression x is <bookmark mark="c2_final"/>negative one,
#                 because we simply have the component x, but we subtract it, and don't add it.
#                 This is the same as adding negative one times x.
#                 """
#         ) as tracker:

#             x,y,_ = func_2.get_start()
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(func_tex), run_time=.3)
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func_2.get_end()))._start_fading(1.5))
#             self.add_pencil_sound(1)
#             self.play(Create(func_2), run_time=1)
#             cursor.blinking=True

#             self.wait_until_bookmark("fx_2")
#             x,y,_ = func_tex[1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("x_cubed")
#             x,y,_ = func_tex[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("minus_x_2")
#             x,y,_ = func_tex[5].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("c1_final")
#             x,y,_ = c1.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da1), Write(c1), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("c2_final")
#             x,y,_ = c2.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da2), Write(c2), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#         self.wait(4)

# class Func_8_1_I_4_d(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Coefficients")

#         cords = self.add_cords([-2,2,1], [-10,10,4], x_ticks=[-2,0,2], y_ticks=[-8,-4,4,8]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: 2*x**2-x, color=PINK)
#         func_2 = plane.plot(lambda x: x**3-x, color=GREEN_E)
#         func_tex = MathTex("f", "(x)", "=", "x^3", "-", "x", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.8)
#         da1 = MathTex("\\Downarrow", color=BLUE).next_to(func_tex[3], DOWN, buff=.2)
#         da2 = MathTex("\\Downarrow", color=MAROON_D).next_to(func_tex[5], DOWN, buff=.2)
#         c1 = MathTex("1", color=BLUE).next_to(da1, DOWN, buff=.2)
#         c2 = MathTex("-1", color=MAROON_D).next_to(da2, DOWN, buff=.2)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not right.

#                 We're looking at<bookmark mark="example_2"/> the function f <bookmark mark="fx_2"/> of x equals
#                 <bookmark mark="x_cubed"/>x cubed <bookmark mark="minus_x_2"/>minus x.
                
#                 The coefficient of the expression x cubed is <bookmark mark="c1_final"/>one,
#                 because we have the component x cubed and don't multiply it with anything, which
#                 is the same as multiplying it with one.

#                 The coefficient of the expression x is <bookmark mark="c2_final"/>negative one,
#                 because we simply have the component x, but we subtract it, and don't add it.
#                 This is the same as adding negative one times x.
#                 """
#         ) as tracker:

#             x,y,_ = func_2.get_start()
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(func_tex), run_time=.3)
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func_2.get_end()))._start_fading(1.5))
#             self.add_pencil_sound(1)
#             self.play(Create(func_2), run_time=1)
#             cursor.blinking=True

#             self.wait_until_bookmark("fx_2")
#             x,y,_ = func_tex[1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("x_cubed")
#             x,y,_ = func_tex[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            
#             self.wait_until_bookmark("minus_x_2")
#             x,y,_ = func_tex[5].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("c1_final")
#             x,y,_ = c1.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da1), Write(c1), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("c2_final")
#             x,y,_ = c2.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da2), Write(c2), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#         self.wait(4)



# #####################################
# #####################################
# TASK_Func_8_1_I_5_q = SophiaTaskDefinition(
#     answerOptions = ["$x^2:1$, $x:1$", "$x^3:1$, $x:0$", "$x^3:3$, $x:1$", "$x^3:1$, $x:-3"],
#     correctAnswerIndex = 1,
#     questionText = "What are the coefficients of $x^3$ and $x$??"
# )
# class Func_8_1_I_5_q(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Coefficients")

#         cords = self.add_cords([-2,2,1], [-4,4,2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: x**2-3, color=GREEN)
#         func_tex = MathTex("f", "(x)", "=", "x^2", "-", "3", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.8)
#         da = MathTex("\\Downarrow", color=ORANGE).next_to(func_tex[-1], DOWN, buff=.2)
#         c = MathTex("-3", color=ORANGE).next_to(da, DOWN, buff=.2)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Another example:
#                 Look at the <bookmark mark="f"/> function f <bookmark mark="fx"/> of x 
#                 <bookmark mark="x_squared"/>equals x squared <bookmark mark="minus_three"/>minus three.
#                 <bookmark mark="draw_qmark"/>
#                 In this example, what is the coefficient of x?
#                 And what is the coefficient of one?
#                 """
#         ) as tracker:

#             x,y,_ = func.get_start()
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(func_tex), run_time=.3)
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(func.get_end()))._start_fading(1.5))
#             self.add_pencil_sound(1)
#             self.play(Create(func), run_time=1)
#             cursor.blinking=True

#             self.wait_until_bookmark("f")
#             x,y,_ = func_tex[0].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("fx")
#             x,y,_ = func_tex[1].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("x_squared")
#             x,y,_ = func_tex[3].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)

#             self.wait_until_bookmark("minus_three")
#             x,y,_ = func_tex[5].get_center()+0.4*DOWN
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("draw_qmark")
#             self.draw_qmark(cursor, DOWN*2.8, 4)


#         self.wait(4)



# class Func_8_1_I_5_a(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Coefficients")

#         cords = self.add_cords([-2,2,1], [-4,4,2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: x**2-3, color=GREEN)
#         func_tex = MathTex("f", "(x)", "=", "x^2", "-", "3", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.8)
#         da = MathTex("\\Downarrow", color=ORANGE, font_size=fs2).next_to(func_tex[-1], DOWN, buff=.2)
#         c = MathTex("-3", color=ORANGE, font_size=fs2).next_to(da, DOWN, buff=.2)
#         no_x = VGroup(Tex("No x-term", color=PURE_BLUE, font_size=fs2), Tex("$\\Rightarrow$ $x$-coefficient $=0$", color=PURE_BLUE, font_size=fs2)).arrange(DOWN, buff=.2, aligned_edge=LEFT).next_to(func_tex, DOWN, buff=1)
#         self.add(func, func_tex)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not right.
                
#                 First, what is the degree of x?
#                 This one's a bit tricky: We have an <bookmark mark="x_squared"/> x squared term,
#                 and <bookmark mark="const"/> minus three, which is a constant term or
#                 a "one" term. So <bookmark mark="no_x"/>since we have no x term, the coefficient of x is zero.

#                 The coefficient of the constant term is <bookmark mark="c_final"/>negative three,
#                 because we have the component minus three and don't multiply it with anything.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("x_squared")
#             x,y,_ = func_tex[3].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True
            
#             self.wait_until_bookmark("const")
#             x,y,_ = func_tex[5].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("no_x")
#             x,y,_ = no_x[1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(no_x), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("c_final")
#             x,y,_ = c.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da), Write(c), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True


#         self.wait(4)


# class Func_8_1_I_5_b(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Coefficients")

#         cords = self.add_cords([-2,2,1], [-4,4,2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: x**2-3, color=GREEN)
#         func_tex = MathTex("f", "(x)", "=", "x^2", "-", "3", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.8)
#         da = MathTex("\\Downarrow", color=ORANGE, font_size=fs2).next_to(func_tex[-1], DOWN, buff=.2)
#         c = MathTex("-3", color=ORANGE, font_size=fs2).next_to(da, DOWN, buff=.2)
#         no_x = VGroup(Tex("No x-term", color=PURE_BLUE, font_size=fs2), Tex("$\\Rightarrow$ $x$-coefficient $=0$", color=PURE_BLUE, font_size=fs2)).arrange(DOWN, buff=.2, aligned_edge=LEFT).next_to(func_tex, DOWN, buff=1)
#         self.add(func, func_tex)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 Yep, that's right.
#                 But why?
#                 First, what is the degree of x?
#                 This one's a bit tricky: We have an <bookmark mark="x_squared"/> x squared term,
#                 and <bookmark mark="const"/> minus three, which is a constant term or
#                 a "one" term. So <bookmark mark="no_x"/>since we have no x term, the coefficient of x is zero.

#                 The coefficient of the constant term is <bookmark mark="c_final"/>negative three,
#                 because we have the component minus three and don't multiply it with anything.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("x_squared")
#             x,y,_ = func_tex[3].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True
            
#             self.wait_until_bookmark("const")
#             x,y,_ = func_tex[5].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("no_x")
#             x,y,_ = no_x[1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(no_x), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("c_final")
#             x,y,_ = c.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da), Write(c), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True


#         self.wait(4)


# class Func_8_1_I_5_c(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Coefficients")

#         cords = self.add_cords([-2,2,1], [-4,4,2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: x**2-3, color=GREEN)
#         func_tex = MathTex("f", "(x)", "=", "x^2", "-", "3", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.8)
#         da = MathTex("\\Downarrow", color=ORANGE, font_size=fs2).next_to(func_tex[-1], DOWN, buff=.2)
#         c = MathTex("-3", color=ORANGE, font_size=fs2).next_to(da, DOWN, buff=.2)
#         no_x = VGroup(Tex("No x-term", color=PURE_BLUE, font_size=fs2), Tex("$\\Rightarrow$ $x$-coefficient $=0$", color=PURE_BLUE, font_size=fs2)).arrange(DOWN, buff=.2, aligned_edge=LEFT).next_to(func_tex, DOWN, buff=1)
#         self.add(func, func_tex)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not right.
                
#                 First, what is the degree of x?
#                 This one's a bit tricky: We have an <bookmark mark="x_squared"/> x squared term,
#                 and <bookmark mark="const"/> minus three, which is a constant term or
#                 a "one" term. So <bookmark mark="no_x"/>since we have no x term, the coefficient of x is zero.

#                 The coefficient of the constant term is <bookmark mark="c_final"/>negative three,
#                 because we have the component minus three and don't multiply it with anything.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("x_squared")
#             x,y,_ = func_tex[3].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True
            
#             self.wait_until_bookmark("const")
#             x,y,_ = func_tex[5].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("no_x")
#             x,y,_ = no_x[1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(no_x), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("c_final")
#             x,y,_ = c.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da), Write(c), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True


#         self.wait(4)


# class Func_8_1_I_5_d(SophiaCursorScene):

#     # Main method for constructing the animation
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Coefficients")

#         cords = self.add_cords([-2,2,1], [-4,4,2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         plane = cords[0]
#         self.add(cords)

#         x,y,_ = plane.c2p(0,0)

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         func = plane.plot(lambda x: x**2-3, color=GREEN)
#         func_tex = MathTex("f", "(x)", "=", "x^2", "-", "3", font_size=fs2, color=c1t).next_to(cords, DOWN, buff=.8)
#         da = MathTex("\\Downarrow", color=ORANGE, font_size=fs2).next_to(func_tex[-1], DOWN, buff=.2)
#         c = MathTex("-3", color=ORANGE, font_size=fs2).next_to(da, DOWN, buff=.2)
#         no_x = VGroup(Tex("No x-term", color=PURE_BLUE, font_size=fs2), Tex("$\\Rightarrow$ $x$-coefficient $=0$", color=PURE_BLUE, font_size=fs2)).arrange(DOWN, buff=.2, aligned_edge=LEFT).next_to(func_tex, DOWN, buff=1)
#         self.add(func, func_tex)

#         # Action Sequence
#         with self.voiceover(
#                 text="""
#                 No, that's not right.
                
#                 First, what is the degree of x?
#                 This one's a bit tricky: We have an <bookmark mark="x_squared"/> x squared term,
#                 and <bookmark mark="const"/> minus three, which is a constant term or
#                 a "one" term. So <bookmark mark="no_x"/>since we have no x term, the coefficient of x is zero.

#                 The coefficient of the constant term is <bookmark mark="c_final"/>negative three,
#                 because we have the component minus three and don't multiply it with anything.
#                 """
#         ) as tracker:
            
#             self.wait_until_bookmark("x_squared")
#             x,y,_ = func_tex[3].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True
            
#             self.wait_until_bookmark("const")
#             x,y,_ = func_tex[5].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("no_x")
#             x,y,_ = no_x[1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(no_x), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("c_final")
#             x,y,_ = c.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da), Write(c), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True


#         self.wait(4)


# #####################################
# #####################################
# ###### Practice Part ################
# #####################################
# #####################################


# #####################################
# #####################################
# class PolynomialQuestionScene(SophiaCursorScene, metaclass=ABCMeta):

#     # Main method for constructing the animation
#     @abstractmethod
#     def construct(self):
#         # Adding initial components to the scene
#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         self.add(self.cords)
#         func_tex = MathTex(*self.func_tex, font_size=fs2, color=c1t).next_to(self.cords, DOWN, buff=.8)

#         # Action Sequence
#         with self.voiceover(
#                 text=f"""
#                 <bookmark mark="start"/>
#                 {self.intro}
#                 {self.func_text}
#                 <bookmark mark="qmark"/>
#                 What is the degree of that polynomial function?
#                 And what is the coefficient of {self.coefficient_text}?
#                 """
#         ) as tracker:

#             self.wait_until_bookmark("start")
#             x,y,_ = self.func.get_start()
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(self.func.get_end()))._start_fading(1.5))
#             self.add_pencil_sound(1)
#             self.play(Create(self.func), run_time=1)
#             cursor.blinking=True

#             self.wait_until_bookmark("fx")
#             x,y,_ = func_tex[1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(func_tex), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("el_1")
#             x,y,_ = func_tex[3].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("el_2")
#             x,y,_ = func_tex[5].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("el_3")
#             x,y,_ = func_tex[7].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("qmark")
#             cursor.blinking=False
#             self.draw_qmark(cursor, DOWN*2.8, 4)


#         self.wait(4)


# class PolynomialAnswerScene(SophiaCursorScene, metaclass=ABCMeta):


#     @abstractmethod
#     def construct(self):

#         super().construct()
#         self.add_mathgrid()
#         title = self.add_title("Polynomial Functions")

#         def cursor_sound_updater(mob, dt):
#             if mob.needSound:
#                 mob.needSound = False
#                 self.add_cursor_sound()
#         cursor = AltCursor(stroke_width=0.0, blinking=True)
#         cursor.autoFadeBackground = True
#         cursor.add_updater(cursor_sound_updater)
#         self.add(cursor)

#         plane = self.cords[0]
#         self.add(self.cords)
#         func_tex = MathTex(*self.func_tex, font_size=fs2, color=c1t).next_to(self.cords, DOWN, buff=.6)

#         da = MathTex("\\Downarrow", color=ORANGE, font_size=fs2).next_to(func_tex[self.coefficient_idx], DOWN, buff=.2)
#         c = MathTex(self.coefficient, color=ORANGE, font_size=fs2).next_to(da, DOWN, buff=.2)
#         coef = Tex("Coefficient:", color=ORANGE, font_size=fs2).next_to(c, LEFT, buff=.1)
#         deg_group = VGroup(Tex(f"Highest power of x: {self.deg}", color=PURE_BLUE, font_size=fs3), Tex(f"$\\Rightarrow f$ has degree {self.deg}", color=PURE_BLUE, font_size=fs3)).arrange(DOWN, buff=.2, aligned_edge=LEFT).next_to(func_tex, DOWN, buff=1.4)

#         # Action Sequence
#         with self.voiceover(
#                 text=f"""
#                 <bookmark mark="start"/>
#                 {self.intro}
#                 We're looking at the function
#                 {self.func_text}
            
#                 The <bookmark mark="show_coefficient"/>coefficient of {self.coefficient_text} is {self.coefficient},
#                 because the component {self.coefficient_text} is multiplied by {self.coefficient}.

#                 And the degree of the function <bookmark mark="show_degree"/> is {self.deg},
#                 because the highest exponent of x is {self.deg}, which we have for the expression {self.highest_term}.
#                 """
#         ) as tracker:

#             self.wait_until_bookmark("start")
#             x,y,_ = self.func.get_start()
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), run_time=.3)
#             self.add(cursor.copy().add_updater(lambda m: m.move_to(self.func.get_end()))._start_fading(1.5))
#             self.add_pencil_sound(1)
#             self.play(Create(self.func), run_time=1)
#             cursor.blinking=True

#             self.wait_until_bookmark("fx")
#             x,y,_ = func_tex[1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(func_tex), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("el_1")
#             x,y,_ = func_tex[3].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("el_2")
#             x,y,_ = func_tex[5].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("el_3")
#             x,y,_ = func_tex[7].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveToCurved(cursor,x,y), run_time=.3)
#             cursor.blinking=True

#             self.wait_until_bookmark("show_coefficient")
#             x,y,_ = c.get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(Write(da), Write(c), Write(coef), CursorMoveTo(cursor,x,y), run_time=.3)
#             cursor.blinking=True           

#             self.wait_until_bookmark("show_degree")
#             x,y,_ = deg_group[1].get_center()+0.4*DOWN
#             cursor.blinking=False
#             self.play(CursorMoveTo(cursor,x,y), Write(deg_group), run_time=.3)
#             cursor.blinking=True


#         self.wait(4)




# #####################################
# #####################################
# ###### Specific Qs ##################
# #####################################
# #####################################


# #####################################
# #####################################
# TASK_Func_8_1_I_1_q = SophiaTaskDefinition(
#     answerOptions = ["degree: $2$, coefficient: $2$", "degree: $1$, coefficient: $-3$", "degree: $2$, coefficient: $1$", "degree: $1$, coefficient: $2$"],
#     correctAnswerIndex = 2,
#     questionText = "What is the degree of the function $f(x)=2x-3\cdot x^2+1$? And what is the coefficient of $x$?"
# )
# class Func_8_1_P_1_q(PolynomialQuestionScene):


#     def construct(self):

#         self.intro = "Now, consider the function"
#         self.func_text = """f<bookmark mark="fx"/> of x equals <bookmark mark="el_1"/>
#                         two x<bookmark mark="el_2"/> minus three x squared <bookmark mark="el_3"/>
#                         plus one.
#                         """
#         self.func_tex = ["f", "(x)", "=", "2x", "-", "3x^2", "+", "1"]
#         self.coefficient_text = "x squared"
#         self.cords = self.add_cords([-2,2,1], [-4,4,2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         self.func = self.cords[0].plot(lambda x: 2*x-3*x**2+1, color=GREEN, x_range=[-1,1.66,0.01])

#         super().construct()


# class Func_8_1_P_1_a(PolynomialAnswerScene):

#     def construct(self):

#         self.intro = "Yep, that's right."
#         self.func_text = """f<bookmark mark="fx"/> of x equals <bookmark mark="el_1"/>
#                         two x<bookmark mark="el_2"/> minus three x squared <bookmark mark="el_3"/>
#                         plus one.
#                         """
#         self.func_tex = ["f", "(x)", "=", "2x", "-", "3x^2", "+", "1"]
#         self.coefficient_text = "x squared"
#         self.coefficient = "3"
#         self.cords = self.add_cords([-2,2,1], [-4,4,2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         self.func = self.cords[0].plot(lambda x: 2*x-3*x**2+1, color=GREEN, x_range=[-1,1.66,0.01])
#         self.coefficient_idx = 5
#         self.deg = 2
#         self.highest_term = "3 times x squared"

#         super().construct()

# class Func_8_1_P_1_b(PolynomialAnswerScene):

#     def construct(self):

#         self.intro = "No, that's not it."
#         self.func_text = """f<bookmark mark="fx"/> of x equals <bookmark mark="el_1"/>
#                         two x<bookmark mark="el_2"/> minus three x squared <bookmark mark="el_3"/>
#                         plus one.
#                         """
#         self.func_tex = ["f", "(x)", "=", "2x", "-", "3x^2", "+", "1"]
#         self.coefficient_text = "x squared"
#         self.coefficient = "3"
#         self.cords = self.add_cords([-2,2,1], [-4,4,2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         self.func = self.cords[0].plot(lambda x: 2*x-3*x**2+1, color=GREEN, x_range=[-1,1.66,0.01])
#         self.coefficient_idx = 5
#         self.deg = 2
#         self.highest_term = "3 times x squared"

#         super().construct()

# class Func_8_1_P_1_c(PolynomialAnswerScene):

#     def construct(self):

#         self.intro = "No, that's not it."
#         self.func_text = """f<bookmark mark="fx"/> of x equals <bookmark mark="el_1"/>
#                         two x<bookmark mark="el_2"/> minus three x squared <bookmark mark="el_3"/>
#                         plus one.
#                         """
#         self.func_tex = ["f", "(x)", "=", "2x", "-", "3x^2", "+", "1"]
#         self.coefficient_text = "x squared"
#         self.coefficient = "3"
#         self.cords = self.add_cords([-2,2,1], [-4,4,2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         self.func = self.cords[0].plot(lambda x: 2*x-3*x**2+1, color=GREEN, x_range=[-1,1.66,0.01])
#         self.coefficient_idx = 5
#         self.deg = 2
#         self.highest_term = "3 times x squared"

#         super().construct()

# class Func_8_1_P_1_d(PolynomialAnswerScene):

#     def construct(self):

#         self.intro = "No, that's not it."
#         self.func_text = """f<bookmark mark="fx"/> of x equals <bookmark mark="el_1"/>
#                         two x<bookmark mark="el_2"/> minus three x squared <bookmark mark="el_3"/>
#                         plus one.
#                         """
#         self.func_tex = ["f", "(x)", "=", "2x", "-", "3x^2", "+", "1"]
#         self.coefficient_text = "x squared"
#         self.coefficient = "3"
#         self.cords = self.add_cords([-2,2,1], [-4,4,2], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4]).shift(DOWN*0.4)
#         self.func = self.cords[0].plot(lambda x: 2*x-3*x**2+1, color=GREEN, x_range=[-1,1.66,0.01])
#         self.coefficient_idx = 5
#         self.deg = 2
#         self.highest_term = "3 times x squared"

#         super().construct()



# #####################################
# #####################################
# TASK_Func_8_1_P_2_q = SophiaTaskDefinition(
#     answerOptions = ["degree: $0$, coefficient: $2$", "degree: $1$, coefficient: $-3$", "degree: $4$, coefficient: $-3$", "degree: $4$, coefficient: $\\tfrac{1}{2}$"],
#     correctAnswerIndex = 2,
#     questionText = "What is the degree of the function $f(x)=2-3\cdot x+\\tfrac{1}{2}x^4$? And what is the coefficient of $x$?"
# )
# class Func_8_1_P_2_q(PolynomialQuestionScene):


#     def construct(self):

#         self.intro = "Next, look at the function"
#         self.func_text = """f<bookmark mark="fx"/> of x equals <bookmark mark="el_1"/> two
#                         <bookmark mark="el_2"/> minus three x<bookmark mark="el_3"/>
#                         plus one half times x to the power of four.
#                         """
#         self.func_tex = ["f", "(x)", "=", "2", "-", "3x", "+", "\\tfrac{1}{2}x^4"]
#         self.coefficient_text = "x"
#         self.coefficient = "3"
#         self.cords = self.add_cords([-2,2,1], [-8,8,4], x_ticks=[-2,0,2], y_ticks=[-8,-4,4,8]).shift(DOWN*0.4)
#         self.func = self.cords[0].plot(lambda x: 2-3*x+x**4/2, x_range=[-1.8,2,0.01], color=BLUE)

#         super().construct()



# class Func_8_1_P_2_a(PolynomialAnswerScene):

#     def construct(self):

#         self.intro = "No, that's not correct."
#         self.func_text = """f<bookmark mark="fx"/> of x equals <bookmark mark="el_1"/> two
#                         <bookmark mark="el_2"/> minus three x<bookmark mark="el_3"/>
#                         plus one half times x to the power of four.
#                         """
#         self.func_tex = ["f", "(x)", "=", "2", "-", "3x", "+", "\\tfrac{1}{2}x^4"]
#         self.coefficient_text = "x"
#         self.coefficient = "3"
#         self.cords = self.add_cords([-2,2,1], [-8,8,4], x_ticks=[-2,0,2], y_ticks=[-8,-4,4,8]).shift(DOWN*0.4)
#         self.func = self.cords[0].plot(lambda x: 2-3*x+x**4/2, x_range=[-1.8,2,0.01], color=BLUE)
#         self.coefficient_idx = 5
#         self.deg = 4
#         self.highest_term = "x to the power of four."

#         super().construct()

# class Func_8_1_P_2_b(PolynomialAnswerScene):

#     def construct(self):

#         self.intro = "No, that's not correct."
#         self.func_text = """f<bookmark mark="fx"/> of x equals <bookmark mark="el_1"/> two
#                         <bookmark mark="el_2"/> minus three x<bookmark mark="el_3"/>
#                         plus one half times x to the power of four.
#                         """
#         self.func_tex = ["f", "(x)", "=", "2", "-", "3x", "+", "\\tfrac{1}{2}x^4"]
#         self.coefficient_text = "x"
#         self.coefficient = "3"
#         self.cords = self.add_cords([-2,2,1], [-8,8,4], x_ticks=[-2,0,2], y_ticks=[-8,-4,4,8]).shift(DOWN*0.4)
#         self.func = self.cords[0].plot(lambda x: 2-3*x+x**4/2, x_range=[-1.8,2,0.01], color=BLUE)
#         self.coefficient_idx = 5
#         self.deg = 4
#         self.highest_term = "x to the power of four."

#         super().construct()

# class Func_8_1_P_2_c(PolynomialAnswerScene):

#     def construct(self):

#         self.intro = "Yep, that's right."
#         self.func_text = """f<bookmark mark="fx"/> of x equals <bookmark mark="el_1"/> two
#                         <bookmark mark="el_2"/> minus three x<bookmark mark="el_3"/>
#                         plus one half times x to the power of four.
#                         """
#         self.func_tex = ["f", "(x)", "=", "2", "-", "3x", "+", "\\tfrac{1}{2}x^4"]
#         self.coefficient_text = "x"
#         self.coefficient = "3"
#         self.cords = self.add_cords([-2,2,1], [-8,8,4], x_ticks=[-2,0,2], y_ticks=[-8,-4,4,8]).shift(DOWN*0.4)
#         self.func = self.cords[0].plot(lambda x: 2-3*x+x**4/2, x_range=[-1.8,2,0.01], color=BLUE)
#         self.coefficient_idx = 5
#         self.deg = 4
#         self.highest_term = "x to the power of four."

#         super().construct()

# class Func_8_1_P_2_d(PolynomialAnswerScene):

#     def construct(self):

#         self.intro = "No, that's not correct."
#         self.func_text = """f<bookmark mark="fx"/> of x equals <bookmark mark="el_1"/> two
#                         <bookmark mark="el_2"/> minus three x<bookmark mark="el_3"/>
#                         plus one half times x to the power of four.
#                         """
#         self.func_tex = ["f", "(x)", "=", "2", "-", "3x", "+", "\\tfrac{1}{2}x^4"]
#         self.coefficient_text = "x"
#         self.coefficient = "3"
#         self.cords = self.add_cords([-2,2,1], [-8,8,4], x_ticks=[-2,0,2], y_ticks=[-8,-4,4,8]).shift(DOWN*0.4)
#         self.func = self.cords[0].plot(lambda x: 2-3*x+x**4/2, x_range=[-1.8,2,0.01], color=BLUE)
#         self.coefficient_idx = 5
#         self.deg = 4
#         self.highest_term = "x to the power of four."

#         super().construct()

scenes/Func/Func_8: Polynomials/Func_8_1.py
Sophia-Edu-Labs/sophia-math
# 8_2: Polynomial Functions: Zeros

# Import necessary libraries and modules
from abc import ABCMeta, abstractmethod
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition


#####################################
#####################################
TASK_Func_8_2_I_1_q = SophiaTaskDefinition(
    answerOptions = ["$\{0,1\}$", "$\{1\}$", "$\{0\}$", "$\{-1,1\}$"],
    correctAnswerIndex = 3,
    questionText = "What are the zeros of the polynomial function $f(x)=x^2-1$?"
)
class Func_8_2_I_1_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Polynomial Functions: Zeros")

        cords = self.add_cords([-2,2,1], [-4,4, 1], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4])
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)


        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        func = plane.plot(lambda x: x**2-1, color=BLUE)
        func_tex = MathTex("f", "(x)", "=", "x^2", "-", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text="""
                In this chapter, we'll learn how to determine the zeros of a polynomial function.

                Let's start with a simple example, a squared function.
                <bookmark mark="draw_graph"/>
                What are the zeros of the <bookmark mark="func"/> function f <bookmark mark="fx"/>
                of x <bookmark mark="x_squared"/> equals x squared <bookmark mark="minus_one"/> minus one?
                """
        ) as tracker:        
            
            self.wait_until_bookmark("draw_graph")
            x,y,_ = func.get_start()
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.5)
            self.add_pencil_sound(1.5)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(func.get_end())))
            self.play(Create(func))
            cursor.blinking=True

            self.wait_until_bookmark("func")
            x,y,_ = func_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(func_tex), CursorMoveTo(cursor,x,y), run_time=0.3)
            

            self.wait_until_bookmark("fx")
            x,y,_ = func_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("x_squared")
            x,y,_ = func_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("minus_one")
            x,y,_ = func_tex[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)


class Func_8_2_I_1_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Polynomial Functions: Zeros")

        cords = self.add_cords([-2,2,1], [-4,4, 1], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4])
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)


        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        func = plane.plot(lambda x: x**2-1, color=BLUE)
        func_tex = MathTex("f", "(x)", "=", "x^2", "-", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        func_tex_zero = MathTex("0", "=", "x^2", "-", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        func_tex_final = MathTex("x^2", "=", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        sol = MathTex("x", "=", "\\pm1", color=GREEN, font_size=fs2).next_to(func_tex_final, DOWN, buff=0.2)

        self.add(func, func_tex)
        
        with self.voiceover(
                text="""
                No, that's not right.

                To find the zeros of a function, we need to find the x values for which the function equals zero.
                So <bookmark mark="set_to_zero"/> we set the function equal to zero, and solve for x.

                Here, we <bookmark mark="zero"/> get zero <bookmark mark="x_squared"/>equals x squared
                <bookmark mark="minus_one"/> minus one.

                We can then add one on both sides to<bookmark mark="sol_1"/> obtain x squared <bookmark mark="sol_2"/>
                equals one. We can then take the root to get the first <bookmark mark="sol_3"/> solution x equals
                negative one, as well as the second <bookmark mark="sol_4"/> solution x equals one.

                So the two zeros are <bookmark mark="show_sol"/> at x equals negative one and x equals one.
                """
        ) as tracker:        
            
            self.wait_until_bookmark("set_to_zero")
            self.play(TransformMatchingTex(func_tex, func_tex_zero))

            self.wait_until_bookmark("zero")
            cursor.blinking=False
            x,y,_ = func_tex_zero[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("x_squared")
            x,y,_ = func_tex_zero[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("minus_one")
            x,y,_ = func_tex_zero[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_1")
            x,y,_ = func_tex_final[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(TransformMatchingTex(func_tex_zero, func_tex_final), CursorMoveTo(cursor,x,y))

            self.wait_until_bookmark("sol_2")
            x,y,_ = func_tex_final[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_3")
            x,y,_ = plane.c2p(-1,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy().set_color(GREEN))

            self.wait_until_bookmark("sol_4")
            x,y,_ = plane.c2p(1,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy().set_color(GREEN))
            self.wait(1)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("show_sol")
            x,y,_ = sol.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(sol), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)


class Func_8_2_I_1_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Polynomial Functions: Zeros")

        cords = self.add_cords([-2,2,1], [-4,4, 1], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4])
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)


        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        func = plane.plot(lambda x: x**2-1, color=BLUE)
        func_tex = MathTex("f", "(x)", "=", "x^2", "-", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        func_tex_zero = MathTex("0", "=", "x^2", "-", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        func_tex_final = MathTex("x^2", "=", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        sol = MathTex("x", "=", "\\pm1", color=GREEN, font_size=fs2).next_to(func_tex_final, DOWN, buff=0.2)

        self.add(func, func_tex)
        
        with self.voiceover(
                text="""
                No, that's not right.

                To find the zeros of a function, we need to find the x values for which the function equals zero.
                So <bookmark mark="set_to_zero"/> we set the function equal to zero, and solve for x.

                Here, we <bookmark mark="zero"/> get zero <bookmark mark="x_squared"/>equals x squared
                <bookmark mark="minus_one"/> minus one.

                We can then add one on both sides to<bookmark mark="sol_1"/> obtain x squared <bookmark mark="sol_2"/>
                equals one. We can then take the root to get the first <bookmark mark="sol_3"/> solution x equals
                negative one, as well as the second <bookmark mark="sol_4"/> solution x equals one.

                So the two zeros are <bookmark mark="show_sol"/> at x equals negative one and x equals one.
                """
        ) as tracker:        
            
            self.wait_until_bookmark("set_to_zero")
            self.play(TransformMatchingTex(func_tex, func_tex_zero))

            self.wait_until_bookmark("zero")
            cursor.blinking=False
            x,y,_ = func_tex_zero[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("x_squared")
            x,y,_ = func_tex_zero[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("minus_one")
            x,y,_ = func_tex_zero[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_1")
            x,y,_ = func_tex_final[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(TransformMatchingTex(func_tex_zero, func_tex_final), CursorMoveTo(cursor,x,y))

            self.wait_until_bookmark("sol_2")
            x,y,_ = func_tex_final[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_3")
            x,y,_ = plane.c2p(-1,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy().set_color(GREEN))

            self.wait_until_bookmark("sol_4")
            x,y,_ = plane.c2p(1,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy().set_color(GREEN))
            self.wait(1)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("show_sol")
            x,y,_ = sol.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(sol), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)


class Func_8_2_I_1_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Polynomial Functions: Zeros")

        cords = self.add_cords([-2,2,1], [-4,4, 1], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4])
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)


        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        func = plane.plot(lambda x: x**2-1, color=BLUE)
        func_tex = MathTex("f", "(x)", "=", "x^2", "-", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        func_tex_zero = MathTex("0", "=", "x^2", "-", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        func_tex_final = MathTex("x^2", "=", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        sol = MathTex("x", "=", "\\pm1", color=GREEN, font_size=fs2).next_to(func_tex_final, DOWN, buff=0.2)

        self.add(func, func_tex)
        
        with self.voiceover(
                text="""
                No, that's not right.

                To find the zeros of a function, we need to find the x values for which the function equals zero.
                So <bookmark mark="set_to_zero"/> we set the function equal to zero, and solve for x.

                Here, we <bookmark mark="zero"/> get zero <bookmark mark="x_squared"/>equals x squared
                <bookmark mark="minus_one"/> minus one.

                We can then add one on both sides to<bookmark mark="sol_1"/> obtain x squared <bookmark mark="sol_2"/>
                equals one. We can then take the root to get the first <bookmark mark="sol_3"/> solution x equals
                negative one, as well as the second <bookmark mark="sol_4"/> solution x equals one.

                So the two zeros are <bookmark mark="show_sol"/> at x equals negative one and x equals one.
                """
        ) as tracker:        
            
            self.wait_until_bookmark("set_to_zero")
            self.play(TransformMatchingTex(func_tex, func_tex_zero))

            self.wait_until_bookmark("zero")
            cursor.blinking=False
            x,y,_ = func_tex_zero[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("x_squared")
            x,y,_ = func_tex_zero[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("minus_one")
            x,y,_ = func_tex_zero[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_1")
            x,y,_ = func_tex_final[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(TransformMatchingTex(func_tex_zero, func_tex_final), CursorMoveTo(cursor,x,y))

            self.wait_until_bookmark("sol_2")
            x,y,_ = func_tex_final[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_3")
            x,y,_ = plane.c2p(-1,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy().set_color(GREEN))

            self.wait_until_bookmark("sol_4")
            x,y,_ = plane.c2p(1,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy().set_color(GREEN))
            self.wait(1)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("show_sol")
            x,y,_ = sol.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(sol), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)


class Func_8_2_I_1_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Polynomial Functions: Zeros")

        cords = self.add_cords([-2,2,1], [-4,4, 1], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4])
        plane = cords[0]
        self.add(cords)

        x,y,_ = plane.c2p(0,0)


        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        func = plane.plot(lambda x: x**2-1, color=BLUE)
        func_tex = MathTex("f", "(x)", "=", "x^2", "-", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        func_tex_zero = MathTex("0", "=", "x^2", "-", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        func_tex_final = MathTex("x^2", "=", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)
        sol = MathTex("x", "=", "\\pm1", color=GREEN, font_size=fs2).next_to(func_tex_final, DOWN, buff=0.2)

        self.add(func, func_tex)
        
        with self.voiceover(
                text="""
                Yep, that's correct.

                To find the zeros of a function, we need to find the x values for which the function equals zero.
                So <bookmark mark="set_to_zero"/> we set the function equal to zero, and solve for x.

                Here, we <bookmark mark="zero"/> get zero <bookmark mark="x_squared"/>equals x squared
                <bookmark mark="minus_one"/> minus one.

                We can then add one on both sides to<bookmark mark="sol_1"/> obtain x squared <bookmark mark="sol_2"/>
                equals one. We can then take the root to get the first <bookmark mark="sol_3"/> solution x equals
                negative one, as well as the second <bookmark mark="sol_4"/> solution x equals one.

                So the two zeros are <bookmark mark="show_sol"/> at x equals negative one and x equals one.
                """
        ) as tracker:        
            
            self.wait_until_bookmark("set_to_zero")
            self.play(TransformMatchingTex(func_tex, func_tex_zero))

            self.wait_until_bookmark("zero")
            cursor.blinking=False
            x,y,_ = func_tex_zero[0].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("x_squared")
            x,y,_ = func_tex_zero[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("minus_one")
            x,y,_ = func_tex_zero[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_1")
            x,y,_ = func_tex_final[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(TransformMatchingTex(func_tex_zero, func_tex_final), CursorMoveTo(cursor,x,y))

            self.wait_until_bookmark("sol_2")
            x,y,_ = func_tex_final[2].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("sol_3")
            x,y,_ = plane.c2p(-1,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy().set_color(GREEN))

            self.wait_until_bookmark("sol_4")
            x,y,_ = plane.c2p(1,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy().set_color(GREEN))
            self.wait(1)
            x,y,_ = plane.c2p(0,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("show_sol")
            x,y,_ = sol.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(sol), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)


#####################################
#####################################
class Func_8_2_I_2(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Polynomial Functions: Zeros")

        cords = self.add_cords([-2,2,1], [-4,4, 1], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4])
        plane = cords[0]

        x,y,_ = plane.c2p(0,0)


        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        func = plane.plot(lambda x: x**2-1, color=BLUE)
        func_tex = MathTex("f", "(x)", "=", "x^2", "-", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)

        x_tex = MathTex("x", color=c1t, font_size=2*fs1)
        x_squared_tex = MathTex("x^2", color=c1t, font_size=2*fs1)
        x_cubed_tex = MathTex("x^3", color=c1t, font_size=2*fs1)
        x_to_the_fourth_tex = MathTex("x^4", color=c1t, font_size=2*fs1)
        x_to_the_fifth_tex = MathTex("x^5", color=c1t, font_size=2*fs1)
        x_to_the_sixth_tex = MathTex("x^6", color=c1t, font_size=2*fs1)
        x_to_the_seventh_tex = MathTex("x^7", color=c1t, font_size=2*fs1)

        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(2.5/qmark.get_width()).move_to([-5, 1.4, 0])
        blist = BulletedList("Degree $1$", "Degree $2$", "Degree $\geq3$", color=c1t, height=2, width=2).shift(0.6*LEFT)
        bracket = Brace(VGroup(blist[0], blist[1]), direction=RIGHT, color=GREEN)
        simple_solution = VGroup(Tex("Simple", font_size=fs3, color=GREEN), Tex("Solution", color=GREEN, font_size=fs3)).arrange(DOWN, aligned_edge=LEFT, buff=.2).next_to(bracket, RIGHT, buff=0.2)
        for idx in range(3):
            blist[idx].set_color(BLACK)
        # Action Sequence
        with self.voiceover(
                text="""
                Ok, so more generally speaking: <bookmark mark="qmark"/>How do we find
                the zeros of polynomial functions?
                
                The tricky thing is that polynomials can contain expressions <bookmark mark="x"/>
                with x, expressions <bookmark mark="x_squared"/> with x squared, expressions
                <bookmark mark="x_cubed"/> with x cubed, expressions with x to the fourth power,
                and so on...

                So we will differentiate three cases:

                Polynomials <bookmark mark="degree_one"/>of degree one, which have one zero,
                and we can find it by solving the equation for x.

                Polynomials <bookmark mark="degree_two"/>of degree two, which have up to two zeros,
                and we can find them using the quadratic formula.

                And finally polynomials <bookmark mark="many"/>of degree three or higher, which can have many
                zeros. Now the key difference is that <bookmark mark="leq_2"/> we can solve polynomial
                equations of degree one and two using relatively simple techniques. But <bookmark mark="greater_2"/>
                finding the zeros for polynomials of degree three or higher can be more difficult.
                """
        ) as tracker:        
            
            self.wait_until_bookmark("qmark")
            self.play(qmark.animate.shift(5*RIGHT), run_time=.5)
            self.wait(1)
            self.play(qmark.animate.shift(5*RIGHT))

            self.wait_until_bookmark("x")
            self.play(Write(x_tex))

            self.wait_until_bookmark("x_squared")
            self.play(Transform(x_tex, x_squared_tex))

            self.wait_until_bookmark("x_cubed")
            self.play(Transform(x_tex, x_cubed_tex))
            self.wait(0.8)
            self.play(Transform(x_tex, x_to_the_fourth_tex))
            self.play(Transform(x_tex, x_to_the_fifth_tex))
            self.play(Transform(x_tex, x_to_the_sixth_tex))
            self.play(Transform(x_tex, x_to_the_seventh_tex))
            self.play(Unwrite(x_tex))

            self.wait_until_bookmark("degree_one")
            x,y,_ = blist[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(blist[0]), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("degree_two")
            x,y,_ = blist[1].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(blist[1]), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("many")
            x,y,_ = blist[2].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(blist[2]), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("leq_2")
            x,y,_ = simple_solution[1].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(bracket), Write(simple_solution), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("greater_2")
            cursor.blinking=False
            x,y,_ = blist[2].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)


#####################################
#####################################
TASK_Func_8_2_I_1_q = SophiaTaskDefinition(
    answerOptions = ["$\{0,1\}$", "$\{1\}$", "$\{0\}$", "$\{-1,1\}$"],
    correctAnswerIndex = 3,
    questionText = "What are the zeros of the polynomial function $f(x)=x^2-1$?"
)
class Func_8_2_I_3_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Degree one Functions")

        cords = self.add_cords([-2,2,1], [-4,4, 1], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4])
        plane = cords[0]

        x,y,_ = plane.c2p(0,0)


        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        crazy_hair = ImageMobject(assets_folder / "img" / "crazy_hair.png")
        crazy_hair = crazy_hair.scale(3.5/crazy_hair.get_width()).move_to([-5, 1.4, 0])

        scissors = ImageMobject(assets_folder / "img" / "scissors.png")
        scissors = scissors.scale(2.5/scissors.get_width()).move_to([-5, -1.4, 0])

        with self.voiceover(
                text="""
                First, let's talk about finding the zero of a polynomial function of degree one.

                Imagine you have a bunch of friends <bookmark mark="friends_in"/> who have the
                coolest hairstyles. Now since you're such a talented artist, they ask you to
                <bookmark mark="scissors_in"/>cut their hair.

                Let's say you <bookmark mark="ten_bucks"/> paid ten bucks for the scissors.
                And then you <bookmark mark="five_bucks"/> charge your friends five bucks per haircut.
                <bookmark mark="qmark"/>
                What is the term of the function describing the amount of money you've made after
                cutting x friends' hair?
                """
        ) as tracker:        
            
            self.wait_until_bookmark("friends_in")
            self.play(crazy_hair.animate.shift(5*RIGHT), run_time=.5)

            self.wait_until_bookmark("scissors_in")
            self.play(scissors.animate.shift(5*RIGHT))

            self.wait_until_bookmark("ten_bucks")
            self.play(scissors.animate.scale(0.4), run_time=.3)
            self.play(scissors.animate.move_to([-1,-1.2,0]), run_time=.3)
            cost_scissors = MathTex("10", "\\$", color=c1t, font_size=fs2).next_to(scissors, RIGHT, buff=0.4)
            self.play(Write(cost_scissors))

            self.wait_until_bookmark("five_bucks")
            self.play(crazy_hair.animate.scale(0.4), run_time=.3)
            self.play(crazy_hair.animate.move_to([-1,-2.6,0]), run_time=.3)
            cost_haircut = MathTex("5", "\\$", color=c1t, font_size=fs2).next_to(crazy_hair, RIGHT, buff=0.4)
            self.play(Write(cost_haircut))

            self.wait_until_bookmark("qmark")
            cursor.blinking=False
            self.draw_qmark(cursor, UP, 2.5, 4)

        self.wait(4)



class Func_8_2_I_3_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Degree one Functions")

        cords = self.add_cords([0,5,1], [-10,15, 5], x_ticks=[-0,5,1], y_ticks=[-5,5,15]).shift(0.2*DOWN)
        plane = cords[0]

        x,y,_ = plane.c2p(0,0)


        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        crazy_hair = ImageMobject(assets_folder / "img" / "crazy_hair.png")
        crazy_hair = crazy_hair.scale(1.4/crazy_hair.get_width()).move_to([-1,-1.2,0])
        cost_haircut = MathTex("5", "\\$", color=c1t, font_size=fs2).next_to(crazy_hair, RIGHT, buff=0.4)

        scissors = ImageMobject(assets_folder / "img" / "scissors.png")
        scissors = scissors.scale(1/scissors.get_width()).move_to([-1,-2.6,0])
        cost_scissors = MathTex("10", "\\$", color=c1t, font_size=fs2).next_to(scissors, RIGHT, buff=0.4)

        self.add(crazy_hair, cost_haircut, scissors, cost_scissors)

        func = plane.plot(lambda x: x*5-10, color=BLUE)
        func_tex = MathTex("f", "(x)", "=", "5x", "-", "10", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.6)

        # Action Sequence
        with self.voiceover(
                text="""
                No, not quite.

                <bookmark mark="cords_in"/>
                At x equals zero, we've paid ten bucks for the scissors, but we haven't made any money yet.

                So the value of the function <bookmark mark="x_zero"/>at zero has to be negative ten.

                From there, for each increase in x, <bookmark mark="start_drawing"/> we make five bucks,
                so the function increases by five.

                This means the term of the <bookmark mark="f"/> function is f <bookmark mark="fx"/>of x
                equals <bookmark mark="five_x"/>five x <bookmark mark="minus_ten"/> minus ten.

                The minus ten correspond to the cost of the scissors,
                <bookmark mark="five_corresponds"/> and the five x corresponds to the
                five bucks we make per haircut.
                """
        ) as tracker:        
            
            self.wait_until_bookmark("cords_in")
            self.play(Write(cords))
            
            self.wait_until_bookmark("x_zero")
            x,y,_ = plane.c2p(0,-10)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y))

            self.wait_until_bookmark("start_drawing")
            cursor_updater = lambda m: m.move_to(func.get_end())
            cursor.add_updater(cursor_updater)
            self.play(Create(func), run_time=4)
            cursor.remove_updater(cursor_updater)
            cursor.blinking=True

            self.wait_until_bookmark("f")
            x,y,_ = func_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(FadeOut(scissors), FadeOut(cost_scissors), FadeOut(crazy_hair), FadeOut(cost_haircut) , Write(func_tex), CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fx")
            x,y,_ = func_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("five_x")
            x,y,_ = func_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("minus_ten")
            x,y,_ = func_tex[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("five_corresponds")
            x,y,_ = func_tex[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)


#####################################
#####################################
TASK_Func_8_2_I_3_q = SophiaTaskDefinition(
    answerOptions = ["$\{0,1\}", "$\{1\}", "$\{0\}", "$\{-1,1\}"],
    correctAnswerIndex = 3,
    questionText = "What are the zeros of the polynomial function $f(x)=x^2-1$?"
)
class Func_8_2_I_3_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Degree one Functions")


        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        crazy_hair = ImageMobject(assets_folder / "img" / "crazy_hair.png")
        crazy_hair = crazy_hair.scale(3.5/crazy_hair.get_width()).move_to([0, -1.4, 0])
        self.add(crazy_hair)

        func_tex = MathTex("f", "(x)", "=", "5x", "-", "10", color=c1t, font_size=fs2).next_to(crazy_hair, UP, buff=0.8)


        with self.voiceover(
                text="""
                Now that we know that the money we have made giving haircuts is described by the <bookmark mark="func"/> function
                f <bookmark mark="fx"/> of x equals <bookmark mark="five_x"/>five x <bookmark mark="minus_ten"/> minus ten,
                after how many haircuts will you break even?
                """
        ) as tracker:        
            
            self.wait_until_bookmark("func")
            x,y,_ = func_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(func_tex), CursorMoveTo(cursor,x,y), run_time=0.6)

            self.wait_until_bookmark("fx")
            x,y,_ = func_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("five_x")
            x,y,_ = func_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("minus_ten")
            x,y,_ = func_tex[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)

class Func_8_2_I_3_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Degree one Functions")


        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        crazy_hair = ImageMobject(assets_folder / "img" / "crazy_hair.png")
        crazy_hair = crazy_hair.scale(3.5/crazy_hair.get_width()).move_to([0, -1.4, 0])
        self.add(crazy_hair)

        func_tex = MathTex("f", "(x)", "=", "5x", "-", "10", color=c1t, font_size=fs2).next_to(crazy_hair, UP, buff=0.8)


        with self.voiceover(
                text="""
                Yep, that's correct.

                <bookmark mark="break_even"/> To break even, we need to make zero dollars. So
                we need to find the zero of the function that describes 
                """
        ) as tracker:        
            
            self.wait_until_bookmark("func")
            x,y,_ = func_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(func_tex), CursorMoveTo(cursor,x,y), run_time=0.6)

            self.wait_until_bookmark("fx")
            x,y,_ = func_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("five_x")
            x,y,_ = func_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("minus_ten")
            x,y,_ = func_tex[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)


#####################################
#####################################
TASK_Func_8_2_I_4_q = SophiaTaskDefinition(
    answerOptions = ["$x_{12}=-\\tfrac{-b\pm\sqrt{b^2-4ac}}{2a}$", "$x_{12}=\pm c", "$x_{12}=-\\tfrac{-a\pm\sqrt{c^2-4ab}}{2b}$", "$x_{12}=-\\tfrac{b\pm\sqrt{c^2-2a}}{4ab}$"],
    correctAnswerIndex = 0,
    questionText = "Which of these formulas describes the zeros of the function $f(x)=ax^2+bx+c$?"
)
class Func_8_2_I_4_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Zeros of Polynomials")


        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        degree_one_bl = BulletedList("Set function to zero", "Solve for x", buff=0.2, font_size=fs3)
        for el in degree_one_bl:
            el.set_color(c1t)
        degree_one_h = Tex("Degree one:", color=c1t, font_size=fs2)
        degree_one = VGroup(degree_one_h, degree_one_bl).arrange(DOWN, aligned_edge=LEFT, buff=.2)

        degree_two_bl = BulletedList("$f(x)=ax^2+bx+c$","Which formula can we use?", buff=0.2, font_size=fs3)
        for el in degree_two_bl:
            el.set_color(c1t)
        degree_two_h = Tex("Degree two:", color=c1t, font_size=fs2)
        degree_two = VGroup(degree_two_h, degree_two_bl).arrange(DOWN, aligned_edge=LEFT, buff=.2).next_to(degree_one, DOWN, buff=0.8)

        both_degrees = VGroup(degree_one, degree_two).arrange(DOWN, aligned_edge=LEFT, buff=0.8)

        with self.voiceover(
                text="""
                We can find the zero <bookmark mark="deg_1"/>of a degree one polynomial
                <bookmark mark="set_to_zero"/> by setting the function equal to zero
                <bookmark mark="solve_for_x"/> and solving for x.

                We can also find the zero<bookmark mark="degree_two"/> of a degree two
                polynomial easily. Let's say you have a quadratic function
                <bookmark mark="f_quad"/>of the form f of x equals a x squared plus b x plus c.

                <bookmark mark="q"/>
                Which of these formulas can you use to find the zeros of the function?
                """
        ) as tracker:
            
            self.wait_until_bookmark("deg_1")
            x,y,_ = degree_one_h.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            self.play(Write(degree_one_h), run_time=0.6)
            cursor.blinking=True
            
            self.wait_until_bookmark("set_to_zero")
            x,y,_ = degree_one_bl[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            self.play(Write(degree_one_bl[0]), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("solve_for_x")
            x,y,_ = degree_one_bl[1].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            self.play(Write(degree_one_bl[1]), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("degree_two")
            x,y,_ = degree_two_h.get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            self.play(Write(degree_two_h), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("f_quad")
            x,y,_ = degree_two_bl[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            self.play(Write(degree_two_bl[0]), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("q")
            cursor.blinking=False
            x,y,_ = degree_two_bl[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=.3)
            self.play(Write(degree_two_bl[1]), run_time=0.6)
            cursor.blinking=True


        self.wait(4)


class Func_8_2_I_4_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Degree 2 Polynomials")


        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        degree_two_bl = BulletedList("$f(x)=ax^2+bx+c$","$\\Rightarrow x_{1,2}=-\\tfrac{-b\pm\sqrt{b^2-4ac}}{2a}$", "Quadratic Formula", buff=0.2, font_size=fs3)
        for el in degree_two_bl:
            el.set_color(c1t)
        degree_two_h = Tex("Degree two:", color=c1t, font_size=fs2)
        degree_two = VGroup(degree_two_h, degree_two_bl).arrange(DOWN, aligned_edge=LEFT, buff=.2)
        self.add(degree_two_h, degree_two_bl[0])

        with self.voiceover(
                text="""
                Yes, that is correct.

                The<bookmark mark="formula"/>formula x 1 2 equals negative b plus or
                minus the square root of b squared minus four a c all over two a
                describes the zeros of the function.

                It is called<bookmark mark="quad_formula"/> the quadratic formula.

                The plus minus symbol means that we can have up to two solutions, one
                where we add the square root and one where we subtract it.
                """
        ) as tracker:
            
            self.wait_until_bookmark("formula")
            x,y,_ = degree_two_bl[1].get_center()

            cursor.blinking=False
            self.play(CursorMoveResize(cursor,x,y, degree_two_bl[1].get_width()+0.2, degree_two_bl[1].get_height()+0.2), run_time=.3)
            self.play(Write(degree_two_bl[1]), run_time=0.6)

            self.wait_until_bookmark("quad_formula")
            x,y,_ = degree_two_bl[2].get_center()+0.4*DOWN
            self.play(CursorMoveResize(cursor,x,y, 0.2, 0.2), run_time=.3)
            self.play(Write(degree_two_bl[2]), run_time=0.6)
            cursor.blinking=True


        self.wait(4)

class Func_8_2_I_4_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Degree 2 Polynomials")


        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        degree_two_bl = BulletedList("$f(x)=ax^2+bx+c$","$\\Rightarrow x_{1,2}=-\\tfrac{-b\pm\sqrt{b^2-4ac}}{2a}$", "Quadratic Formula", buff=0.2, font_size=fs3)
        for el in degree_two_bl:
            el.set_color(c1t)
        degree_two_h = Tex("Degree two:", color=c1t, font_size=fs2)
        degree_two = VGroup(degree_two_h, degree_two_bl).arrange(DOWN, aligned_edge=LEFT, buff=.2)
        self.add(degree_two_h, degree_two_bl[0])

        with self.voiceover(
                text="""
                No, that's not right.

                The<bookmark mark="formula"/>formula x 1 2 equals negative b plus or
                minus the square root of b squared minus four a c all over two a
                describes the zeros of the function.

                It is called<bookmark mark="quad_formula"/> the quadratic formula.

                The plus minus symbol means that we can have up to two solutions, one
                where we add the square root and one where we subtract it.
                """
        ) as tracker:
            
            self.wait_until_bookmark("formula")
            x,y,_ = degree_two_bl[1].get_center()

            cursor.blinking=False
            self.play(CursorMoveResize(cursor,x,y, degree_two_bl[1].get_width()+0.2, degree_two_bl[1].get_height()+0.2), run_time=.3)
            self.play(Write(degree_two_bl[1]), run_time=0.6)

            self.wait_until_bookmark("quad_formula")
            x,y,_ = degree_two_bl[2].get_center()+0.4*DOWN
            self.play(CursorMoveResize(cursor,x,y, 0.2, 0.2), run_time=.3)
            self.play(Write(degree_two_bl[2]), run_time=0.6)
            cursor.blinking=True


        self.wait(4)

class Func_8_2_I_4_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Degree 2 Polynomials")


        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        degree_two_bl = BulletedList("$f(x)=ax^2+bx+c$","$\\Rightarrow x_{1,2}=-\\tfrac{-b\pm\sqrt{b^2-4ac}}{2a}$", "Quadratic Formula", buff=0.2, font_size=fs3)
        for el in degree_two_bl:
            el.set_color(c1t)
        degree_two_h = Tex("Degree two:", color=c1t, font_size=fs2)
        degree_two = VGroup(degree_two_h, degree_two_bl).arrange(DOWN, aligned_edge=LEFT, buff=.2)
        self.add(degree_two_h, degree_two_bl[0])

        with self.voiceover(
                text="""
                No, that's not right.

                The<bookmark mark="formula"/>formula x 1 2 equals negative b plus or
                minus the square root of b squared minus four a c all over two a
                describes the zeros of the function.

                It is called<bookmark mark="quad_formula"/> the quadratic formula.

                The plus minus symbol means that we can have up to two solutions, one
                where we add the square root and one where we subtract it.
                """
        ) as tracker:
            
            self.wait_until_bookmark("formula")
            x,y,_ = degree_two_bl[1].get_center()

            cursor.blinking=False
            self.play(CursorMoveResize(cursor,x,y, degree_two_bl[1].get_width()+0.2, degree_two_bl[1].get_height()+0.2), run_time=.3)
            self.play(Write(degree_two_bl[1]), run_time=0.6)

            self.wait_until_bookmark("quad_formula")
            x,y,_ = degree_two_bl[2].get_center()+0.4*DOWN
            self.play(CursorMoveResize(cursor,x,y, 0.2, 0.2), run_time=.3)
            self.play(Write(degree_two_bl[2]), run_time=0.6)
            cursor.blinking=True


        self.wait(4)

class Func_8_2_I_4_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Degree 2 Polynomials")


        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        degree_two_bl = BulletedList("$f(x)=ax^2+bx+c$","$\\Rightarrow x_{1,2}=-\\tfrac{-b\pm\sqrt{b^2-4ac}}{2a}$", "Quadratic Formula", buff=0.2, font_size=fs3)
        for el in degree_two_bl:
            el.set_color(c1t)
        degree_two_h = Tex("Degree two:", color=c1t, font_size=fs2)
        degree_two = VGroup(degree_two_h, degree_two_bl).arrange(DOWN, aligned_edge=LEFT, buff=.2)
        self.add(degree_two_h, degree_two_bl[0])

        with self.voiceover(
                text="""
                No, that's not right.

                The<bookmark mark="formula"/>formula x 1 2 equals negative b plus or
                minus the square root of b squared minus four a c all over two a
                describes the zeros of the function.

                It is called<bookmark mark="quad_formula"/> the quadratic formula.

                The plus minus symbol means that we can have up to two solutions, one
                where we add the square root and one where we subtract it.
                """
        ) as tracker:
            
            self.wait_until_bookmark("formula")
            x,y,_ = degree_two_bl[1].get_center()

            cursor.blinking=False
            self.play(CursorMoveResize(cursor,x,y, degree_two_bl[1].get_width()+0.2, degree_two_bl[1].get_height()+0.2), run_time=.3)
            self.play(Write(degree_two_bl[1]), run_time=0.6)

            self.wait_until_bookmark("quad_formula")
            x,y,_ = degree_two_bl[2].get_center()+0.4*DOWN
            self.play(CursorMoveResize(cursor,x,y, 0.2, 0.2), run_time=.3)
            self.play(Write(degree_two_bl[2]), run_time=0.6)
            cursor.blinking=True


        self.wait(4)




#####################################
#####################################
class Func_8_2_I_5(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Polynomial Functions: Zeros")

        cords = self.add_cords([-2,2,1], [-4,4, 1], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4])
        plane = cords[0]

        x,y,_ = plane.c2p(0,0)


        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        func = plane.plot(lambda x: x**2-1, color=BLUE)
        func_tex = MathTex("f", "(x)", "=", "x^2", "-", "1", color=c1t, font_size=fs2).next_to(cords, DOWN, buff=0.4)

        x_tex = MathTex("x", color=c1t, font_size=2*fs1)
        x_squared_tex = MathTex("x^2", color=c1t, font_size=2*fs1)
        x_cubed_tex = MathTex("x^3", color=c1t, font_size=2*fs1)
        x_to_the_fourth_tex = MathTex("x^4", color=c1t, font_size=2*fs1)
        x_to_the_fifth_tex = MathTex("x^5", color=c1t, font_size=2*fs1)
        x_to_the_sixth_tex = MathTex("x^6", color=c1t, font_size=2*fs1)
        x_to_the_seventh_tex = MathTex("x^7", color=c1t, font_size=2*fs1)

        qmark = ImageMobject(assets_folder / "img" / "qmark.png")
        qmark = qmark.scale(2.5/qmark.get_width()).move_to([-5, 1.4, 0])
        blist = BulletedList("Degree $1$: 1 zero\\\\ $\\Rightarrow$ set to zero, solve for $x$", "Degree $2$: $\\leq2$ zeros\\\\ $\\Rightarrow$ Quadratic Formula", "Degree $\geq3$: Many zeros\\\\ $\\Rightarrow$ Can be tricky", color=c1t, height=2, width=2).shift(0.6*LEFT)
        bracket = Brace(VGroup(blist[0], blist[1]), direction=RIGHT, color=GREEN)
        simple_solution = VGroup(Tex("Simple", font_size=fs3, color=GREEN), Tex("Solution", color=GREEN, font_size=fs3)).arrange(DOWN, aligned_edge=LEFT, buff=.2).next_to(bracket, RIGHT, buff=0.2)
        for idx in range(3):
            blist[idx].set_color(BLACK)
        # Action Sequence
        with self.voiceover(
                text="""              
                Here's a quick recap of finding the zeros of polynomial functions with different degrees

                Polynomials <bookmark mark="degree_one"/>of degree one have exactly one zero. We can find it
                by setting it to zero and then solving for x.

                Polynomials <bookmark mark="degree_two"/>of degree two have up to two zeros. We can find them
                using the quadratic formula.

                And finally polynomials <bookmark mark="many"/>of degree three or higher can have many
                zeros. In general, they can be more difficult to find.
                
                We just saw, that <bookmark mark="leq_2"/> we can solve polynomial
                equations of degree one and two using relatively simple techniques.
                <bookmark mark="greater_2"/>
                Finding the zeros for polynomials of degree three or higher can be more difficult,
                but we'll now learn about different ways we can still find them.
                """
        ) as tracker:        

            
            self.play(Write(x_tex))
            self.play(Transform(x_tex, x_squared_tex))
            self.play(Transform(x_tex, x_cubed_tex))
            self.play(Transform(x_tex, x_to_the_fourth_tex))
            self.play(Transform(x_tex, x_to_the_fifth_tex))
            self.play(Transform(x_tex, x_to_the_sixth_tex))
            self.play(Transform(x_tex, x_to_the_seventh_tex))
            self.play(Unwrite(x_tex))

            self.wait_until_bookmark("degree_one")
            x,y,_ = blist[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(blist[0]), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("degree_two")
            x,y,_ = blist[1].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(blist[1]), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("many")
            x,y,_ = blist[2].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(blist[2]), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("leq_2")
            x,y,_ = simple_solution[1].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(bracket), Write(simple_solution), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("greater_2")
            cursor.blinking=False
            x,y,_ = blist[2].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True


        self.wait(4)


#####################################
#####################################
TASK_Func_8_2_I_6_q = SophiaTaskDefinition(
    answerOptions = ["$\{2,1\}$", "$\{0,1\}$", "$\{0,1,2\}$", "$\{-1,1,2\}$"],
    correctAnswerIndex = 3,
    questionText = "What are the zeros of the function?"
)
class Func_8_2_I_6_q(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Polynomial Functions: Zeros")

        cords = self.add_cords([-2,2,1], [-4,4, 1], x_ticks=[-2,0,2], y_ticks=[-4,-2,2,4])
        plane = cords[0]

        x,y,_ = plane.c2p(0,0)


        cursor = AltCursor(stroke_width=0.0, blinking=True, x=x, y=y)
        cursor.autoFadeBackground = True
        
        self.add(cursor)

        func = plane.plot(lambda x: x**2-1, color=BLUE)
        func_tex = MathTex("f", "(x)", "=", "(x-2)", "(x+1)", "(x-1)", color=c1t, font_size=fs3).next_to(cords, DOWN, buff=0.4)

        # Action Sequence
        with self.voiceover(
                text="""              
                Now check out <bookmark mark="func"/> the function f <bookmark mark="fx"/> of x
                equals <bookmark mark="bracket_1"/> open bracket x minus two close bracket
                times <bookmark mark="bracket_2"/> open bracket x plus one close bracket
                times <bookmark mark="bracket_3"/> open bracket x minus one close bracket.

                It's a polynomial of degree three, because we're<bookmark mark="three"/>
                multiplying three factors of x together.
                <bookmark mark="qmark"/>
                What are the zeros of this function?
                """
        ) as tracker:        

            self.wait_until_bookmark("func")
            x,y,_ = func_tex[0].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(Write(func_tex), CursorMoveTo(cursor,x,y), run_time=0.6)

            self.wait_until_bookmark("fx")
            x,y,_ = func_tex[1].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("bracket_1")
            x,y,_ = func_tex[3].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("bracket_2")
            x,y,_ = func_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("bracket_3")
            x,y,_ = func_tex[5].get_center()+0.4*DOWN
            self.play(CursorMoveToCurved(cursor,x,y), run_time=0.3)
            self.wait(2)
            self.play(CursorMoveTo(cursor,0,-1.6))
            self.wait(0.2)
            cursor.blinking=True

            self.wait_until_bookmark("three")
            cursor.blinking=False
            one, two, three = cursor.copy()._start_fading(4), cursor.copy()._start_fading(4), cursor.copy()._start_fading(4)
            x1,y1,_ = func_tex[3].get_center()+0.3*DOWN
            x2,y2,_ = func_tex[4].get_center()+0.3*DOWN
            x3,y3,_ = func_tex[5].get_center()+0.3*DOWN
            self.play(CursorMoveTo(one,x1,y1), CursorMoveTo(two,x2,y2), CursorMoveTo(three,x3,y3), run_time=0.6)

            self.wait_until_bookmark("qmark")
            cursor.blinking=False
            self.draw_qmark(cursor, 2*DOWN, run_time=3)

        self.wait(4)


class Func_8_2_I_6_a(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Polynomial Functions: Zeros")

        cords = self.add_cords([-3,3,1], [-4,4, 1], x_ticks=[-3,0,3], y_ticks=[-4,-2,2,4])
        plane = cords[0]


        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0, y=-1.6)
        cursor.autoFadeBackground = True
        # 
        self.add(cursor)

        func = plane.plot(lambda x: (x-2)*(x-1)*(x+1), x_range=[-1.5, 2.6,0.01], color=BLUE)
        func_tex = MathTex("f", "(x)", "=", "(x-2)", "(x+1)", "(x-1)", color=c1t, font_size=fs3).next_to(cords, DOWN, buff=0.4)
        zeros = Tex("$\\Rightarrow$ Zeros: $\\{-1,1,2\\}$", color=c1t, font_size=fs2).next_to(func_tex, DOWN, buff=0.4)
        self.add(func_tex)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right.

                The zeros of a function are the values of x where the function equals zero.

                Since we are <bookmark mark="three"/>multiplying three factors together, the function equals zero
                when any of the factors equals zero.

                <bookmark mark="factor_one"/> The first factor equals zero when x equals two,
                <bookmark mark="factor_two"/>the second factor equals zero when x equals negative one,
                and <bookmark mark="factor_three"/>the third factor equals zero when x equals one.
                <bookmark mark="fade_cursor"/>
                So the zeros of the function are <bookmark mark="zeros"/> negative one, one, and two.

                <bookmark mark="cords"/>
                We can also verify this by <bookmark mark="graph"/>looking at the graph of the function.
                As you can see, the function equals zero at<bookmark mark="z1"/> x equals negative one,
                <bookmark mark="z2"/>x equals one, and<bookmark mark="z3"/>x equals two.
                """
        ) as tracker:        


            self.wait_until_bookmark("three")
            cursor.blinking=False
            one, two, three = cursor.copy()._start_fading(4), cursor.copy()._start_fading(4), cursor.copy()._start_fading(4)
            x1,y1,_ = func_tex[3].get_center()+0.3*DOWN
            x2,y2,_ = func_tex[4].get_center()+0.3*DOWN
            x3,y3,_ = func_tex[5].get_center()+0.3*DOWN
            self.play(CursorMoveTo(one,x1,y1), CursorMoveTo(two,x2,y2), CursorMoveTo(three,x3,y3), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("factor_one")
            x,y,_ = func_tex[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("factor_two")
            x,y,_ = func_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("factor_three")
            x,y,_ = func_tex[5].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fade_cursor")
            cursor.blinking=True

            self.wait_until_bookmark("zeros")
            cursor.blinking=False
            x,y,_ = zeros.get_center()+0.4*DOWN
            self.play(Write(zeros), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Create(cords))

            self.wait_until_bookmark("graph")
            x,y,_ = func.get_start()
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(func.get_end())))
            self.play(Create(func))
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            x,y,_ = plane.c2p(-1,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("z2")
            x,y,_ = plane.c2p(1,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("z3")
            x,y,_ = plane.c2p(2,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.wait(1)
            cursor.blinking=True


        self.wait(4)


class Func_8_2_I_6_b(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Polynomial Functions: Zeros")

        cords = self.add_cords([-3,3,1], [-4,4, 1], x_ticks=[-3,0,3], y_ticks=[-4,-2,2,4])
        plane = cords[0]


        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0, y=-1.6)
        cursor.autoFadeBackground = True
        # 
        self.add(cursor)

        func = plane.plot(lambda x: (x-2)*(x-1)*(x+1), x_range=[-1.5, 2.6,0.01], color=BLUE)
        func_tex = MathTex("f", "(x)", "=", "(x-2)", "(x+1)", "(x-1)", color=c1t, font_size=fs3).next_to(cords, DOWN, buff=0.4)
        zeros = Tex("$\\Rightarrow$ Zeros: $\\{-1,1,2\\}$", color=c1t, font_size=fs2).next_to(func_tex, DOWN, buff=0.4)
        self.add(func_tex)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right.

                The zeros of a function are the values of x where the function equals zero.

                Since we are <bookmark mark="three"/>multiplying three factors together, the function equals zero
                when any of the factors equals zero.

                <bookmark mark="factor_one"/> The first factor equals zero when x equals two,
                <bookmark mark="factor_two"/>the second factor equals zero when x equals negative one,
                and <bookmark mark="factor_three"/>the third factor equals zero when x equals one.
                <bookmark mark="fade_cursor"/>
                So the zeros of the function are <bookmark mark="zeros"/> negative one, one, and two.

                <bookmark mark="cords"/>
                We can also verify this by <bookmark mark="graph"/>looking at the graph of the function.
                As you can see, the function equals zero at<bookmark mark="z1"/> x equals negative one,
                <bookmark mark="z2"/>x equals one, and<bookmark mark="z3"/>x equals two.
                """
        ) as tracker:        


            self.wait_until_bookmark("three")
            cursor.blinking=False
            one, two, three = cursor.copy()._start_fading(4), cursor.copy()._start_fading(4), cursor.copy()._start_fading(4)
            x1,y1,_ = func_tex[3].get_center()+0.3*DOWN
            x2,y2,_ = func_tex[4].get_center()+0.3*DOWN
            x3,y3,_ = func_tex[5].get_center()+0.3*DOWN
            self.play(CursorMoveTo(one,x1,y1), CursorMoveTo(two,x2,y2), CursorMoveTo(three,x3,y3), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("factor_one")
            x,y,_ = func_tex[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("factor_two")
            x,y,_ = func_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("factor_three")
            x,y,_ = func_tex[5].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fade_cursor")
            cursor.blinking=True

            self.wait_until_bookmark("zeros")
            cursor.blinking=False
            x,y,_ = zeros.get_center()+0.4*DOWN
            self.play(Write(zeros), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Create(cords))

            self.wait_until_bookmark("graph")
            x,y,_ = func.get_start()
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(func.get_end())))
            self.play(Create(func))
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            x,y,_ = plane.c2p(-1,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("z2")
            x,y,_ = plane.c2p(1,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("z3")
            x,y,_ = plane.c2p(2,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.wait(1)
            cursor.blinking=True


        self.wait(4)


class Func_8_2_I_6_c(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        title = self.add_title("Polynomial Functions: Zeros")

        cords = self.add_cords([-3,3,1], [-4,4, 1], x_ticks=[-3,0,3], y_ticks=[-4,-2,2,4])
        plane = cords[0]


        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0, y=-1.6)
        cursor.autoFadeBackground = True
        # 
        self.add(cursor)

        func = plane.plot(lambda x: (x-2)*(x-1)*(x+1), x_range=[-1.5, 2.6,0.01], color=BLUE)
        func_tex = MathTex("f", "(x)", "=", "(x-2)", "(x+1)", "(x-1)", color=c1t, font_size=fs3).next_to(cords, DOWN, buff=0.4)
        zeros = Tex("$\\Rightarrow$ Zeros: $\\{-1,1,2\\}$", color=c1t, font_size=fs2).next_to(func_tex, DOWN, buff=0.4)
        self.add(func_tex)

        # Action Sequence
        with self.voiceover(
                text="""
                That's not right.

                The zeros of a function are the values of x where the function equals zero.

                Since we are <bookmark mark="three"/>multiplying three factors together, the function equals zero
                when any of the factors equals zero.

                <bookmark mark="factor_one"/> The first factor equals zero when x equals two,
                <bookmark mark="factor_two"/>the second factor equals zero when x equals negative one,
                and <bookmark mark="factor_three"/>the third factor equals zero when x equals one.
                <bookmark mark="fade_cursor"/>
                So the zeros of the function are <bookmark mark="zeros"/> negative one, one, and two.

                <bookmark mark="cords"/>
                We can also verify this by <bookmark mark="graph"/>looking at the graph of the function.
                As you can see, the function equals zero at<bookmark mark="z1"/> x equals negative one,
                <bookmark mark="z2"/>x equals one, and<bookmark mark="z3"/>x equals two.
                """
        ) as tracker:        


            self.wait_until_bookmark("three")
            cursor.blinking=False
            one, two, three = cursor.copy()._start_fading(4), cursor.copy()._start_fading(4), cursor.copy()._start_fading(4)
            x1,y1,_ = func_tex[3].get_center()+0.3*DOWN
            x2,y2,_ = func_tex[4].get_center()+0.3*DOWN
            x3,y3,_ = func_tex[5].get_center()+0.3*DOWN
            self.play(CursorMoveTo(one,x1,y1), CursorMoveTo(two,x2,y2), CursorMoveTo(three,x3,y3), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("factor_one")
            x,y,_ = func_tex[3].get_center()+0.4*DOWN
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("factor_two")
            x,y,_ = func_tex[4].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("factor_three")
            x,y,_ = func_tex[5].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("fade_cursor")
            cursor.blinking=True

            self.wait_until_bookmark("zeros")
            cursor.blinking=False
            x,y,_ = zeros.get_center()+0.4*DOWN
            self.play(Write(zeros), CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            self.play(Create(cords))

            self.wait_until_bookmark("graph")
            x,y,_ = func.get_start()
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(func.get_end())))
            self.play(Create(func))
            cursor.blinking=True

            self.wait_until_bookmark("z1")
            x,y,_ = plane.c2p(-1,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("z2")
            x,y,_ = plane.c2p(1,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)

            self.wait_until_bookmark("z3")
            x,y,_ = plane.c2p(2,0)
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            self.wait(1)
            cursor.blinking=True


        self.wait(4)


class Func_8_2_I_6_d(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
    
        #Adding the checkered grid
        self.add_mathgrid()

        #Adding the title
        title = self.add_title("Polynomial Functions: Zeros")

        #Adding the coordinate system
        cords = self.add_cords([-3,3,1], [-4,4, 1], x_ticks=[-3,0,3], y_ticks=[-4,-2,2,4])
        plane = cords[0]

        #Adding the cursor to the scene at x,y = 0,-1.6
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0, y=-1.6)
        cursor.autoFadeBackground = True
        self.add(cursor)


        func = plane.plot(lambda x: (x-2)*(x-1)*(x+1), x_range=[-1.5, 2.6,0.01], color=BLUE) #plot of the function
        func_tex = MathTex("f", "(x)", "=", "(x-2)", "(x+1)", "(x-1)", color=c1t, font_size=fs3).next_to(cords, DOWN, buff=0.4) #tex of the function
        zeros = Tex("$\\Rightarrow$ Zeros: $\\{-1,1,2\\}$", color=c1t, font_size=fs2).next_to(func_tex, DOWN, buff=0.4) #tex describing the zeros of the function
        self.add(func_tex)

        # Action Sequence
        with self.voiceover(
                text="""
                Yes, that's correct. Well done.

                The zeros of a function are the values of x where the function equals zero.

                Since we are <bookmark mark="three"/>multiplying three factors together, the function equals zero
                when any of the factors equals zero.

                <bookmark mark="factor_one"/> The first factor equals zero when x equals two,
                <bookmark mark="factor_two"/>the second factor equals zero when x equals negative one,
                and <bookmark mark="factor_three"/>the third factor equals zero when x equals one.
                <bookmark mark="fade_cursor"/>
                So the zeros of the function are <bookmark mark="zeros"/> negative one, one, and two.

                <bookmark mark="cords"/>
                We can also verify this by <bookmark mark="graph"/>looking at the graph of the function.
                As you can see, the function equals zero at<bookmark mark="z1"/> x equals negative one,
                <bookmark mark="z2"/>x equals one, and<bookmark mark="z3"/>x equals two.
                """
        ) as tracker:        

            self.wait_until_bookmark("three") #sync with the text at the bookmark "three"
            cursor.blinking=False
            one, two, three = cursor.copy()._start_fading(4), cursor.copy()._start_fading(4), cursor.copy()._start_fading(4) #create three copies of the cursor

            #get the coordinates of the three factors in the tex of the function
            x1,y1,_ = func_tex[3].get_center()+0.3*DOWN
            x2,y2,_ = func_tex[4].get_center()+0.3*DOWN
            x3,y3,_ = func_tex[5].get_center()+0.3*DOWN

            #move the three cursors to the three factors
            self.play(CursorMoveTo(one,x1,y1), CursorMoveTo(two,x2,y2), CursorMoveTo(three,x3,y3), run_time=0.6)
            cursor.blinking=True

            self.wait_until_bookmark("factor_one") #sync with the text at the bookmark "factor_one"
            x,y,_ = func_tex[3].get_center()+0.4*DOWN #get the coordinates of the first factor
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3) #move the cursor to the first factor

            self.wait_until_bookmark("factor_two") #sync with the text at the bookmark "factor_two"
            x,y,_ = func_tex[4].get_center()+0.4*DOWN #get the coordinates of the second factor
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3) #move the cursor to the second factor

            self.wait_until_bookmark("factor_three") #sync with the text at the bookmark "factor_three"
            x,y,_ = func_tex[5].get_center()+0.4*DOWN #get the coordinates of the third factor
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3) #move the cursor to the third factor

            self.wait_until_bookmark("fade_cursor") #sync with the text at the bookmark "fade_cursor"
            cursor.blinking=True #make the cursor blink again

            self.wait_until_bookmark("zeros") #sync with the text at the bookmark "zeros"
            cursor.blinking=False
            x,y,_ = zeros.get_center()+0.4*DOWN #get the coordinates of the tex describing the zeros
            self.play(Write(zeros), CursorMoveTo(cursor,x,y), run_time=0.3) #write the tex describing the zeros and move the cursor to it
            cursor.blinking=True

            self.wait_until_bookmark("cords") #sync with the text at the bookmark "cords"
            self.play(Create(cords)) #create the coordinate system

            self.wait_until_bookmark("graph") #sync with the text at the bookmark "graph"
            x,y,_ = func.get_start() #get the coordinates of the start of the plot
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3) #move the cursor to the start of the plot
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(func.get_end()))) #create a copy of the cursor that fades out and add an updater that always moves it to the end of the plot
            self.play(Create(func)) #create the plot
            cursor.blinking=True

            self.wait_until_bookmark("z1") #sync with the text at the bookmark "z1"
            x,y,_ = plane.c2p(-1,0) #get the coordinates of the zero at x=-1
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3) #move the cursor to the zero at x=-1

            self.wait_until_bookmark("z2") #sync with the text at the bookmark "z2"
            x,y,_ = plane.c2p(1,0) #get the coordinates of the zero at x=1
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3) #move the cursor to the zero at x=1

            self.wait_until_bookmark("z3") #sync with the text at the bookmark "z3"
            x,y,_ = plane.c2p(2,0) #get the coordinates of the zero at x=2
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3) #move the cursor to the zero at x=2
            self.wait(1) 
            cursor.blinking=True


        self.wait(4)

scenes/Func/Func_8: Polynomials/Func_8_2.py
Sophia-Edu-Labs/sophia-math
# 4_2: Quadratic Functions: Shifting

# Import necessary libraries and modules
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition

def create_piecewise_linear(points):
    def piecewise_linear(x):
        # Sort the points based on x-coordinate
        sorted_points = sorted(points, key=lambda p: p[0])

        # Find the closest two points for interpolation
        left_point, right_point = None, None
        for point in sorted_points:
            if x < point[0]:
                right_point = point
                break
            left_point = point

        # Extrapolate if x is outside the range of points
        if right_point is None:
            return sorted_points[-1][1]
        if left_point is None:
            return sorted_points[0][1]

        # Linear interpolation
        x1, y1 = left_point
        x2, y2 = right_point
        slope = (y2 - y1) / (x2 - x1)
        interpolated_value = y1 + slope * (x - x1)

        return interpolated_value

    return piecewise_linear


class Func_1_Intro(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Functions - Intro")
        
        #Create the coordinate system
        cords = self.add_cords([6, 24, 3], [5, 25, 5], x_ticks=[6, 12, 18, 24], y_ticks=[10, 15, 20, 25],
                               x_labels=[6, 12, 18, 24], y_labels=[5, 10, 15, 20, 25]).shift(DOWN*1.4)
        plane = cords[0]
        # self.add(cords)

        func = create_piecewise_linear([[6, 9], [8, 12], [10, 17], [12, 19], [14, 22], [16, 18], [18, 13], [20, 11], [22, 8], [24, 7]])
        graph = plane.plot(func, color=BLUE)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0, y=-2)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)



        # Action Sequence
        with self.voiceover(
                text="""
                How fast is your friend, who is currently running from a wild cow, at any given time?
                How much money would you accumulate over time, if you got a Dollar every time you are bored in class?
                Or what is the speed of the person you see skating on the ice at any given time?
                In the first chapter of the functions series, you will learn how to describe real-world scenarios like these.
                using functions. You will also learn more about <bookmark mark="f"/>graphs of functions, like the one you see on screen.
                Once you've finished the chapter you'll know what a function is, how to plot a function, how to
                model real world scenarios using functions, and more!
                Functions are also very important for many other topics in math, <bookmark mark="fOut"/> so it's super important to understand them well.
                So let's make sure to try our best! Let's get started!
                """
        ) as tracker:

            self.wait_until_bookmark("f")
            self.play(Write(cords), Write(graph))

            self.wait_until_bookmark("fOut")
            self.play(FadeOut(cords), FadeOut(graph), run_time=1)


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_2_Intro(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Functions - Intro")
        
        #Create the coordinate system
        cords = self.add_cords([-4, 4, 2], [-4,4,2], x_ticks=[-4,-2,2,4], y_ticks=[-4,-2,2,4]).shift(DOWN*1.4)
        plane = cords[0]
        # self.add(cords)

        term = MathTex("f(x)=ax+b", color=c1t).next_to(cords, DOWN, buff=0.2)

        func = lambda x: x
        graph = plane.plot(func, color=BLUE)
        graph2 = graph.copy()
        cords2 = cords.copy()

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0, y=-2)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)



        # Action Sequence
        with self.voiceover(
                text="""
                Here are three situations, that can be modeled with linear functions:
                One: You're ordering burgers with your friends and you're figuring out, how much you will have to spend
                depending on how many burgers you're ordering. Two: you've got a job working as a lifeguard with a fixed
                hourly salary, and you want to determine how much money you'll receive for your work. Three: you're going
                to a sports game and in addition to the ticket price, you have to pay for each drink you're getting. In
                this chapter, you will learn how to model situations like these <bookmark mark="plot"/>using linear functions.
                Many concepts, in this chapter are some of the most <bookmark mark="fOut"/>fundamental techniques in all of mathematics, so
                understanding them well will make your life much easier later on, when you learn about other functions.
                Specifically, we'll learn about how to use <bookmark mark="term"/>terms to describe linear functions, how to<bookmark mark="plot2"/> plot linear functions,
                how to model interpret linear <bookmark mark="plotOut"/>functions and much more. 
                """
        ) as tracker:

            self.wait_until_bookmark("plot")
            self.play(Write(cords), Write(graph))

            self.wait_until_bookmark("fOut")
            self.play(FadeOut(cords), FadeOut(graph), run_time=1)

            self.wait_until_bookmark("term")
            self.play(Write(term))

            self.wait_until_bookmark("plot2")
            self.play(FadeOut(term), Write(cords2), Write(graph2))

            self.wait_until_bookmark("plotOut")
            self.play(FadeOut(cords2), FadeOut(graph2), run_time=1)


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_3_Intro(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_title("Functions - Intro")
        
        #Create the coordinate system
        cords = self.add_cords([-4, 4, 2], [-4,4,2], x_ticks=[-4,-2,2,4], y_ticks=[-4,-2,2,4]).shift(DOWN*1.4)
        plane = cords[0]
        # self.add(cords)

        func = lambda x:1/x
        graph = VGroup(plane.plot(func, color=BLUE, x_range=[-4,-0.25,0.0001]), plane.plot(func, color=BLUE, x_range=[0.25,4,0.0001]))

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0, y=-2)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)



        # Action Sequence
        with self.voiceover(
                text="""
                Sharing is caring and because I care about your math skills, in this chapter I will share all of my
                knowledge about <bookmark mark="plot"/> fractional rational functions. They will help you share
                everything you have with your friends and other people in your life, because they are
                the perfect tool to model situations where you have to share something. <bookmark mark="fOut"/>
                For example, you can use fractional rational functions
                to model how much food each person gets, if the food is shared equally between a group of people.
                Or, if you prefer to look out for your own good, you can use them to determine how much money you'll
                have to pay for a shared bill, depending on how many people are sharing it. In this chapter, you will
                learn how to model situations like these <bookmark mark="plot2"/>using fractional rational functions.
                You will learn about important concepts like asymptotes, singularities and many other things that have
                fancy sounding names. 
                """
        ) as tracker:

            self.wait_until_bookmark("plot")
            self.play(Write(cords), Write(graph))

            self.wait_until_bookmark("fOut")
            self.play(FadeOut(cords), FadeOut(graph), run_time=1)

            self.wait_until_bookmark("plot2")
            self.play(Write(cords), Write(graph))


        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_4_Intro(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        
        #Create the coordinate system
        cords = self.add_cords([-2, 2, 1], [-4,4,2], x_ticks=[-2,-1,1,2], y_ticks=[-4,-2,2,4]).shift(DOWN)
        plane = cords[0]
        # self.add(cords)

        func = lambda x:x**2
        graph = plane.plot(func, color=BLUE)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0, y=-2)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        qf = Tex("Quadratic ", "Functions", color=c1t).next_to(cords, UP, buff=1.4).scale(0.8)



        # Action Sequence
        with self.voiceover(
                text="""
                Scoring the perfect shot in basketball.
                Or designing the most exciting rollercoaster ride.
                Or calculating the speed at which you fall towards the water when we jump off a cliff.
                These are all situations that can be modeled with <bookmark mark="quadratic"/> quadratic<bookmark mark="functions"/> functions.
                And guess what! <bookmark mark="reset"/>Quadratic functions are what this chapter is all about!
                In this chapter, you will learn how to model situations like these using quadratic functions.
                <bookmark mark="cords"/>We will learn how to <bookmark mark="plot"/>plot quadratic functions, how to find their function terms, different ways
                of writing their function terms, and much more. Let's get started!
                """
        ) as tracker:

            self.wait_until_bookmark("quadratic")
            cursor.blinking=False
            x,y,_ = qf[0].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(qf[0]), run_time=0.3)

            self.wait_until_bookmark("functions")
            x,y,_ = qf[1].get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(qf[1]), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("reset")
            x,y,_ = plane.c2p(0,0)
            cursor.blinking=False
            self.play(CursorMoveTo(cursor,x,y), run_time=0.3)
            cursor.blinking=True

            self.wait_until_bookmark("cords")
            cursor.blinking=False
            x,y,_ = graph.get_start()
            self.play(CursorMoveTo(cursor,x,y), Write(cords), run_time=0.5)

            self.wait_until_bookmark("plot")
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(graph.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(graph))
            cursor.blinking=True

        # Wait for 4 seconds at the end of the animation
        self.wait(4)


class Func_5_Intro(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        
        #Create the coordinate system
        cords = self.add_cords([-2, 2, 1], [-4,4,2], x_ticks=[-2,-1,1,2], y_ticks=[-4,-2,2,4]).shift(DOWN)
        plane = cords[0]
        self.add(cords)

        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True, x=0, y=-2)
        cursor.autoFadeBackground = False
        cursor.add_updater(cursor_sound_updater)
        cursor.add_updater(lambda m: self.bring_to_front(cursor) if not m.isHidden else None)
        self.add(cursor)

        pf = Tex("Power ", "Functions", color=c1t).next_to(cords, UP, buff=1.4).scale(0.8)

        x2f = lambda x: x**2
        x3f = lambda x: x**3
        x4f = lambda x: x**4

        x2g = plane.plot(x2f, color=BLUE)
        x3g = plane.plot(x3f, color=PURPLE, x_range=[-4**(1/3),4**(1/3), 0.0001])
        x4g = plane.plot(x4f, color=GREEN, x_range=[-4**(1/4),4**(1/4), 0.0001])

        x2t = MathTex("x^2", color=BLUE, font_size=fs2).next_to(cords, DOWN, buff=0.2)
        x3t = MathTex("x^3", color=PURPLE, font_size=fs2).next_to(cords, DOWN, buff=0.2)
        x4t = MathTex("x^4", color=GREEN, font_size=fs2).next_to(cords, DOWN, buff=0.2)

        roots1 = Tex("Roots", color=c1t).scale(0.8).next_to(x4t, DOWN, buff=0.4)
        roots2 = Tex("$\\sqrt{x}$", color=c1t).scale(0.8).next_to(roots1, DOWN, buff=0.2)



        # Action Sequence
        with self.voiceover(
                text="""
                There are square functions, that involve terms like <bookmark mark="x2"/> x squared.
                But there is so much more. There are <bookmark mark="cubic"/> cubic functions, that involve terms like x cubed.
                And there are <bookmark mark="quartic"/> functions of degree four, that involve terms like x to the power of four,
                and you can continue this for any number you want. These functions are called <bookmark mark="power"/> power functions.
                In this chapter, you will learn how to deal with power functions, and you will<bookmark mark="roots"/> learn about roots. Roots are
                the opposite of powers. So to undo what a power function does, you can use a root function. Curious?
                Then let's get started!
                """
        ) as tracker:

            self.wait_until_bookmark("x2")
            cursor.blinking=False
            x,y,_ = x2g.get_start()
            self.play(CursorMoveTo(cursor,x,y), Write(x2t), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(x2g.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(x2g))

            self.wait_until_bookmark("cubic")
            x,y,_ = x3g.get_start()
            self.play(CursorMoveTo(cursor,x,y), Write(x3t), Unwrite(x2g), Unwrite(x2t), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(x3g.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(x3g))

            self.wait_until_bookmark("quartic")
            x,y,_ = x4g.get_start()
            self.play(CursorMoveTo(cursor,x,y), Write(x4t), Unwrite(x3g), Unwrite(x3t), run_time=0.3)
            self.add(cursor.copy()._start_fading(2).add_updater(lambda m: m.move_to(x4g.get_end())))
            self.add_pencil_sound(1.5)
            self.play(Create(x4g))
            cursor.blinking=True

            self.wait_until_bookmark("power")
            cursor.blinking=False
            x,y,_ = pf.get_center()+0.4*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(pf), run_time=0.3)
            cursor.blinking=True


            self.wait_until_bookmark("roots")
            cursor.blinking=False
            x,y,_ = roots2.get_center()+0.6*DOWN
            self.play(CursorMoveTo(cursor,x,y), Write(roots1), Write(roots2), run_time=0.3)
            cursor.blinking=True


        # Wait for 4 seconds at the end of the animation
        self.wait(4)

scenes/Func/Func_ChapterIntros/Func_intros.py
Sophia-Edu-Labs/sophia-math
# 4_1: Quadratic Functions: Intro, Term
# To-Do Here: add practice part, add recognizing non-standard squared fct. termsb

# Import necessary libraries and modules
from sophialib.page_prototypes.prototype import PagePrototypeQuestion, PagePrototypeVideo
from sophialib.styles.sophiascene import (CursorMoveToCurved, CursorPositionTracker,
                                          CursorPositionTracking,
                                          CursorResizeDefault, SophiaScene,
                                          assets_folder, AltCursor,
                                          SophiaCursorScene, CursorMoveTo,
                                          CursorMoveResize, Notepad, CursorMarkAxis, Bubble)
from sophialib.styles.styleconstants import *
from sophialib.styles.sophiaobjects import *
from manim import *
from PIL import Image
import numpy as np
from pathlib import Path
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition

class Review_Intro(SophiaCursorScene):

    # Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        
        def cursor_sound_updater(mob, dt):
            if mob.needSound:
                mob.needSound = False
                self.add_cursor_sound()
        cursor = AltCursor(stroke_width=0.0, blinking=True)
        cursor.autoFadeBackground = True
        cursor.add_updater(cursor_sound_updater)
        self.add(cursor)


        self.add_title("Review Section")

        with self.voiceover(
                text="""
                Well Hello there! Welcome to the review section of the App.
                This is how it works: Go to the "focus section", and choose a topic you want to learn about.
                Once you've learned about one or more topics there, you can come back here and review
                what you have learned. This way, you can make sure that you will remember what you have learned. 
                """
        ) as tracker:

            self.wait()
        self.wait()




class TestSquareDrawing(SophiaCursorScene):

# Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()



        Squares = [Square(side_length=0.2, color=RED, fill_color=RED, fill_opacity=1).shift([0.1,-3.5+0.4*idx,0]) for idx in range(40)]
        for square_idx in range(39):
            square = Squares[square_idx+1]
            prevSquare = Squares[square_idx].copy()
            self.add(prevSquare)
            cursor = Circle(radius=0.1, fill_color=RED, fill_opacity=1, color=RED).move_to(square).shift([-0.2,-0.2,0])
            self.play(ReplacementTransform(prevSquare, cursor), run_time=0.5)
            self.play(ReplacementTransform(cursor, square), run_time=0.5)
            

        self.wait(10)


class drawQmark(SophiaCursorScene):

# Main method for constructing the animation
    def construct(self):
        # Adding initial components to the scene
        super().construct()
        self.add_mathgrid()
        self.add_orientation()

        
        cursor=AltCursor()
        def draw_decorative_line(cursor, downshift = 0, run_time=2):

            sq = lambda : Square(side_length=0.2, color=RED, fill_color=RED, fill_opacity=1, stroke_width=0)
            c = lambda : Circle(radius=0.1, fill_color=RED, fill_opacity=1, color=RED, stroke_width=0).shift([-0.1,-0.3,0])

            decoration1 = VGroup(*[sq().shift([-2.1+0.4*idx,0.1,0]) for idx in range(12)]).shift(DOWN*downshift)
            decoration2 = VGroup(*[sq().shift([-1.9+0.4*idx,-0.1,0]) for idx in range(12)]).shift(DOWN*downshift)
            decoration = VGroup(*decoration1, *decoration2)

            self.play(cursor.animate.move_to(decoration1[0]), run_time=0.2*run_time)

            circ = c().move_to(decoration1[0])
            self.add(circ)
            cursor.move_to(decoration2[-1])
            for idx in range(12):
                self.play(ReplacementTransform(circ, decoration1[idx]), run_time=0.1*run_time)
                self.play(ReplacementTransform(c().move_to(decoration1[idx]), decoration2[idx]), run_time=0.1*run_time)
                circ = c().move_to(decoration2[idx])

            cursor.move_to(decoration1[-1])

            return decoration

        draw_decorative_line(cursor)
        self.wait(10)


class SquareToCircle(Scene):
    def construct(self):
        circle = Circle()  # create a circle
        circle.set_fill(RED, opacity=0.5)  # set color and transparency

        square = Square()  # create a square
        square.rotate(PI / 4)  # rotate a certain amount
        square_2 = square.copy()

        triangle = Triangle()
        triangle.rotate(-PI / 4).set_fill(BLUE, opacity=0.5)


        self.play(Create(square))  # animate the creation of the square
        self.play(Transform(square, circle))  # interpolate the square into the circle
        self.play(Transform(square, triangle))  # interpolate the square into the triangle
        self.play(Transform(square, square_2))  # interpolate the square into the circle
        self.play(FadeOut(square))  # fade out animation
        

class SineCurveUnitCircle(SophiaCursorScene):
    # contributed by heejin_park, https://infograph.tistory.com/230
    def construct(self):
        super().construct()
        self.add_mathgrid()
        self.show_axis()
        self.show_circle()
        self.move_dot_and_draw_curve()
        self.wait()

    def show_axis(self):
        x_start = np.array([-6,0,0])
        x_end = np.array([2,0,0])

        y_start = np.array([-4,-2,0])
        y_end = np.array([-4,2,0])

        x_axis = Line(x_start, x_end, color=BLACK)
        y_axis = Line(y_start, y_end, color=BLACK)

        self.add(x_axis, y_axis)
        self.add_x_labels()

        self.origin_point = np.array([-4,0,0])
        self.curve_start = np.array([-3,0,0])

    def add_x_labels(self):
        x_labels = [
            MathTex("\pi", color=BLACK), MathTex("2 \pi", color=BLACK)
        ]

        for i in range(len(x_labels)):
            x_labels[i].next_to(np.array([-1 + 2*i, 0, 0]), DOWN)
            self.add(x_labels[i])

    def show_circle(self):
        circle = Circle(radius=1)
        circle.move_to(self.origin_point)
        self.add(circle)
        self.circle = circle

    def move_dot_and_draw_curve(self):
        orbit = self.circle
        origin_point = self.origin_point

        dot = Dot(radius=0.08, color=PURPLE)
        dot.move_to(orbit.point_from_proportion(0))
        self.t_offset = 0
        rate = 0.25
        going_forward = True

        def go_around_circle(mob, dt):
            nonlocal going_forward  # Declare the flag as nonlocal
            if going_forward:
                self.t_offset += (dt * rate)
            else:
                self.t_offset -= (dt * rate)
                
            if self.t_offset >= 1:  # Stop and reverse after one revolution
                going_forward = False
            elif self.t_offset <= 0:  # Stop and go forward after reaching the start
                going_forward = True

            mob.move_to(orbit.point_from_proportion(self.t_offset % 1))

        def get_line_to_circle():
            return Line(origin_point, dot.get_center(), color=BLUE)

        def get_line_to_curve():
            x = self.curve_start[0] + self.t_offset * 4
            y = dot.get_center()[1]
            return Line(dot.get_center(), np.array([x,y,0]), color=PURPLE, stroke_width=2 )


        self.curve = VGroup()
        self.curve.add(Line(self.curve_start,self.curve_start))
        def get_curve():
            nonlocal going_forward  # Declare the flag as nonlocal
            last_line = self.curve[-1]

            if going_forward:
                x = self.curve_start[0] + self.t_offset * 4
                y = dot.get_center()[1]
                new_line = Line(last_line.get_end(), np.array([x, y, 0]), color=PURPLE_B)
                self.curve.add(new_line)
            else:
                if len(self.curve) > 1:  # Ensure we don't remove the first line
                    self.curve.remove(self.curve[-1])  # Remove the last line

            return self.curve
        dot.add_updater(go_around_circle)

        origin_to_circle_line = always_redraw(get_line_to_circle)
        dot_to_curve_line = always_redraw(get_line_to_curve)
        sine_curve_line = always_redraw(get_curve)

        self.add(dot)
        self.add(orbit, origin_to_circle_line, dot_to_curve_line, sine_curve_line)
        self.wait(8.5)

        dot.remove_updater(go_around_circle)
scenes/General/general.py
Sophia-Edu-Labs/sophia-math
# based on this: https://godatadriven.com/blog/a-practical-guide-to-using-setup-py/
# and this: https://python-packaging.readthedocs.io/en/latest/minimal.html

from setuptools import setup, find_packages

setup(
    name='sophialib',
    version='0.1.0',
    description='Everything that sophia-math can use, etc.',
    author='Friedrich Wicke and Gero Embser',
    author_email='sophia@sophiaedulabs.com',
    url='sophiaedulabs.com',
    packages=find_packages(include=['sophialib', 'sophialib.*']),
)
sophialib/setup.py
Sophia-Edu-Labs/sophia-math
from pathlib import Path

WORKSPACE_FOLDER = Path(__file__).parent.parent.parent.parent.resolve() # resolve only workspace folder

RENDER_RESULTS_FOLDER = WORKSPACE_FOLDER / "renderresults"

SCENES_FOLDER = WORKSPACE_FOLDER / "scenes"

# The folder where the assets for scenes are stored
SCENES_ASSETS_FOLDER = SCENES_FOLDER / "assets"

# The folder where the locales are stored
LOCALES_PATH = SCENES_FOLDER / "i18n" / "locales"
sophialib/sophialib/constants/directories.py
Sophia-Edu-Labs/sophia-math
DEFAULT_FPS = 60
sophialib/sophialib/constants/videos.py
Sophia-Edu-Labs/sophia-math
import subprocess

def extract_audio_to_path(rendered_video_path: str, output_path: str):
    command = f"ffmpeg -hide_banner -loglevel error -i {rendered_video_path} -i {rendered_video_path} -q:a 0 -filter_complex '[1:a]apad' -shortest -map 0:v -map 1:a {output_path}"
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output, error = process.communicate()

    if process.returncode == 0:
        ffmpeg_output = output.decode("utf-8").strip()
        print(f"ffmpeg returned with output: {ffmpeg_output}")
        print(f"Completed audio extraction to {output_path}.")
    else:
        print(f"Error: {error.decode('utf-8').strip()}")
sophialib/sophialib/filehelpers/extract.py
Sophia-Edu-Labs/sophia-math
import subprocess

# Hashes the audio of a given media file at the given path (should work for audio and video files)
def hash_audio_at_path(audio_path: str):
    command = f"ffmpeg -hide_banner -loglevel error -i {audio_path} -map 0:a -f md5 - | cut -d'=' -f2"
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output, error = process.communicate()

    if process.returncode == 0:
        audio_hash = output.decode("utf-8").strip()
        print(f"Audio hash: {audio_hash}")

        return audio_hash
    else:
        print(f"Error: {error.decode('utf-8').strip()}")

def hash_video_and_audio_at_path(video_path: str):
    command = f"ffmpeg -hide_banner -loglevel error -i {video_path} -f hash - | cut -d'=' -f2"
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output, error = process.communicate()

    if process.returncode == 0:
        video_audio_hash = output.decode("utf-8").strip()
        print(f"Video+Audio hash: {video_audio_hash}")

        return video_audio_hash
    else:
        print(f"Error: {error.decode('utf-8').strip()}")
sophialib/sophialib/filehelpers/hashing.py
Sophia-Edu-Labs/sophia-math
from abc import ABC
import importlib.util
import inspect
from pathlib import Path
import sys

from sophialib.styles.sophiascene import SophiaScene

def get_module_manim_sophiascene_classes(file_path: Path, add_parent_folder_to_sys_path: bool = False, result_sorted: bool = False):
    """Takes the file at the given path and returns all classes in the file that are subclasses of SophiaScene. If add_parent_folder_to_sys_path is True, the parent folder of the file will be added to sys.path, which allows realtive imports in that folder."""

    if add_parent_folder_to_sys_path:
        sys.path.append(str(file_path.parent))

    module_name = file_path.stem
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)

    results = [obj for name, obj in inspect.getmembers(module) if inspect.isclass(obj) and obj.__module__ == module_name and issubclass(obj, SophiaScene) and not inspect.isabstract(obj)]

    if result_sorted:
        results = sorted(results, key=lambda sc: sc.__name__)

    return results


sophialib/sophialib/filehelpers/load_sophia_scenes.py
Sophia-Edu-Labs/sophia-math
import importlib.util
import inspect
import itertools
from pathlib import Path
import sys
from typing import List, Literal, Type, Union, Optional

from sophialib.styles.sophiascene import SophiaQuestionInfo, SophiaScene
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition

class PagePrototype:
    def __init__(self, prototypeID: str, type: Union[Literal['video'], Literal['question']]):
        self.prototypeID = prototypeID
        self.type = type

    def to_json(self):
        return {
            "prototypeID": self.prototypeID,
            "type": self.type
        }

class PagePrototypeVideo(PagePrototype):
    def __init__(self, prototypeID: str, videoID: Optional[str] = None):
        super().__init__(prototypeID, 'video')
        self.videoID = videoID

    def to_json(self):
        return {
            **super().to_json(),
            "videoID": self.videoID
        }

    # Factory method that will create a PagePrototypeVideo from a SophiaScene
    @staticmethod
    def from_scene(scene: SophiaScene):
        return PagePrototypeVideo(
            prototypeID = f"VIDEO_{scene.__name__}",
            videoID = scene.videoID if hasattr(scene, 'videoID') else None
        )

class PagePrototypeQuestion(PagePrototype):
    def __init__(
        self,
        prototypeID: str,
        questionVideoPrototypeID: str,
        answerOptions: List[str],
        correctAnswerIndex: int,
        questionText: str
    ):
        super().__init__(prototypeID, 'question')
        self.questionVideoPrototypeID = questionVideoPrototypeID
        self.answerOptions = answerOptions
        self.correctAnswerIndex = correctAnswerIndex
        self.questionText = questionText

    def to_json(self):
        return {
            **super().to_json(),
            "questionVideoPrototypeID": self.questionVideoPrototypeID,
            "answerOptions": self.answerOptions,
            "correctAnswerIndex": self.correctAnswerIndex,
            "questionText": self.questionText
        }

    # Factory method that will create a PagePrototypeQuestion from a SophiaTaskDefinition
    @staticmethod
    def from_task_definition(task_definition: SophiaTaskDefinition, unprefixed_prototypeID: str):
        return PagePrototypeQuestion(
            prototypeID = f"QUESTION_{unprefixed_prototypeID}",
            questionVideoPrototypeID = task_definition.questionVideoPrototypeID,
            answerOptions = task_definition.answerOptions,
            correctAnswerIndex = task_definition.correctAnswerIndex,
            questionText = task_definition.questionText
        )
    
    # Factory method that will create a PagePrototypeQuestion from a SophiaScene
    @staticmethod
    def from_scene(sceneWithQuestionInfoType: Type[SophiaQuestionInfo]):

        # instantiate such a question info
        sceneWithQuestionInfo = sceneWithQuestionInfoType()
        
        task_def = sceneWithQuestionInfo.task_definition()

        return PagePrototypeQuestion.from_task_definition(
            task_definition = task_def,
            unprefixed_prototypeID = sceneWithQuestionInfoType.__name__
        )



def get_page_prototype_variables(file_path: Path, add_parent_folder_to_sys_path: bool = False):
    """Takes the file at the given path and returns all classes in the file that are subclasses of PagePrototype. 
    If add_parent_folder_to_sys_path is True, the parent folder of the file will be added to sys.path, which allows realtive imports in that folder."""
    if add_parent_folder_to_sys_path:
        sys.path.append(str(file_path.parent))


    module_name = file_path.stem
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)

    objs = [obj for name, obj in inspect.getmembers(module) if isinstance(obj, PagePrototype) or (isinstance(obj, list) and all(isinstance(v, PagePrototype) for v in obj))]
    # flatten objs, i.e. flatten an array of the form: [[a, b], c, [d, e]] -> [a, b, c, d, e]
    objs = list(itertools.chain.from_iterable([e if isinstance(e, list) else [e] for e in objs]))
    return objs

sophialib/sophialib/page_prototypes/prototype.py
Sophia-Edu-Labs/sophia-math
from pathlib import Path
import subprocess
import tempfile
from time import sleep
from typing import Callable, List, Optional
import soundfile as sf
import pyrubberband as pyrb

def time_stretch_audio(input_file: Path, output_file: Path, target_duration: Optional[float], destination_volume: float = 1.0, timemap_function: Optional[Callable[[float],float]] = None):
    # Load the audio file
    audio, sample_rate = sf.read(str(input_file))
    
    # Calculate the current duration
    current_duration = len(audio) / sample_rate

    if target_duration is None:
        target_duration = current_duration
    
    # Calculate the time stretch ratio
    time_stretch_ratio = 1/(target_duration / current_duration)
    
    # Time-stretch the audio
    if timemap_function is not None:
        source_sample_count = len(audio)
        target_sample_count = round(target_duration * sample_rate)
        scale_factor = target_sample_count / source_sample_count
        # a timemap maps indices in the source audio sample array to indices in the target audio sample array (while rubberband will determine the exact sample values in the target array, we only need to give it the indices)
        # linear_time_map_stretched = [((i+1), (i*scale_factor +1)) for i, sample in enumerate(audio)]
        time_map_stretched_from_function = [(i+1, round(timemap_function((i+1)/len(audio))*len(audio))*scale_factor) for i, sample in enumerate(audio)]
        time_stretched_audio = pyrb.timemap_stretch(audio, sample_rate, time_map_stretched_from_function)
    else:
        time_stretched_audio = pyrb.time_stretch(audio, sample_rate, time_stretch_ratio)
    
    # Write the time-stretched audio to the output file
    sf.write(str(output_file), time_stretched_audio, sample_rate)
    print(f"Time-stretched {input_file} from {current_duration} to {target_duration} seconds and saved to {output_file}.")

    # if destination volume is not 1.0, adjust the volume
    if destination_volume != 1.0:
        adusted_volume_audio_path = adjust_volume(output_file, destination_volume)

        # move the adjusted volume audio file to the output file
        adusted_volume_audio_path.rename(output_file)



# Method to create a temporary file from the given input sound file, stretched to the given target duration
def create_temporary_stretched_audio_file(input_file: Path, target_duration: float, destination_volume: float = 1.0, reverse: bool = False, rate_function: Optional[Callable[[float],float]] = None, repeat_count: Optional[int] = 0):
    # Create a temporary file
    temp_file = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)
    temp_file_path = Path(temp_file.name)

    # if reverse is True, reverse the audio file
    if reverse:
        input_file = reverse_audio(input_file, temp_file_path)

    # Stretch the audio file to the target duration and save it to the temporary file
    time_stretch_audio(input_file, temp_file_path, target_duration, destination_volume, rate_function)
    print(f"Created temporary file {temp_file_path}.", flush=True)

    # if repeat_count is greater than 0, repeat the audio file
    if repeat_count > 0:
        temp_file_path = repeat_audio(temp_file_path, repeat_count)

    # convert the temporary file to mp3
    temp_file_path = convert_to_mp3(temp_file_path)

    return temp_file_path

class StretchedAudioFileConfig: 
    def __init__(self, input_file: Path, target_duration: float, destination_volume: float = 1.0, reverse: bool = False, rate_function: Optional[Callable[[float],float]] = None, repeat_count: Optional[int] = 0):
        self.input_file = input_file
        self.target_duration = target_duration
        self.destination_volume = destination_volume
        self.reverse = reverse
        self.rate_function = rate_function
        self.repeat_count = repeat_count

def create_temporary_stretched_audio_file_from_config(config: StretchedAudioFileConfig):
    return create_temporary_stretched_audio_file(config.input_file, config.target_duration, config.destination_volume, config.reverse, config.rate_function, config.repeat_count)

def create_combined_temporary_stretched_audio_file_from_configs(configs: List[StretchedAudioFileConfig]):
    # Create a list of temporary files
    temp_files = []
    for config in configs:
        temp_files.append(create_temporary_stretched_audio_file_from_config(config))

    # Combine the temporary files
    return combine_mp3_files(temp_files)

# Method to repeat the given audio file
def repeat_audio(input_file: Path, repeat_count: int):
    # Throw an error if repeat count is less than 1
    if repeat_count < 1:
        raise Exception(f"Repeat count must be greater than 1. Given repeat count: {repeat_count}")
    
    # Create a temporary file
    temp_file = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)
    temp_file_path = Path(temp_file.name)

    # Repeat the audio file and save it to the temporary file
    command = f"ffmpeg -y -hide_banner -loglevel error -stream_loop {repeat_count} -i {input_file} -c copy {temp_file_path}"
    print(f"Running command: {command}", flush=True)
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output, error = process.communicate()

    if process.returncode == 0:
        ffmpeg_output = output.decode("utf-8").strip()
        print(f"ffmpeg returned with output: {ffmpeg_output}")
        print(f"Repeated {input_file} {repeat_count} times and saved to {temp_file_path}.")
    else:
        raise Exception(f"Error: {error.decode('utf-8').strip()}")

    return temp_file_path


# Method to combine multiple input mp3 files to a single output mp3 file (at a temporary path)
def combine_mp3_files(input_files: List[Path]):
    # Create a temporary file
    temp_file = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False)
    temp_file_path = Path(temp_file.name)

    # Combine the mp3 files and save it to the temporary file
    command = f"ffmpeg -y -hide_banner -loglevel error -i \"concat:{'|'.join([str(input_file) for input_file in input_files])}\" -acodec copy {temp_file_path}"
    print(f"Running command: {command}", flush=True)
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output, error = process.communicate()

    if process.returncode == 0:
        ffmpeg_output = output.decode("utf-8").strip()
        print(f"ffmpeg returned with output: {ffmpeg_output}")
        print(f"Combined {len(input_files)} mp3 files and saved to {temp_file_path}.")
    else:
        raise Exception(f"Error: {error.decode('utf-8').strip()}")

    return temp_file_path

# Method to convert the given audio file to mp3
def convert_to_mp3(input_file: Path):
    # Create a temporary file
    temp_file = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False)
    temp_file_path = Path(temp_file.name)

    # Convert the audio file to mp3 by using ffmpeg and subprocess
    command = f"ffmpeg -y -hide_banner -loglevel error -i {input_file} -vn -ar 44100 -ac 2 -b:a 192k {str(temp_file_path)}"
    print(f"Running command: {command}", flush=True)
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output, error = process.communicate()

    if process.returncode == 0:
        ffmpeg_output = output.decode("utf-8").strip()
        print(f"ffmpeg returned with output: {ffmpeg_output}")
        print(f"Converted {input_file} to {temp_file_path}.")
        return temp_file_path
    else:
        raise Exception(f"Error: {error.decode('utf-8').strip()}")
    

# Method to adjust the volume of the given audio file
def adjust_volume(input_file: Path, destination_volume: float):
    # Create a temporary file
    temp_file = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)
    temp_file_path = Path(temp_file.name)

    # Adjust the volume of the audio file and save it to the temporary file
    command = f"ffmpeg -y -hide_banner -loglevel error -i {input_file} -filter:a 'volume={destination_volume}' {temp_file_path}"
    print(f"Running command: {command}", flush=True)
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output, error = process.communicate()

    if process.returncode == 0:
        ffmpeg_output = output.decode("utf-8").strip()
        print(f"ffmpeg returned with output: {ffmpeg_output}")
        print(f"Adjusted volume of {input_file} to {destination_volume} and saved to {temp_file_path}.")
    else:
        raise Exception(f"Error: {error.decode('utf-8').strip()}")

    return temp_file_path


# Method to reverse the given audio file
def reverse_audio(input_file: Path, output_file: Path):
    # Reverse the audio file and save it to the output file
    command = f"ffmpeg -y -hide_banner -loglevel error -i {input_file} -filter_complex 'areverse' {output_file}"
    print(f"Running command: {command}", flush=True)
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output, error = process.communicate()

    if process.returncode == 0:
        ffmpeg_output = output.decode("utf-8").strip()
        print(f"ffmpeg returned with output: {ffmpeg_output}")
        print(f"Reversed {input_file} and saved to {output_file}.")
    else:
        raise Exception(f"Error: {error.decode('utf-8').strip()}")

    return output_file
sophialib/sophialib/sounds/dynamic_sounds.py
Sophia-Edu-Labs/sophia-math
# BASED ON: https://github.com/ManimCommunity/manim-voiceover/blob/main/manim_voiceover/services/coqui.py



import datetime
import os
from pathlib import Path
import sys
from typing import Iterator, Optional, Union
from dotenv import load_dotenv, find_dotenv
from manim_voiceover.helper import (
    create_dotenv_file,
    prompt_ask_missing_extras,
    remove_bookmarks,
    wav2mp3,
    prompt_ask_missing_package
)
from manim import logger
import json

from multiprocessing import Semaphore

# base speech services stuff
from manim_voiceover.services.base import SpeechService
from sophialib.utils.xml import remove_xml_tags

load_dotenv(find_dotenv(usecwd=True))

# Elevenlabs setup
try:
    from elevenlabs import generate, set_api_key, get_api_key
    from elevenlabs.api import Models, Voices, User, History, HistoryItem
except ImportError:
    logger.error("Missing packages. Run `pip install elevenlabs` to use Elevenlabs service.")


# DEFAULT_MODEL = "eleven_multilingual_v1"
# DEFAULT_MODEL = "eleven_multilingual_v2"
DEFAULT_MODEL = "eleven_monolingual_v1"
# DEFAULT_MODEL = "eleven_english_v2"



# Define the semaphore that will be used to limit the number of parallel requests to the elevenlabs api
parallel_request_sem = Semaphore(3)


class ElevenlabsVoiceoverService(SpeechService):
    """Speech service for Elevenlabs TTS.
    Default model: ``eleven_multilingual_v1``.
    """

    def __init__(
        self,
        model_id: str = DEFAULT_MODEL,
        voice_name: str = "Bella",
        should_use_history: bool = True,
        **kwargs,
    ):
        # Set env has not ELEVENLABS_API_KEY, throw an error
        if not get_api_key():
            api_key = os.getenv("ELEVENLABS_API_KEY")
            if not api_key:
                raise ValueError(
                    "ELEVENLABS_API_KEY not found. Please set it in your environment variables (i.e. in your .env file)."
                )
            set_api_key(api_key)

        # save if we should use history
        self.should_use_history = should_use_history

        # save model id
        self.model_id = model_id

        # get all model ids
        self.models = Models.from_api()
        # make sure the given model name is in the models list, otherwise throw an exception
        if model_id not in [ m.model_id for m in self.models]:
            raise ValueError(f"Model id {model_id} not found in models list gotten from elevenlabs api!")

        # get all voices
        self.voices = Voices.from_api()

        # Make sure the given voice name is in the voices list, otherwise throw an exception
        if voice_name not in [ v.name for v in self.voices]:
            raise ValueError(f"Voice name {voice_name} not found in voices list gotten from elevenlabs api!")
        self.voice_name = voice_name

        # get current elevenlabs user
        self.user = User.from_api()

        # default manim voiceover stuff
        self.init_kwargs = kwargs
        prompt_ask_missing_package("elevenlabs", "elevenlabs>=0.2.24")
        
        # set openai-whisper transcription model (currently use base model)
        SpeechService.__init__(self, transcription_model = "base", **kwargs,)
    
    def get_audio_from_history(self, text: str, max_days: int = 7) -> Optional[Union[bytes, Iterator[bytes]]]:
        # compute the datetime, max_days days ago from now
        max_days_ago = datetime.datetime.now() - datetime.timedelta(days=max_days)

        # get the history from the api
        history = History.from_api()
        
        # iterate over all history items and break if the text was found or the item is older than max_days_ago (if iteration is finished before, try to request more pages)
        for item in history: # when iterating over history, the elevenlabs api will automatically retrieve the pages
            if item.text == text:
                # get the audio bytes from the history item
                return item.audio
            elif item.date < max_days_ago:
                return None
        


    @property
    def _user_character_limit_per_request(self):
        return 2500 if self.user.subscription.status == "free" else 5000

    def generate_from_text(
        self, text: str, cache_dir: str = None, path: str = None, **kwargs
    ) -> dict:
        if cache_dir is None:
            cache_dir = self.cache_dir

        # text preprocessing
        input_text = remove_bookmarks(text)
        input_text = remove_xml_tags(input_text, exclude_tags=["break"])
        input_text = "\n".join([line.strip() for line in input_text.split("\n")]) # remove all leading and trailing whitespaces from every line


        # make sure the input is no longer than allowed character limit
        if len(input_text) > self._user_character_limit_per_request:
            raise ValueError(
                f"Text input is too long. The maximum number of characters is {self._user_character_limit_per_request}."
            ) 
        
        input_data = {"input_text": text, "service": "elevenlabs"}

        cached_result = self.get_cached_result(input_data, cache_dir)
        if cached_result is not None:
            return cached_result

        if path is None:
            audio_path = self.get_audio_basename(input_data) + ".mp3"
        else:
            audio_path = path

        if not kwargs:
            kwargs = self.init_kwargs

        output_path = str(Path(cache_dir) / audio_path)
        
        with parallel_request_sem:
            audio_bytes = None
            # get audio bytes from history if possible
            if self.should_use_history:
                audio_bytes = self.get_audio_from_history(input_text)
            
            if audio_bytes is None:
                # should be audio bytes in mp3 format
                audio_bytes = generate(
                    text=input_text,
                    voice=self.voice_name,
                    model=self.model_id,
                    stream=False,
                )

        # save audio bytes to file
        with open(output_path, "wb") as f:
            f.write(audio_bytes)
        

        json_dict = {
            "input_text": text,
            "input_data": input_data,
            "original_audio": audio_path,
            # "word_boundaries": word_boundaries,
        }

        return json_dict

sophialib/sophialib/styles/ElevenlabsVoiceoverService.py
Sophia-Edu-Labs/sophia-math
# BASED ON: https://github.com/ManimCommunity/manim-voiceover/blob/main/manim_voiceover/services/azure.py



import os
from pathlib import Path
import sys
from dotenv import load_dotenv, find_dotenv
from manim_voiceover.helper import (
    create_dotenv_file,
    prompt_ask_missing_extras,
    remove_bookmarks,
)
from manim import logger
import json


# import AWS API stuff
from boto3 import Session
from botocore.exceptions import BotoCoreError, ClientError
from contextlib import closing

# base speech services stuff
from manim_voiceover.services.base import SpeechService

# load_dotenv(find_dotenv(usecwd=True))

def byte_index_to_char_index(byte_index, input_string):
    """
    Convert a byte index in a string to the corresponding character index.

    Args:
    byte_index (int): The byte index to convert.
    string (str): The string to convert the byte index for.

    Returns:
    int: The corresponding character index in the string.
    """
    encoded_s = input_string.encode()
    
    # Use the decode() method to convert the bytes back to a string,
    # then slice up to the number of characters in the original string.
    # Finally, use the len() function to get the number of characters
    # in the slice.
    num_chars = len((encoded_s[:byte_index]).decode())
    
    # Return the number of characters.
    return num_chars

def serialize_word_boundary(wb):
    return {
        "audio_offset": int(wb["audio_offset"]),
        "duration_milliseconds": int(wb["duration_milliseconds"]),
        "text_offset": wb["text_offset"],
        "word_length": wb["word_length"],
        "text": wb["text"],
        "boundary_type": wb["boundary_type"],
    }



class AWSPollyService(SpeechService):
    """Speech service for AWS Polly TTS API."""

    def __init__(
        self,
        voice: str = "Vicki",
        output_format: str = "Audio48Khz192KBitRateMonoMp3",
        prosody: dict = None,
        **kwargs,
    ):
        """
        Args:
            voice (str, optional): The voice to use. See the `API page <https://learn.microsoft.com/en-us/azure/cognitive-services/speech-service/language-support?tabs=stt-tts>`__ for all the available options. Defaults to ``en-US-AriaNeural``.
            output_format (str, optional): The output format to use. See the `API page <https://learn.microsoft.com/en-us/azure/cognitive-services/speech-service/rest-text-to-speech?tabs=streaming#audio-outputs>`__ for all the available options. Defaults to ``Audio48Khz192KBitRateMonoMp3``.
            prosody (dict, optional): Global prosody settings to use. See the `API page <https://learn.microsoft.com/en-us/azure/cognitive-services/speech-service/speech-synthesis-markup#adjust-prosody>`__ for all the available options. Defaults to None.
        """
        # prompt_ask_missing_extras(
        #     "azure.cognitiveservices.speech", "azure", "AzureService"
        # )

        self.voice = voice
        self.output_format = output_format
        self.prosody = prosody
        SpeechService.__init__(self, **kwargs)

    def generate_from_text(
        self, text: str, cache_dir: str = None, path: str = None, **kwargs
    ) -> dict:
        """"""
        # Remove bookmarks
        pure_text = remove_bookmarks(text)
        inner = pure_text
        if cache_dir is None:
            cache_dir = self.cache_dir

        # Apply prosody
        prosody = kwargs.get("prosody", self.prosody)

        if prosody is not None:
            if not isinstance(prosody, dict):
                raise ValueError(
                    "The prosody argument must be a dict that contains at least one of the following keys: 'pitch', 'contour', 'range', 'rate', 'volume'."
                )

            opening_tag = (
                "<prosody "
                + " ".join(
                    ['%s="%s"' % (key, str(val)) for key, val in prosody.items()]
                )
                + ">"
            )
            inner = opening_tag + inner + "</prosody>"

        ssml = r"""<speak version="1.1" 
            xmlns="http://www.w3.org/2001/10/synthesis"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xsi:schemaLocation="http://www.w3.org/2001/10/synthesis http://www.w3.org/TR/speech-synthesis11/synthesis.xsd"
            xml:lang="de-DE">
            %s
        </speak>
        """ % (
            inner,
        )

        input_data = {
            "input_text": text,
            "ssml": ssml,
            "service": "azure",
            "config": {
                "voice": self.voice,
                "output_format": self.output_format,
                "prosody": self.prosody,
            },
        }

        cached_result = self.get_cached_result(input_data, cache_dir)
        if cached_result is not None:
            return cached_result

        if path is None:
            audio_path = self.get_audio_basename(input_data) + ".mp3"
        else:
            audio_path = path
            
        audio_path_filename=str(Path(cache_dir) / audio_path)
        

        ########## AWS Stuff ##########
        # Create a client using the credentials and region defined in the [default]
        # section of the AWS credentials file (~/.aws/credentials).
        session = Session()
        polly = session.client("polly")

        try:
            engine = "neural"
            language_code = "de-DE"
            text_type = "ssml"
            voice_id=self.voice

            # Request speech synthesis
            audio_response = polly.synthesize_speech(
                Engine=engine,
                LanguageCode=language_code,
                OutputFormat='mp3',
                Text=ssml,
                TextType=text_type,
                VoiceId=voice_id
            )

            speechmark_response = polly.synthesize_speech(
                Engine=engine,
                LanguageCode=language_code,
                OutputFormat='json',
                SpeechMarkTypes=['word'],
                Text=ssml,
                TextType=text_type,
                VoiceId=voice_id
            )

        except (BotoCoreError, ClientError) as error:
            # The service returned an error, exit gracefully
            print(error)
            sys.exit(-1)


         # Access the speech mark stream from the response
        if "AudioStream" in speechmark_response:
            # Note: Closing the stream is important because the service throttles on the
            # number of parallel connections. Here we are using contextlib.closing to
            # ensure the close method of the stream object will be called automatically
            # at the end of the with statement's scope.
            with closing(speechmark_response["AudioStream"]) as stream:
                speechmark_data: str = stream.read().decode('utf-8')
                speechmarks = [json.loads(l) for l in speechmark_data.split("\n") if len(l) > 0]
                
                # parse speechmark into word boundaries (it should basically be different names for the same concept, just different syntax)
                last_audio_offset = 0
                def process_speechmark(evt):
                    nonlocal last_audio_offset #https://stackoverflow.com/a/8178808

                    # see here for documentation
                    # https://docs.aws.amazon.com/polly/latest/dg/using-speechmarks.html
                    # and to compare with the above linked "azure reference implementation", see: https://learn.microsoft.com/en-us/dotnet/api/microsoft.cognitiveservices.speech.speechsynthesiswordboundaryeventargs?view=azure-dotnet
                    result = {}

                    # duration
                    result["duration_milliseconds"] = evt["time"] - last_audio_offset # this way we can compute the duration

                    # audio offset (should be in 100ns)
                    result["audio_offset"] = evt["time"] * 1e+6 / 100 # time is in milliseconds -> convert to nanoseconds -> then make it in 100ns ticks
                    
                    # text
                    result["text"] = evt["value"]

                    # boundary type (is static here)
                    result["boundary_type"] = "Word"

                    # word length
                    word_length = len(evt["value"])
                    result["word_length"] = word_length #evt["end"] - evt["start"] 

                    # text offset
                    first_word_offset_in_ssml = speechmarks[0]["start"]
                    result["text_offset"] = byte_index_to_char_index(evt["start"], ssml) - byte_index_to_char_index(first_word_offset_in_ssml, ssml) #everything relative to first word
                    
                    # update counter variables…
                    last_audio_offset=evt["time"]

                    return result
                
                word_boundaries = [process_speechmark(sm) for sm in speechmarks]

        else:
            # The response didn't contain speech mark data, exit gracefully
            print("Could not stream speech marks")
            sys.exit(-1)

        # Access the audio stream from the response
        if "AudioStream" in audio_response:
            # Note: Closing the stream is important because the service throttles on the
            # number of parallel connections. Here we are using contextlib.closing to
            # ensure the close method of the stream object will be called automatically
            # at the end of the with statement's scope.
                with closing(audio_response["AudioStream"]) as stream:
                    try:
                        # Open a file for writing the output as a binary stream
                        with open(audio_path_filename, "wb") as file:
                            file.write(stream.read())

                        json_dict = {
                            "input_text": text,
                            "input_data": input_data,
                            "ssml": ssml,
                            "word_boundaries": [serialize_word_boundary(wb) for wb in word_boundaries],
                            "original_audio": audio_path,
                        }

                        return json_dict
                    except IOError as error:
                        # Could not write to file, exit gracefully
                        print(error)
                        sys.exit(-1)

        else:
            # The response didn't contain audio data, exit gracefully
            print("Could not stream audio")
            sys.exit(-1)
sophialib/sophialib/styles/PollyVoiceoverService.py
Sophia-Edu-Labs/sophia-math
from sophialib.styles.sophiascene import SophiaScene, assets_folder
from manim import *
from PIL import Image
import numpy as np

sophialib/sophialib/styles/functions.py
Sophia-Edu-Labs/sophia-math
from manim.camera.camera import Camera
from sophialib.styles.sophiascene import *



#Takes a list stating the number of squares in each row and creates a grid of squares
def create_grid(rows, width=0.5, color=BLUE):
    squares = []
    grids = []
    for idx1, row in enumerate(rows):
        for idx2 in range(row):
            square = Rectangle(height=width, width=width, color=color, fill_color=color, fill_opacity=1).shift((idx1*width)*UP+(idx2*width)*RIGHT)
            grid = Rectangle(height=width, width=width, color=BLACK).shift((idx1*width)*UP+(idx2*width)*RIGHT)
            squares.append(square)
            grids.append(grid)

    return VGroup(*squares), VGroup(*grids)


class GeoSophiaScene(SophiaCursorScene):
    x = 1


sophialib/sophialib/styles/geosophiascene.py
Sophia-Edu-Labs/sophia-math
from manim import *
from sophialib.styles.styleconstants import *


class Updown_Arrow(Line):


    ### TODO: Make it work with the tip
    def __init__(self, origin_loc=ORIGIN, vert=True, **kwargs):
        perturb = [0,0.0000001,0]
        super().__init__(start=origin_loc+perturb, end=origin_loc, **kwargs)
        self.vert = vert
        # self.add_tip()
        # tip = self.get_tip()
        self.origin_loc = origin_loc
        self.add_updater(self.update_color)
        # self.add_updater(self.update_tip)

    def update_color(self, dt, arrow):
        if self.vert:
            if self.get_y()>self.origin_loc[1]:
                self.set_color(GREEN)
            else:
                self.set_color(RED)
        else:
            if self.get_x()<self.origin_loc[0]:
                self.set_color(GREEN)
            else:
                self.set_color(RED)
        # print(self.get_length())

    def update_tip(self, dt, arrow):
        if self.get_length()<0.05:
            self.tip.length=self.get_length()
            self.tip.move_to(self.get_end())
        else:
            self.tip.length=0.05
            self.tip.move_to(self.get_end())

sophialib/sophialib/styles/sophiaobjects.py
Sophia-Edu-Labs/sophia-math
from abc import ABC, abstractmethod
import os
from typing import List, Literal, Optional, Callable, Union as UnionType
from manim import *
from PIL import Image
from manim.mobject.mobject import Mobject
from manim.scene.scene import Scene
import numpy as np
import urllib.request
from pathlib import Path
import math

from manim_voiceover import VoiceoverScene
from sophialib.constants.directories import SCENES_ASSETS_FOLDER
from sophialib.sounds.dynamic_sounds import StretchedAudioFileConfig, create_combined_temporary_stretched_audio_file_from_configs, create_temporary_stretched_audio_file, create_temporary_stretched_audio_file_from_config
from sophialib.styles.styleconstants import *
from sophialib.styles.PollyVoiceoverService import AWSPollyService
from sophialib.styles.ElevenlabsVoiceoverService import ElevenlabsVoiceoverService
from sophialib.tasks.sophiataskdefinition import SophiaTaskDefinition
from sophialib.translation.currentlocale import CURRENT_LOCALE
from sophialib.translation.translate import get_translation
from sophialib.utils.xml import remove_xml_tags

# class EmojiSVGMobject(SVGMobject):
#     def __init__(self, emoji, **kwargs):
#         emoji_code = '-'.join(f'{ord(c):x}' for c in emoji)
#         url = f'https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg/{emoji_code}.svg'
#         path_svg = Path.cwd() / f'{emoji_code}.svg'
#         urllib.request.urlretrieve(url, path_svg)
#         SVGMobject.__init__(self, str(path_svg), **kwargs)
#         path_svg.unlink()  # delete downloaded svg again locally

aspect_ratio = 9/16
sophia_radius_scale_factor_relative_to_height = 0.4*0.5
sophia_center_as_percentage_of_height = 1-sophia_radius_scale_factor_relative_to_height*0.8

# Define an "interface" that allows specific scenes to provide task defintion information
class SophiaQuestionInfo(ABC):
    @abstractmethod
    def task_definition(self) -> SophiaTaskDefinition:
        pass

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)

        # Check if the subclass is also a subclass of SophiaScene
        if not issubclass(cls, SophiaScene):
            raise TypeError(f"{cls.__name__} must also inherit from SophiaScene!")


class SophiaScene(VoiceoverScene):
    should_add_dev_rects = True
    prevlocs = [RIGHT, RIGHT, RIGHT]
    cheight, cwidth = ValueTracker(0.2), ValueTracker(0.2)
    cx, cy = ValueTracker(0), ValueTracker(0)
    fill_opacity = 1
    blinking = 1

    def current_locale(self) -> str:
        return CURRENT_LOCALE

    def translate(self, key: str, fallback: Optional[str] = None) -> str:
        # use the translate helpers to search for the given key in the translation files
        translation = get_translation(key, self.current_locale())

        # if no translation was found, use the fallback if it was given, otherwise raise an error
        if translation is None:
            if fallback is not None:
                return fallback
            else:
                raise Exception(f"Could not find translation for key {key} in locale {self.current_locale()}")
            
        return translation


    def add_wrapped_subcaption(
        self,
        subcaption: str,
        duration: float,
        subcaption_buff: float = 0.1,
        max_subcaption_len: int = 70,
    ) -> None:
        subcaption_without_xml = remove_xml_tags(subcaption)
        super().add_wrapped_subcaption(subcaption_without_xml, duration, subcaption_buff, max_subcaption_len)

#Add Rectangles describing the Phone Screen
    def add_basic_rectangles(self):
        if not self.should_add_dev_rects:
            return
        main_rect = Rectangle(width=self.camera.frame_height*aspect_ratio, height=self.camera.frame_height, color=c_rects)
        self.add(main_rect)

#Add numbers for orientation in manim coordinates
    def add_orientation(self):
        
        for idx in range(-4,5,1):
            line = Line((-2.2,idx,-100),(2.2,idx,-100), color=c_or, stroke_width=1)
            t1 = Tex(f"{idx}", color=c_or).move_to((-3,idx,-100))
            t2 = Tex(f"{idx}", color=c_or).move_to((3,idx,-100))
            self.add(line, t1, t2)

        for idx in range(-2,3,1):
            line = Line((idx,-4,-100),(idx,4,-100), color=c_or, stroke_width=1)
            t1 = Tex(f"{idx}", color=c_or).move_to((idx, -3.5,-100))
            self.add(line, t1)

        tx = Text("X:", color=BLACK, font_size=fs3).move_to([-6,3,0])
        ty = Text("Y:", color=BLACK, font_size=fs3).move_to([-6,2,0])
        console = Text("Console", color=BLACK, font_size=fs3).move_to([-6,1,0])
        self.add(DecimalNumber(0, color=BLACK, font_size=fs3).add_updater(lambda m: m.set_value(self.cx.get_value())).next_to(tx, RIGHT, buff=0.2))
        self.add(DecimalNumber(1, color=BLACK, font_size=fs3).add_updater(lambda m: m.set_value(self.cy.get_value())).next_to(ty, RIGHT, buff=0.2))
        self.add(tx, ty, console)
        return console
            
#Add the mathgrid for notebook-look
    def add_mathgrid(self):
        # xrange = [2.2,6.6,0.2]
        xrange = [-2.2,11,0.2]
        yrange = [4,12,0.2]
        linestyledict = {"stroke_color": c_mathgrid, "stroke_width": 1}
        grid = NumberPlane(x_range=xrange, y_range=yrange, background_line_style=linestyledict, faded_line_style=linestyledict, x_axis_config=linestyledict, y_axis_config=linestyledict)
        self.add(grid)
        self.bring_to_back(grid)

    def add_divider(self):
        line = DashedLine([-2.2,-1,0], [2.2,-1,0], color=BLACK, stroke_width=1)
        self.add(line)
        

    def construct(self):
    
        # large debug print to debug which language this scene is rendered with
        print("##################################################################")
        print(f"\033[91mRendering scene {self.__class__.__name__} with locale \033[92m{self.current_locale()}\033[0m", flush=True)
        print("##################################################################", flush=True)

        self.add_basic_rectangles()
        self.camera.background_color = c_bg
        
        
        #if the environmentvariable SPEECH_SERVICE is set, always use this service, otherwise the defeault specified below
        if os.environ.get('SPEECH_SERVICE') == 'aws':
            speechs = AWSPollyService()
        elif os.environ.get('SPEECH_SERVICE') == 'elevenlabs':
            speechs = ElevenlabsVoiceoverService(should_use_history = True)
        else:
            ##################################################################
            ##################################################################
            ##################################################################
            ################# Manually modify? BELOW!!!! #####################
            ##################################################################
            ##################################################################
            ##################################################################
            speechs = ElevenlabsVoiceoverService(should_use_history = True)
            # optionally use this. 
            # speechs = AWSPollyService()
        
        # set speech service
        self.set_speech_service(speechs)

    def voiceover(self, text: str = None, ssml: str = None, **kwargs):
        if (len(text) > 2145 and not "subcaption" in kwargs): # noone knows from where this number comes from, but it seems to be the (a?) limit
            raise Exception("Try to call voiceover with subcaption='NOT AVAILABLE DUE TO BUG' (no empty value!) again, because the text is too long which raises some exceptions in manim-voiceover, which seems to be a bug with manim-voiceover…")
        return super().voiceover(text, ssml, **kwargs)
    
    #Functions used in Scenes:
    #Movement-Related

    #Smoothly move an object to a new position
    #TO BE REMOVED
    def move_smooth(self, obj, end_point, run_time=1.2):
        start_point=obj.get_center()
        start_point[2] = end_point[2]
        #curve = CurvedArrow(start_point=start_point, end_point=end_point)
        curve = Line(start_point, end_point, color=c1)
        self.play(MoveAlongPath(obj, curve), rate_func=smooth, run_time=run_time)


    #TO BE REMOVED
    def draw_point(self, loc, object, offset, color=c1, rate_func=smooth):
        loc, offset = np.array(loc), np.array(offset)
        self.move_smooth(object, loc+offset, run_time=0.5)
        point  = Dot(color=color).move_to(loc)
        object.add_updater(lambda d: d.move_to(point.get_center()+offset+fg))
        self.play(Write(point))
        object.clear_updaters()
        return point
    
    #TO BE REMOVED
    def fly_out(self, object, run_time=1):
        self.move_smooth(object, outloc, run_time=run_time)


    def pulse(self, object, run_time=1, factor=2):
        self.play(ScaleInPlace(object, factor), run_time=run_time/2)
        self.play(ScaleInPlace(object, 1/factor), run_time=run_time/2)

    #TO BE REMOVED
    def move_curved(self, t1, t2, dest, depth=0.25, run_time=0.4):
                o1, o2 = t1.get_value(), t2.get_value()
                dummy = Circle(stroke_width=0)
                self.add(dummy) 
                def updater(x):
                    eps = 0.0001
                    t2.set_value(o2 -depth*(1-(2*(t1.get_value() - (eps+dest+o1)/2)/(eps+dest-o1))**2))
                dummy.add_updater(updater)
                self.play(t1.animate(run_time=run_time).set_value(dest))
                self.remove(dummy)

    #TO BE REMOVED
    def circle(self, radius, iterations=3, run_time=1.5):
        x,y = self.cx.get_value()-radius, self.cy.get_value()
        angle = ValueTracker(0)
        self.add(angle)
        circ = Circle(stroke_width=0).add_updater(lambda m: self.cx.set_value(x+radius*np.cos(angle.get_value()))).add_updater(lambda m: self.cy.set_value(y+radius*np.sin(angle.get_value())))
        self.add(circ)
        for idx in range(iterations):
            self.play(angle.animate.set_value(2*(idx+1)*PI), run_time=run_time, rate_func=linear)
        self.remove(circ, angle)




        
    #TO BE REMOVED
    #Creating Things
    def draw_line(self, a, b, object, offset, color=GREY, run_time=2, rate_func=smooth, linetype="Line"):
        a, b, offset = np.array(a), np.array(b), np.array(offset)
        self.move_smooth(object, a+offset, run_time=0.5)
        path = Line(a+offset+fg, b+offset+fg)
        line = VMobject().move_to(a)
        self.add(line)
        if linetype=="Line":
            line.add_updater(lambda x: x.become(Line(a, object.get_center()-offset-fg, color=color)))
        elif linetype=="DashedLine":
            line.add_updater(lambda x: x.become(DashedLine(a, object.get_center()-offset-fg, dash_length=0.05, dashed_ratio=0.5, color=color)))
        self.play(MoveAlongPath(object, path), rate_func=rate_func, run_time=run_time)
        line.clear_updaters()
        if linetype=="Line":
            line2 = Line(path.get_start()-fg, path.get_end()-fg, color=color).move_to(line)
        elif linetype=="DashedLine":
            line2 = DashedLine(path.get_start()-fg, path.get_end()-fg, dash_length=0.05, dashed_ratio=0.5, color=color).move_to(line)
        self.add(line2)
        self.remove(line)
        return line2
    
    #TO BE REMOVED
    def draw_func(self, cords, func, object, offset, color=c1, run_time=2, stroke_width=3, rate_func=linear):
        object.add_updater(lambda m: m.move_to(func.get_end()+offset))
        func = cords[0].plot(func, color=color, stroke_width=stroke_width)
        self.play(Write(func), run_time=run_time, rate_func=rate_func)
        object.clear_updaters()
        return func
        



    def add_title(self, title="Title of a SophiaScene", tex=True):
        font_size = fs1 if len(title) < 12 else (fs2 if len(title) < 20 else fs3)
        title = Text(title, font_size=font_size, color=c1, font=font_0).to_edge(UP) if not tex else Tex(title, font_size=font_size, color=c1).to_edge(UP)
        title = title.scale(min(3.2/title.get_width(), 0.4/title.get_height()))
        self.add(title)
        return title
        
    def add_cords(self, x_range = [-1,1,1], y_range = [-1,1,1], x_ticks=[-1,0,1], y_ticks=[-1,0,1], x_labels = None, y_labels = None, width=2.4, height=2.4, axisLabelX='x', axisLabelY='y', tip_x=StealthTip, tip_y=StealthTip):

        if x_labels is None:
            x_labels = x_ticks
        if y_labels is None:
            y_labels = y_ticks
            

        cords = VGroup()
        num_x_ticks = len(x_ticks) - 1
        num_y_ticks = len(y_ticks) - 1
        max_ticks = max(num_x_ticks, num_y_ticks)
        unit_size_x = width / num_x_ticks
        unit_size_y = height / num_y_ticks
        x_length = num_x_ticks * unit_size_x
        y_length = num_y_ticks * unit_size_y

        # Adjust y_length to ensure y-axis has length 2.4
        if max_ticks == num_y_ticks:
            y_length = height

        plane = NumberPlane(x_range=x_range, y_range=y_range, x_length=x_length, y_length=y_length, background_line_style={"stroke_opacity": 0}, axis_config={"include_tip": True, 'tip_width': 0.15, 'tip_height': 0.1}).move_to(np.array([0,1.4,0]))
        plane.color=BLACK
        plane.x_axis.add_ticks()
        plane.y_axis.add_ticks()
        #plane.unit_size = unit_size
        cords.add(plane)
        if x_range[0] <= 0:
            cords.add(Tex('0', color=c1, font_size=fs3).move_to(plane.x_axis.n2p(0)).shift(0.2*DOWN+0.2*RIGHT))

        for idx, tick in enumerate(x_ticks):
            if tick != 0:
                cords.add(MathTex(x_labels[idx], color=c1, font_size=fs3).move_to(plane.x_axis.n2p(tick)).shift(0.2*DOWN))
        for idx, tick in enumerate(y_ticks):
            if tick != 0:
                cords.add(MathTex(y_labels[idx], color=c1, font_size=fs3).move_to(plane.y_axis.n2p(tick)).shift(0.2*LEFT))

        cords.add(plane.get_x_axis_label(Tex(axisLabelX, color=c1, font_size=fs3))) if axisLabelX is not None else None
        cords.add(plane.get_y_axis_label(Tex(axisLabelY, color=c1, font_size=fs3))) if axisLabelY is not None else None
        # if axisLabelX is not None: 
        #     xlabel = Tex(axisLabelX, color=c1t, font_size=fs3).next_to(plane.x_axis, DOWN, buff=0.2)
        #     xlabel = xlabel.scale(min(1,0.6*plane.x_axis.get_width()/xlabel.get_width()))
        #     cords.add(xlabel)
        # if axisLabelY is not None:
        #     ylabel = Tex(axisLabelY, color=c1t, font_size=fs3).next_to(plane.y_axis, UP, buff=0.2)
        #     ylabel = ylabel.scale(min(1,0.6*plane.y_axis.get_height()/ylabel.get_height()))
        #     cords.add(ylabel)

        return cords


    #TO BE REMOVED
    def equation_parts(self, parts, colors=c1, font_size=fs2, **kwargs):
        if type(colors)==str or type(colors)==type(rgb_to_color([0,0,0])):
            colors = [colors]*len(parts)
        elements = [MathTex(parts[0], color=colors[0], font_size=font_size, **kwargs) if type(parts[0])==str else parts[0]]
        for idx, part in enumerate(parts[1:]):
            if type(part)==str:
                elements.append(MathTex(part, color=colors[1+idx], font_size=font_size, **kwargs).next_to(elements[-1], 0.35*RIGHT))
            elif type(part)==Tex or type(part)==DecimalNumber:
                elements.append(part.next_to(elements[-1], 0.35*RIGHT))
            else:
                raise Exception("Type of part not supported")
        return VGroup(*elements)#, elements
    

    def transition_to_question(self, question, choices, idx_logged=0, idx_correct=0, fontsizeQ=fs2, fontsizeChoices=fs2):
        all_elements = VGroup(*[x for x in self.mobjects if isinstance(x, VMobject)][2:])
        for element in all_elements:
            element.clear_updaters()

        rectangles=VGroup(*[RoundedRectangle(height=0.8, width=3.5, corner_radius=0.2, color=c1, fill_opacity=0.2).move_to([0, -10-choices.index(choice), 0]) for choice in choices])
        rectangles.add(*[MathTex(choices[idx], color=c1, font_size=fontsizeChoices).move_to(rectangles[idx]) for idx in range(len(choices))])
        self.add(rectangles)

        q = Tex(question, color=c1, font_size=fontsizeQ).move_to([-10,3.2,0])

        self.play(rectangles.animate.shift(UP*10), all_elements.animate.shift(UP*10), q.animate.shift(RIGHT*10), run_time=1.5)
        self.wait(5)
        self.play(rectangles[idx_logged].animate.set_color(YELLOW), run_time=0.5)
        self.wait(2)
        if idx_logged != idx_correct:
            self.play(rectangles[idx_logged].animate.set_color(RED), rectangles[idx_correct].animate.set_color(GREEN), run_time=1)
        else:
            self.play(rectangles[idx_logged].animate.set_color(GREEN), run_time=1)

            
    # The desired final dimensions of the square
    def redraw_square(self):
        newloc = RIGHT*(self.cx.get_value()+self.cwidth.get_value()/2)+UP*(self.cy.get_value()+self.cheight.get_value()/2)
        self.prevlocs = [newloc, self.prevlocs[0], self.prevlocs[1]]
        rect = RoundedRectangle(color=RED, height=self.cheight.get_value(), width=self.cwidth.get_value(), corner_radius=0.1,
                            fill_opacity = self.fill_opacity, stroke_width=0).shift(newloc)
        return rect

    #TO BE REMOVED
    def add_cursor(self, color=RED, bg_opacity=0.4):
            self.cheight, self.cwidth = ValueTracker(0.2), ValueTracker(0.2)
            self.cx, self.cy = ValueTracker(0), ValueTracker(0)
            self.prevlocs = [RIGHT, RIGHT, RIGHT]


            def updater(mob, dt):
                if max(mob.height, mob.width)>=0.201:
                    self.fill_opacity = max(bg_opacity, math.exp(-2.5 * (max(mob.height, mob.width) - bg_opacity)))
                    self.bring_to_back(mob)
                    return
                if self.blinking==0 or not np.array_equal(self.prevlocs[0],self.prevlocs[1]) or not np.array_equal(self.prevlocs[1],self.prevlocs[2]):
                    self.fill_opacity = 1
                    mob.time_passed = 0
                    self.bring_to_front(mob)
                    return
                mob.time_passed += dt
                if mob.time_passed >= 0.6:
                    mob.time_passed -= 0.6
                    self.bring_to_front(mob)
                    if self.blinking==2:
                        self.fill_opacity = 1 if self.fill_opacity==0 else 0
                    else:
                        1 if self.fill_opacity ==0 else 0


            updated_square = Square()
            updated_square = always_redraw(self.redraw_square)
            updated_square.time_passed = 0
            updated_square.add_updater(updater)

            return updated_square
    
    ###################
    ####Sounds#########
    ###################
    def _get_sound_file(self, sound_file_name: str) -> str:
        return str(SCENES_ASSETS_FOLDER / "sounds" / f"{sound_file_name}.wav")
    
    def add_stretched_sound(self, sound_name: str, target_duration: float, target_volume: float = 1.0, reverse: bool = False, rate_func: Optional[Callable[[float],float]] = None, repeat_count: Optional[int] = 0):
        print(f"Adding stretched sound {sound_name} with target duration {target_duration}", flush=True)
        # create the temporary stretched version of the sound file
        temp_audio_file = create_temporary_stretched_audio_file(self._get_sound_file(sound_name), target_duration, target_volume, reverse, rate_func, repeat_count)

        # add the stretched sound to the scene
        self.add_sound(temp_audio_file)

    def add_stretched_sounds(self, sound_configs: List[StretchedAudioFileConfig]): 
        # if a single sound config input file is not a path, then it is a sound name so we need to convert it to a path using the _get_sound_file method
        for sound_config in sound_configs:
            if not isinstance(sound_config.input_file, Path):
                sound_config.input_file = self._get_sound_file(sound_config.input_file)
        temp_audio_file = create_combined_temporary_stretched_audio_file_from_configs(sound_configs)
        self.add_sound(temp_audio_file)


    def add_scale_sound(self, direction: UnionType[Literal["up"], Literal["down"]], duration=0.5, rate_func=smooth):
        self.add_stretched_sound("swipe-zoom-short", duration, target_volume=0.06, reverse=(direction=="down"), rate_func=rate_func)
    
    def add_move_sound(self, direction: UnionType[Literal["forward"], Literal["backward"]], duration=0.5, rate_func=smooth, target_volume=0.3):
        self.add_stretched_sound("jump", duration, target_volume=target_volume, reverse=(direction=="backward"), rate_func=rate_func)

    def add_reflect_sound(self, duration=0.5, rate_func=smooth):
        self.add_stretched_sound("huuup", duration, target_volume=0.1, rate_func=rate_func)

    def add_shift_sound(self, duration=0.5, rate_func=smooth):
        self.add_stretched_sound("shift", duration, target_volume=0.8, rate_func=rate_func )

    def add_cursor_sound(self, duration=0.3, rate_func=smooth):
        self.add_stretched_sound("cursor", duration, target_volume=0.2, rate_func=rate_func )

    def add_pencil_sound(self, duration=0.5, rate_func=smooth):
        self.add_stretched_sound("pencil", duration*0.6, target_volume=0.4, rate_func=rate_func )

    def add_bubble_sound(self, duration=0.5, rate_func=smooth):
        self.add_stretched_sound("bubble", duration, target_volume=0.3, rate_func=rate_func )

    ###################
    ####Drawings#######
    ###################
    def draw_smile(self, cursor, loc, happy=True, run_time=1.5):

        sq = lambda : Square(side_length=0.2, color=RED, fill_color=RED, fill_opacity=1).shift([-0.1,-0.1,0])
        c = lambda : Circle(radius=0.1, fill_color=RED, fill_opacity=1, color=RED).shift([-0.1,-0.3,0])

        eL = c().shift(LEFT*0.7)
        eR = c().shift(RIGHT*0.9)
        mouth = ArcBetweenPoints(LEFT+DOWN, RIGHT+DOWN, stroke_color=RED, stroke_width=12, angle=(2*(happy)-1)*2/3*PI).shift(DOWN*0.6*(1-happy))
        smile = VGroup(eL, eR, mouth).move_to(loc)
        circ = c().move_to(cursor.get_center())
        self.add(circ)
        cursorCopy = cursor.copy()
        self.remove(cursor)
        self.play(circ.animate.move_to(eL), run_time=0.2*run_time)
        self.add(eL)
        self.play(circ.animate.move_to(eR), run_time=0.2*run_time)
        self.add(eR)
        self.play(circ.animate.move_to(mouth.get_start()), run_time=0.2*run_time)
        circ.add_updater(lambda x: x.move_to(mouth.get_end()))
        self.play(Create(mouth), run_time=0.2*run_time)
        self.add(cursorCopy.move_to(circ))
        self.remove(circ)
        self.add(cursorCopy)
        return cursorCopy, smile
    
    def draw_qmark(self, cursor, loc=ORIGIN, run_time=1.5, apply_waves=2, wave_time=1):

        sq = lambda : Square(side_length=0.2, color=RED, fill_color=RED, fill_opacity=1).shift([-0.1,-0.1,0])
        c = lambda : Circle(radius=0.1, fill_color=RED, fill_opacity=1, color=RED).shift([-0.1,-0.3,0])
        Qmark = VGroup(sq().shift(UP*0.8+LEFT*0.2), sq().shift(UP), sq().shift(UP*0.8+RIGHT*0.2), sq().shift(UP*0.6+RIGHT*0.2), sq().shift(UP*0.4), sq().shift(UP*0.3), c().shift([0,-0.1,0])).move_to(loc)
        
        self.play(cursor.animate.move_to(Qmark[0]), run_time=0.2*run_time)
        circ = c().move_to(cursor)
        self.add(circ)

        for idx in range(6):
            self.play(ReplacementTransform(circ, Qmark[idx]), run_time=0.1*run_time)
            circ = c().move_to(Qmark[idx])
        
        self.play(circ.animate.move_to(Qmark[-1]), run_time=0.2*run_time)

        for _ in range(apply_waves):
            self.play(ApplyWave(circ), run_time=wave_time)

        
        cursor.move_to(Qmark[-1])
        self.remove(circ)

        return Qmark
    
    def draw_decorative_line(self, cursor, downshift = 0, run_time = 2):

        sq = lambda : Square(side_length=0.2, color=RED, fill_color=RED, fill_opacity=1, stroke_width=0)
        c = lambda : Circle(radius=0.1, fill_color=RED, fill_opacity=1, color=RED, stroke_width=0).shift([-0.1,-0.3,0])

        decoration1 = VGroup(*[sq().shift([-2.1+0.4*idx,0.1,0]) for idx in range(12)]).shift(DOWN*downshift)
        decoration2 = VGroup(*[sq().shift([-1.9+0.4*idx,-0.1,0]) for idx in range(12)]).shift(DOWN*downshift)
        decoration = VGroup(*decoration1, *decoration2)

        cursor.blinking=False
        self.play(cursor.animate.move_to(decoration1[0]), run_time=0.2*run_time)

        circ = c().move_to(decoration1[0])
        self.add(circ)
        cursor.move_to(decoration2[-1])
        for idx in range(12):
            self.play(ReplacementTransform(circ, decoration1[idx]), run_time=0.1*run_time)
            self.play(ReplacementTransform(c().move_to(decoration1[idx]), decoration2[idx]), run_time=0.1*run_time)
            circ = c().move_to(decoration2[idx])

        cursor.move_to(decoration1[-1])

        return decoration
        

    

# class Cursor(Mobject):
#     def __init__(self, scene, color=RED, bg_opacity=0.4, blinking=True, stroke_width=0, fill=True, **kwargs):
#         super().__init__(**kwargs)
#         self.scene = scene
#         self.cheight = ValueTracker(0.2)
#         self.cwidth = ValueTracker(0.2)
#         self.cx = ValueTracker(0)
#         self.cy = ValueTracker(0)
#         self.fill_opacity = 1
#         self.blinking = blinking
#         self.color = color
#         self.bg_opacity = bg_opacity
#         self.stroke_width = ValueTracker(stroke_width)
#         self.fill = fill
#         self.override_fill = ValueTracker(-1)
#         self.force_foreground=False

#         #This function updates the values from which the rectangle is built
#         def updater(mob, dt):
#             if self.force_foreground:
#                 scene.bring_to_front(mob)
#             #Deal with Larger Rectangles: Opacity depends on size
#             if self.override_fill.get_value() != -1:
#                 self.fill_opacity = self.override_fill.get_value()
#                 return
#             if max(mob.height, mob.width) >= 0.201:
#                 self.fill_opacity = max(self.bg_opacity, math.exp(-2.5 * (max(mob.height, mob.width) - self.bg_opacity)))
#                 if not self.force_foreground:
#                     scene.bring_to_back(mob)
#                 return
#             #If it doesn't blink, it's filled
#             if not self.blinking:
#                 self.fill_opacity = 1
#                 mob.time_passed = 0
#                 scene.bring_to_front(mob)
#                 return
            
#             else:
#                 mob.time_passed += dt
#                 if mob.time_passed >= 0.6:
#                     mob.time_passed -= 0.6
#                     scene.bring_to_front(mob)
#                     self.fill_opacity = 1 if self.fill_opacity == 0 else 0

#         self.square = Square()
#         self.square = always_redraw(self.redraw_square)
#         self.square.time_passed = 0
#         self.square.add_updater(updater)

#         self.add(self.square)

#     def redraw_square(self):
#         rect = RoundedRectangle(
#             color=self.color,
#             height=self.cheight.get_value(),
#             width=self.cwidth.get_value(),
#             corner_radius = min(0.1, min(self.cheight.get_value(), self.cwidth.get_value())/2),
#             fill_opacity=self.fill_opacity*self.fill,
#             stroke_width=self.stroke_width.get_value()
#         ).move_to([self.cx.get_value(), self.cy.get_value(), 0])
#         return rect
    
    #DEPRECATED, DO NOT USE
    # def move_curved(self, t1, t2, dest, depth=0.25, run_time=0.4):
    #     o1, o2 = t1.get_value(), t2.get_value()
    #     dummy = Circle(stroke_width=0)
    #     self.add(dummy) 
    #     def updater(x):
    #         eps = 0.0001
    #         t2.set_value(o2 -depth*(1-(2*(t1.get_value() - (eps+dest+o1)/2)/(eps+dest-o1))**2))
    #     dummy.add_updater(updater)
    #     self.scene.play(t1.animate(run_time=run_time).set_value(dest))
    #     self.remove(dummy)

    # def curved_updater(self, dest, t1=None, t2=None, depth=0.25):
    #     if t1==None:
    #         t1 = self.cx
    #     if t2==None:
    #         t2 = self.cy
    #     o1, o2 = t1.get_value(), t2.get_value()
    #     dummy = Circle(stroke_width=0)
    #     self.scene.add(dummy) 
    #     def updater(x):
    #         eps = 0.0001
    #         t2.set_value(o2 -depth*(1-(2*(t1.get_value() - (eps+dest+o1)/2)/(eps+dest-o1))**2))
    #     dummy.add_updater(updater)
    #     return dummy


    # def circle_updater(self, radius=0.2):
    #     ## USAGE EXAMPLE: ##
    #     # circ, angle = cursor.circle_updater(0.35)
    #     # for idx in range(3):
    #     #     self.play(angle.animate.set_value(2*(idx+1)*PI), run_time=0.5, rate_func=linear)
    #     # self.remove(circ, angle)
    #     ##  END OF EXAMPLE ##
    #     x,y = self.cx.get_value()-radius, self.cy.get_value()
    #     angle = ValueTracker(0)
    #     self.scene.add(angle)
    #     circ = Circle(stroke_width=0).add_updater(lambda m: self.cx.set_value(x+radius*np.cos(angle.get_value()))).add_updater(lambda m: self.cy.set_value(y+radius*np.sin(angle.get_value())))
    #     self.scene.add(circ)
    #     return circ, angle
    
class AltCursor(RoundedRectangle):
    DEFAULT_SIZE = 0.2
    DEFAULT_CURSOR_OPACITY = 1.0
    DEFAULT_CURSOR_OPACITY_IN_BACKGROUND = 0.4
    def __init__(self, 
                 width=DEFAULT_SIZE,
                 height=DEFAULT_SIZE,
                 corner_radius=DEFAULT_SIZE/2.0,
                 x=0,
                 y=0,
                 color=RED, 
                 fill_opacity=DEFAULT_CURSOR_OPACITY, 
                 blinking=False,
                 stroke_width=0,
                 idle = False,
                 autoFadeBackground = True,
                 **kwargs):
        
        super().__init__(corner_radius=corner_radius, 
                         height=height, 
                         width=width, 
                         color=color, 
                         fill_opacity=fill_opacity,  
                         stroke_width=stroke_width,
                         **kwargs)
        self.move_to([x,y,0])
        self.blinking = blinking
        self.initial_fill_opcacity = fill_opacity
        # self._setup_blinking()
        self._setup_idle()
        self.autoFadeBackground = autoFadeBackground
        self.needSound = False
        self.idle = idle
    
    def animationTo(self, dest, run_time=1, rate_func=linear):
        return ApplyMethod(self.move_to, dest, run_time=run_time, rate_func=rate_func)

    def changeForm(self, 
                width = None, 
                height = None, 
                corner_radius = None,
                x = None,
                y = None,
                fill_opacity = None, 
                color = None, 
                stroke_width = None,
                idle = None,
                **kwargs
                ):
        if corner_radius is None:
            corner_radius = self.corner_radius
        if x is None:
            x = self.get_center()[0]
        if y is None:
            y = self.get_center()[1]
        if width is None:
            width = self.width
        if height is None:
            height = self.height
        if fill_opacity is None:
            fill_opacity = self.fill_opacity
        if self.autoFadeBackground and fill_opacity!=0 and not self.idle:
            fill_opacity = max(self.DEFAULT_CURSOR_OPACITY_IN_BACKGROUND, math.exp(-2.5 * (max(height, width) - self.DEFAULT_CURSOR_OPACITY_IN_BACKGROUND)))
        if color is None:
            color = self.color
        if stroke_width is None:
            stroke_width = self.stroke_width
        if idle is None:
            idle = self.idle


        newCursor = AltCursor(x=x, 
                              y=y, 
                              width=width,
                              height=height,
                              corner_radius=corner_radius,
                              fill_opacity=fill_opacity, 
                              color=color,
                              blinking=self.blinking,
                              stroke_width=stroke_width,
                              idle = self.idle,
                              **kwargs,
                              )
        newCursor.initial_fill_opcacity = self.initial_fill_opcacity
        self.become(newCursor)

        

    def animationToForm(self, 
                        width,
                        height, 
                        corner_radius,
                        x = None,
                        y = None,
                        fill_opacity = None, 
                        color = None, 
                        ):
        return ApplyMethod(self.changeForm, width, height, corner_radius, x, y, fill_opacity, color)
    
    def setBlinking(self, blinking):
        self.blinking = blinking

    def _setup_blinking(self):
        self.time_passed = 0
        self.isHidden = False

        def _blinking_updater(mob: AltCursor, dt: float):

            if mob.blinking:
                mob.time_passed += dt
                if mob.time_passed >= 0.6:
                    mob.time_passed -= 0.6
                    mob.isHidden = not mob.isHidden
                    if not mob.isHidden:
                        self.needSound = True
                    mob.changeForm(fill_opacity=0 if mob.isHidden else mob.initial_fill_opcacity)

            elif mob.isHidden: # reset not required if not blinking and already visible
                mob.changeForm(fill_opacity=mob.initial_fill_opcacity)
                mob.time_passed = 0
                mob.isHidden = False
        self.add_updater(_blinking_updater)


    def set_idle(self, idle):
        self.idle = idle
    
    def _setup_idle(self):
        self.time_passed = 0

        last_idle_state = [False]  # Using a list to store the state

        def _idle_updater(mob: AltCursor, dt: float):
            idle_interval = 2  # Adjust as per your requirement

            if mob.idle:
                if not last_idle_state[0]:  # i.e., if mob.idle has been changed from False to True
                    mob.time_passed = 0  # Resetting time_passed as mob.idle is True now
                mob.time_passed += dt  # Incrementing time_passed
                # Calculate the new fill_opacity
                new_opacity = max(c_bg_opacity, c_fg_opacity - (c_fg_opacity - c_bg_opacity) * (mob.time_passed / idle_interval))
                mob.changeForm(fill_opacity=new_opacity)
            else:
                mob.changeForm(fill_opacity=c_fg_opacity)

            # Update the last_idle_state list with the current idle state of the mob.
            last_idle_state[0] = mob.idle



        self.add_updater(_idle_updater)





    def _start_fading(self, time):

        def _fade_updater(mob, dt):
            mob.fade_passed += dt
            mob.set_opacity(max(0,1-mob.fade_passed/mob.fade_time))

        self.fade_time = time
        self.fade_passed = 0
        self.blinking=False
        self.add_updater(_fade_updater)

        return self


class CursorPositionTracker:
    def __init__(self, cursor: AltCursor, pos_func: Callable[[], List[float]]):
        self.cursor = cursor
        self.pos_func = pos_func

    def __enter__(self):
        def update_cursor_position(mob, dt):
            pos = self.pos_func()
            mob.changeForm(x=pos[0], y=pos[1])

        self.updater = update_cursor_position
        self.cursor.add_updater(self.updater)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.cursor.remove_updater(self.updater)
    
class CursorMoveTo(ApplyMethod):
    def __init__(self, cursor, x, y, run_time=1, rate_func=smooth, **kwargs):
        if x is None:
            x = cursor.get_center()[0]
        if y is None:
            y = cursor.get_center()[1]
        
        super().__init__(cursor.move_to, [x,y,cursor.get_center()[2]], run_time=run_time, rate_func=rate_func, **kwargs)
        self.cursor = cursor
        self.x = x
        self.y = y

class CursorMoveToCurved(CursorMoveTo):
    def __init__(self, cursor, x, y, run_time=1, path_arc=PI/2, rate_func=smooth,  **kwargs):

        if cursor.get_x() > x:
            path_arc *= -1
        super().__init__(cursor, x, y, run_time=run_time, rate_func=rate_func, path_arc=path_arc, **kwargs)
        self.cursor = cursor
        self.x = x
        self.y = y

class CursorMarkAxis(ApplyMethod):
    def __init__(self, cursor: AltCursor, plane, axis='x', autoFadeBackground=False, moveToBackground=False, **kwargs):

        if axis == 'x':
            x,y,_ = plane.x_axis.get_center()
            width = plane.x_axis.get_width()+0.2
            height = 0.3
        elif axis == 'y':
            x, y, _ = plane.y_axis.get_center()
            width = 0.3
            height = plane.y_axis.get_height()+0.2
        else:
            raise ValueError("axis must be 'x' or 'y'")
        self.cursor = cursor
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.autoFadeBackground = autoFadeBackground
        self.moveToBackground = moveToBackground

        self.fill_opacity = cursor.DEFAULT_CURSOR_OPACITY
        if self.autoFadeBackground and max(self.height, self.width) >= 0.201:
            self.fill_opacity = max(cursor.DEFAULT_CURSOR_OPACITY_IN_BACKGROUND, math.exp(-2.5 * (max(self.height, self.width) - cursor.DEFAULT_CURSOR_OPACITY_IN_BACKGROUND)))
        
        super().__init__(cursor.changeForm, width, height, None, x, y, self.fill_opacity, None, None, **kwargs)

class CursorMoveResize(ApplyMethod):
    def __init__(self, cursor: AltCursor, x,y, width, height, autoFadeBackground=False, moveToBackground=False, **kwargs):
        if x is None:
            x = cursor.get_center()[0]
        if y is None:
            y = cursor.get_center()[1]
        self.cursor = cursor
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.autoFadeBackground = autoFadeBackground
        self.moveToBackground = moveToBackground

        self.fill_opacity = cursor.DEFAULT_CURSOR_OPACITY
        if self.autoFadeBackground and max(self.height, self.width) >= 0.201:
            self.fill_opacity = max(cursor.DEFAULT_CURSOR_OPACITY_IN_BACKGROUND, math.exp(-2.5 * (max(self.height, self.width) - cursor.DEFAULT_CURSOR_OPACITY_IN_BACKGROUND)))
        
        super().__init__(cursor.changeForm, width, height, None, x, y, self.fill_opacity, None, None, **kwargs)


    def _setup_scene(self, scene: Scene) -> None:
        if self.moveToBackground:
            scene.bring_to_back(self.cursor)
        
        super()._setup_scene(scene)
    

class CursorResizeDefault(ApplyMethod):
    def __init__(self, cursor: AltCursor, run_time, **kwargs):
        super().__init__(cursor.changeForm, cursor.DEFAULT_SIZE, cursor.DEFAULT_SIZE, cursor.DEFAULT_SIZE/2.0, None, None, cursor.DEFAULT_CURSOR_OPACITY, None, None, run_time=run_time, **kwargs)
        self.cursor = cursor

    def _setup_scene(self, scene: Scene) -> None:
        scene.bring_to_front(self.cursor) # to front always!
        super()._setup_scene(scene)


class CursorPositionTracking(Animation):
    def __init__(self, cursor, pos: Callable[[], list], **kwargs):
        super().__init__(cursor, **kwargs)
        self.cursor = cursor
        self.pos = pos

    def interpolate_mobject(self, alpha):
        currentPos = self.pos()
        self.cursor.changeForm(x=currentPos[0], y=currentPos[1])


class SophiaCursorScene(SophiaScene):
    def playInBackground(self, animation: Animation, run_time=None):
        if run_time is not None:
            animation = animation.set_run_time(run_time)
        turn_animation_into_updater(animation)



def format_text_group(texts, color = c1t, buff=0.4, buff_inner = 0.1, font_size=fs4):
    texts_formatted = []

    for text in texts:
        if isinstance(text, list):
            # If the element is a sublist, format its elements with low distance
            sublist = [Tex(sub_text, font_size=font_size, color=color) for sub_text in text]
            sublist_group = Group(*sublist).arrange(DOWN, aligned_edge=LEFT, buff=buff_inner)
            texts_formatted.append(sublist_group)
        else:
            # If the element is a string, format it with medium distance
            string = Tex(text, font_size=font_size, color=color)
            texts_formatted.append(string)

    # Group all formatted elements and arrange them with medium distance
    texts_group = Group(*texts_formatted).arrange(DOWN, aligned_edge=LEFT, buff=buff)

    return texts_group

class Notepad(Group):


    def __init__(self,
                 texts = None,
                 buff = 0.4,
                 buff_inner = 0.1,
                 primary_color = c1t,
                 secondary_color = c2,
                 *mobjects,
                 **kwargs):
        super().__init__(*mobjects, **kwargs)
        self.notepad = ImageMobject(assets_folder / "img" / "paper.png").scale(0.95).move_to([0,-2.4,0])
        self.texts = texts
        self.buff = buff
        self.buff_inner = buff_inner
        self.primary_color = Text("").set_color(primary_color).get_color(),
        self.secondary_color = Text("").set_color(secondary_color).get_color()
        self.add(self.notepad)
        
        if self.texts is not None:
            self.texts = format_text_group(self.texts, buff=self.buff).move_to(self.notepad)
            self.add(self.texts)

    def switch_texts(self, texts):
        self.remove(self.texts)
        self.texts = format_text_group(texts, buff=self.buff).move_to(self.notepad)
        self.add(self.texts)

    def change_colors(self, idcs, colors=None):
        if colors is None:
            for idx in idcs:
                if isinstance(self.texts[idx], Group):
                    for subidx in range(len(self.texts[idx])):
                        self.texts[idx][subidx].set_color(self.primary_color if self.texts[idx][subidx].get_color()==self.secondary_color else self.secondary_color)                   
                else:
                    self.texts[idx].set_color(self.primary_color if self.texts[idx].get_color()==self.secondary_color else self.secondary_color)
        else:       
            for idx in idcs:
                self.texts[idx].set_color(colors[idx])


class Bubble(VGroup):

    def __init__(self, texts, width=2, height=1, corner_radius=1/4, center=ORIGIN, start_point = [0,-1.2,0], run_time=2, color=BLACK, loc = "b1"):
        super().__init__()

        #set up the text
        self.text = VGroup(*[Tex(text, color=c1t, font_size=fs3) for text in texts]).arrange(DOWN, buff=0.1, aligned_edge=LEFT).move_to(center)
        self.text.scale(min(width/self.text.get_width(), height/self.text.get_height())*0.8)

        #Preparations for rectangle and line
        loc = "l2" if "r2" in loc else "r2" if "l2" in loc else loc
        switch_hw = True if 'b' in loc or 't' in loc else False
        if switch_hw:
            width, height = height, width
        rotate = 90 if 't' in loc else 180 if 'l' in loc else 270 if 'b' in loc else 0
        flip = True if '2' in loc else False

        #set up the rectangle and line
        self.rect = RoundedRectangle(width=width, height=height, corner_radius=1/4, color=BLACK).rotate(rotate*DEGREES).shift(center)
        if flip:
            self.rect.flip()
        self.line = Line(start_point, self.rect.get_start(), color=color)
        self.bubble = VGroup(self.line, self.rect)
        self.add(self.line, self.rect)

    def get_end(self):
        return self.line.get_end() if not np.linalg.norm(self.rect.get_end()-self.rect.get_start())>0.00001 else self.rect.get_end()
    
    def get_center(self):
        return self.rect.get_center()
    
class Updown_Arrow(Line):


    ### TODO: Make it work with the tip
    def __init__(self, origin_loc=ORIGIN, vert=True, **kwargs):
        perturb = [0,0.0000001,0]
        super().__init__(start=origin_loc+perturb, end=origin_loc, **kwargs)
        self.vert = vert
        # self.add_tip()
        # tip = self.get_tip()
        self.origin_loc = origin_loc
        self.add_updater(self.update_color)
        # self.add_updater(self.update_tip)

    def update_color(self, dt, arrow):
        if self.vert:
            if self.get_y()>self.origin_loc[1]:
                self.set_color(GREEN)
            else:
                self.set_color(RED)
        else:
            if self.get_x()<self.origin_loc[0]:
                self.set_color(GREEN)
            else:
                self.set_color(RED)
        # print(self.get_length())

    def update_tip(self, dt, arrow):
        if self.get_length()<0.05:
            self.tip.length=self.get_length()
            self.tip.move_to(self.get_end())
        else:
            self.tip.length=0.05
            self.tip.move_to(self.get_end())




# The folder where the assets are stored, include here for compatibility with the old version
assets_folder = SCENES_ASSETS_FOLDER
sophialib/sophialib/styles/sophiascene.py
Sophia-Edu-Labs/sophia-math
from pathlib import Path
from manim import *
import urllib.request
import manimpango

SOPHIALIB_FONT_FOLDER = Path(__file__).parent / "fonts"
SOPHIALIB_MEDIA_FOLDER = Path(__file__).parent / "media"

#Colors for lines, points etc.
c1 = BLACK
c2 = RED
c3 = BLUE
c4 = ORANGE
c5 = PURPLE
c6 = GREEN

#Colors for the Text
c1t = BLACK
c2t = GRAY_E
c3t = GRAY_D

fs1 = 48
fs2 = 36
fs3 = 24
fs4 = 18
fs5 = 12
#Fonts
font_0 = ""

#Colors for the Background, delimiting Rectangles, Orientation lines and the Mathgrid
c_bg = rgb_to_color([255/255, 252/255, 245/255])
c_rects = BLACK
c_or = GREEN
c_mathgrid = GRAY_B

#Location for the pointers etc. to rest
outloc = [-3.5,0,0]

#Offset for the pointers etc.
fg = np.array([0,0,1000])

class EmojiSVGMobject(SVGMobject):
    def __init__(self, emoji, **kwargs):
        emoji_code = "-".join(f"{ord(c):x}" for c in emoji)
        url = f"https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg/{emoji_code}.svg"
        path_svg = Path.cwd() / f"{emoji_code}.svg"
        urllib.request.urlretrieve(url, path_svg)
        SVGMobject.__init__(self, str(path_svg), **kwargs)
        path_svg.unlink()  # delete downloaded svg again locally



c_bg_opacity = .3
c_fg_opacity = 1

# nums = ["Null", "Eins", "Zwei", "Drei", "Vier", "Fünf", "Sechs", "Sieben", "Acht", "Neun",
# "Zehn", "Elf", "Zwölf", "Dreizehn", "Vierzehn", "Fünfzehn", "Sechzehn", "Siebzehn", "Achtzehn", "Neunzehn",
# "Zwanzig", "Einundzwanzig", "Zweiundzwanzig", "Dreiundzwanzig", "Vierundzwanzig", "Fünfundzwanzig", "Sechsundzwanzig",
# "Siebenundzwanzig", "Achtundzwanzig", "Neunundzwanzig", "Dreißig", "Einunddreißig", "Zweiunddreißig", "Dreiunddreißig",
# "Vierunddreißig", "Fünfunddreißig", "Sechsunddreißig", "Siebenunddreißig", "Achtunddreißig", "Neununddreißig",
# "Vierzig", "Einundvierzig", "Zweiundvierzig", "Dreiundvierzig", "Vierundvierzig", "Fünfundvierzig", "Sechsundvierzig",
# "Siebenundvierzig", "Achtundvierzig", "Neunundvierzig", "Fünfzig", "Einundfünfzig", "Zweiundfünfzig", "Dreiundfünfzig",
# "Vierundfünfzig", "Fünfundfünfzig", "Sechsundfünfzig", "Siebenundfünfzig", "Achtundfünfzig", "Neunundfünfzig",
# "Sechzig", "Einundsechzig", "Zweiundsechzig", "Dreiundsechzig", "Vierundsechzig", "Fünfundsechzig", "Sechsundsechzig",
# "Siebenundsechzig", "Achtundsechzig", "Neunundsechzig", "Siebzig", "Einundsiebzig", "Zweiundsiebzig", "Dreiundsiebzig",
# "Vierundsiebzig", "Fünfundsiebzig", "Sechsundsiebzig", "Siebenundsiebzig", "Achtundsiebzig", "Neunundsiebzig",
# "Achtzig", "Einundachtzig", "Zweiundachtzig", "Dreiundachtzig", "Vierundachtzig", "Fünfundachtzig", "Sechsundachtzig",
# "Siebenundachtzig", "Achtundachtzig", "Neunundachtzig", "Neunzig", "Einundneunzig", "Zweiundneunzig", "Dreiundneunzig",
# "Vierundneunzig", "Fünfundneunzig", "Sechsundneunzig", "Siebenundneunzig", "Achtundneunzig", "Neunundneunzig",
# "Hundert"]

nums = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine",
        "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen",
        "Twenty", "Twenty-One", "Twenty-Two", "Twenty-Three", "Twenty-Four", "Twenty-Five", "Twenty-Six",
        "Twenty-Seven", "Twenty-Eight", "Twenty-Nine", "Thirty", "Thirty-One", "Thirty-Two", "Thirty-Three",
        "Thirty-Four", "Thirty-Five", "Thirty-Six", "Thirty-Seven", "Thirty-Eight", "Thirty-Nine",
        "Forty", "Forty-One", "Forty-Two", "Forty-Three", "Forty-Four", "Forty-Five", "Forty-Six",
        "Forty-Seven", "Forty-Eight", "Forty-Nine", "Fifty", "Fifty-One", "Fifty-Two", "Fifty-Three",
        "Fifty-Four", "Fifty-Five", "Fifty-Six", "Fifty-Seven", "Fifty-Eight", "Fifty-Nine",
        "Sixty", "Sixty-One", "Sixty-Two", "Sixty-Three", "Sixty-Four", "Sixty-Five", "Sixty-Six",
        "Sixty-Seven", "Sixty-Eight", "Sixty-Nine", "Seventy", "Seventy-One", "Seventy-Two", "Seventy-Three",
        "Seventy-Four", "Seventy-Five", "Seventy-Six", "Seventy-Seven", "Seventy-Eight", "Seventy-Nine",
        "Eighty", "Eighty-One", "Eighty-Two", "Eighty-Three", "Eighty-Four", "Eighty-Five", "Eighty-Six",
        "Eighty-Seven", "Eighty-Eight", "Eighty-Nine", "Ninety", "Ninety-One", "Ninety-Two", "Ninety-Three",
        "Ninety-Four", "Ninety-Five", "Ninety-Six", "Ninety-Seven", "Ninety-Eight", "Ninety-Nine",
        "Hundred"]


def get_num(x, negation="negative", pos=None):
    def get_decNum(f):
        if int(f)==f:
            return nums[int(f)]
        # Convert float to string and split on decimal point
        int_part, _, frac_part = str(f).partition('.')
        
        # Convert integer part to words
        int_words = nums[int(int_part)]
        
        # Convert fractional part to words
        frac_words = [nums[int(digit)] for digit in frac_part]
        
        # Combine integer and fractional words with the "point" word in between
        return ' '.join([int_words] + ["point"] + frac_words)
    if x>=0:
        if pos is not None:
            return pos + " " + get_decNum(x)
        return get_decNum(x)
    else:
        return negation + " " + get_decNum(-x)
    
def get_texNum(x):
    if x>=0:
        return "+"+str(x)
    return str(x)

# nums_ordinal = ["Nullte", "Erste", "Zweite", "Dritte", "Vierte", "Fünfte", "Sechste", "Siebte", "Achte", "Neunte",
#                "Zehnte", "Elfte", "Zwölfte", "Dreizehnte", "Vierzehnte", "Fünfzehnte", "Sechzehnte", "Siebzehnte", "Achtzehnte", "Neunzehnte",
#                "Zwanzigste", "Einundzwanzigste", "Zweiundzwanzigste", "Dreiundzwanzigste", "Vierundzwanzigste", "Fünfundzwanzigste", "Sechsundzwanzigste",
#                "Siebenundzwanzigste", "Achtundzwanzigste", "Neunundzwanzigste", "Dreißigste", "Einunddreißigste", "Zweiunddreißigste", "Dreiunddreißigste",
#                "Vierunddreißigste", "Fünfunddreißigste", "Sechsunddreißigste", "Siebenunddreißigste", "Achtunddreißigste", "Neununddreißigste",
#                "Vierzigste", "Einundvierzigste", "Zweiundvierzigste", "Dreiundvierzigste", "Vierundvierzigste", "Fünfundvierzigste", "Sechsundvierzigste",
#                "Siebenundvierzigste", "Achtundvierzigste", "Neunundvierzigste", "Fünfzigste", "Einundfünfzigste", "Zweiundfünfzigste", "Dreiundfünfzigste",
#                "Vierundfünfzigste", "Fünfundfünfzigste", "Sechsundfünfzigste", "Siebenundfünfzigste", "Achtundfünfzigste", "Neunundfünfzigste",
#                "Sechzigste", "Einundsechzigste", "Zweiundsechzigste", "Dreiundsechzigste", "Vierundsechzigste", "Fünfundsechzigste", "Sechsundsechzigste",
#                "Siebenundsechzigste", "Achtundsechzigste", "Neunundsechzigste", "Siebzigste", "Einundsiebzigste", "Zweiundsiebzigste", "Dreiundsiebzigste",
#                "Vierundsiebzigste", "Fünfundsiebzigste", "Sechsundsiebzigste", "Siebenundsiebzigste", "Achtundsiebzigste", "Neunundsiebzigste",
#                "Achtzigste", "Einundachtzigste", "Zweiundachtzigste", "Dreiundachtzigste", "Vierundachtzigste", "Fünfundachtzigste", "Sechsundachtzigste",
#                "Siebenundachtzigste", "Achtundachtzigste", "Neunundachtzigste", "Neunzigste", "Einundneunzigste", "Zweiundneunzigste", "Dreiundneunzigste",
#                "Vierundneunzigste", "Fünfundneunzigste", "Sechsundneunzigste", "Siebenundneunzigste", "Achtundneunzigste", "Neunundneunzigste",
#                "Hundertste"]


nums_ordinal = ["Zeroth", "First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Seventh", "Eighth", "Ninth",
               "Tenth", "Eleventh", "Twelfth", "Thirteenth", "Fourteenth", "Fifteenth", "Sixteenth", "Seventeenth", "Eighteenth", "Nineteenth",
               "Twentieth", "Twenty-First", "Twenty-Second", "Twenty-Third", "Twenty-Fourth", "Twenty-Fifth", "Twenty-Sixth",
               "Twenty-Seventh", "Twenty-Eighth", "Twenty-Ninth", "Thirtieth", "Thirty-First", "Thirty-Second", "Thirty-Third",
               "Thirty-Fourth", "Thirty-Fifth", "Thirty-Sixth", "Thirty-Seventh", "Thirty-Eighth", "Thirty-Ninth",
               "Fortieth", "Forty-First", "Forty-Second", "Forty-Third", "Forty-Fourth", "Forty-Fifth", "Forty-Sixth",
               "Forty-Seventh", "Forty-Eighth", "Forty-Ninth", "Fiftieth", "Fifty-First", "Fifty-Second", "Fifty-Third",
               "Fifty-Fourth", "Fifty-Fifth", "Fifty-Sixth", "Fifty-Seventh", "Fifty-Eighth", "Fifty-Ninth",
               "Sixtieth", "Sixty-First", "Sixty-Second", "Sixty-Third", "Sixty-Fourth", "Sixty-Fifth", "Sixty-Sixth",
               "Sixty-Seventh", "Sixty-Eighth", "Sixty-Ninth", "Seventieth", "Seventy-First", "Seventy-Second", "Seventy-Third",
               "Seventy-Fourth", "Seventy-Fifth", "Seventy-Sixth", "Seventy-Seventh", "Seventy-Eighth", "Seventy-Ninth",
               "Eightieth", "Eighty-First", "Eighty-Second", "Eighty-Third", "Eighty-Fourth", "Eighty-Fifth", "Eighty-Sixth",
               "Eighty-Seventh", "Eighty-Eighth", "Eighty-Ninth", "Ninetieth", "Ninety-First", "Ninety-Second", "Ninety-Third",
               "Ninety-Fourth", "Ninety-Fifth", "Ninety-Sixth", "Ninety-Seventh", "Ninety-Eighth", "Ninety-Ninth",
               "Hundredth"]

sophialib/sophialib/styles/styleconstants.py
Sophia-Edu-Labs/sophia-math

from dataclasses import dataclass
import re
from typing import List, Optional

def remove_latex_dollar_signs(text):
    # Pattern to match "$[...]" and "$$[...$$" sequences
    pattern = r'\$\$?(.*?)\$\$?'
    
    # Find all matches
    matches = re.findall(pattern, text)
    
    # Remove all matches
    text_without_dollars = re.sub(pattern, r'\1', text)

    return text_without_dollars



@dataclass
class SophiaTaskDefinition():
    answerOptions: List[str]
    correctAnswerIndex: int
    questionText: str
    questionVideoPrototypeID: Optional[str] = None

    # Function that will return the question text, but without the Latex-Like math sequences of "$[...]$" and "$$[...]$$"
    def get_question_text_without_dollars(self):
        return remove_latex_dollar_signs(self.questionText)
    
    @property
    def questionTextWithoutDollars(self):
        return self.get_question_text_without_dollars()
    
    def get_answer_options_without_dollars(self):
        return [remove_latex_dollar_signs(answerOption) for answerOption in self.answerOptions]

    @property
    def answerOptionsWithoutDollars(self):
        return self.get_answer_options_without_dollars()
sophialib/sophialib/tasks/sophiataskdefinition.py
Sophia-Edu-Labs/sophia-math
import os

# Define a default fallback locale
DEFAULT_LOCALE = "en"

# Get the locale from an environment variable. If it is not set, use the default locale.
CURRENT_LOCALE = os.getenv('LOCALE', DEFAULT_LOCALE)

sophialib/sophialib/translation/currentlocale.py
Sophia-Edu-Labs/sophia-math
import json
from pathlib import Path
from collections import defaultdict

from sophialib.constants.directories import LOCALES_PATH

# Helper to access nested dictionaries through a dot-separated key
def nested_dict_get(d, keys, default=None):
    keys_list = keys.split(".")
    for key in keys_list:
        if isinstance(d, dict) and key in d:
            d = d[key]
        else:
            return default  # return default value if key is not found
    return d  # return the nested value if all keys are found


def parse_locales():
    result = defaultdict(list)  # Initialize a default dictionary to hold lists of dictionaries.
    for path in LOCALES_PATH.rglob('*.json'):  # Use rglob to iterate over all json files in all subdirectories.
        lang_code = path.stem  # Get the language code from the file name (without extension).
        
        # Load the JSON file content 
        try:
            with open(path, 'r', encoding='utf-8') as f:
                content = json.load(f)
                result[lang_code] = content
        except json.JSONDecodeError:
            print(f"Error decoding JSON in {path}")
    
    return dict(result)


# variable to cache the parsed locales/translations
TRANSLATIONS = parse_locales()


def get_translation(key: str, lang_code: str):
    """Returns the translation for the given key and language code, or None if no translation was found."""
    return nested_dict_get(TRANSLATIONS[lang_code],key, None)
sophialib/sophialib/translation/translate.py
Sophia-Edu-Labs/sophia-math
# Helper function to remove all kind of xml-like tags from text (as elevenlabs api does not support ssml, we need to remove all ssml-like tags)
import re


def remove_xml_tags(text, exclude_tags=[]):
    """
    This function removes all xml tags from a string, except for those listed in exclude_tags.
    :param text: str, input string containing xml tags
    :param exclude_tags: list of str, optional, tags to be excluded from removal
    :return: str, the input string with xml tags removed (except those in exclude_tags)
    """
    
    # Prepare the list of excluded tags in regex pattern format
    excluded = '|'.join(f'{tag}' for tag in exclude_tags)
    
    # If there are tags to be excluded, adjust the regex pattern accordingly
    if excluded:
        pattern = fr"<(?!/?({excluded})\b)[^>]*>"
        entity_pattern = fr"&lt;(?!/?({excluded})\b)[^>]*&gt;"
    else:
        pattern = r"<[^>]*>"
        entity_pattern = r"&lt;[^>]*&gt;"
    
    # Remove all tags except for those in exclude_tags
    text = re.sub(pattern, "", text)
    text = re.sub(entity_pattern, "", text)
    
    return text
sophialib/sophialib/utils/xml.py
Sophia-Edu-Labs/sophia-math
from pathlib import Path
import tempfile

import subprocess

def get_video_resolution(f: Path):
    command = [
        'ffprobe',
        '-v', 'error',
        '-select_streams', 'v:0',
        '-show_entries', 'stream=width,height',
        '-of', 'csv=s=x:p=0',
        str(f)
    ]

    try:
        output = subprocess.check_output(command).decode('utf-8').strip()
        width, height = output.split('x')
        return (int(width), int(height))
    except subprocess.CalledProcessError as e:
        print(f'ffprobe command resulted in error: {e.output.decode("utf-8")}')
        return None


def crop_video_to_aspect_ratio(f: Path, aspect_ratio: float = 9/16):
    width, height = get_video_resolution(str(f))

    # temp file for output
    fd, tempname = tempfile.mkstemp(dir=f.parent, suffix=".mp4")

    # write cropped clip
    new_height = height
    new_width = int(new_height * aspect_ratio)
    
    # Form the command
    command = [
        'ffmpeg',
        '-y', # overwrite output file if it exists
        '-hide_banner', 
        '-loglevel', 'error',
        '-i', str(f),
        '-filter:v', f'crop={new_width}:{new_height}',
        tempname
    ]

    # Execute the command
    subprocess.run(command, check=True)

    # replace original file
    Path(tempname).replace(f)
sophialib/sophialib/video_editing/crop.py
Sophia-Edu-Labs/sophia-math
from pathlib import Path
from sophialib.styles.sophiascene import aspect_ratio
from sophialib.video_editing.crop import crop_video_to_aspect_ratio


def crop_video_file(f: Path):
    """Crops a video file at the given path to the aspect ratio of the SophiaScene. Replaces the original file"""
    
    crop_video_to_aspect_ratio(f, aspect_ratio)
sophialib/sophialib/videopostprocessing/crop.py
Sophia-Edu-Labs/sophia-math
# based on this: https://godatadriven.com/blog/a-practical-guide-to-using-setup-py/
# and this: https://python-packaging.readthedocs.io/en/latest/minimal.html

from setuptools import setup, find_packages

setup(
    name='sophiarenderlib',
    version='0.1.0',
    description='Everything that we need for rendering',
    author='Friedrich Wicke and Gero Embser',
    author_email='sophia@sophiaedulabs.com',
    url='sophiaedulabs.com',
    packages=find_packages(include=['sophiarenderlib', 'sophiarenderlib.*']),
)
sophiarenderlib/setup.py
Sophia-Edu-Labs/sophia-math
from pathlib import Path
from typing import List

from sophialib.constants.directories import SCENES_FOLDER, WORKSPACE_FOLDER


def find_repository_scene_module_paths(result_sorted: bool = False) -> List[Path]:
    paths = []

    for pf in Path(SCENES_FOLDER / "Func").glob("*/*.py"):
        paths.append(pf)
    
    # exclude the legacy SCENES_FOLDER/scenes/sophiascene.py file
    paths = [p for p in paths if not (p.name == "sophiascene.py" and p.parent.name == "styles")]

    if result_sorted: # so we get more consistent results, if required.
        paths.sort()

    return paths



RENDER_RESULTS_MEDIA_FOLDER = WORKSPACE_FOLDER / "renderresults_media"

sophiarenderlib/sophiarenderlib/render/filehelpers.py
Sophia-Edu-Labs/sophia-math
from pathlib import Path
import tempfile
from typing import List, Type
from manim import tempconfig
from sophialib.filehelpers.extract import extract_audio_to_path
from sophialib.filehelpers.hashing import hash_audio_at_path
from sophialib.filehelpers.load_sophia_scenes import get_module_manim_sophiascene_classes
import multiprocessing as mp 


# afterwards import sophiascene, to only import it once (and dynamic import stuff below won't import it again as a different object)
from sophialib.styles.sophiascene import SophiaScene
from sophialib.videopostprocessing.crop import crop_video_file



def render_scene(sc: Type[SophiaScene], output_dir: Path, scene_media_folder: Path, test_run_with_last_frame: bool = False, disable_progressbar: bool = False):
    if test_run_with_last_frame:
        output_path = (output_dir/sc.__module__/f"{sc.__name__}_lastframe.png").resolve()
    else: 
        output_path = (output_dir/sc.__module__/f"{sc.__name__}.mp4").resolve()
    output_path.parent.mkdir(parents=True, exist_ok=True) #make sure always exist
    config = {"quality": "production_quality", "preview": False, "output_file": str(output_path), "disable_caching": True, "media_dir": scene_media_folder} # disable caching is important for manim-voiceover (due to a bug in manim)
    if test_run_with_last_frame:
        config["quality"] = "low_quality"
        config["save_last_frame"] = True
        config["write_to_movie"] = False

    if disable_progressbar:
        config["progress_bar"] = "none"
    
    with tempconfig(config):
        # instantiate sc 
        scene = sc()

        # render scene
        scene.should_add_dev_rects = False # do not render dev-rects
        scene.render()

        if test_run_with_last_frame:
            # no more to do here in that case :)
            return

        # crop output file
        crop_video_file(output_path)


def render_scenes(scenes: List[Type[SophiaScene]], output_dir: Path, media_parent_folder: Path, test_run_with_last_frame: bool = False, disable_progressbar: bool = False, rethrow_exceptions: bool = False):
    """Renders all scenes in a list of scenes. Returns a list of scenes for which rendering failed, if rethrow_exceptions is False, otherwise it will rethrow the exceptions."""
    failed_rendered_scenes = []

    # render all scenes in module
    for sc in scenes:
        # create a new media folder for each scene
        scene_media_folder = media_parent_folder / f"{sc.__module__}_{sc.__name__}_media"
        scene_media_folder.mkdir(parents=True, exist_ok=True)

        try: 
            render_scene(sc, output_dir, scene_media_folder, test_run_with_last_frame, disable_progressbar)
        except Exception as e:
            print(f"Error while rendering scene {sc.__name__}: {e}")
            if rethrow_exceptions:
                raise e
            else:
                failed_rendered_scenes.append(sc)
    
    return failed_rendered_scenes




def render_all_scenes_in_module(module_path: Path, output_dir: Path, media_parent_folder: Path, test_run_with_last_frame: bool = False, disable_progressbar: bool = False):
    """Renders all scenes in a module. Returns True if successful, False otherwise."""
    try:
        # get all scene classes in module
        scene_classes = get_module_manim_sophiascene_classes(module_path, add_parent_folder_to_sys_path=True) # add parent folder to sys path, to allow relative imports


        # render all scenes
        render_scenes(scene_classes, output_dir, media_parent_folder, test_run_with_last_frame, disable_progressbar, rethrow_exceptions=True)
        
        return True
    except Exception as e:
        print(f"Error while rendering module {module_path}: {e}")
        return e

def render_scene_modules(scene_module_paths: List[Path], output_dir: Path, media_parent_folder: Path, parallelize: bool = True, test_run_with_last_frame: bool = False, disable_progressbar: bool = False, rethrow_exceptions: bool = False):
    """Renders all scenes in a list of scene modules. To the given output folder by using the given media folder. If parallelize is true, it will try to render multiple scenes in parallel. If test_run_with_last_frame is true, it will only render the last frame of each scene, which makes rendering much faster but can nevertheless show errors in the rendering process (like type errors), so it is like a test/dry-run."""
    # separate media folder seems necessary for parallelization, so that there will be no interference between the different processes when they try to access "their" media folder
    # make sure a separate media folder parent for the renderall script exists
    media_parent_folder.mkdir(parents=True, exist_ok=True)

    # also make sure output folder always exists
    Path.mkdir(output_dir, parents=True, exist_ok=True) 

    # start rendering now
    print("-------- [ will start rendering now ] --------")

    results = []

    render_func = render_all_scenes_in_module
    parameters = [[sc_mod_path, output_dir, media_parent_folder, test_run_with_last_frame, disable_progressbar] for sc_mod_path in scene_module_paths]
    if parallelize:
        # create a pool of processes
        pool_count = mp.cpu_count() -1 # leave one core for other stuff
        pool_count = 3 # DEBUG: only use 3 cores
        print(f"Using {pool_count} cores for rendering.")
        pool = mp.Pool(pool_count, maxtasksperchild=1)

        # map the list of modules with scenes to the pool of processes
        results = pool.starmap(render_func, parameters, chunksize=1)

        # close the pool and wait for the work to finish
        pool.close()
        pool.join()
    else:
        results = [render_func(*p) for p in parameters]

    # check results and print out a list of failed modules
    failed_modules = [(module_path, result) for module_path, result in zip(scene_module_paths, results) if result is not True]

    if len(failed_modules) > 0:
        print("-------- [ errors occurred ] --------")
        print(f"Failed to render the following modules: ")
        for module_path, e in failed_modules:
            print(f"  {module_path}: {e}")

        if rethrow_exceptions:
            raise Exception(f"Failed to render the following modules: {failed_modules}")

    print("-------- [ finished rendering ] --------")

sophiarenderlib/sophiarenderlib/render/scenes.py
Sophia-Edu-Labs/sophia-math