to attach the Desmos graph to.
+# In tex mode, print a message to direct the student to the html version.
+# Desmos API reference: https://www.desmos.com/api/v1.7/docs/index.html
+
+
+HEADER_TEXT(MODES(
+ HTML=>'',
+ TeX=>''
+));
+
+$desmos_div = MODES(
+ HTML=>qq(
),
+ TeX=>'Interactive graph best viewed online'
+);
+
+##############################################################
+#
+# Setup
+
+Context("Point");
+Context("Numeric");
+Context()->variables->add(t=>'Real',c=>'Real');
+
+$x1 = random(-5,2);
+$x2 = $x1+3;
+$a = 3*$x1+3*$x2;
+$b = 6*$x1*$x2;
+$y1 = random(-10,10);
+$c = random(-10,10);
+$c_left = $c-1;
+$c_right = $c+1;
+$d = random(1,10);
+
+$f = Formula("2*x^3-$a*x^2+$b*x+$y1")->reduce;
+$fp = Formula("6*x^2-2*$a*x+$b")->reduce;
+$fpc = Formula("6*c^2-2*$a*c+$b")->reduce;
+$g_partial = Formula("x-$c")->reduce;
+$g_partial_c = Formula("c-$c")->reduce;
+$g = Formula("x-3*((x-$c)^2)^(1/3)+$d"); #displays badly; only using to evaluate
+$gp = Formula("1-2*(x-$c)^(-1/3)");
+$gpc = Formula("1-2*(c-$c)^(-1/3)");
+
+$left=$x1-1;
+$right=$x2+2;
+
+$y2 = $f->eval(x=>$left);
+$y3 = $f->eval(x=>$x1);
+$y4 = $f->eval(x=>$x2);
+$y5 = $f->eval(x=>$right);
+
+$y_max = $y5; #underscore for f
+if ($y2>$y_max){$y_max=$y2};
+if ($y3>$y_max){$y_max=$y3};
+if ($y4>$y_max){$y_max=$y4};
+
+$y_min = $y4; #underscore for f
+if ($y2<$y_min){$y_min=$y2};
+if ($y3<$y_min){$y_min=$y3};
+if ($y5<$y_min){$y_min=$y5};
+
+$y7 = $g->eval(x=>$c);
+$y6 = $g->eval(x=>$c_left);
+$y8 = $g->eval(x=>$c_right);
+
+$ymax = $y7; #no underscore for g
+if ($y6>$ymax){$ymax=$y6};
+if ($y8>$ymax){$ymax=$y8};
+
+$ymin = $y6; #no underscore for g
+if ($y7<$ymin){$ymin=$y7};
+if ($y8<$ymin){$ymin=$y8};
+
+#$list1=List(1,3);
+
+$dropmenu = PopUp(
+ ["Choose one", "wrong1","wrong2","correct"],
+ "correct");
+
+## THIS IS PROBLEM 3 OF A 3 PROBLEM SERIES INTRODUCING THE EXTREME VALUE THEOREM. IF YOU USE THEM TOGETHER, YOU CAN USE PASSCODES TO ALLOW YOU TO REQUIRE THE PROBLEMS BE DONE IN ORDER. BELOW IS SOME OF THE CODE YOU'LL NEED:
+
+#SRAND($psvn);
+#$passcode1 = random(1000,9999);
+#$passcode2 = random(1000,9999);
+
+## END PASSCODE CODE
+
+
+
+##############################################################
+#
+# Text
+
+Scaffold::Begin(
+ can_open => "when_previous_correct",
+ is_open => "first_incorrect"
+);
+
+Section::Begin("Passcode");
+
+BEGIN_PGML
+
+At the end of the previous problem, we saw...
+
+[@ openDiv({ "class" => "importantFormula" }) @]*
+*Extreme Value Theorem*:
+
+If a function [`f`] is continuous on a closed interval [`[a,b]`], then [`f`] has both an absolute minimum and an absolute maximum on [`[a,b]`].
+[@ closeDiv() @]*
+
+[% Enter the passcode from the previous problem: [_]{$passcode2} %]
+
+So far, we have been finding the absolute maximum and minimum from graphs. How do we find them from an algebraic expression?
+
+END_PGML
+Section::End();
+
+Section::Begin("Closed Interval Method");
+
+BEGIN_PGML
+
+[@ openDiv({ "class" => "importantFormula" }) @]*
+*Fermat's Theorem*:
+
+If [`(c,f(c))`] is a local maximum or minimum, then either [`f'(c)=0`] or [`f'(c)`] does not exist.
+[@ closeDiv() @]*
+
+If [`f'(c)=0`] or [`f'(c)`] does not exist, we call the point [`(c,f(c))`] a _critical point_ (or [`c`] a _critical number_). The absolute maximum of [`f`] on a closed interval [`[a,b]`] can be [`a`], or [`b`], or one of the critical points. Anywhere else, the tangent line would slope up or down, so there would be nearby points both above and below (see "Why is Fermat's Theorem true?" in the previous problem).
+
+If we can find the [`x`]-values for these points, we can plug them in and get the [`y`]-values. One will be the highest, and one will be the lowest!
+
+[% Enter the passcode again: [_]{$passcode2} %]
+
+END_PGML
+Section::End();
+
+Section::Begin("Finding critical numbers");
+
+BEGIN_PGML
+
+Let [`f(x)=[$f]`]. Let's find the absolute maximum and minimum of [`f`] on [`[[$x1-1],[$x2+2]]`].
+
+[`f'(x)=`] [_]{$fp}
+
+We need all values of [`c`] such that [`f'(c)=0`] or [`f'(c)`] does not exist. In this case, [`f'(c)`] will always exist, but we can set [`f'(c)=0`]. Type [`f'(c)`] in the box below (same as your previous answer, but replace each [`x`] with [`c`]):
+
+[_]{$fpc} [` =0`]
+
+Now let's factor it! The first box should be a constant, and the others should be [`(c+\mbox{something})`] or [`(c-\mbox{something})`]. (If WebWork won't accept your factors, try swapping the order.)
+
+[_]{6}[`\cdot\Big(`][_]{Formula("c-$x1")}[`\Big)\cdot\Big(`][_]{Formula("c-$x2")}[`\Big)=0`]
+
+Now solve for [`c`]. Enter the lower value first, and the higher one second: [`c=`] [_]{$x1} or [`c=`] [_]{$x2}.
+
+These are our critical numbers!
+
+END_PGML
+Section::End();
+
+Section::Begin("Choosing the correct maximum and minimum");
+
+BEGIN_PGML
+
+Recall that the interval is [`[[$left],[$right]]`].
+
+To find the maximum and minimum, we test the critical numbers and the endpoints of the interval. List those four [`x`] values, separated by commas: [_]{List("$left,$x1,$x2,$right")};
+
+Now we evaluate [`f`] at each of these [`x`]-values. Enter the [`x`]-values in increasing order on the left, then enter the correct [`y`]-value in each box on the right.
+
+Enter the [`x`]-value at the left endpoint (the first number in the interval). Then find the [`y`]-value. of the interval:
+
+[`f\Big(`][_]{$left}[`\Big)=`] [_]{$y2};
+
+[`f\Big(`][_]{$x1}[`\Big)=`] [_]{$y3};
+
+[`f\Big(`][_]{$x2}[`\Big)=`] [_]{$y4};
+
+[`f\Big(`][_]{$right}[`\Big)=`] [_]{$y5};
+
+The absolute maximum is the highest [`y`]-value: [_]{$y_max}
+
+The absolute maximum is the lowest [`y`]-value: [_]{$y_min}
+
+END_PGML
+Section::End();
+
+Section::Begin("Another example");
+
+BEGIN_PGML
+
+Let [`g(x)=x-3([$g_partial])^{\frac23}+[$d]`]. Let's find the absolute maximum and minimum of [`g`] on [`[[$c-1],[$c+1]]`].
+
+[`g'(x)=`] [_]{$gp}
+
+END_PGML
+Section::End();
+
+Section::Begin("Zero derivative");
+
+BEGIN_PGML
+
+Now let's solve the equation [`g'(c)=0`]. Fill in [`g'(c)`] in the box. Express it without any negative or fractional exponents (introducing fractions and roots as needed).
+
+[_]{$gpc} [`=0`]
+
+Now solve it for [`c`].
+
+[`c=`] [_]{$c+8}
+
+
+END_PGML
+Section::End();
+
+Section::Begin("Nonexistent derivative");
+
+BEGIN_PGML
+
+But we also need the values where [`g'(c)`] does not exist. In this case, that will happen when [`\sqrt[3]{[$g_partial_c]}=0`]. Solve this for [`c`].
+
+[`c=`] [_]{$c}
+
+END_PGML
+Section::End();
+
+Section::Begin("Finishing the job");
+
+BEGIN_PGML
+
+Recall that the interval is [`[[$c-1],[$c+1]]`].
+
+List the four [`x`] values that are either a critical number or an endpoint (separated by commas): [_]{List("$c-1,$c,$c+1,$c+8")}
+
+You may have noticed that one of these numbers is outside the interval. We don't need to worry about that one! List the other three: [_]{List("$c-1,$c,$c+1")}
+
+Now we evaluate [`g`] at each of these [`x`]-values (in increasing order), as before.
+
+[`g\Big(`][_]{$c-1}[`\Big)=`] [_]{$y6};
+
+[`g\Big(`][_]{$c}[`\Big)=`] [_]{$y7};
+
+[`g\Big(`][_]{$c+1}[`\Big)=`] [_]{$y8};
+
+The absolute maximum is the highest [`y`]-value: [_]{$ymax}
+
+The absolute maximum is the lowest [`y`]-value: [_]{$ymin}
+
+END_PGML
+Section::End();
+
+Scaffold::End();
+
+Context()->normalStrings;
+
+##################################
+# Desmos graph (via the API)
+# Execute this only after the $desmos_div object has been put on the html page.
+
+ENDDOCUMENT();
diff --git a/Contrib/Wisconsin/EauClaire/calculus/limits_with_formulas_problem_1_of_4.pg b/Contrib/Wisconsin/EauClaire/calculus/limits_with_formulas_problem_1_of_4.pg
new file mode 100644
index 0000000000..ab43bb0109
--- /dev/null
+++ b/Contrib/Wisconsin/EauClaire/calculus/limits_with_formulas_problem_1_of_4.pg
@@ -0,0 +1,523 @@
+# DESCRIPTION
+## DBsubject('Calculus')
+## DBchapter('Limits')
+## DBsection('Investigating Limits')
+## KEYWORDS('Limits')
+## TitleText1('Calculus: Early Transcendentals')
+## EditionText1('4')
+## AuthorText1('Rogawski')
+## Section1('2.2')
+## Institution('UW Eau Claire')
+## Copied and modified by Warren Shull (UWEC) July 29, 2023
+
+DOCUMENT();
+loadMacros("PG.pl",
+ "PGcourse.pl",
+ "PGbasicmacros.pl",
+ "PGchoicemacros.pl",
+ "PGanswermacros.pl",
+ "scaffold.pl",
+ "PGauxiliaryFunctions.pl",
+ "PGgraphmacros.pl",
+ "freemanMacros.pl",
+ "AnswerFormatHelp.pl",
+ "Parser.pl");
+
+loadMacros("niceTables.pl");
+
+loadMacros(
+ "PGstandard.pl", # Standard macros for PG language
+ "MathObjects.pl",
+ "PGML.pl",
+ #"source.pl", # allows code to be displayed on certain sites.
+ #"PGcourse.pl", # Customization file for the course
+ #"scaffold.pl",
+ "unionTables.pl",
+ "parserPopUp.pl", # <--------------------------------------NEEDED FOR DROPDOWN MENUS
+ "PGtikz.pl",
+);
+
+Context("Numeric");
+
+$dne = String("DNE");
+
+$a3=random(30,40,1);
+$a=random(1,3,1);
+
+$a2=Formula(".5+$a");
+$aa1=Formula("$a+.01");
+$aa2=Formula("$a+.001");
+$aa3=Formula("$a+.0001");
+$aa4=Formula("$a-.01");
+$aa5=Formula("$a-.001");
+$aa6=Formula("$a-.0001");
+
+$av1=Real("($a3*$aa1-4.9*(($aa1)^2)-($a3 *$a -4.9* (($a)^2)))/0.01");
+$av2=Real("($a3*$aa2-4.9*(($aa2)^2)-($a3 *$a -4.9* (($a)^2)))/0.001");
+$av3=Real("($a3*$aa3-4.9*(($aa3)^2)-($a3 *$a -4.9* (($a)^2)))/0.0001");
+$av4=Real("($a3*$a-4.9*(($a)^2)-($a3 *$aa4 -4.9* (($aa4)^2)))/0.01");
+$av5=Real("($a3*$a-4.9*(($a)^2)-($a3 *$aa5 -4.9* (($aa5)^2)))/0.001");
+$av6=Real("($a3*$a-4.9*(($a)^2)-($a3 *$aa6 -4.9* (($aa6)^2)))/0.0001");
+$answ=Real("$a3-9.8*$a");
+
+$b=non_zero_random(-5,5);
+$b_example=$b+2.5;
+$c=non_zero_random(-5,5);
+
+$f_top=Formula("x^2-([$b+$c])x+$b*$c")->reduce;
+$f_bottom=Formula("x-$b")->reduce;
+
+$f=Formula("$f_top/$f_bottom")->reduce;
+$fp=Formula("x");
+$gp=Formula("x");
+
+$b1=$b-.2;
+$b2=$b-.05;
+$b3=$b-.01;
+$b4=$b+.2;
+$b5=$b+.05;
+$b6=$b+.01;
+
+$fb1 = $f->eval(x=>$b1);
+$fb2 = $f->eval(x=>$b2);
+$fb3 = $f->eval(x=>$b3);
+$fb4 = $f->eval(x=>$b4);
+$fb5 = $f->eval(x=>$b5);
+$fb6 = $f->eval(x=>$b6);
+
+$j=random(-7,-1);
+$d=$j+2;
+$i=$j+random(1,10-$j,2);
+#while($i==$j){$i=non_zero_random(-10,10);}
+
+$g_top=Formula("x^2-([$d+$i])x+$d*$i")->reduce;
+$g_bottom=Formula("x^2-([$d+$j])x+$d*$j")->reduce;
+
+$g=Formula("$g_top/$g_bottom");
+
+$d1=$d-.01;
+$d2=$d-.001;
+$d3=$d-.0001;
+$d4=$d+.01;
+$d5=$d+.001;
+$d6=$d+.0001;
+
+$gd1 = $g->eval(x=>$d1);
+$gd2 = $g->eval(x=>$d2);
+$gd3 = $g->eval(x=>$d3);
+$gd4 = $g->eval(x=>$d4);
+$gd5 = $g->eval(x=>$d5);
+$gd6 = $g->eval(x=>$d6);
+
+$p=random(1,5);
+while($p==3){
+ $p=random(1,5);
+}
+
+$p1=-.15;
+$p2=-.06;
+$p3=-.02;
+$p4=.15;
+$p5=.06;
+$p6=.02;
+
+$h_top=Formula("1-cos(x)")->reduce;
+$h_bottom=Formula("$p*x^2")->reduce;
+
+$h=Formula("$h_top/$h_bottom")->reduce;
+
+$hp1 = $h->eval(x=>$p1);
+$hp2 = $h->eval(x=>$p2);
+$hp3 = $h->eval(x=>$p3);
+$hp4 = $h->eval(x=>$p4);
+$hp5 = $h->eval(x=>$p5);
+$hp6 = $h->eval(x=>$p6);
+
+$width = 200;
+$height = 200;
+
+HEADER_TEXT(MODES(
+ HTML=>'',
+ TeX=>''
+));
+
+$unique_div_id = "evaluating_f";
+$desmos_div = MODES(
+ HTML=>qq(
),
+ TeX=>'Interactive graph best viewed online'
+);
+
+$unique_div_id2 = "evaluating_g";
+$desmos_div2 = MODES(
+ HTML=>qq(
),
+ TeX=>'Interactive graph best viewed online'
+);
+
+$unique_div_id3 = "evaluating_h";
+$desmos_div3 = MODES(
+ HTML=>qq(
),
+ TeX=>'Interactive graph best viewed online'
+);
+
+## THIS IS PROBLEM 1 OF A 4 PROBLEM SERIES INTRODUCING LIMITS ALGEBRAICALLY. IF YOU USE THEM TOGETHER, YOU CAN USE PASSCODES TO ALLOW YOU TO REQUIRE THE PROBLEMS BE DONE IN ORDER. BELOW IS SOME OF THE CODE YOU'LL NEED:
+
+#SRAND($psvn);
+#$passcode1 = random(1000,9999);
+
+## END PASSCODE CODE
+
+TEXT(beginproblem());
+Context()->texStrings;
+
+Scaffold::Begin(can_open => "when_previous_correct", is_open => "first_incorrect");
+###########################################
+Section::Begin("Close, but not exact");
+
+BEGIN_PGML
+Throughout the previous section, we looked at average rates of change (such as average velocities) between a "base point" and another point. We wanted the other point to be _close_ to the first one, but *not the exact same point*. (If it were the exact same point, finding the slope would involve dividing by zero.)
+
+As a reminder, here is one of the tables you filled out in the previous section (with the answer boxes removed, and possibly with different numbers):
+
+[@
+DataTable(
+[
+ ["time interval","average velocity" ],
+ ['\( ['.$a.', '.$aa1.'] \)',''],
+ ['\( ['.$a.', '.$aa2.'] \)',""],
+ ['\( ['.$a.', '.$aa3.'] \)',""],
+ ['\( ['.$aa4.', '.$a.'] \)',""],
+ ['\( ['.$aa5.', '.$a.'] \)',""],
+ ['\( ['.$aa6.', '.$a.'] \)',""],
+],
+align => '|l | l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+@]*
+
+[%BEGIN_TEXT (OLD VERSION OF THE TABLE)
+
+$PAR
+\{begintable(2)\}
+ \{row("time interval","average velocity",@firstrow)\}
+ \{row("\( [$a, $aa1]\)","\(\qquad \qquad\)",@secondrow)\}
+ \{row("\([$a, $aa2]\)","\(\qquad \qquad\)",@thirdrow)\}
+ \{row("\([$a, $aa3]\)","\(\qquad \qquad\)",@fourthrow)\}
+ \{row("\([$aa6, $a]\)","\(\qquad \qquad\)",@fifthrow)\}
+ \{row("\([$aa5, $a]\)","\(\qquad \qquad\)",@sixthrow)\}
+ \{row("\([$aa4, $a]\)","\(\qquad \qquad\)",@seventhrow)\}
+\{endtable()\}$PAR
+
+END_TEXT%]
+
+After filling out the table, you estimated what number your answers were getting _close_ to, even though they were not exactly the same. However, it was *not possible* to find the "average velocity" over [`[[$a],[$a]]`] as the rise and run would both be 0.
+
+We would like more precise language for talking about inputs and outputs that are _close_ to certain numbers, but not exactly equal. As an example, let [``f(x)=[$f]``]. Retype the numerator and denominator here:
+
+[`f(x)=\Big(`][_]{Formula("$f_top")->reduce}[`\Big)/\Big(`][_]{Formula("$f_bottom")->reduce}[`\Big)`]
+
+END_PGML
+
+Section::End();
+
+Section::Begin("Filling in a table");
+
+BEGIN_PGML
+
+Fill in the table below. You can use the window on the right as a calculator; simply backspace out the [`[$b_example]`] and replace it with any other value of [`x`].
+
+END_PGML
+
+$table=DataTable(
+[
+ ['\(x\)','\(f(x)\)'],
+ ['\('.$b1.'\)',ans_rule(10)],
+ ['\('.$b2.'\)',ans_rule(10)],
+ ['\('.$b3.'\)',ans_rule(10)],
+ ['\('.$b4.'\)',ans_rule(10)],
+ ['\('.$b5.'\)',ans_rule(10)],
+ ['\('.$b6.'\)',ans_rule(10)],
+],
+align => '|l | l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+
+TEXT(ColumnTable($table,$desmos_div));
+
+#[@ $desmos_div @]*
+
+#ANS($fb1->cmp(tolType => 'absolute',tolerance => .5));
+
+ANS($fb1->cmp());
+
+ANS($fb2->cmp());
+
+ANS($fb3->cmp());
+
+ANS($fb4->cmp());
+
+ANS($fb5->cmp());
+
+#Context()->{format}{number} = "%.1f";
+
+ANS($fb6->cmp());
+
+#Context()->{format}{number} = "%g";
+
+BEGIN_PGML
+As [`x`] gets closer to [`[$b]`], what number is [`f(x)`] getting closer to? [_]{Formula("$b-$c")->reduce}
+END_PGML
+
+Section::End();
+
+Section::Begin("Introducing Limits!");
+
+BEGIN_PGML
+
+Since [`f(x)`] gets closer to [`[$b-$c]`] as [`x`] gets closer to [`[$b]`], we write:
+
+[``\lim_{x\rightarrow[$b]}f(x)=[$b-$c]``]
+
+which we say out loud as:
+
+"The limit of [`f(x)`] as [`x`] approaches [`[$b]`] equals [`[$b-$c]`]."
+
+Meanwhile, what is [`f([$b])`]? If it does not exist, you may write DNE.
+
+[`f([$b])=`] [_]{$dne}
+
+END_PGML
+
+Section::End();
+
+Section::Begin("More examples");
+
+BEGIN_PGML
+
+Let [`g(x)=[$g]`]. Let's try to find [``\lim_{x\rightarrow[$d]}g(x)``]. Round each answer to as many decimal places as the number in the "rounding" column. (You can still type [`g(`]any number[`)`] in line 2 of the window on the right as a calculator.)
+
+END_PGML
+#[@ $desmos_div2 @]*
+
+
+$table=DataTable(
+[
+ ['\(x\)',"rounding",'\(g(x)\)'],
+ ['\('.$d1.'\)',3,ans_rule(10)],
+ ['\('.$d2.'\)',4,ans_rule(10)],
+ ['\('.$d3.'\)',5,ans_rule(10)],
+ ['\('.$d4.'\)',3,ans_rule(10)],
+ ['\('.$d5.'\)',4,ans_rule(10)],
+ ['\('.$d6.'\)',5,ans_rule(10)],
+],
+align => '|l | c|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+
+TEXT(ColumnTable($table,$desmos_div2));
+
+#Context()->{format}{number} = "%18.15f";
+Context()->{format}{number} = "%.3f";
+
+ANS(Real(sprintf("%.3f",$gd1))->cmp());
+
+Context()->{format}{number} = "%.4f";
+
+ANS(Real(sprintf("%.4f",$gd2))->cmp());
+
+#ANS(Real(sprintf("%.3f",$gd2->value))->cmp(tolType => 'absolute',tolerance => .01));
+Context()->{format}{number} = "%.5f";
+
+ANS(Real(sprintf("%.5f",$gd3))->cmp());
+
+Context()->{format}{number} = "%.3f";
+
+ANS(Real(sprintf("%.3f",$gd4))->cmp());
+
+Context()->{format}{number} = "%.4f";
+ANS(Real(sprintf("%.4f",$gd5))->cmp());
+Context()->{format}{number} = "%.5f";
+
+ANS(Real(sprintf("%.5f",$gd6))->cmp());
+
+#ANS(Real(sprintf("%.8f",$gd6))->cmp(tolType => 'absolute',tolerance => 1e-7));
+Context()->{format}{number} = "%g";
+
+#ANS($gd6->cmp());
+
+BEGIN_PGML
+
+[``\lim_{x\rightarrow[$d]}g(x)=``] [_]{Formula("($d-$i)/($d-$j)")->reduce}
+
+[`g([$d])=`] [_]{$dne}
+
+--------
+
+Let [`h(x)=[$h]`]. Let's try to find [``\lim_{x\rightarrow0}h(x)``]. Again, round to as many decimal places as the number in the "rounding" column.
+
+END_PGML
+
+$table=DataTable(
+[
+ ['\(x\)',"rounding",'\(h(x)\)'],
+ ['\('.$p1.'\)',4,ans_rule(10)],
+ ['\('.$p2.'\)',5,ans_rule(10)],
+ ['\('.$p3.'\)',6,ans_rule(10)],
+ ['\('.$p4.'\)',4,ans_rule(10)],
+ ['\('.$p5.'\)',5,ans_rule(10)],
+ ['\('.$p6.'\)',6,ans_rule(10)],
+],
+align => '|l | c|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+
+TEXT(ColumnTable($table,$desmos_div3));
+
+Context()->{format}{number} = "%.4f";
+ANS(Real(sprintf("%.4f",$hp1))->cmp());
+
+Context()->{format}{number} = "%.5f";
+ANS(Real(sprintf("%.5f",$hp2))->cmp());
+
+Context()->{format}{number} = "%.6f";
+ANS(Real(sprintf("%.6f",$hp3))->cmp());
+
+Context()->{format}{number} = "%.4f";
+ANS(Real(sprintf("%.4f",$hp4))->cmp());
+
+Context()->{format}{number} = "%.5f";
+ANS(Real(sprintf("%.5f",$hp5))->cmp());
+
+Context()->{format}{number} = "%.6f";
+ANS(Real(sprintf("%.6f",$hp6))->cmp());
+
+Context()->{format}{number} = "%g";
+
+BEGIN_PGML
+
+[``\lim_{x\rightarrow0}h(x)=``] [_]{Formula("1/(2*$p)")->reduce}
+
+[`h(0)=`] [_]{$dne}
+
+END_PGML
+
+Section::End();
+
+#Section::Begin("Passcode");
+
+#BEGIN_PGML
+
+#In the examples you just saw, [``\lim_{x\rightarrow a}f(x)``] always existed even though [`f(a)`] did not. Not all limits exist, however! In the next problem, you will see some limits that do not exist, and some problems where [`f(a)`] and [``\lim_{x\rightarrow a}f(x)``] are two different numbers!
+
+#The passcode for the next problem is [`[$passcode1]`]. Enter it here: [_]{$passcode1}
+
+#END_PGML
+
+#Section::End();
+
+ Scaffold::End();
+
+Context()->normalStrings;
+
+#ANS( num_cmp( $answ, tol=>0.001, tolType=>"absolute" ));
+
+#ANS($dq->cmp);
+
+TEXT( MODES(TeX=>'', HTML=><
+
+ var arstarst = document.getElementById("$unique_div_id");
+
+ var my_calculator = Desmos.Calculator(arstarst, {
+ keypad: false,
+ //expressions: false,
+ graphpaper: false,
+ expressions: true,
+ settingsMenu: true,
+ expressionsTopbar: true
+ });
+
+ my_calculator.setExpressions([
+ { id: 'function', latex: 'f(x)=\\frac{$f_top}{$f_bottom}'},
+ { id: 'plugin', latex: 'f($b_example)'},
+ ]);
+
+ my_calculator.setMathBounds({
+ left: -101,
+ right: -99,
+ bottom: -1,
+ top: 1
+ });
+
+ my_calculator.updateSettings({ fontSize: Desmos.FontSizes.SMALL, expressions: true });
+
+ var state = my_calculator.getState();
+
+END_SCRIPT
+
+TEXT( MODES(TeX=>'', HTML=><
+
+ var arstarst = document.getElementById("$unique_div_id2");
+
+ var my_calculator = Desmos.Calculator(arstarst, {
+ keypad: false,
+ //expressions: false,
+ expressions: true,
+ graphpaper: false,
+ settingsMenu: true,
+ expressionsTopbar: true
+ });
+
+ my_calculator.setExpressions([
+ { id: 'function', latex: 'g(x)=\\frac{$g_top}{$g_bottom}'},
+ ]);
+
+ my_calculator.setMathBounds({
+ left: 99,
+ right: 101,
+ bottom: 99,
+ top: 101
+ });
+
+ my_calculator.updateSettings({ fontSize: Desmos.FontSizes.SMALL, expressions: true });
+
+ var state = my_calculator.getState();
+
+END_SCRIPT
+
+TEXT( MODES(TeX=>'', HTML=><
+
+ var arstarst = document.getElementById("$unique_div_id3");
+
+ var my_calculator = Desmos.Calculator(arstarst, {
+ keypad: false,
+ //expressions: false,
+ expressions: true,
+ graphpaper: false,
+ settingsMenu: true,
+ expressionsTopbar: true
+ });
+
+ my_calculator.setExpressions([
+ { id: 'function', latex: 'h(x)=\\frac{1-\\cos x}{$p x^2}'},
+ ]);
+
+ my_calculator.setMathBounds({
+ left: 99,
+ right: 101,
+ bottom: 99,
+ top: 101
+ });
+
+ my_calculator.updateSettings({ fontSize: Desmos.FontSizes.SMALL, expressions: true });
+
+ var state = my_calculator.getState();
+
+END_SCRIPT
+
+ENDDOCUMENT();
diff --git a/Contrib/Wisconsin/EauClaire/calculus/limits_with_formulas_problem_2_of_4.pg b/Contrib/Wisconsin/EauClaire/calculus/limits_with_formulas_problem_2_of_4.pg
new file mode 100644
index 0000000000..f3e5774826
--- /dev/null
+++ b/Contrib/Wisconsin/EauClaire/calculus/limits_with_formulas_problem_2_of_4.pg
@@ -0,0 +1,523 @@
+# DESCRIPTION
+## DBsubject('Calculus')
+## DBchapter('Limits')
+## DBsection('Investigating Limits')
+## KEYWORDS('Limits', 'one-sided', 'infinity')
+## TitleText1('Calculus: Early Transcendentals')
+## EditionText1('4')
+## AuthorText1('Rogawski')
+## Section1('2.2')
+## Institution('UW Eau Claire')
+
+# Copied and modified by Warren Shull (UWEC) August 7, 2023
+
+DOCUMENT();
+loadMacros("PG.pl",
+ "PGbasicmacros.pl",
+ "PGchoicemacros.pl",
+ "PGanswermacros.pl",
+ "scaffold.pl",
+ "PGauxiliaryFunctions.pl",
+ "PGgraphmacros.pl",
+ "freemanMacros.pl",
+ "AnswerFormatHelp.pl",
+ "Parser.pl");
+
+loadMacros("niceTables.pl");
+
+loadMacros(
+ "PGstandard.pl", # Standard macros for PG language
+ "MathObjects.pl",
+ "PGML.pl",
+ #"source.pl", # allows code to be displayed on certain sites.
+ #"PGcourse.pl", # Customization file for the course
+ #"scaffold.pl",
+ "unionTables.pl",
+ "parserPopUp.pl", # <--------------------------------------NEEDED FOR DROPDOWN MENUS
+ "PGtikz.pl",
+);
+
+loadMacros(
+ "contextFraction.pl",
+ "parserMultiAnswer.pl",
+"answerHints.pl",
+ "PGcourse.pl", # Customization file for the course
+ "customCSS.pl", # <---- MAKES BOXES PURPLE
+);
+
+Context("Numeric");
+
+$yes = PopUp(
+ ["Choose one", "yes","no"],
+ "yes");
+
+$no = PopUp(
+ ["Choose one", "yes","no"],
+ "no");
+
+$dne = String("DNE");
+
+#$contin = String('continuous');
+
+$a=random(-3,3,2);
+
+$a1=$a-.1;
+$a2=$a-.01;
+$a3=$a-.001;
+$a4=$a+.1;
+$a5=$a+.01;
+$a6=$a+.001;
+
+$f=Formula("cos(pi/x)")->reduce;
+
+$fa = $f->eval(x=>$a);
+$fa1 = $f->eval(x=>$a1);
+$fa2 = $f->eval(x=>$a2);
+$fa3 = $f->eval(x=>$a3);
+$fa4 = $f->eval(x=>$a4);
+$fa5 = $f->eval(x=>$a5);
+$fa6 = $f->eval(x=>$a6);
+
+$b1=2;
+$b2=2/3;
+$b3=2/5;
+$b4=-2;
+$b5=-2/3;
+$b6=-2/5;
+
+$fb1 = $f->eval(x=>$b1);
+$fb2 = $f->eval(x=>$b2);
+$fb3 = $f->eval(x=>$b3);
+$fb4 = $f->eval(x=>$b4);
+$fb5 = $f->eval(x=>$b5);
+$fb6 = $f->eval(x=>$b6);
+
+$c1=-1;
+$c2=-1/3;
+$c3=-1/5;
+$c4=1;
+$c5=1/3;
+$c6=1/5;
+
+$fc1 = $f->eval(x=>$c1);
+$fc2 = $f->eval(x=>$c2);
+$fc3 = $f->eval(x=>$c3);
+$fc4 = $f->eval(x=>$c4);
+$fc5 = $f->eval(x=>$c5);
+$fc6 = $f->eval(x=>$c6);
+
+$d1=-1/2;
+$d2=-1/4;
+$d3=-1/6;
+$d4=1/2;
+$d5=1/4;
+$d6=1/6;
+
+$fd1 = $f->eval(x=>$d1);
+$fd2 = $f->eval(x=>$d2);
+$fd3 = $f->eval(x=>$d3);
+$fd4 = $f->eval(x=>$d4);
+$fd5 = $f->eval(x=>$d5);
+$fd6 = $f->eval(x=>$d6);
+
+$j=random(-7,-1);
+$d=$j+2;
+$i=$j+random(1,10-$j,2);
+#while($i==$j){$i=non_zero_random(-10,10);}
+
+
+$p1=-1;
+$p2=-.2;
+$p3=-.05;
+$p4=1;
+$p5=.2;
+$p6=.05;
+
+## THIS IS PROBLEM 2 OF A 4 PROBLEM SERIES INTRODUCING LIMITS ALGEBRAICALLY. IF YOU USE THEM TOGETHER, YOU CAN USE PASSCODES TO ALLOW YOU TO REQUIRE THE PROBLEMS BE DONE IN ORDER. BELOW IS SOME OF THE CODE YOU'LL NEED:
+
+#SRAND($psvn);
+#$passcode1 = random(1000,9999);
+#$passcode2 = random(1000,9999);
+#$passcode3 = random(1000,9999);
+
+## END PASSCODE CODE
+
+
+
+
+$p=non_zero_random(-5,5);
+$g=Formula("$p*x/|x|");
+
+$gp1 = $g->eval(x=>$p1);
+$gp2 = $g->eval(x=>$p2);
+$gp3 = $g->eval(x=>$p3);
+$gp4 = $g->eval(x=>$p4);
+$gp5 = $g->eval(x=>$p5);
+$gp6 = $g->eval(x=>$p6);
+
+$width = 200;
+$height = 200;
+
+HEADER_TEXT(MODES(
+ HTML=>'',
+ TeX=>''
+));
+
+$unique_div_id = "evaluating_f";
+$desmos_div = MODES(
+ HTML=>qq(),
+ TeX=>'Interactive graph best viewed online'
+);
+
+
+TEXT(beginproblem());
+Context()->texStrings;
+
+Scaffold::Begin(can_open => "when_previous_correct", is_open => "first_incorrect");
+###########################################
+Section::Begin("New function!");
+
+BEGIN_PGML
+
+The next function we will look at is [``f(x)=\cos\left(\frac\pi x\right)``].
+
+[% Enter the passcode from the previous problem: [_]{$passcode1} %]
+
+END_PGML
+
+Section::End();
+
+Section::Begin('x approaching ' . $a);
+
+BEGIN_PGML
+
+First, let's find [``\lim_{x\rightarrow[$a]}\cos\left(\frac\pi x\right)``]:
+
+END_PGML
+
+$table=DataTable(
+[
+ ['\(x\)',"rounding",'\(f(x)\)'],
+ ['\('.$a1.'\)',2,ans_rule(10)],
+ ['\('.$a2.'\)',4,ans_rule(10)],
+ ['\('.$a3.'\)',6,ans_rule(10)],
+ ['\('.$a4.'\)',2,ans_rule(10)],
+ ['\('.$a5.'\)',4,ans_rule(10)],
+ ['\('.$a6.'\)',6,ans_rule(10)],
+],
+align => '|l | c|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+
+TEXT(ColumnTable($table,$desmos_div));
+
+
+Context()->{format}{number} = "%.2f";
+ANS(Real(sprintf("%.2f",$fa1))->cmp());
+
+Context()->{format}{number} = "%.4f";
+ANS(Real(sprintf("%.4f",$fa2))->cmp());
+
+Context()->{format}{number} = "%.6f";
+ANS(Real(sprintf("%.6f",$fa3))->cmp());
+
+Context()->{format}{number} = "%.2f";
+ANS(Real(sprintf("%.2f",$fa4))->cmp());
+
+Context()->{format}{number} = "%.4f";
+ANS(Real(sprintf("%.4f",$fa5))->cmp());
+
+Context()->{format}{number} = "%.6f";
+ANS(Real(sprintf("%.6f",$fa6))->cmp());
+
+Context()->{format}{number} = "%g";
+
+# EXTRA LINES OF CODE FOR OTHER PURPOSES:
+# Context()->{format}{number} = "%18.15f";
+# ANS(Real(sprintf("%.3f",$gd2->value))->cmp(tolType => 'absolute',tolerance => .01));
+# ANS(Real(sprintf("%.8f",$gd6))->cmp(tolType => 'absolute',tolerance => 1e-7));
+# ANS($fb1->cmp(tolType => 'absolute',tolerance => .5));
+# ANS($gd6->cmp());
+
+BEGIN_PGML
+
+[``\lim_{x\rightarrow[$a]}f(x)=``] [_]{$fa}
+
+[``f([$a])=``] [_]{$fa}
+
+Are these the same? [_]{$yes}
+
+END_PGML
+
+Section::End();
+
+Section::Begin("Continuity");
+
+# DESMOS NEXT TO TABLE OF VALUES (hopefully):
+# $column1 = $desmos_div ."$PAR $PAR $PAR $PAR ". $desmos_div2;
+
+BEGIN_PGML
+
+Since [``\lim_{x\rightarrow[$a]}f(x)=f([$a])``], we say [`f`] is *continuous* at [`[$a]`] (or "continuous at [`x=[$a]`]").
+
+[@ openDiv({ "class" => "importantFormula" }) @]*
+Continuity:
+
+If [``\lim_{x\rightarrow c}f(x)=f(c)``], then [`f`] is *continuous* at [`x=c`].
+[@ closeDiv() @]*
+
+Keep this in mind for the future. [%Retype the word "continuous" here: [_]{$contin}%]
+END_PGML
+
+Section::End();
+
+Section::Begin("x approaching 0");
+
+BEGIN_PGML
+
+Let's look at the same function, but as [`x`] approaches [`0`].
+
+[@
+DataTable(
+[
+ ['\(x\)','\(f(x)\)'],
+ ['\(-2\)',ans_rule(10)],
+ ['\(-\frac23\)',ans_rule(10)],
+ ['\(-\frac25\)',ans_rule(10)],
+ ['\(2\)',ans_rule(10)],
+ ['\(\frac23\)',ans_rule(10)],
+ ['\(\frac25\)',ans_rule(10)],
+],
+align => '|l | l|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+@]*
+
+END_PGML
+
+ANS($fb1->cmp());
+
+ANS($fb2->cmp());
+
+ANS($fb3->cmp());
+
+ANS($fb4->cmp());
+
+ANS($fb5->cmp());
+
+ANS($fb6->cmp());
+
+BEGIN_PGML
+
+What number does [`f(x)`] seem to be approaching? [_]{0}
+
+END_PGML
+Section::End();
+
+Section::Begin("Trying other numbers");
+
+BEGIN_PGML
+
+Seems like the limit might be 0. But just in case, let's try different numbers:
+
+[@
+DataTable(
+[
+ ['\(x\)','\(f(x)\)'],
+ ['\(-1\)',ans_rule(10)],
+ ['\(-\frac13\)',ans_rule(10)],
+ ['\(-\frac15\)',ans_rule(10)],
+ ['\(1\)',ans_rule(10)],
+ ['\(\frac13\)',ans_rule(10)],
+ ['\(\frac15\)',ans_rule(10)],
+],
+align => '|l | l|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+@]*
+
+END_PGML
+
+ANS($fc1->cmp());
+
+ANS($fc2->cmp());
+
+ANS($fc3->cmp());
+
+ANS($fc4->cmp());
+
+ANS($fc5->cmp());
+
+ANS($fc6->cmp());
+
+BEGIN_PGML
+
+What do these answers seem to be approaching? [_]{-1}
+
+END_PGML
+
+Section::End();
+
+Section::Begin("More numbers!");
+
+BEGIN_PGML
+
+It seems like [`f(x)`] is approaching two different numbers!
+
+Let's try a few more values of [`x`]:
+
+[@
+DataTable(
+[
+ ['\(x\)','\(f(x)\)'],
+ ['\(-\frac12\)',ans_rule(10)],
+ ['\(-\frac14\)',ans_rule(10)],
+ ['\(-\frac16\)',ans_rule(10)],
+ ['\(\frac12\)',ans_rule(10)],
+ ['\(\frac14\)',ans_rule(10)],
+ ['\(\frac16\)',ans_rule(10)],
+],
+align => '|l | l|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+@]*
+
+END_PGML
+
+ANS($fd1->cmp());
+
+ANS($fd2->cmp());
+
+ANS($fd3->cmp());
+
+ANS($fd4->cmp());
+
+ANS($fd5->cmp());
+
+ANS($fd6->cmp());
+
+BEGIN_PGML
+
+What are these approaching? [_]{1}
+
+END_PGML
+Section::End();
+
+Section::Begin("Another function");
+BEGIN_PGML
+
+This function is very strange! It seems to be approaching a bunch of different numbers all at once!
+
+If we use an expression like [``\lim_{x\rightarrow c}f(x)``], we want it to refer to _one_ number, not a bunch of numbers at the same time. So if the function approaches more than one number, we say the limit *does not exist*.
+
+Let's look at one more function:
+
+[``g(x)=\frac{[$p]x}{|x|}``]
+
+(Recall that [`|x|`] is [`x`] if [`x\geq0`], and it's [`-x`] if [`x<0`].)
+
+This time, you can calculate [`g(x)`] yourself for these values of [`x`]:
+
+[@
+DataTable(
+[
+ ['\(x\)','\(g(x)\)'],
+ ['\(-1\)',ans_rule(10)],
+ ['\(-.2\)',ans_rule(10)],
+ ['\(-.05\)',ans_rule(10)],
+ ['\(1\)',ans_rule(10)],
+ ['\(.2\)',ans_rule(10)],
+ ['\(.05\)',ans_rule(10)],
+],
+align => '|l | l|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+@]*
+
+END_PGML
+
+ANS($gp1->cmp());
+
+ANS($gp2->cmp());
+
+ANS($gp3->cmp());
+
+ANS($gp4->cmp());
+
+ANS($gp5->cmp());
+
+ANS($gp6->cmp());
+
+#Context()->{format}{number} = "%18.15f";
+#ANS(Real(sprintf("%.3f",$gd2->value))->cmp(tolType => 'absolute',tolerance => .01));
+#ANS(Real(sprintf("%.8f",$gd6))->cmp(tolType => 'absolute',tolerance => 1e-7));
+
+Section::End();
+
+Section::Begin("Limit existence?");
+
+BEGIN_PGML
+
+Based on the table we just filled in, do you think [``\lim_{x\rightarrow0}g(x)``] exists? [_]{$no}
+
+END_PGML
+
+Section::End();
+
+Section::Begin("Passcode");
+
+BEGIN_PGML
+
+In this problem, we saw two nonexistent limits! In both cases, they did not exist because the function approached _more than one number_. But you may notice some differences between them. We will explore that in the next problem.
+
+[% The passcode for the next problem is [`[$passcode2]`]. Enter it here: [_]{$passcode2} %]
+
+END_PGML
+
+Section::End();
+
+ Scaffold::End();
+
+Context()->normalStrings;
+
+#ANS( num_cmp( $answ, tol=>0.001, tolType=>"absolute" ));
+
+#ANS($dq->cmp);
+
+TEXT( MODES(TeX=>'', HTML=><
+
+ var arstarst = document.getElementById("$unique_div_id");
+
+ var my_calculator = Desmos.Calculator(arstarst, {
+ keypad: false,
+ //expressions: false,
+ expressions: true,
+ graphpaper: false,
+ settingsMenu: true,
+ expressionsTopbar: true
+ });
+
+ my_calculator.setExpressions([
+ { id: 'function', latex: 'f(x)=\\cos(\\pi/x)'},
+ ]);
+
+ my_calculator.setMathBounds({
+ left: -101,
+ right: -99,
+ bottom: -1,
+ top: 1
+ });
+
+ my_calculator.updateSettings({ fontSize: Desmos.FontSizes.SMALL, expressions: true });
+
+ var state = my_calculator.getState();
+
+END_SCRIPT
+
+ENDDOCUMENT();
diff --git a/Contrib/Wisconsin/EauClaire/calculus/limits_with_formulas_problem_3_of_4.pg b/Contrib/Wisconsin/EauClaire/calculus/limits_with_formulas_problem_3_of_4.pg
new file mode 100644
index 0000000000..f455c68705
--- /dev/null
+++ b/Contrib/Wisconsin/EauClaire/calculus/limits_with_formulas_problem_3_of_4.pg
@@ -0,0 +1,604 @@
+# DESCRIPTION
+## DBsubject('Calculus')
+## DBchapter('Limits')
+## DBsection('Investigating Limits')
+## KEYWORDS('Limits', 'one-sided', 'infinity')
+## TitleText1('Calculus: Early Transcendentals')
+## EditionText1('4')
+## AuthorText1('Rogawski')
+## Section1('2.2')
+## Institution('UW Eau Claire')
+## Copied and modified by Warren Shull (UWEC) August 8, 2023
+
+DOCUMENT();
+loadMacros("PG.pl",
+ "PGbasicmacros.pl",
+ "PGchoicemacros.pl",
+ "PGanswermacros.pl",
+ "scaffold.pl",
+ "PGauxiliaryFunctions.pl",
+ "PGgraphmacros.pl",
+ "freemanMacros.pl",
+ "AnswerFormatHelp.pl",
+ "Parser.pl", "desmos.pl",);
+
+loadMacros("niceTables.pl");
+
+loadMacros(
+ "PGstandard.pl", # Standard macros for PG language
+ "MathObjects.pl",
+ "PGML.pl",
+ #"source.pl", # allows code to be displayed on certain sites.
+ #"PGcourse.pl", # Customization file for the course
+ #"scaffold.pl",
+ "unionTables.pl",
+ "parserPopUp.pl", # <--------------------------------------NEEDED FOR DROPDOWN MENUS
+ "PGtikz.pl",
+);
+
+loadMacros(
+ "contextFraction.pl",
+ "parserMultiAnswer.pl",
+"answerHints.pl",
+ "PGcourse.pl", # Customization file for the course
+ "customCSS.pl", # <---- MAKES BOXES PURPLE
+);
+
+Context("Numeric");
+
+$yes = PopUp(
+ ["Choose one", "yes","no"],
+ "yes");
+
+$no = PopUp(
+ ["Choose one", "yes","no"],
+ "no");
+
+$dne = String("DNE");
+
+$width = 200;
+$height = 350;
+
+desmos_enable_construct_new();
+$unique_div_id = "evaluating_f";
+$desmos_div = MODES(
+ HTML=>qq(),
+ TeX=>'Interactive graph best viewed online'
+);
+
+$unique_div_id2 = "evaluating_h";
+$desmos_div2 = MODES(
+ HTML=>qq(),
+ TeX=>'Interactive graph best viewed online'
+);
+
+#$contin = String('continuous');
+
+$p1=-1;
+$p2=-.2;
+$p3=-.05;
+$p4=1;
+$p5=.2;
+$p6=.05;
+
+$a=random(2,6); #left piece $a*x
+$b=random(-5,-1); #left to middle
+#middle piece x^2
+$c=random(1,5); #middle to right
+$d=random(1,5); #right piece $d-x
+while($d-$c==$c*$c){$d=random(1,5);}
+
+$f1=Formula("$a*x")->reduce; #left
+$f2=Formula("x^2")->reduce; #middle
+$f3=Formula("$d-x")->reduce; #right
+
+$b1=$b-.1;
+$b2=$b-.01;
+$b3=$b-.001;
+
+$fb1 = $f1->eval(x=>$b1);
+$fb2 = $f1->eval(x=>$b2);
+$fb3 = $f1->eval(x=>$b3);
+
+$b4=$b+.1;
+$b5=$b+.01;
+$b6=$b+.001;
+
+$fb4 = $f2->eval(x=>$b4);
+$fb5 = $f2->eval(x=>$b5);
+$fb6 = $f2->eval(x=>$b6);
+
+$fb_left = $f1->eval(x=>$b);
+$fb_right = $f2->eval(x=>$b);
+
+$c1=$c-.1;
+$c2=$c-.01;
+$c3=$c-.001;
+
+$fc1 = $f2->eval(x=>$c1);
+$fc2 = $f2->eval(x=>$c2);
+$fc3 = $f2->eval(x=>$c3);
+
+$c4=$c+.1;
+$c5=$c+.01;
+$c6=$c+.001;
+
+$fc4 = $f3->eval(x=>$c4);
+$fc5 = $f3->eval(x=>$c5);
+$fc6 = $f3->eval(x=>$c6);
+
+$fc_left = $f2->eval(x=>$c);
+$fc_right = $f3->eval(x=>$c);
+
+SRAND($psvn);
+
+$i=random(-7,-2); #left-to-middle
+$j=random(1,5); #vertical asymptote on the right
+$j_less=$j-2; #middle-to-right
+
+$h1 = Formula("2^(x-$i)")->reduce; #left piece
+$h3 = Formula("(($j+2)*x-($j*$j+2*$j-2))/(x-$j)")->reduce; #right piece; x=j asymptote
+
+$hi_left=$h1->eval(x=>$i);
+$hj_right=$h3->eval(x=>$j-2); #j-2 not j; should equal j+1
+
+Context("Fraction");
+
+$h_slope = Fraction("$hj_right/($j-2-$i)")->reduce;
+
+Context("Numeric");
+
+$h2_partial = Formula("(x-$i)")->reduce; #just the x-i part without the slope
+
+$h2=Formula("$h_slope*$h2_partial");
+
+$hi_right=$h2->eval(x=>$i);
+$hj_left=$h2->eval(x=>$j-2); #j-2 not j
+
+$k=random(-10,10);
+while($k==$hj_left){$k=random(-10,10);}
+
+$i1=$i-.02;
+$i2=$i-.005;
+$i3=$i-.001;
+
+$hi1=$h1->eval(x=>$i1);
+$hi2=$h1->eval(x=>$i2);
+$hi3=$h1->eval(x=>$i3);
+
+$i4=$i+.1;
+$i5=$i+.01;
+$i6=$i+.001;
+
+$hi4=$h2->eval(x=>$i4);
+$hi5=$h2->eval(x=>$i5);
+$hi6=$h2->eval(x=>$i6);
+
+$j1=$j-2-.1;
+$j2=$j-2-.01;
+$j3=$j-2-.001;
+
+$hj1=$h2->eval(x=>$j1);
+$hj2=$h2->eval(x=>$j2);
+$hj3=$h2->eval(x=>$j3);
+
+$j4=$j-2+.1;
+$j5=$j-2+.01;
+$j6=$j-2+.001;
+
+$hj4=$h3->eval(x=>$j4);
+$hj5=$h3->eval(x=>$j5);
+$hj6=$h3->eval(x=>$j6);
+
+## THIS IS PROBLEM 3 OF A 4 PROBLEM SERIES INTRODUCING LIMITS ALGEBRAICALLY. IF YOU USE THEM TOGETHER, YOU CAN USE PASSCODES TO ALLOW YOU TO REQUIRE THE PROBLEMS BE DONE IN ORDER. BELOW IS SOME OF THE CODE YOU'LL NEED:
+
+#SRAND($psvn);
+
+#$passcode1 = random(1000,9999);
+#$passcode2 = random(1000,9999);
+#$passcode3 = random(1000,9999);
+
+## END PASSCODE CODE
+
+$p=non_zero_random(-5,5);
+$g=Formula("$p*x/|x|");
+
+$gp1 = $g->eval(x=>$p1);
+$gp2 = $g->eval(x=>$p2);
+$gp3 = $g->eval(x=>$p3);
+$gp4 = $g->eval(x=>$p4);
+$gp5 = $g->eval(x=>$p5);
+$gp6 = $g->eval(x=>$p6);
+
+$cts_neither = PopUp(
+ ["Choose one", 'x='.$i,"x=".$j_less,"both","neither"],
+ "neither");
+
+TEXT(beginproblem());
+Context()->texStrings;
+
+Scaffold::Begin(can_open => "when_previous_correct", is_open => "first_incorrect");
+###########################################
+Section::Begin("Passcode");
+
+BEGIN_PGML
+
+In the previous problem, we looked at
+
+[```g(x)=[$g]```]
+
+[% Enter the passcode from the previous problem: [_]{$passcode2} %]
+
+END_PGML
+
+Section::End();
+
+Section::Begin("Previous table");
+
+BEGIN_PGML
+
+Here is the table we made for [``\lim_{x\rightarrow0}g(x)``]. I've added a few rows; go ahead and fill them in!
+
+[@
+DataTable(
+[
+ ['\(x\)','\(g(x)\)'],
+ ['\(-1\)','\('.$gp1.'\)'],
+ ['\(-.2\)','\('.$gp2.'\)'],
+ ['\(-.05\)','\('.$gp3.'\)'],
+ ['\(-.02\)',ans_rule(10)],
+ ['\(-.005\)',ans_rule(10)],
+ ['\(1\)','\('.$gp4.'\)'],
+ ['\(.2\)','\('.$gp5.'\)'],
+ ['\(.05\)','\('.$gp6.'\)'],
+ ['\(.02\)',ans_rule(10)],
+ ['\(.005\)',ans_rule(10)],
+],
+align => '|l | l|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+@]*
+
+END_PGML
+
+ANS($gp2->cmp());
+
+ANS($gp3->cmp());
+
+ANS($gp5->cmp());
+
+ANS($gp6->cmp());
+
+BEGIN_PGML
+
+As we established in the previous problem, [``\lim_{x\rightarrow0}g(x)``] does not exist. However, if you look *only* at [`x`]-values *less than* 0, [`g(x)`] is approaching what number? [_]{$gp1}
+
+Similarly, for [`x`]-values *greater than* 0, what number is [`g(x)`] approaching? [_]{$gp4}
+
+END_PGML
+
+Section::End();
+
+Section::Begin("One-sided limits");
+
+BEGIN_PGML
+
+We call these numbers *one-sided limits*! For [`x`]-values less than any number [`c`], we write
+
+[```\lim_{x\rightarrow c^-}g(x)```]
+
+and for [`x`]-values greater than [`c`], we write
+
+[```\lim_{x\rightarrow c^+}g(x)```]
+
+So, in this example,
+
+[``\lim_{x\rightarrow0^-}g(x)=``][_]{$gp1}
+
+and
+
+[``\lim_{x\rightarrow0^+}g(x)=``] [_]{$gp4}
+
+One-sided limits will be especially common in _piecewise functions_. We will look at one next! If you would like a refresher on what piecewise functions are, the next scaffold bar (which should appear green instead of yellow) has a video about it from Prof. Shull. (Feel free to skip if you remember piecewise functions well.)
+
+END_PGML
+
+Section::End();
+
+Section::Begin("Piecewise function review video (20:45)");
+
+BEGIN_PGML
+
+[@
+kalturaShull("1_4ver89yh")
+@]*
+
+END_PGML
+Section::End();
+
+
+Section::Begin("Piecewise function limits");
+
+BEGIN_PGML
+
+Let's find some limits for this piecewise function!
+
+You can use the window on the right as a calculator, but you need to type the function yourself! Don't try to type the whole piecewise function; just type the piece you need for each value of [`x`].
+
+[```f(x)=
+\begin{cases}
+[$a]x&x<[$b]\\
+x^2&[$b]\leq x\leq[$c]\\
+[$d]-x&x>[$c]\\
+\end{cases}```]
+
+END_PGML
+
+$table=DataTable(
+[
+ ['\(x\)','\(f(x)\)'],
+ ['\('.$b1.'\)',ans_rule(10)],
+ ['\('.$b2.'\)',ans_rule(10)],
+ ['\('.$b3.'\)',ans_rule(10)],
+ ['\('.$b4.'\)',ans_rule(10)],
+ ['\('.$b5.'\)',ans_rule(10)],
+ ['\('.$b6.'\)',ans_rule(10)],
+ ['\('.$c1.'\)',ans_rule(10)],
+ ['\('.$c2.'\)',ans_rule(10)],
+ ['\('.$c3.'\)',ans_rule(10)],
+ ['\('.$c4.'\)',ans_rule(10)],
+ ['\('.$c5.'\)',ans_rule(10)],
+ ['\('.$c6.'\)',ans_rule(10)],
+],
+align => '|l | l|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+
+TEXT(ColumnTable($table,$desmos_div));
+
+#Context()->{format}{number} = "%.2f";
+#ANS(Real(sprintf("%.2f",$fb1))->cmp());
+ANS($fb1->cmp());
+
+#Context()->{format}{number} = "%.4f";
+#ANS(Real(sprintf("%.4f",$fb2))->cmp());
+ANS($fb2->cmp());
+
+#Context()->{format}{number} = "%.6f";
+#ANS(Real(sprintf("%.6f",$fb3))->cmp());
+ANS($fb3->cmp());
+
+#Context()->{format}{number} = "%.2f";
+#ANS(Real(sprintf("%.2f",$fb4))->cmp());
+ANS($fb4->cmp());
+
+#Context()->{format}{number} = "%.4f";
+#ANS(Real(sprintf("%.4f",$fb5))->cmp());
+ANS($fb5->cmp());
+
+#Context()->{format}{number} = "%.6f";
+#ANS(Real(sprintf("%.6f",$fb6))->cmp());
+ANS($fb6->cmp());
+
+#Context()->{format}{number} = "%g";
+
+ANS($fc1->cmp());
+ANS($fc2->cmp());
+ANS($fc3->cmp());
+ANS($fc4->cmp());
+ANS($fc5->cmp());
+ANS($fc6->cmp());
+
+BEGIN_TEXT
+$PAR $PAR $PAR
+END_TEXT
+
+BEGIN_PGML
+
+Use your answers in the table to evaluate these four one-sided limits, then evaluate [`f`] at the two numbers listed.
+
+[``\lim_{x\rightarrow[$b]^-}f(x)=``] [_]{$fb_left}
+
+[``\lim_{x\rightarrow[$b]^+}f(x)=``] [_]{$fb_right}
+
+[``\lim_{x\rightarrow[$c]^-}f(x)=``] [_]{$fc_left}
+
+[``\lim_{x\rightarrow[$c]^+}f(x)=``] [_]{$fc_right}
+
+[``f([$b])=``] [_]{$fb_right}
+
+[``f([$c])=``] [_]{$fc_left}
+
+END_PGML
+
+Section::End();
+
+Section::Begin("Another piecewise function");
+
+BEGIN_PGML
+
+Here's another piecewise function:
+
+[```h(x)=
+\begin{cases}
+[$h1]&x\leq[$i]\\
+[$h_slope]([$h2_partial])&[$i][$j-2]\\
+\end{cases}```]
+
+Fill in the table, rounding as indicated.
+
+END_PGML
+
+$table=DataTable(
+[
+ ['\(x\)',"rounding",'\(h(x)\)'],
+ ['\('.$i1.'\)',2,ans_rule(10)],
+ ['\('.$i2.'\)',3,ans_rule(10)],
+ ['\('.$i3.'\)',4,ans_rule(10)],
+ ['\('.$i4.'\)',3,ans_rule(10)],
+ ['\('.$i5.'\)',4,ans_rule(10)],
+ ['\('.$i6.'\)',5,ans_rule(10)],
+ ['\('.$j1.'\)',2,ans_rule(10)],
+ ['\('.$j2.'\)',3,ans_rule(10)],
+ ['\('.$j3.'\)',4,ans_rule(10)],
+ ['\('.$j4.'\)',2,ans_rule(10)],
+ ['\('.$j5.'\)',3,ans_rule(10)],
+ ['\('.$j6.'\)',4,ans_rule(10)],
+],
+align => '|l | c|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+
+TEXT(ColumnTable($table,$desmos_div2));
+
+Context()->{format}{number} = "%.2f";
+ANS(Real(sprintf("%.2f",$hi1))->cmp());
+
+Context()->{format}{number} = "%.3f";
+ANS(Real(sprintf("%.3f",$hi2))->cmp());
+
+Context()->{format}{number} = "%.4f";
+ANS(Real(sprintf("%.4f",$hi3))->cmp());
+
+Context()->{format}{number} = "%.3f";
+ANS(Real(sprintf("%.3f",$hi4))->cmp());
+
+Context()->{format}{number} = "%.4f";
+ANS(Real(sprintf("%.4f",$hi5))->cmp());
+
+Context()->{format}{number} = "%.5f";
+ANS(Real(sprintf("%.5f",$hi6))->cmp());
+
+Context()->{format}{number} = "%.2f";
+ANS(Real(sprintf("%.2f",$hj1))->cmp());
+
+Context()->{format}{number} = "%.3f";
+ANS(Real(sprintf("%.3f",$hj2))->cmp());
+
+Context()->{format}{number} = "%.4f";
+ANS(Real(sprintf("%.4f",$hj3))->cmp());
+
+Context()->{format}{number} = "%.2f";
+ANS(Real(sprintf("%.2f",$hj4))->cmp());
+
+Context()->{format}{number} = "%.3f";
+ANS(Real(sprintf("%.3f",$hj5))->cmp());
+
+Context()->{format}{number} = "%.4f";
+ANS(Real(sprintf("%.4f",$hj6))->cmp());
+
+Context()->{format}{number} = "%g";
+
+BEGIN_PGML
+
+Based on the table, answer the following questions (write "DNE" if something does not exist):
+
+[``\lim_{x\rightarrow[$i]^-}h(x)=``] [_]{$hi_left}
+
+[``\lim_{x\rightarrow[$i]^+}h(x)=``] [_]{$hi_right}
+
+[``\lim_{x\rightarrow[$i]}h(x)=``] [_]{$dne}
+
+[``\lim_{x\rightarrow[$j-2]^-}h(x)=``] [_]{$hj_left}
+
+[``\lim_{x\rightarrow[$j-2]^+}h(x)=``] [_]{$hj_right}
+
+[``\lim_{x\rightarrow[$j-2]}h(x)=``] [_]{$hj_left}
+
+[`h([$i])=`] [_]{$hi_left}
+
+[`h([$j-2])=`] [_]{$k}
+
+END_PGML
+
+Section::End();
+
+Section::Begin("Continuity & passcode");
+
+BEGIN_PGML
+
+As you just saw, one of the two-sided limits in the previous part _did_ exist, and one did not. But what about continuity? Based on what we know so far, [`h(x)`] is continuous at [_]{$cts_neither}.
+
+[% The passcode for the next question is [`[$passcode3]`]. Enter it here: [_]{$passcode3} %]
+
+END_PGML
+
+Section::End();
+
+# EXTRA LINES OF CODE FOR OTHER PURPOSES:
+# Context()->{format}{number} = "%18.15f";
+# ANS(Real(sprintf("%.3f",$gd2->value))->cmp(tolType => 'absolute',tolerance => .01));
+# ANS(Real(sprintf("%.8f",$gd6))->cmp(tolType => 'absolute',tolerance => 1e-7));
+# ANS($fb1->cmp(tolType => 'absolute',tolerance => .5));
+# ANS($gd6->cmp());
+
+# SIDE BY SIDE CODE:
+# $column1 = $desmos_div ."$PAR $PAR $PAR $PAR ". $desmos_div2;
+
+ Scaffold::End();
+
+TEXT( MODES(TeX=>'', HTML=><
+
+ var arstarst = document.getElementById("$unique_div_id");
+
+ var my_calculator = Desmos.Calculator(arstarst, {
+ keypad: false,
+ //expressions: false,
+ expressions: true,
+ settingsMenu: true,
+ graphpaper: false,
+ expressionsTopbar: true
+ });
+
+
+ my_calculator.setMathBounds({
+ left: -101,
+ right: -99,
+ bottom: -1,
+ top: 1
+ });
+
+ my_calculator.updateSettings({ fontSize: Desmos.FontSizes.SMALL, expressions: true });
+
+ var state = my_calculator.getState();
+
+END_SCRIPT
+
+TEXT( MODES(TeX=>'', HTML=><
+
+ var arstarst = document.getElementById("$unique_div_id2");
+
+ var my_calculator = Desmos.Calculator(arstarst, {
+ keypad: false,
+ //expressions: false,
+ expressions: true,
+ settingsMenu: true,
+ graphpaper: false,
+ expressionsTopbar: true
+ });
+
+
+ my_calculator.setMathBounds({
+ left: -101,
+ right: -99,
+ bottom: -1,
+ top: 1
+ });
+
+ my_calculator.updateSettings({ fontSize: Desmos.FontSizes.SMALL, expressions: true });
+
+ var state = my_calculator.getState();
+
+END_SCRIPT
+
+Context()->normalStrings;
+
+ENDDOCUMENT();
+
diff --git a/Contrib/Wisconsin/EauClaire/calculus/limits_with_formulas_problem_4_of_4.pg b/Contrib/Wisconsin/EauClaire/calculus/limits_with_formulas_problem_4_of_4.pg
new file mode 100644
index 0000000000..e4f34fbb97
--- /dev/null
+++ b/Contrib/Wisconsin/EauClaire/calculus/limits_with_formulas_problem_4_of_4.pg
@@ -0,0 +1,573 @@
+# DESCRIPTION
+## DBsubject('Calculus')
+## DBchapter('Limits')
+## DBsection('Investigating Limits')
+## KEYWORDS('Limits', 'one-sided', 'infinity')
+## TitleText1('Calculus: Early Transcendentals')
+## EditionText1('4')
+## AuthorText1('Rogawski')
+## Section1('2.2')
+## Institution('UW Eau Claire')
+## Copied and modified by Warren Shull (UWEC) August 8, 2023
+
+DOCUMENT();
+loadMacros("PG.pl",
+ "PGbasicmacros.pl",
+ "PGchoicemacros.pl",
+ "PGanswermacros.pl",
+ "scaffold.pl",
+ "PGauxiliaryFunctions.pl",
+ "PGgraphmacros.pl",
+ "freemanMacros.pl",
+ "AnswerFormatHelp.pl",
+ "Parser.pl", "desmos.pl",);
+
+loadMacros("niceTables.pl");
+
+loadMacros(
+ "PGstandard.pl", # Standard macros for PG language
+ "MathObjects.pl",
+ "PGML.pl",
+ #"source.pl", # allows code to be displayed on certain sites.
+ #"PGcourse.pl", # Customization file for the course
+ #"scaffold.pl",
+ "unionTables.pl",
+ "parserPopUp.pl", # <--------------------------------------NEEDED FOR DROPDOWN MENUS
+ "PGtikz.pl",
+);
+
+loadMacros(
+ "contextFraction.pl",
+ "parserMultiAnswer.pl",
+"answerHints.pl",
+ "PGcourse.pl", # Customization file for the course
+ "customCSS.pl", # <---- MAKES BOXES PURPLE
+);
+
+Context("Numeric");
+
+$Inf = Infinity;
+$NInf = -(Infinity);
+
+$yes = PopUp(
+ ["Choose one", "yes","no"],
+ "yes");
+
+$no = PopUp(
+ ["Choose one", "yes","no"],
+ "no");
+
+$negative_infinity = PopUp(
+ ["Choose one", "Approaches more than one number", "Goes up forever","Goes down forever", "Jumps around unpredictably", "Stops existing"],
+ "Goes down forever");
+
+$positive_infinity = PopUp(
+ ["Choose one", "Approaches more than one number", "Goes up forever","Goes down forever", "Jumps around unpredictably", "Stops existing"],
+ "Goes up forever");
+
+$dne = String("DNE");
+
+#$contin = String('continuous');
+
+#a,b,c,d available
+
+$width = 200;
+$height = 200;
+
+desmos_enable_construct_new();
+
+$unique_div_id = "evaluating_h_5_left";
+$desmos_div = MODES(
+ HTML=>qq(),
+ TeX=>'Interactive graph best viewed online'
+);
+
+$unique_div_id2 = "evaluating_h_5_right";
+$desmos_div2 = MODES(
+ HTML=>qq(),
+ TeX=>'Interactive graph best viewed online'
+);
+
+$unique_div_id3 = "evaluating_h_inf";
+$desmos_div3 = MODES(
+ HTML=>qq(),
+ TeX=>'Interactive graph best viewed online'
+);
+
+$unique_div_id4 = "evaluating_h_neg_inf";
+$desmos_div4 = MODES(
+ HTML=>qq(),
+ TeX=>'Interactive graph best viewed online'
+);
+
+$p1=-1;
+$p2=-.2;
+$p3=-.05;
+$p4=1;
+$p5=.2;
+$p6=.05;
+
+SRAND($psvn);
+
+$i=random(-7,-2); #left-to-middle
+$j=random(1,5); #vertical asymptote on the right
+$j_less=$j-2; #middle-to-right
+
+$h1 = Formula("2^(x-$i)")->reduce; #left piece
+$h3 = Formula("(($j+2)*x-($j*$j+2*$j-2))/(x-$j)")->reduce; #right piece; x=j asymptote
+
+$hi_left=$h1->eval(x=>$i);
+$hj_right=$h3->eval(x=>$j-2); #j-2 not j; should equal j+1
+
+Context("Fraction");
+
+$h_slope = Fraction("$hj_right/($j-2-$i)")->reduce;
+
+Context("Numeric");
+
+$h2_partial = Formula("(x-$i)")->reduce; #just the x-i part without the slope
+
+$h2=Formula("$h_slope*$h2_partial");
+
+$hi_right=$h2->eval(x=>$i);
+$hj_left=$h2->eval(x=>$j-2); #j-2 not j
+
+$k=random(-10,10);
+while($k==$hj_left){$k=random(-10,10);}
+
+$i1=$i-.02;
+$i2=$i-.005;
+$i3=$i-.001;
+
+$hi1=$h1->eval(x=>$i1);
+$hi2=$h1->eval(x=>$i2);
+$hi3=$h1->eval(x=>$i3);
+
+$i4=$i+.1;
+$i5=$i+.01;
+$i6=$i+.001;
+
+$hi4=$h2->eval(x=>$i4);
+$hi5=$h2->eval(x=>$i5);
+$hi6=$h2->eval(x=>$i6);
+
+$j1=$j-2-.1;
+$j2=$j-2-.01;
+$j3=$j-2-.001;
+
+$hj1=$h2->eval(x=>$j1);
+$hj2=$h2->eval(x=>$j2);
+$hj3=$h2->eval(x=>$j3);
+
+$j4=$j-2+.1;
+$j5=$j-2+.01;
+$j6=$j-2+.001;
+
+$hj4=$h3->eval(x=>$j4);
+$hj5=$h3->eval(x=>$j5);
+$hj6=$h3->eval(x=>$j6);
+
+
+## THIS IS PROBLEM 4 OF A 4 PROBLEM SERIES INTRODUCING LIMITS ALGEBRAICALLY. IF YOU USE THEM TOGETHER, YOU CAN USE PASSCODES TO ALLOW YOU TO REQUIRE THE PROBLEMS BE DONE IN ORDER. BELOW IS SOME OF THE CODE YOU'LL NEED:
+
+#SRAND($psvn);
+
+#$passcode1 = random(1000,9999);
+#$passcode2 = random(1000,9999);
+#$passcode3 = random(1000,9999);
+
+## END PASSCODE CODE
+
+
+$p=non_zero_random(-5,5);
+$g=Formula("$p*x/|x|");
+
+$gp1 = $g->eval(x=>$p1);
+$gp2 = $g->eval(x=>$p2);
+$gp3 = $g->eval(x=>$p3);
+$gp4 = $g->eval(x=>$p4);
+$gp5 = $g->eval(x=>$p5);
+$gp6 = $g->eval(x=>$p6);
+
+$cts_neither = PopUp(
+ ["Choose one", 'x='.$i,"x=".$j_less,"both","neither"],
+ "neither");
+
+$ja0=$j-.2;
+$ja1=$j-.05;
+$ja2=$j-.01;
+$ja3=$j-.002;
+$ja4=$j-.0005;
+
+$hja0=$h3->eval(x=>$ja0);
+$hja1=$h3->eval(x=>$ja1);
+$hja2=$h3->eval(x=>$ja2);
+$hja3=$h3->eval(x=>$ja3);
+$hja4=$h3->eval(x=>$ja4);
+
+$ja5=$j+.2;
+$ja6=$j+.05;
+$ja7=$j+.01;
+$ja8=$j+.002;
+$ja9=$j+.0005;
+
+$hja5=$h3->eval(x=>$ja5);
+$hja6=$h3->eval(x=>$ja6);
+$hja7=$h3->eval(x=>$ja7);
+$hja8=$h3->eval(x=>$ja8);
+$hja9=$h3->eval(x=>$ja9);
+
+$jb1=$j+100;
+$jb2=$j+1000;
+$jb3=$j+10000;
+
+$hjb1=$h3->eval(x=>$jb1);
+$hjb2=$h3->eval(x=>$jb2);
+$hjb3=$h3->eval(x=>$jb3);
+
+$jb4=$i-3;
+$jb5=$i-9;
+$jb6=$i-14;
+
+$hjb4=$h1->eval(x=>$jb4);
+$hjb5=$h1->eval(x=>$jb5);
+$hjb6=$h1->eval(x=>$jb6);
+
+TEXT(beginproblem());
+Context()->texStrings;
+
+Scaffold::Begin(can_open => "when_previous_correct", is_open => "first_incorrect");
+###########################################
+Section::Begin("Passcode");
+
+BEGIN_PGML
+
+In the previous problem, we looked at
+
+[```h(x)=
+\begin{cases}
+[$h1]&x\leq[$i]\\
+[$h_slope]([$h2_partial])&[$i][$j-2]\\
+\end{cases}```]
+
+[% Enter the passcode from the previous problem: [_]{$passcode3} %]
+
+END_PGML
+
+Section::End();
+
+Section::Begin("One more limit...");
+
+BEGIN_PGML
+
+Let's see what happens when [`x`] is close to [`[$j]`]. We will start with [`x`] values slightly _less_ than [`[$j]`]:
+
+END_PGML
+
+$table=DataTable(
+[
+ ['\(x\)','\(h(x)\)'],
+ ['\('.$ja0.'\)',ans_rule(10)],
+ ['\('.$ja1.'\)',ans_rule(10)],
+ ['\('.$ja2.'\)',ans_rule(10)],
+ ['\('.$ja3.'\)',ans_rule(10)],
+ ['\('.$ja4.'\)',ans_rule(10)],
+],
+align => '|l | l|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+
+TEXT(ColumnTable($table,$desmos_div));
+
+#Context()->{format}{number} = "%.2f";
+#ANS(Real(sprintf("%.2f",$hja0))->cmp());
+ANS($hja0->cmp());
+ANS($hja1->cmp());
+ANS($hja2->cmp());
+ANS($hja3->cmp());
+ANS($hja4->cmp());
+
+#Context()->{format}{number} = "%g";
+
+BEGIN_PGML
+
+Is there any number these [`y`]-values are approaching? [_]{$no}
+
+END_PGML
+Section::End();
+
+Section::Begin("Describing the y-values");
+
+BEGIN_PGML
+
+When [`x`] is slightly less than [`[$j]`] and getting closer to it, how would you describe what the output [`h(x)`] does? [_]{$negative_infinity}
+
+END_PGML
+
+Section::End();
+
+Section::Begin("Other side");
+
+$table2=DataTable(
+[
+ ['\(x\)','\(h(x)\)'],
+ ['\('.$ja5.'\)',ans_rule(10)],
+ ['\('.$ja6.'\)',ans_rule(10)],
+ ['\('.$ja7.'\)',ans_rule(10)],
+ ['\('.$ja8.'\)',ans_rule(10)],
+ ['\('.$ja9.'\)',ans_rule(10)],
+],
+align => '|l | l|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+
+TEXT(ColumnTable($table2,$desmos_div2));
+
+ANS($hja5->cmp());
+ANS($hja6->cmp());
+ANS($hja7->cmp());
+ANS($hja8->cmp());
+ANS($hja9->cmp());
+
+BEGIN_PGML
+
+When [`x`] is slightly _more_ than [`[$j]`] and getting closer to it, how would you describe what the output [`h(x)`] does? [_]{$positive_infinity}
+
+END_PGML
+
+Section::End();
+
+Section::Begin("Infinite Limits!");
+
+BEGIN_PGML
+
+When [`h(x)`] goes up or down forever, we often refer to that limit as "equaling" either [`\infty`] or [`-\infty`] (you can type [`\infty`] with "inf"). In this case:
+
+[``\lim_{x\rightarrow[$j]^-}h(x)=``] [_]{$NInf}
+
+[``\lim_{x\rightarrow[$j]^+}h(x)=``] [_]{$Inf}
+
+We call both of these *infinite limits*. Keep in mind that [`\infty`] and [`-\infty`] are _not_ numbers, so in a sense we can still say these limits "do not exist." However, sometimes we want to specify if a function goes up or down forever, and the limit notation along with the [`\infty`] symbol is a great way to do it!
+
+If you are ever unsure whether a problem wants you to answer "DNE" for an infinite limit, or to answer [`\infty`] or [`-\infty`] where they would fit, either try it both ways or ask your instructor. (For this problem set, use [`\infty`] and [`-\infty`].)
+
+Are your last two answers the same? [_]{$no}
+
+So what is [``\lim_{x\rightarrow5}h(x)``]? [_]{$dne}
+
+END_PGML
+
+Section::End();
+
+Section::Begin('What about when \(x\) goes way up...?');
+
+BEGIN_PGML
+
+We just saw an example of _output_ numbers approaching [`\infty`] or [`-\infty`]. But what about _input_ numbers?
+
+END_PGML
+
+$table3=DataTable(
+[
+ ['\(x\)','\(h(x)\)'],
+ ['\('.$jb1.'\)',ans_rule(10)],
+ ['\('.$jb2.'\)',ans_rule(10)],
+ ['\('.$jb3.'\)',ans_rule(10)],
+],
+align => '|l | l|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+
+TEXT(ColumnTable($table3,$desmos_div3));
+
+#Context()->{format}{number} = "%.2f";
+#ANS(Real(sprintf("%.2f",$hja0))->cmp());
+ANS($hjb1->cmp());
+ANS($hjb2->cmp());
+ANS($hjb3->cmp());
+
+#Context()->{format}{number} = "%g";
+
+BEGIN_PGML
+
+As [`x`] keeps going up, what is [`h(x)`] getting close to? [_]{2+$j}
+
+We call this number [``\lim_{x\rightarrow\infty}h(x)``].
+
+END_PGML
+
+Section::End();
+
+Section::Begin('...or down?');
+
+BEGIN_PGML
+
+Let's see what happens when [`x`] keeps going down.
+END_PGML
+
+$table4=DataTable(
+[
+ ['\(x\)',"rounding",'\(h(x)\)'],
+ ['\('.$jb4.'\)','',ans_rule(10)],
+ ['\('.$jb5.'\)',5,ans_rule(10)],
+ ['\('.$jb6.'\)',6,ans_rule(10)],
+],
+align => '|l | c|l|',
+midrules => 1,
+tablecss => " border-spacing:0px 0px; border-radius: 5px; border-collapse:separate;"
+);
+
+TEXT(ColumnTable($table4,$desmos_div4));
+
+Context()->normalStrings;
+
+ANS($hjb4->cmp());
+
+Context()->{format}{number} = "%.5f";
+ANS(num_cmp($hjb5,tol=>5e-6, tolType=>"absolute"));
+
+Context()->{format}{number} = "%.6f";
+ANS(num_cmp($hjb6,tol=>5e-7, tolType=>"absolute"));
+
+Context()->{format}{number} = "%g";
+
+Context()->texStrings;
+
+BEGIN_PGML
+
+[``\lim_{x\rightarrow-\infty}=``] [_]{0}
+
+(It might not seem like these [`x`] values are that far down, but this number is approached _really_ fast.)
+
+END_PGML
+
+Section::End();
+ Scaffold::End();
+
+TEXT( MODES(TeX=>'', HTML=><
+
+ var arstarst = document.getElementById("$unique_div_id");
+
+ var my_calculator = Desmos.Calculator(arstarst, {
+ keypad: false,
+ //expressions: false,
+ expressions: true,
+ settingsMenu: true,
+ graphpaper: false,
+ expressionsTopbar: true
+ });
+
+ my_calculator.setMathBounds({
+ left: -101,
+ right: -99,
+ bottom: -1,
+ top: 1
+ });
+
+ my_calculator.updateSettings({ fontSize: Desmos.FontSizes.SMALL, expressions: true });
+
+ var state = my_calculator.getState();
+
+END_SCRIPT
+
+TEXT( MODES(TeX=>'', HTML=><
+
+ var arstarst = document.getElementById("$unique_div_id2");
+
+ var my_calculator = Desmos.Calculator(arstarst, {
+ keypad: false,
+ //expressions: false,
+ expressions: true,
+ settingsMenu: true,
+ graphpaper: false,
+ expressionsTopbar: true
+ });
+
+ my_calculator.setMathBounds({
+ left: -101,
+ right: -99,
+ bottom: -1,
+ top: 1
+ });
+
+ my_calculator.updateSettings({ fontSize: Desmos.FontSizes.SMALL, expressions: true });
+
+ var state = my_calculator.getState();
+
+END_SCRIPT
+
+TEXT( MODES(TeX=>'', HTML=><
+
+ var arstarst = document.getElementById("$unique_div_id3");
+
+ var my_calculator = Desmos.Calculator(arstarst, {
+ keypad: false,
+ //expressions: false,
+ expressions: true,
+ settingsMenu: true,
+ graphpaper: false,
+ expressionsTopbar: true
+ });
+
+ my_calculator.setMathBounds({
+ left: -101,
+ right: -99,
+ bottom: -1,
+ top: 1
+ });
+
+ my_calculator.updateSettings({ fontSize: Desmos.FontSizes.SMALL, expressions: true });
+
+ var state = my_calculator.getState();
+
+END_SCRIPT
+
+TEXT( MODES(TeX=>'', HTML=><
+
+ var arstarst = document.getElementById("$unique_div_id4");
+
+ var my_calculator = Desmos.Calculator(arstarst, {
+ keypad: false,
+ //expressions: false,
+ expressions: true,
+ settingsMenu: true,
+ graphpaper: false,
+ expressionsTopbar: true
+ });
+
+ my_calculator.setMathBounds({
+ left: -101,
+ right: -99,
+ bottom: -1,
+ top: 1
+ });
+
+ my_calculator.updateSettings({ fontSize: Desmos.FontSizes.SMALL, expressions: true });
+
+ var state = my_calculator.getState();
+
+END_SCRIPT
+
+Context()->normalStrings;
+
+ENDDOCUMENT();
+
+# EXTRA LINES OF CODE FOR OTHER PURPOSES:
+# Context()->{format}{number} = "%18.15f";
+# ANS(Real(sprintf("%.3f",$gd2->value))->cmp(tolType => 'absolute',tolerance => .01));
+# ANS(Real(sprintf("%.8f",$gd6))->cmp(tolType => 'absolute',tolerance => 1e-7));
+# ANS($fb1->cmp(tolType => 'absolute',tolerance => .5));
+# ANS($gd6->cmp());
+
+# SIDE BY SIDE CODE:
+# $column1 = $desmos_div ."$PAR $PAR $PAR $PAR ". $desmos_div2;
+