The Navigator Object
The appName property returns the application name of the browser:
Strange enough, "Netscape" is the application name for IE11, Chrome, Firefox, and Safari.
The appName property returns the application name of the browser:
Strange enough, "Netscape" is the application name for IE11, Chrome, Firefox, and Safari.
Web pages devoted to problems which are clones of hard copy pages, are just as likely to be successful in enhancing learning as their predecessors, i.e., not very effective. Learning from the written word is not part of current dogma, hence teachers, tutors, etc..
Videos of chalk boards should be as effective as lectures in affecting learning i.e., not very effective. Passive web instruments are little better than last century text books in enhancing self learning. Passive web instruments are little better than lectures.
Pedagogically, one should be searching for problems on web pages which require reader input to achieve solutions, with instantaneous grading of student inputs, and possible help in overcoming error inputs. Interactive web pages make the motivated learner learn, while leaving the unmotivated learner in stupid city.
Those interactive web pages that exist are primarily multiple-choice queries, a scheme invented to ease the burden of hand grading examinations, and not subject to part credit variances in grading schemes. But multiple-choice responses warp the thinking of students, i.e., enhance gamesmanship, and rarely guarantee that students know what they claim to know. In a world which never presents multiple-choice problems to anything in reality, training children to pass such examinations is tantamount to malpractice.
Clearly, constructed responses are preferable to multiple choice ones, as they offer no subliminal hints concerning the “right” answer. Constructed response questions are the closest thing to perfect assessment tools as exist.
Using cgi-bin programming (in my case using Perl, and chemistry examples), I have created pages and pages of constructed response questions in physical chemistry and freshman chemistry including some new chemical equilibrium problems which illustrate the constructed response question approach. These examples are just the tip of the iceberg, as better handling of potential student incorrect responses offers unlimited possibilities for improvement. See:
https://chemphys.uconn.edu/~chem12x/cgi-bin/sophiakp1a.pl
and
https://chemphys.uconn.edu/~chem12x/cgi-bin/sophiakp2.pl
At this time of the covid remote learning environment we have exactly the right time to create tools for self learning which will enhance future self learning especially when our students have left school. No graduates/adults can expect teachers to answer their questions and grade their learning. Adulthood demands a modus operandi of self learning and self validation of learning which far exceeds what is available today.
These ideas are offered in the hope of encouraging Computer Assisted Learning as a primary way of using remote on-line STEM instruction for interactive problem solving everywhere in the quantitative domain.
For web authors of teaching materials who have public_html access but not cgi-bin access, php alternatives to Perl should be easy to develop. My attempt is currently underway.
This is the code for one of the chemical equilibrium problems presented on the web site:
https://chemphys.uconn.edu/~chem12x/cgi-bin/sophiakp1.pl.
It goes without saying (althought it is being said) that I am not a professional programmer, and that therefore the code presented is not a template.
It is loaded with debugging detrious which may or may not be relevant.
The purpose of releasing the code is to suggest a scheme whereby a professional programmer can create computer assisted learning modules. S/he should regard the following lines as an effort to suggest approaches, rather than a prescription.
The code is centered on CGI.pm, which has been declared obsolete by Perl authors and managers.
I have yet to find a substitute for CGI.pm for allowing perl code to be included in web forms in a transparent manner, and suggest that anyone preparing to use the following code as a suggeestion, should have his/her system administratopr install CGI.pm, since it is no longer included in the standard Perl library.
To make it abundently clear, CGI.pm allows one to write Perl code, which
resides in the executable directory public_html/cgi-bin/ on a standard Unix server of web pages. The public_html directory contains (HTML sourced) web pages which can be loaded directly, while Perl programs located in cgi-bin need to be executed.
We start with the preliminary code:
#!/usr/local/bin/perl -- -*-perl-*-
#
# This is sophiakp1(Computer Assisted Learning, CAL1)
#
require "CleanUp.pl";
require "top.pl";
require "JSCRIPT.js";
use CGI;
use CGI qw/:standard *table start_ul/;
use CGI::Carp qw(fatalsToBrowser);
#
use CAT2p4pchem;
use CGRutils3;
use lib '/home/cdavid/perl5/lib/perl5';
use Mail::Mailer;
$query = new CGI;
$qCAT = new CAT2p4pchem;
$qCGR = new CGRutils3;
$debug = 1;# set to zero to remove print statements
The real work starts here
$first = 1;#ignore box check first time
prin
print $query-&header;
$title = "Sophia's K<sub>p</sub> I. C. E. page";
print $query-&start_html($title);
$global_debug="false";
srand;
top();
$redz = "<font color=red>z</font>";
print "<h1>$title</h1>";
$scriptname = $query->script_name();#this gives the question name
$rnoby3 = $qCAT->rno(3)/3;
$temp_rno = $qCAT->rno(3)/3;
$qCAT->save_vars($query,'rnoby3',\$rnoby3);#save list for this variable
$qCAT->save_vars($query,'temp_rno',\$temp_rno);#save list for this variable
We have defined peripheral constants and we are ready to start the form which will be used to
print $query->start_form();
$student_id = "?";
print <<EOD;
Messages for the author concerning errors, mistakes, bad grammar, etc., can be sent
<a href="mailto:my.name\@uni.edu?subject=Sophiakp1%comment.">to my.name\@uni.edu using your own mail handler.</a> .
EOD
print "<hr>";
$var11 = 10*$qCAT->rno(3)+5;#create random number with two digits behind decimal point
$qCAT->save_vars($query,'var11',\$var11);#save list for this variable
$var12 = 10*$qCAT->rno(3)+$var11;#create random number with two digits behind decimal point
$qCAT->save_vars($query,'var12',\$var12);#save list for this variable
$var13 = 10*$qCAT->rno(3)+$var12;#create random number with two digits behind decimal point
$qCAT->save_vars($query,'var13',\$var13);#save list for this variable
$var11string = sprintf "%5.2f", $var11;
$var12string = sprintf "%5.2f", $var12;
$var13string = sprintf "%5.2f", $var13;
$var21 = "2*z";
$var23 = "-2*z";
$var31 = $var11string."+2*z";
$var32 = $var12string."+z";
$var33 = $var13string."-2*z";
$varz = $var13*$qCAT->rno(3)/3;
$qCAT->save_vars($query,'varz',\$varz);#save list for this variable
$varzstring = sprintf "%5.2f", $varz;
$answerKpusingQp = Qp(($var13-2*$varz), ($var11+2*$varz),($var12+$varz));
$error = 0;
$student_id = "?";
print "To unlock this page, please enter your e-mail address:", $query->textfield( -name=>'student_id',-default=>'?',-size=>40,-maxlength=>50);
$qCAT->save_vars($query,'student_id',\$student_id);#save
print <<EOF;
<br>
The equilibrium constant for the reaction of NO(g) with O<sub>2</sub>(g) to
form NO<sub>2</sub>(g) is unknown.
EOF
The following code gives the Kp expression as long as this site (sciweavers) stays alive.
print <<EOF;
<center>
<img src="http://www.sciweavers.org/tex2img.php?eq=NO%28g%29%20%2B%20%0A%20%5Cfrac%7B1%7D%7B2%7DO_2%28g%29%20%5Crightleftharpoons%0ANO_2%28g%29%20&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit=0" align="center" border="0" alt="NO(g) + \frac{1}{2}O_2(g) \rightleftharpoonsNO_2(g) " width="221" height="43" />
</center>
In a recent experiment, the initial pressure of NO(g) was $var11, while the initial pressure of
O<sub>2</sub>(g) was $var12, and the initial pressure of NO<sub>2</sub>(g) was
$var13.
Please fill in the following tableau (remember to include the '*' sign when multiplying):
EOF
We've stated the problem (at least part of it) and now we are going
to switch from text to a table, i.e., use HTML explicitly.
Here is where the discussion of separating the HTML from the Perl
makes no sense to me.
The HTML flows perfectly, and templating it makes no sense, since the next
problem will require a different kind of table, with its own coding.
The tableau code follows, with the table entries indicating the box indexing
scheme which will be lost as the student fills in the boxes.
Perhaps coding these (x,y) couples into the table with persistence, would
be preferable, but this works as the simplest way of beginning.
print "<center>";
print table({-border=>undef},
caption('I.C.E. Table'),
Tr({-align=>'CENTER',-valign=>'TOP'},
[
th(['', 'P<sub>NO</sub>','P<sub>O<sub>2</sub></sub>','P<sub>NO<sub>2</sub></sub>']),
td(['Initial' ,
$query->textfield( -name=>'box11',
-default=>'1,1',
-size=>5,
-maxlength=>7
),
$query->textfield(-name=>'box12',
-default=>'1,2',
-size=>5,
-maxlength=>7),
$query->textfield(-name=>'box13',
-default=>'1,3',
-size=>5,
-maxlength=>7),
]),
td(['Change' ,
$query->textfield(-name=>'box21',
-default=>'2,1',
-size=>5,
-maxlength=>7),
$redz,
$query->textfield(-name=>'box23',
-default=>'2,3',
-size=>5,
-maxlength=>7),
]),
td(['Equilibium' ,
$query->textfield(-name=>'box31',
-default=>'3,1',
-size=>5,
-maxlength=>9),
$query->textfield(-name=>'box32',
-default=>'3,2',
-size=>5,
-maxlength=>9),
$query->textfield(-name=>'box33',
-default=>'3,3',
-size=>5,
-maxlength=>9)
])
] )
);
When the submit button is pressed, the contents of the boxes are assigned to Perl variables:
$ans11 = $query->param('box11');
$ans12 = $query->param('box12');
$ans13 = $query->param('box13');
$ans21 = $query->param('box21');
$ans22 = $query->param('box22');
$ans23 = $query->param('box23');
$ans31 = $query->param('box31');
$ans32 = $query->param('box32');
$ans33 = $query->param('box33');
#begin judging box answers:
if($query->param('student_id') ne "?"){
In order to unlock the screen, we force the "?" to have been changed.
Then each box is checked and the error messages printed.
if (grade_student_txt_against_correct($ans11,$var11,"Does not seem right ","z") == 0){
print "<br>box 1,1 appears to be wrong";
$error = 1;
}else{print"box 1,1 appears to be right <br>";}
if (grade_student_txt_against_correct($ans12,$var12,"Does not seem right ","z") == 0){
print "<br>box 1,2 appears to be wrong ";
$error = 1;
}else{print"box 1,2 appears to be right <br>";}
if (grade_student_txt_against_correct($ans13,$var13,"Does not seem right ","z") == 0){
print "<br>box 1,3 appears to be wrong ";
$error = 1;
}else{print"box 1,3 appears to be right <br>";}
if (grade_student_txt_against_correct($ans21,$var21,"Does not seem right ","z") == 0){
print "<br>box 2,1 appears to be wrong ";
$error = 1;
}else{print"box 2,1 appears to be right <br>";}
if (grade_student_txt_against_correct($ans23,$var23,"Does not seem right ","z") == 0){
print "<br>box 2,3 appears to be wrong ";
$error = 1;
}else{print"box 2,3 appears to be right <br>";}
if (grade_student_txt_against_correct($ans31,$var31,"Does not seem right ","z") == 0){
print "<br>box 3,1 appears to be wrong ";
$error = 1;
}else{print"box 3,1 appears to be right <br>";}
if (grade_student_txt_against_correct($ans32,$var32,"Does not seem right ","z") == 0){
print "<br>box 3,2 appears to be wrong ";
$error = 1;
}else{print"box 3,2 appears to be right <br>";}
if (grade_student_txt_against_correct($ans33,$var33,"Does not seem right ","z") == 0){
print "<br>box 3,3 appears to be wrong ";
$error = 1;
}else{print"box 3,3 appears to be right<br> ";}
$first = 0;#enable box checking
#
print "<hr>";
$ans11 = $query->param('box11');
$ans12 = $query->param('box12');
$ans13 = $query->param('box13');
$ans21 = $query->param('box21');
$ans22 = $query->param('box22');
$ans23 = $query->param('box23');
$ans31 = $query->param('box31');
$ans32 = $query->param('box32');
$ans33 = $query->param('box33');
$NO2_eq = $ans13-2*$varz;
$NO_eq = $ans11+2*$varz;
$O2_eq = $ans12+$varz;
# NO_2 then NO and then O_2
$Kp_correct = &Qp($NO2_eq,$NO_eq,$O2_eq);
$ans = $Kp_correct;
When all boxes are correct, we present the real problem.
if ($error == 0) {
print "<br>If the value of $redz = $varzstring , what is the value of
K<sub>p</sub>? ";
#=========start
my $ret = $qCAT->qnd($query,'t0',$ans,2,$filename,'');#to be extended
Above is the request for a student numerical answer. The function qnd is a 3 significant figure comparer. $qCAT points at CAT2p4pchem.pm which contains a set of support subroutines that are commonly used in this kind of work. The text for CAT2p4pchem.pm is included in these posts elsewhere.
if($ret == 0){ #here if answer wrong
print "<img src=../icons/RAIN_LINE.gif>";
print "
<br>Do you want to see how this problem is done (or at least a hint)?
If so, please check this box (and resubmit) ",$query->checkbox('to')," enable this feature.
";
The text of help, is solely in the programmer's discretion.
if ($query->param('to') eq 'on'){
print <<EOF;
<br>
Once the boxes are correctly filled in, the
the equilibrium pressure of NO<sub>2</sub> = $NO2_eq,
the equilibrium pressure of NO = $NO_eq,
and the equilibrium pressure of O<sub>2</sub> = $O2_eq.
Knowing $redz one can compute these values, and substitute them into
the K<sub>p</sub> expression to finish the problem.
EOF
}
}
else {
#here if answer right
Again, when the student gets the answer correct, the programmer can "reward" him/her as s/he sees fit. In our case here, while the question is being circulated in a campaign to get Perl based cgi-bin modules to be added to all computer assisted learning modules, the "reward" text is aimed at educators rather than students.
print "Great";
print <<EOF;
<br>This is the ultimate formulation of computer assisted learning that I can produce.
It offers no help whatsoever in terms of filling in the boxes in the tableau, but tells students when they are wrong.
Suggestions about interventions when students make mistakes would certainly be appreciated.
EOF
$student_id = $query->param('student_id');
print "<br><img src=../icons/RAIN_LINE.gif><br>";
When the student gets the right answer, the programmer needs to record this event.
This can be done by adding remarks to a database of student activity, (as one `can record
wrong responses, for analysis and improvement purposes).
In this case, I wanted to monitor whether or not anyone (i.e., an educator visiting the site) had actually carried out the computation required to finish the problem, hence the use of an e-mail to me.
$mailer = new Mail::Mailer;
$email = 'carl.david@uconn.edu';
$mailer->open( {
To => $email,
From => 'The Webmaster <chem12x@chemphys.uconn.edu>',
Subject => 'Web Site Feedback using Mail::Mailer'
} );
print $mailer <<END_OF_MESSAGE;
This is the Mail::Mailer message sent by $student_id using the page $scriptname.
END_OF_MESSAGE
};
}
}
$first = 0;
$qCAT->save_vars($query,'first',\$first);#save list for this variable
print $query->submit;
print $qusery->end_form;
This calculator (below) can easily be omitted.
&JSCRIPT();
print $query->end_html;
This is specific to the chemistry problem.
sub Qp{
# NO_2 then NO and then O_2
#print "dump = ";print Dumper(@_);print "<br>";
return(($_[0])/(($_[1])*sqrt($_[2])));
}
This is a constructed response evaluating subroutine, which in our case is being used for the box fillin section of the problem.
sub grade_student_txt_against_correct
#note no input in this subroutine
# calling sequence, required!!!!!
{
# my ($query) = $_[1];# this seems to work only in the newer version of CGI.pm
# this is a subroutine which gets a query, an answer, a student answer, and a list
# of variables and returns 1 (True) if the student answer is OK, and 0 (False) otherwise.
# my $q = $_[2];#passing unique textual identifier
#
$total_args = scalar(@_);
my $student = $_[0];#passing a student answwer
my $correct = $_[1];#passing the correct answer
my $error_response = $_[2];#response for a wrong answer
my $variables1 = $_[3];#passing list of variables
my $dump = 0;
$variables = $variables1;
#print "<br>inside subroutine, global_debug = $global_debug";
if ( $global_debug eq "true"){$dump = 1};
if($dump){
print "<br> total_args = $total_args";
print "<br> student = $student";
print "<br> correct = $correct";
print "<br> variables = $variables";
}
# if ($query->param($q)ne ''){
my $ans1 = $student;
my $saved_stu_ans1 = $ans1;
if($dump){
print "<br> ans1 = $ans1";
print "<br> saved_stu_ans1= $saved_stu_ans1";
}
$escape = '?!';
if(substr($ans1,0,length($escape)) eq $escape){print "<br> test mode, answer expected = $correct";}
&CleanUp($ans1);
&CleanUp2($ans1);#someone else's attempt, lost reference
&CleanUp($correct);
if($dump){
print "<br> ans1 (after CleanUp) = $ans1";
print "<br> saved_stu_ans1 (after CleanUp) = $correct";
}
$var = $variables1;
if($dump){
print "<br> substitution variable var = $var";
}
$rno = 1+rand();
$ans1 =~ s/$var/$rno/gi;
$correct =~ s/$var/$rno/g;
if($dump){
print "<br> rno = $rnob";
print "<br> after substitution variable var = $var";
print "<br> after a cycle of substitutions, ans1 = $ans1, and correct = $correct";
}
if($dump){
print "<br> criterion = ",abs(eval($correct)-eval($ans1));
print "<br> correct = ",eval($correct);
print "<br> ans1 = ",eval($ans1);
}
This is the core of the scheme. The expressions, with the same random variable in both the student's and the author's answer are compared.
if(abs(eval($correct) -eval( $ans1)) < 0.0001){
print "<img src=../icons/check.gif>";
return 1
}
else{
print "<br><img src=../icons/checkno.gif>";
#print "<br>You did not submit a correct answer.<br>";
print $error_response;
return 0
}
# }#end of if param
if($global_debug eq "true"){ $dump = 0; $global_debug = "false"};
}#end of subroutine grade_student_txt_against_correct
sub CleanUp2{#Author's name and address unfortunately lost. Not my code.
$_ = shift;
s/\-+(.*)/\1/g;
s/(.*)[ \t]+\-(.*)/\1\2/g;
tr/\$\'\`\"\<\>\/\;\!\|/_/;
return($_);
}
That the work is harder than composing passive html pages is obvious. I have failed repeatedly over the past 20 years in interesting anyone in doing this, despite papers written, examples displayed, and blog posts/linkedin/facebook propaganda intended to incite someone, anyone, to join in rigorizing STEM education.
As usual, the mathematicians are ahead of us; ixl.com
is a site offering constructed math problems.
Our offering is
https://chemphys.uconn.edu/~chem12x/cgi-bin/sophiakp1.pl which is one of several of these problems which illustrate how rigorous CAT/L is. The last of them in essence presents a spreadsheet to the student for exploration of the approach to equilibrium:https://chemphys.uconn.edu/~chem12x/cgi-bin/sophiakp2.pl. These are freshman chemistry specific, but illustrative of what can be done.
https://chemphys.uconn.edu/~cdavid/book.html is a site with Perl code, intended to teach how to write CAT/L programs on the web for teachers.