Exemplo n.º 1
0
    def construct(self):
        t1 = TextMobject(
            "Let's look at our \\texttt{power(x,n)} function from Part 1 again"
        )
        t1.to_edge(UP)
        power1_code = CodeBlock(
            'Java', r"""
            public static int power(int x, int n) {
                if (n == 0) {
                    return 1;
                }
                int t = power(x, n - 1);
                return x * t;
            }
            """)
        power1_code.next_to(t1, DOWN, buff=MED_LARGE_BUFF)
        self.play(
            FadeIn(t1),
            FadeIn(power1_code),
        )
        self.wait()

        t2 = TextMobject("How many times does it call itself?")
        t2.next_to(power1_code, DOWN, buff=MED_LARGE_BUFF)
        self.play(Write(t2))
        self.wait(duration=2)

        t3 = TextMobject(
            "It call's itself $n$ times. Recall our original equation:")
        t3.move_to(t2)
        f1 = TexMobject('x^n=', 'x \\times x \\times ... \\times x',
                        '= x \\times x^{n-1}')
        f1.next_to(t3, DOWN)
        b1 = BraceLabel(f1[1],
                        '$n$ times',
                        brace_direction=DOWN,
                        label_constructor=TextMobject)
        f1 = VGroup(f1, b1)
        hr = SurroundingRectangle(power1_code.get_code().get_lines(5)[-5:-2])
        self.play(ReplacementTransform(t2, t3), FadeInFromDown(f1), FadeIn(hr))
        self.wait(duration=4)

        t4 = TextMobject('Can we do better?')
        self.play(*[FadeOut(o) for o in self.mobjects], FadeIn(t4))
        self.wait()

        self.play(FadeOut(t4))
Exemplo n.º 2
0
    def construct(self):
        code_scale = 0.75
        foo_code = CodeBlock(
            'Java',
            r"""
            int foo() {
                int n = bar(2, 1);
                n += bar(2, 2);
                return n;
            }
            """,
            code_scale=code_scale,
        )
        bar_code = CodeBlock(
            'Java',
            r"""
            int bar(int x, int y) {
                if (x == 1) {
                    return y;
                }
                int b = bar(x - 1, y + 1);
                return b;
            }
            """,
            line_offset=5,
            code_scale=code_scale,
        )
        main_code = CodeBlock('Java', 'off_screen')
        main_code.shift(UP * 8)  # Offscreen up
        self.add(main_code)

        title = TextMobject('CodeBlock Stepping Demo')
        title.to_edge(UP)
        foo_code.next_to(title, DOWN)
        bar_code.next_to(foo_code.get_code(),
                         DOWN,
                         buff=MED_LARGE_BUFF,
                         aligned_edge=LEFT,
                         submobject_to_align=bar_code.get_code())
        self.play(*[FadeIn(o) for o in [title, foo_code, bar_code]])
        self.wait()

        # Step through both code blocks until done.
        xi = main_code.pre_call(foo_code, 1)
        self.play(*main_code.get_control_transfer_counterclockwise(xi))
        foo_code.post_control_transfer(xi, self)

        foo_code.prep_annotations(2, 3)
        foo_code.generate_target().highlight_lines(2).set_annotation(2, 'n: ?')
        self.play(MoveToTarget(foo_code))
        n = self.run_bar(bar_code, foo_code, 2, 2, 1)
        self.play(foo_code.highlight_lines, 3, foo_code.set_annotation, 2,
                  None, foo_code.set_annotation, 3, 'n: %d' % n,
                  bar_code.fade_labels)
        n += self.run_bar(bar_code, foo_code, 3, 2, 2)
        self.play(foo_code.highlight_lines, 4, foo_code.set_annotation, 3,
                  'n: %d' % n)

        xi = foo_code.pre_return(main_code, 1)
        self.play(*foo_code.get_control_transfer_clockwise(xi))
        main_code.post_control_transfer(xi, self)

        self.play(FadeOut(title), FadeOut(foo_code), FadeOut(bar_code))
        self.wait()
Exemplo n.º 3
0
    def construct(self):
        code_scale = 0.75
        foo_code = CodeBlock(
            'Java',
            r"""
            int foo() {
                int n = bar(2, 1);
                n += bar(2, 2);
                return n;
            }
            """,
            add_labels=True,
            code_scale=code_scale,
        )
        bar_code = CodeBlock(
            'Java',
            r"""
            int bar(int x, int y) {
                if (x == 1) {
                    return y;
                }
                int b = bar(x - 1, y + 1);
                return b;
            }
            """,
            line_offset=5,
            add_labels=True,
            code_scale=code_scale,
        )

        title = TextMobject('CodeBlock Basics Demo')
        title.to_edge(UP)
        foo_code.next_to(title, DOWN)
        foo_code.fade_labels()
        bar_code.next_to(foo_code.get_code(),
                         DOWN,
                         buff=MED_LARGE_BUFF,
                         aligned_edge=LEFT,
                         submobject_to_align=bar_code.get_code())
        self.play(*[FadeIn(o) for o in [title, foo_code, bar_code]])
        self.wait(0.5)

        self.play(foo_code.highlight_lines, 1, bar_code.highlight_lines,
                  (6, 8))
        self.wait(0.5)
        self.play(foo_code.highlight_lines, 2, bar_code.highlight_lines,
                  (8, 10))
        self.play(foo_code.highlight_lines, 3, bar_code.highlight_lines,
                  (10, 12))
        self.wait(0.5)
        self.play(Indicate(foo_code))
        self.wait(0.5)
        self.play(Indicate(bar_code))
        self.wait(0.5)
        self.play(foo_code.remove_highlight, bar_code.remove_highlight)
        self.wait(0.5)
        self.play(FadeOut(foo_code))
        self.wait(0.5)
        self.play(FadeIn(foo_code))
        self.wait(0.5)
        self.play(foo_code.show_labels, bar_code.fade_labels)
        self.wait(0.5)
        self.play(foo_code.fade_labels, bar_code.show_labels)
        self.wait(0.5)

        foo_code.move_hidden_highlight(2)
        bar_code.move_hidden_highlight((8, 10))
        self.wait(0.5)
        self.play(foo_code.highlight_lines, 2, bar_code.highlight_lines,
                  (8, 10))
        self.wait(0.5)
        self.play(foo_code.highlight_lines, 4, bar_code.highlight_lines,
                  (6, 9))
        self.wait(0.5)
        self.play(foo_code.remove_highlight, bar_code.remove_highlight)
        self.wait(0.5)

        self.play(FadeOut(foo_code), FadeOut(bar_code))
        self.wait()
Exemplo n.º 4
0
    def construct(self):
        unsorted = [11, 0, 8, 2, 2, 9, 14, 5]

        code_scale = 0.6
        # TODO: move to base, since it references code lines and runs this code
        ms_code = CodeBlock(
            'Java',
            r"""
            public static int[] mergeSort(int[] a) {
                if (a.length == 1) {
                    return a;
                }
                int m = a.length / 2;
                int[] l, r;
                l = Arrays.copyOfRange(a, 0, m);
                r = Arrays.copyOfRange(a, m, a.length);
                l = mergeSort(l);
                r = mergeSort(r);
                return merge(l, r);
            }
            """,
            code_scale=code_scale,
        )
        ms_code.set_annotation(5, None)

        t1 = TextMobject("Recursive mergesort in Java")
        t1.to_edge(UP)
        ms_code.next_to(t1, DOWN, buff=MED_LARGE_BUFF)
        self.play(FadeIn(t1))
        self.play(
            LaggedStartMap(FadeInFromDown, ms_code.get_code(), lag_ratio=0.2))
        self.wait(duration=3.0)

        t2 = TextMobject(
            "Let's trace through this and track our work with a tree",
            buff=LARGE_BUFF)
        t2.next_to(ms_code, DOWN, buff=LARGE_BUFF)
        self.play(FadeInFromDown(t2))
        self.wait(duration=3)

        self.play(ms_code.to_edge, DR, FadeOutAndShiftDown(t2),
                  FadeOutAndShift(t1, UP))

        colors = color_gradient([PINK, BLUE, YELLOW_D], 15)
        tree = build_merge_sort_tree(unsorted, text_scale=1.0)
        update_tree_colors(tree, colors)
        tree.layout(1.6, 1.2)
        g = tree.to_vgroup()
        g.center().to_edge(UP)

        be = Merge8Exposition(self, tree, ms_code)

        t1 = TextMobject("Start with an array of random numbers")
        t1.next_to(tree.label, DOWN, buff=MED_LARGE_BUFF)
        be.deferred_play(1, FadeIn(t1))
        be.deferred_wait(1)
        be.deferred_play(3, FadeOut(t1))

        be.play(FadeIn(tree.label))
        self.run_merge_sort(tree, be, 0)
        self.wait()

        t1 = TextMobject("We divide the problem on the way down")
        t2 = TextMobject("and we recombine by merging on the way up")
        t1.shift(DOWN * 1.5)
        t2.next_to(t1, DOWN)
        self.play(FadeInFromDown(t1))
        self.wait()
        self.play(FadeInFromDown(t2))
        self.wait(duration=3)

        t3 = TextMobject("We call this \\textit{divide-and-conquer}")
        t4 = TextMobject("\\textit{This is very common!} You'll see it a lot.")
        t3.shift(DOWN * 1.5)
        t4.next_to(t3, DOWN)
        self.play(FadeOutAndShiftDown(t1), FadeOutAndShiftDown(t2))
        self.play(FadeInFromDown(t3))
        self.wait()
        self.play(FadeInFromDown(t4))
        self.wait(duration=3)

        t5 = TextMobject("This one was nicely balanced and even...")
        t6 = TextMobject("let's try one that's a little bit odd")
        t5.shift(DOWN * 1.5)
        t6.next_to(t5, DOWN)
        self.play(FadeOutAndShiftDown(t3), FadeOutAndShiftDown(t4))
        self.play(FadeInFromDown(t5))
        self.wait()
        self.play(FadeInFromDown(t6))
        self.wait(duration=3)

        self.play(*[FadeOut(o) for o in self.mobjects])
Exemplo n.º 5
0
    def construct(self):
        high_quality = False

        # - Foo calls bar passing some args. Bar does something, returns.
        code_scale = 0.75
        main_code = CodeBlock(
            'Java',
            r"""
            public static
            void main(String[] args) {
                foo();
            }
            """,
            code_scale=code_scale,
        )
        foo_code = CodeBlock(
            'Java',
            r"""
            static int foo() {
                int n = bar(1, 2);
                return n;
            }
            """,
            code_scale=code_scale,
        )
        bar_code = CodeBlock(
            'Java',
            r"""
            static int bar(int x,
                           int y) {
                int a = x + y;
                int b = a * 2;
                return b;
            }
            """,
            code_scale=code_scale,
        )
        fbg = VGroup(foo_code, bar_code)
        bar_code.next_to(foo_code, DOWN, aligned_edge=LEFT, buff=LARGE_BUFF)
        fbg.to_edge(TOP)
        title = TextMobject('We have two Java functions, foo() and bar()')
        title.to_edge(UP)
        self.play(
            ShowCreation(title),
            FadeInFromDown(fbg),
        )
        self.wait(duration=2)

        # Let's write down what happens when we run this.
        t2 = TextMobject("Let's run them and write down\\\\"
                         "each variable as we go...")
        t2.to_edge(LEFT)
        self.play(Write(t2), fbg.to_edge, RIGHT, {'buff': MED_SMALL_BUFF})
        self.wait()

        t3 = TextMobject('Running foo() and bar() by hand').to_edge(UP)
        if high_quality:
            self.play(ReplacementTransform(VGroup(title, t2), t3))
        else:
            self.play(FadeOut(title), FadeOut(t2), FadeIn(t3))
        self.remove(title, t2)
        title = t3
        self.wait()

        t4 = TextMobject('First, make a place\\\\to write each variable')
        t4.next_to(title, DOWN, buff=LARGE_BUFF).to_edge(LEFT)
        self.play(FadeIn(t4))
        self.wait()

        foo_vars = VGroup(TexMobject('n:', '\\_'))
        foo_vars.next_to(foo_code, LEFT, buff=LARGE_BUFF * 2)

        bar_vars = VGroup(
            TexMobject('x:', '\\_'),
            TexMobject('y:', '\\_').shift(DOWN * .75),
            TexMobject('a:', '\\_').shift(DOWN * 1.5),
            TexMobject('b:', '\\_').shift(DOWN * 2.25),
        )
        bar_vars.next_to(bar_code, LEFT, aligned_edge=TOP, buff=LARGE_BUFF * 2)
        self.play(Write(foo_vars))
        self.play(Write(bar_vars))
        self.wait()

        t5 = TextMobject("Start in foo()...")
        t5.move_to(t4, aligned_edge=LEFT)
        self.play(FadeOut(t4), FadeIn(t5))
        self.wait()

        foo_code.move_hidden_highlight(2)
        self.play(FadeOut(t5), foo_code.highlight_lines, 2)
        self.wait()

        foo_n_q = TexMobject('?').move_to(foo_vars[0][1],
                                          aligned_edge=BOTTOM).shift(UP * 0.1)
        self.play(Write(foo_n_q))
        foo_vars.add(foo_n_q)
        self.wait()

        xi = foo_code.pre_call(bar_code, (1, 3))
        self.play(*foo_code.get_control_transfer_counterclockwise(xi), )
        bar_code.post_control_transfer(xi, self)
        self.wait()

        bar_x = TexMobject('1').move_to(bar_vars[0][1],
                                        aligned_edge=BOTTOM).shift(UP * 0.1)
        bar_y = TexMobject('2').move_to(bar_vars[1][1],
                                        aligned_edge=BOTTOM).shift(UP * 0.1)
        a = Arrow(bar_code.get_code().get_lines(2),
                  VGroup(bar_x, bar_y).get_right(),
                  stroke_width=3)
        self.play(Write(bar_x), Write(bar_y), ShowCreationThenDestruction(a))
        bar_vars_extras = VGroup()
        bar_vars_extras.add(bar_x, bar_y)
        self.play(bar_code.highlight_lines, 3)
        self.wait()

        bar_a = TexMobject('3').move_to(bar_vars[2][1],
                                        aligned_edge=BOTTOM).shift(UP * 0.1)
        a = Arrow(bar_code.get_code().get_lines(3),
                  bar_a.get_right(),
                  stroke_width=3)
        self.play(Write(bar_a), ShowCreationThenDestruction(a))
        bar_vars_extras.add(bar_a)
        self.play(bar_code.highlight_lines, 4)
        self.wait()

        bar_b = TexMobject('6').move_to(bar_vars[3][1],
                                        aligned_edge=BOTTOM).shift(UP * 0.1)
        a = Arrow(bar_code.get_code().get_lines(4),
                  bar_b.get_right(),
                  stroke_width=3)
        self.play(Write(bar_b), ShowCreationThenDestruction(a))
        bar_vars_extras.add(bar_b)
        self.play(bar_code.highlight_lines, 5)
        self.wait()

        xi = bar_code.pre_return(foo_code, 2)
        self.play(*bar_code.get_control_transfer_clockwise(xi), )
        foo_code.post_control_transfer(xi, self)
        self.wait()

        foo_n = TexMobject('6').move_to(foo_vars[0][1],
                                        aligned_edge=BOTTOM).shift(UP * 0.1)
        a = Arrow(foo_code.get_code().get_lines(2),
                  foo_n.get_right(),
                  stroke_width=3)
        self.play(
            foo_code.highlight_lines,
            3,
            ReplacementTransform(foo_n_q, foo_n),
            ShowCreationThenDestruction(a),
        )
        foo_vars.add(foo_n)
        self.wait()

        # - Now give the variables "homes" in each function. Variables like
        # homes; they're warm and safe and sized just for them!
        print('Give variables homes')

        t1 = TextMobject('So how does the\\\\computer do this?').to_edge(LEFT)
        self.play(FadeIn(t1), foo_code.remove_highlight)
        self.wait(duration=2)

        t2 = TextMobject(
            'Every variable is stored\\\\someplace in memory').to_edge(LEFT)
        new_title = TextMobject('Where are variables stored?').to_edge(UP)
        self.play(
            FadeOut(t1),
            FadeOut(title),
            FadeIn(new_title),
            FadeIn(t2),
        )
        title = new_title
        self.wait()

        em = TextMobject('M')
        slot_height = em.get_height() + SMALL_BUFF * 2
        slot_width = em.get_width() * 4 + SMALL_BUFF * 2

        def build_var_home(name, value):
            var_name = TextMobject(name)
            slot_box = Rectangle(height=slot_height,
                                 width=slot_width,
                                 stroke_width=1)
            var_value = TextMobject(value)
            var_value.move_to(slot_box)
            var_name.next_to(slot_box, LEFT)
            stack_slot = VGroup(slot_box, var_name, var_value)
            return stack_slot

        foo_homes = build_var_home('n', '6')
        foo_homes.move_to(foo_vars, aligned_edge=LEFT)
        self.play(ReplacementTransform(foo_vars, foo_homes))
        self.wait()

        bar_var_vals = [('x', '1'), ('y', '2'), ('a', '3'), ('b', '6')]
        bar_homes = VGroup()
        bar_homes_shift = 0
        for n, v in bar_var_vals:
            bar_homes.add(build_var_home(n, v).shift(DOWN * bar_homes_shift))
            bar_homes_shift += 0.75
        bar_homes.move_to(bar_vars, aligned_edge=LEFT)
        t3 = TextMobject("Each variable lives in a\\\\``slot''").to_edge(LEFT)
        self.play(
            ReplacementTransform(bar_vars, bar_homes),
            # FadeOut(bar_vars),
            FadeOut(bar_vars_extras),
            FadeIn(bar_homes),
        )
        self.wait()
        self.play(
            FadeOut(t2),
            FadeIn(t3),
        )
        self.wait()

        # - Now arrange the homes into a "stack frame".
        print('Build stack frames')

        t4 = TextMobject(
            "All slots for a function\\\\are put together in a\\\\``frame''")
        t4.to_edge(LEFT)
        self.play(FadeOut(t3), FadeIn(t4))

        frame_width = 2.8
        foo_vars = [('n', '6')]
        foo_frame = StackFrame(foo_code,
                               'foo()',
                               3,
                               foo_vars,
                               width=frame_width)
        foo_frame.move_to(foo_homes, aligned_edge=LEFT).shift(LEFT * .5)
        self.play(ReplacementTransform(foo_homes, foo_frame))
        self.wait()

        bar_frame = StackFrame(bar_code,
                               'bar(1,2)',
                               9,
                               bar_var_vals,
                               width=frame_width)
        bar_frame.move_to(bar_homes, aligned_edge=LEFT).shift(LEFT * .5)
        self.play(ReplacementTransform(bar_homes, bar_frame))
        self.wait()

        t5 = TextMobject("\\textit{They're happy and warm\\\\together!}")\
            .scale(0.75).next_to(t4, DOWN, buff=LARGE_BUFF)
        self.play(FadeIn(t5))
        self.wait()

        # Cool, so where do frames live?
        print('Where do frames live')
        t6 = TextMobject('So where do frames live?').to_edge(LEFT)
        self.play(
            FadeOut(t5),
            FadeOut(t4),
            FadeIn(t6),
        )
        self.wait()

        t7 = TextMobject("On the ``call stack''!").next_to(t6,
                                                           DOWN,
                                                           buff=LARGE_BUFF)
        self.play(FadeIn(t7))
        self.wait()

        new_title = TextMobject('The Call Stack').to_edge(UP)
        t1 = TextMobject('Function calls push a new frame\\\\onto the stack')\
            .to_edge(LEFT).shift(UP)
        t2 = TextMobject('Returning pops a frame off\\\\the stack').next_to(
            t1, DOWN, buff=LARGE_BUFF)

        box_count = 8
        colors = color_gradient([BLUE, ORANGE], box_count)
        little_boxes = VGroup(*[
            Rectangle(height=0.25, width=0.75, fill_opacity=1, color=colors[i])
            for i in range(box_count)
        ])
        little_boxes.arrange(UP, buff=0.1)
        little_boxes.next_to(VGroup(foo_code, bar_code), LEFT, buff=LARGE_BUFF)

        self.play(
            ReplacementTransform(title, new_title),
            FadeOut(t6),
            FadeOut(t7),
            FadeOut(foo_frame),
            FadeOut(bar_frame),
            FadeIn(t1),
            LaggedStartMap(FadeInFrom,
                           little_boxes,
                           lambda m: (m, UP),
                           lag_ratio=1.0,
                           run_time=4.0),
        )
        title = new_title
        self.wait()

        self.play(
            FadeIn(t2),
            LaggedStartMap(FadeOutAndShift,
                           VGroup(*reversed(little_boxes)),
                           lambda m: (m, UP),
                           lag_ratio=1.0,
                           run_time=4.0),
        )
        self.wait(duration=1)

        t3 = TextMobject(
            "Let's run again and see\\\\the call stack in action...").to_edge(
                LEFT)
        t3.shift(UP)
        self.play(FadeOut(t1), FadeOut(t2), FadeIn(t3))
        self.wait()

        print('Run with real call stack')

        # Let's also put main() into the picture. Start it off-frame upper right
        t4 = TextMobject("... and get main()\\\\into the picture.")\
            .next_to(t3, DOWN, buff=LARGE_BUFF)
        main_code.next_to(title, DOWN, buff=MED_SMALL_BUFF).to_edge(RIGHT)
        main_code.shift(UP * 3 + RIGHT * 3)
        g = VGroup(main_code, foo_code, bar_code)
        self.play(
            g.arrange,
            DOWN,
            {
                'aligned_edge': LEFT,
                'buff': MED_SMALL_BUFF
            },
            g.next_to,
            title,
            DOWN,
            {'buff': MED_SMALL_BUFF},
            g.to_edge,
            RIGHT,
            FadeInFromDown(t4),
        )
        self.wait(duration=2)

        t1 = TextMobject('Start in main()...')
        t1.next_to(title, DOWN, buff=LARGE_BUFF).to_edge(LEFT)
        frame_width = 3.0
        args_ref = TextMobject('[ ]').scale(0.5)
        main_frame = StackFrame(main_code,
                                'main()',
                                3, [('args', args_ref)],
                                width=frame_width)
        main_frame.next_to(g, LEFT, buff=LARGE_BUFF).to_edge(DOWN)
        main_code.move_hidden_highlight(3)
        self.play(FadeIn(t1), FadeInFromDown(main_frame),
                  main_code.highlight_lines, 3, FadeOut(t3), FadeOut(t4))
        self.wait()

        foo_frame = StackFrame(foo_code, 'foo()', 5, ['n'], width=frame_width)
        foo_frame.next_to(main_frame, UP, buff=SMALL_BUFF)
        b1 = BraceLabel(foo_frame,
                        'Calling foo()\\\\pushes a frame',
                        brace_direction=LEFT,
                        label_constructor=TextMobject)

        xi = main_code.pre_call(foo_code, 1)
        self.play(
            *main_code.get_control_transfer_counterclockwise(xi),
            FadeInFrom(foo_frame, UP),
            FadeInFrom(b1, UP),
            FadeOut(t1),
        )
        foo_code.post_control_transfer(xi, self)
        self.wait(duration=2)

        self.play(foo_code.highlight_lines, 2, foo_frame.set_line, 6,
                  FadeOut(b1))
        self.wait()

        bar_frame = StackFrame(bar_code,
                               'bar(1, 2)',
                               10, ['x', 'y', 'a', 'b'],
                               width=frame_width)
        bar_frame.next_to(foo_frame, UP, buff=SMALL_BUFF)
        b1 = BraceLabel(bar_frame,
                        'Calling bar()\\\\pushes a frame',
                        brace_direction=LEFT,
                        label_constructor=TextMobject)

        xi = foo_code.pre_call(bar_code, (1, 3))
        self.play(
            *foo_code.get_control_transfer_counterclockwise(xi),
            FadeInFrom(bar_frame, UP),
            FadeInFrom(b1, UP),
        )
        bar_code.post_control_transfer(xi, self)
        self.wait()

        self.play(bar_frame.update_slot, 'x', 1, bar_frame.update_slot, 'y', 2,
                  FadeOut(b1))
        self.play(bar_code.highlight_lines, 3, bar_frame.set_line, 11)
        self.wait()

        self.play(bar_frame.update_slot, 'a', 3)
        self.play(bar_code.highlight_lines, 4, bar_frame.set_line, 12)
        self.wait()

        self.play(bar_frame.update_slot, 'b', 6)
        self.play(bar_code.highlight_lines, 5, bar_frame.set_line, 13)
        b1 = BraceLabel(bar_frame,
                        "Returning pops\\\\bar's frame",
                        brace_direction=LEFT,
                        label_constructor=TextMobject)
        self.play(FadeIn(b1))
        self.wait(duration=2)

        xi = bar_code.pre_return(foo_code, 2)
        self.play(
            *bar_code.get_control_transfer_clockwise(xi),
            Uncreate(bar_frame),
            FadeOut(b1),
        )
        foo_code.post_control_transfer(xi, self)
        self.wait()

        self.play(foo_code.highlight_lines, 3, foo_frame.set_line, 7,
                  foo_frame.update_slot, 'n', 6)
        b1 = BraceLabel(foo_frame,
                        "Returning pops\\\\foo's frame",
                        brace_direction=LEFT,
                        label_constructor=TextMobject)
        self.play(FadeIn(b1))
        self.wait()

        xi = foo_code.pre_return(main_code, 3)
        self.play(
            *foo_code.get_control_transfer_clockwise(xi),
            Uncreate(foo_frame),
            FadeOut(b1),
        )
        main_code.post_control_transfer(xi, self)
        self.wait()

        self.play(main_code.highlight_lines, 4, main_frame.set_line, 4)
        self.wait()

        t1 = TextMobject(
            'And when main() returns\\\\the program ends').to_edge(LEFT)
        self.play(FadeIn(t1))
        self.wait()

        off_screen_code = CodeBlock('Java', 'off_screen')
        off_screen_code.shift(UP * 8)  # Offscreen up
        self.add(off_screen_code)

        xi = main_code.pre_return(off_screen_code, 1)
        self.play(
            *main_code.get_control_transfer_clockwise(xi),
            Uncreate(main_frame),
            FadeOut(t1),
        )
        off_screen_code.post_control_transfer(xi, self)
        self.wait()

        t1 = TextMobject("Alright, let's do a more complicated one!")
        self.play(
            FadeInFromDown(t1),
            FadeOutAndShift(g, RIGHT),
        )
        self.wait()