You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(58) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(53) |
Feb
(56) |
Mar
|
Apr
|
May
(30) |
Jun
(78) |
Jul
(121) |
Aug
(155) |
Sep
(77) |
Oct
(61) |
Nov
(45) |
Dec
(94) |
2006 |
Jan
(116) |
Feb
(33) |
Mar
(11) |
Apr
(23) |
May
(60) |
Jun
(89) |
Jul
(130) |
Aug
(109) |
Sep
(124) |
Oct
(63) |
Nov
(82) |
Dec
(45) |
2007 |
Jan
(31) |
Feb
(35) |
Mar
(123) |
Apr
(36) |
May
(18) |
Jun
(134) |
Jul
(133) |
Aug
(241) |
Sep
(126) |
Oct
(31) |
Nov
(15) |
Dec
(5) |
2008 |
Jan
(11) |
Feb
(6) |
Mar
(16) |
Apr
(29) |
May
(43) |
Jun
(149) |
Jul
(27) |
Aug
(29) |
Sep
(37) |
Oct
(20) |
Nov
(4) |
Dec
(6) |
2009 |
Jan
(34) |
Feb
(30) |
Mar
(16) |
Apr
(6) |
May
(1) |
Jun
(32) |
Jul
(22) |
Aug
(7) |
Sep
(18) |
Oct
(50) |
Nov
(22) |
Dec
(8) |
2010 |
Jan
(17) |
Feb
(15) |
Mar
(10) |
Apr
(9) |
May
(67) |
Jun
(30) |
Jul
|
Aug
|
Sep
(2) |
Oct
|
Nov
(1) |
Dec
|
From: Mike G. v. a. <we...@ma...> - 2008-06-24 21:54:39
|
Log Message: ----------- Remove duplicate definitions of subroutines Tags: ---- rel-2-4-patches Modified Files: -------------- pg/lib: Value.pm Revision Data ------------- Index: Value.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value.pm,v retrieving revision 1.53.2.3.2.1 retrieving revision 1.53.2.3.2.2 diff -Llib/Value.pm -Llib/Value.pm -u -r1.53.2.3.2.1 -r1.53.2.3.2.2 --- lib/Value.pm +++ lib/Value.pm @@ -285,21 +285,6 @@ return $code && $code ne $self->can($method); } - -# -# Check if the object class matches one of a list of classes -# -sub classMatch { - my $self = shift; my $class = class($self); - my $ref = ref($self); my $isHash = ($ref && $ref ne 'ARRAY' && $ref ne 'CODE'); - my $context = ($isHash ? $self->{context} || Value->context : Value->context); - foreach my $name (@_) { - return 1 if $class eq $name || $ref eq $context->Package($name,1) || - $ref eq "Value::$name" || ($isHash && $self->{"is".$name}); - } - return 0; -} - # # Check if a value is a number, complex, etc. # @@ -375,16 +360,6 @@ return 0; } -###################################################################### - -# -# Value->Package(name[,noerror]]) -# -# Returns the package name for the specificied Value object class -# (as specified by the context's {value} hash, or "Value::name"). -# -sub Package {(shift)->context->Package(@_)} - =head3 makeValue Usage: Value::makeValue(45); |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 21:53:49
|
Log Message: ----------- Formatting Modified Files: -------------- pg/lib: Value.pm Revision Data ------------- Index: Value.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value.pm,v retrieving revision 1.95 retrieving revision 1.96 diff -Llib/Value.pm -Llib/Value.pm -u -r1.95 -r1.96 --- lib/Value.pm +++ lib/Value.pm @@ -580,6 +580,8 @@ return $self; } +###################################################################### + # # Return the hash data as an array of key=>value pairs # |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 21:53:34
|
Log Message: ----------- forward port of the rel-2-4-5 changes that allow BEGIN_HINT, etc. Modified Files: -------------- pg/lib/WeBWorK/PG: Translator.pm Revision Data ------------- Index: Translator.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/WeBWorK/PG/Translator.pm,v retrieving revision 1.20 retrieving revision 1.21 diff -Llib/WeBWorK/PG/Translator.pm -Llib/WeBWorK/PG/Translator.pm -u -r1.20 -r1.21 --- lib/WeBWorK/PG/Translator.pm +++ lib/WeBWorK/PG/Translator.pm @@ -154,6 +154,8 @@ my $class = shift; my $safe_cmpt = new Safe; #('PG_priv'); my $self = { + preprocess_code => \&default_preprocess_code, + postprocess_code => \&default_postprocess_code, envir => undef, PG_PROBLEM_TEXT_ARRAY_REF => [], PG_PROBLEM_TEXT_REF => 0, @@ -882,13 +884,19 @@ ########################################## ###### PG preprocessing code ############# ########################################## - # BEGIN_TEXT and END_TEXT must occur on a line by themselves. - $evalString =~ s/\n\s*END_TEXT[\s;]*\n/\nEND_TEXT\n/g; - $evalString =~ s/\n\s*BEGIN_TEXT[\s;]*\n/\nTEXT\(EV3\(<<'END_TEXT'\)\);\n/g; - $evalString =~ s/ENDDOCUMENT.*/ENDDOCUMENT();/s; # remove text after ENDDOCUMENT + + $evalString = &{$self->{preprocess_code}}($evalString); + + +# # default_preprocess_code +# # BEGIN_TEXT and END_TEXT must occur on a line by themselves. +# $evalString =~ s/\n\s*END_TEXT[\s;]*\n/\nEND_TEXT\n/g; +# $evalString =~ s/\n\s*BEGIN_TEXT[\s;]*\n/\nTEXT\(EV3\(<<'END_TEXT'\)\);\n/g; +# $evalString =~ s/ENDDOCUMENT.*/ENDDOCUMENT();/s; # remove text after ENDDOCUMENT +# +# $evalString =~ s/\\/\\\\/g; # \ can't be used for escapes because of TeX conflict +# $evalString =~ s/~~/\\/g; # use ~~ as escape instead, use # for comments - $evalString =~ s/\\/\\\\/g; # \ can't be used for escapes because of TeX conflict - $evalString =~ s/~~/\\/g; # use ~~ as escape instead, use # for comments =pod @@ -922,6 +930,12 @@ ########## end EVALUATION code ########### ############################################################################# + ########################################## + ###### PG postprocessing code ############# + ########################################## + $PG_PROBLEM_TEXT_REF = &{$self->{postprocess_code}}($PG_PROBLEM_TEXT_REF); + + =pod (5) B<Process errors> @@ -960,7 +974,7 @@ $self -> {errors}."\r\n" . "****************<BR>\n"); - push(@PROBLEM_TEXT_OUTPUT , "------Input Read\r\n"); + push(@PROBLEM_TEXT_OUTPUT , "------Input Read\r\n"); $self->{source} =~ s/</</g; @input=split("\n", $self->{source}); $lineNumber = 1; @@ -1607,6 +1621,37 @@ } +sub original_preprocess_code { + my $evalString = shift; + # BEGIN_TEXT and END_TEXT must occur on a line by themselves. + $evalString =~ s/\n\s*END_TEXT[\s;]*\n/\nEND_TEXT\n/g; + $evalString =~ s/\n\s*BEGIN_TEXT[\s;]*\n/\nTEXT\(EV3\(<<'END_TEXT'\)\);\n/g; + $evalString =~ s/ENDDOCUMENT.*/ENDDOCUMENT();/s; # remove text after ENDDOCUMENT + + $evalString =~ s/\\/\\\\/g; # \ can't be used for escapes because of TeX conflict + $evalString =~ s/~~/\\/g; # use ~~ as escape instead, use # for comments + $evalString; +} +sub default_preprocess_code { + my $evalString = shift; + # BEGIN_TEXT and END_TEXT must occur on a line by themselves. + $evalString =~ s/\n\s*END_TEXT[\s;]*\n/\nEND_TEXT\n/g; + $evalString =~ s/\n\s*END_SOLUTION[\s;]*\n/\nEND_SOLUTION\n/g; + $evalString =~ s/\n\s*END_HINT[\s;]*\n/\nEND_HINT\n/g; + $evalString =~ s/\n\s*BEGIN_TEXT[\s;]*\n/\nTEXT\(EV3\(<<'END_TEXT'\)\);\n/g; + $evalString =~ s/\n\s*BEGIN_SOLUTION[\s;]*\n/\nSOLUTION\(EV3\(<<'END_SOLUTION'\)\);\n/g; + $evalString =~ s/\n\s*BEGIN_HINT[\s;]*\n/\nHINT\(EV3\(<<'END_HINT'\)\);\n/g; + $evalString =~ s/ENDDOCUMENT.*/ENDDOCUMENT();/s; # remove text after ENDDOCUMENT + + $evalString =~ s/\\/\\\\/g; # \ can't be used for escapes because of TeX conflict + $evalString =~ s/~~/\\/g; # use ~~ as escape instead, use # for comments + $evalString; +} +sub default_postprocess_code { + my $evalString_ref = shift; + $evalString_ref; +} + sub dumpvar { my ($packageName) = @_; |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 21:47:55
|
Log Message: ----------- formatting changes Modified Files: -------------- pg/macros: PG.pl parserFunction.pl Revision Data ------------- Index: PG.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/PG.pl,v retrieving revision 1.37 retrieving revision 1.38 diff -Lmacros/PG.pl -Lmacros/PG.pl -u -r1.37 -r1.38 --- macros/PG.pl +++ macros/PG.pl @@ -612,9 +612,6 @@ (\$STRINGforOUTPUT, \$STRINGforHEADER_TEXT,\%PG_ANSWERS_HASH,eval(q!\%main::PG_FLAGS!)); } -=back - -=cut ################################################################################ Index: parserFunction.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/parserFunction.pl,v retrieving revision 1.12 retrieving revision 1.13 diff -Lmacros/parserFunction.pl -Lmacros/parserFunction.pl -u -r1.12 -r1.13 --- macros/parserFunction.pl +++ macros/parserFunction.pl @@ -160,9 +160,14 @@ return (($Df->substitute($x=>$g))*($g->D(@_)))->{tree}->reduce; } +=head3 NameForNumber($number) + # # Get the name for a number # + +=cut + sub NameForNumber { my $n = shift; my $name = ('zeroth','first','second','third','fourth','fifth', |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 19:10:52
|
Log Message: ----------- jsMath 3.5 Tags: ---- rel-2-4-patches Modified Files: -------------- webwork2/htdocs/jsMath/easy: load.js Revision Data ------------- Index: load.js =================================================================== RCS file: /webwork/cvs/system/webwork2/htdocs/jsMath/easy/load.js,v retrieving revision 1.2.2.1 retrieving revision 1.2.2.1.2.1 diff -Lhtdocs/jsMath/easy/load.js -Lhtdocs/jsMath/easy/load.js -u -r1.2.2.1 -r1.2.2.1.2.1 --- htdocs/jsMath/easy/load.js +++ htdocs/jsMath/easy/load.js @@ -50,13 +50,14 @@ // to add the <DIV> and <SPAN> tags that jsMath needs. See the // documentation for the tex2math plugin for more information. // - processSlashParens: 1, // process \(...\) in text? - processSlashBrackets: 1, // process \[...\] in text? - processDoubleDollars: 1, // process $$...$$ in text? - processSingleDollars: 0, // process $...$ in text? - fixEscapedDollars: 0, // convert \$ to $ outside of math mode? - doubleDollarsAreInLine: 0, // make $$...$$ be in-line math? - allowDisableTag: 1, // allow ID="tex2math_off" to disable tex2math? + processSlashParens: 1, // process \(...\) in text? + processSlashBrackets: 1, // process \[...\] in text? + processDoubleDollars: 1, // process $$...$$ in text? + processSingleDollars: 0, // process $...$ in text? + processLaTeXenvironments: 0, // process \begin{xxx}...\end{xxx} outside math mode? + fixEscapedDollars: 0, // convert \$ to $ outside of math mode? + doubleDollarsAreInLine: 0, // make $$...$$ be in-line math? + allowDisableTag: 1, // allow ID="tex2math_off" to disable tex2math? // // If you want to use your own custom delimiters for math instead // of the usual ones, then uncomment the following four lines and @@ -83,13 +84,12 @@ // showFontWarnings: 1, - // // Use "Process" or "ProcessBeforeShowing". See the jsMath // author's documentation for the difference between these // two routines. // - method: "Process", + method: "Process", // // List of plug-ins and extensions that you want to be @@ -106,6 +106,7 @@ // // Allow jsMath to enter global mode? + // (Uses frames, so may not always work with complex web sites) // allowGlobal: 1, @@ -126,9 +127,14 @@ if (jsMath.Easy.root == "") { jsMath.Easy.root = document.getElementsByTagName("script"); - jsMath.Easy.root = jsMath.Easy.root[jsMath.Easy.root.length-1].src. - replace(/\/(jsMath\/(easy\/)?)?[^\/]*$/,"/jsMath"); + jsMath.Easy.root = jsMath.Easy.root[jsMath.Easy.root.length-1].src + if (jsMath.Easy.root.match(/\/easy\/[^\/]*$/)) { + jsMath.Easy.root = jsMath.Easy.root.replace(/\/easy\/[^\/]*$/,""); + } else { + jsMath.Easy.root = jsMath.Easy.root.replace(/\/(jsMath\/(easy\/)?)?[^\/]*$/,"/jsMath"); + } } +jsMath.Easy.root = jsMath.Easy.root.replace(/\/$/,""); // trim trailing "/" if any document.write('<SCRIPT SRC="'+jsMath.Easy.root+'/jsMath-easy-load.js"><'+'/SCRIPT>'); |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 18:56:28
|
Log Message: ----------- another file for jsMath3.5 Tags: ---- rel-2-4-patches Added Files: ----------- webwork2/htdocs/jsMath: jsMath-loader-post.html Revision Data ------------- --- /dev/null +++ htdocs/jsMath/jsMath-loader-post.html @@ -0,0 +1,78 @@ +<html> +<head> +<!-- + | jsMath-loader-post.html + | + | Part of the jsMath package for mathematics on the web. + | + | This file is used for loading jsMath components in Firefox3 when + | used in a file: url from a directory other than the one containing + | jsMath (gets around Firefox3's more restrictive same-origin policy. + | + | --------------------------------------------------------------------- + | + | Copyright 2008 by Davide P. Cervone + | + | Licensed under the Apache License, Version 2.0 (the "License"); + | you may not use this file except in compliance with the License. + | You may obtain a copy of the License at + | + | http://www.apache.org/licenses/LICENSE-2.0 + | + | Unless required by applicable law or agreed to in writing, software + | distributed under the License is distributed on an "AS IS" BASIS, + | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + | See the License for the specific language governing permissions and + | limitations under the License. +--> +</head> +<body> + +<script> +var isCheck = 0; +var url = location.search.substr(1); var ID = "jsMLD"; +if (url.substr(0,9) == "autoload=") {url = url.substr(9); ID = "jsMAL"} + +if (url == 'http://www.math.union.edu/locate/jsMath/jsMath/jsMath-version-check.js') { + // + // Handle version check separately + // + var jsMath = {Controls: {}}; isCheck = 1; + document.write('<script src="'+url+'"></'+'script>'); +} else if (url != "" && url.match(/\.js$/) && !url.match('(^|[/\\?#=])[a-z]+://')) { + // + // Load the file and pass it to jsMath + // + var request = new XMLHttpRequest; + try { + request.open("GET",url,false); + request.send(null); + window.parent.postMessage(ID+":BGN:"); + window.parent.postMessage(ID+":SCR:"+request.responseText); + window.parent.postMessage(ID+":END:1"); + } catch (err) { + window.parent.postMessage(ID+":ERR:Can't load "+url+": "+err.message); + } +} else { + window.parent.postMessage(ID+":END:"); +} +</script> + +<script> +// +// If we are loading the version check, pass it to jsMath +// and run the check. +// +if (isCheck) { + var fn = jsMath.Controls.TestVersion.toString(); + window.parent.postMessage(ID+":SCR:" + + "jsMath.Controls.TestVersion = "+fn+";" + + "jsMath.Message.Clear(); jsMath.Message.doClear();" + + "jsMath.Controls.TestVersion()" + ); + window.parent.postMessage(ID+":END:"); +} +</script> + +</body> +</html> |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 18:55:23
|
Log Message: ----------- Updating to jsMath3.5 Tags: ---- rel-2-4-patches Modified Files: -------------- webwork2/htdocs/jsMath: jsMath-controls.html jsMath-easy-load.js jsMath-loader.html jsMath.js Revision Data ------------- Index: jsMath-loader.html =================================================================== RCS file: /webwork/cvs/system/webwork2/htdocs/jsMath/jsMath-loader.html,v retrieving revision 1.4 retrieving revision 1.4.4.1 diff -Lhtdocs/jsMath/jsMath-loader.html -Lhtdocs/jsMath/jsMath-loader.html -u -r1.4 -r1.4.4.1 --- htdocs/jsMath/jsMath-loader.html +++ htdocs/jsMath/jsMath-loader.html @@ -7,7 +7,7 @@ | | This file is used for jsMath components when the browser doesn't | handle the XmlHttpRequest function, or when they must be obtained - | from a server other than the one server the page that is using jsMath. + | from a server other than the one serving the page that is using jsMath. | | --------------------------------------------------------------------- | Index: jsMath-controls.html =================================================================== RCS file: /webwork/cvs/system/webwork2/htdocs/jsMath/jsMath-controls.html,v retrieving revision 1.12 retrieving revision 1.12.4.1 diff -Lhtdocs/jsMath/jsMath-controls.html -Lhtdocs/jsMath/jsMath-controls.html -u -r1.12 -r1.12.4.1 --- htdocs/jsMath/jsMath-controls.html +++ htdocs/jsMath/jsMath-controls.html @@ -28,6 +28,8 @@ <script> var showWarning = 0; +var domain = document.domain || ""; +var mustPost = ((domain == "" || domain == "localhost") && window.postMessage); while (!window.jsMath && !showWarning) { try { window.jsMath = window.parent.jsMath; @@ -58,8 +60,16 @@ ); } -if (showWarning) {setTimeout("Warning()",1)} else { -var debug = window.parent.debug; var show = window.parent.show; +if (showWarning) { + if (!mustPost) setTimeout("Warning()",1); +} else { + var debug = window.parent.debug; + var show = window.parent.show; +} +</SCRIPT> + +<SCRIPT ID="jsMath_script"> +if (window.jsMath) { jsMath.Add(jsMath.Controls,{ @@ -87,7 +97,7 @@ Main: function () { this.oldCookie = {}; jsMath.Add(this.oldCookie,this.cookie); - this.GetPanel("panel"); + this.GetPanel("main"); jsMath.Element("_version").innerHTML = jsMath.version; @@ -192,13 +202,13 @@ } }, + HTML: {}, // storage for panels for Firefox3 in local mode + GetPanel: function (name) { this.panel.innerHTML = ""; // for MSIE on the Mac - if (jsMath.browser == 'Mozilla') { - this.panel.appendChild(document.getElementById("jsMath_"+name).cloneNode(true)); - } else { - this.panel.innerHTML = document.getElementById("jsMath_"+name).innerHTML; - } + var html = this.HTML[name]; + if (html == null) {html = document.getElementById("jsMath_"+name).innerHTML} + this.panel.innerHTML = html; }, SaveOptions: function (close) { @@ -249,12 +259,23 @@ }); +jsMath.Add(jsMath.Post.Commands,{ + PAN: function (message) {jsMath.Controls.HTML.main = message}, + OPT: function (message) {jsMath.Controls.HTML.options = message}, + + PST: function (message) { + jsMath.Controls.Main(); + jsMath.Script.endLoad(); + jsMath.Message.doClear(); + } +}); + } </script> <!------------------------------------------------------------> -<div id="jsMath_panel"> +<div id="jsMath_main"> <div style="text-align:center"> <b style="font-size:133%">jsMath v<span ID="jsMath__version"></span></b> (<span id="jsMath__fontType">type</span> fonts) @@ -434,7 +455,19 @@ <!------------------------------------------------------------> <script> - if (!showWarning) {jsMath.Controls.Main()} + if (showWarning) { + if (mustPost) { + var scr = document.getElementById("jsMath_script"); + window.parent.postMessage("jsMCP:SCR:"+scr.innerHTML); + var main = document.getElementById("jsMath_main"); + window.parent.postMessage("jsMCP:PAN:"+main.innerHTML); + var options = document.getElementById("jsMath_options"); + window.parent.postMessage("jsMCP:OPT:"+options.innerHTML); + window.parent.postMessage("jsMCP:PST:"); + } + } else { + jsMath.Controls.Main() + } </script> <script> if (window.jsMath) { Index: jsMath-easy-load.js =================================================================== RCS file: /webwork/cvs/system/webwork2/htdocs/jsMath/jsMath-easy-load.js,v retrieving revision 1.1 retrieving revision 1.1.4.1 diff -Lhtdocs/jsMath/jsMath-easy-load.js -Lhtdocs/jsMath/jsMath-easy-load.js -u -r1.1 -r1.1.4.1 --- htdocs/jsMath/jsMath-easy-load.js +++ htdocs/jsMath/jsMath-easy-load.js @@ -71,17 +71,19 @@ jsMath.Easy.fixEscapedDollars) { jsMath.Easy.findCustomSettings = { - processSingleDollars: jsMath.Easy.processSingleDollars, - processDoubleDollars: jsMath.Easy.processDoubleDollars, - processSlashParens: jsMath.Easy.processSlashParens, - processSlashBrackets: jsMath.Easy.processSlashBrackets, - fixEscapedDollars: jsMath.Easy.fixEscapedDollars, + processSingleDollars: jsMath.Easy.processSingleDollars, + processDoubleDollars: jsMath.Easy.processDoubleDollars, + processSlashParens: jsMath.Easy.processSlashParens, + processSlashBrackets: jsMath.Easy.processSlashBrackets, + processLaTeXenvironments: jsMath.Easy.processLaTeXenvironments, + fixEscapedDollars: jsMath.Easy.fixEscapedDollars, custom: 0 } } if (!jsMath.Autoload) {jsMath.Autoload = {}} jsMath.Autoload.root = jsMath.Easy.root+'/'; + if (jsMath.Easy.autoload) { jsMath.Autoload.findTeXstrings = 0; jsMath.Autoload.findLaTeXstrings = 0; @@ -89,9 +91,8 @@ jsMath.Autoload.findCustomSettings = jsMath.Easy.findCustomSettings; jsMath.Autoload.loadFiles = jsMath.Easy.loadFiles; jsMath.Autoload.loadFonts = jsMath.Easy.loadFonts; - jsMath.Autoload.root = jsMath.Easy.root + '/'; - - if (!document.body) {jsMath.Easy.autoloadCheck = 1} + jsMath.Autoload.delayCheck = 1; + jsMath.Easy.autoloadCheck = 1; document.write('<script src="'+jsMath.Autoload.root+'plugins/autoload.js"></script>'); } else { @@ -100,6 +101,7 @@ jsMath.Easy.processDoubleDollars || jsMath.Easy.processSlashParens || jsMath.Easy.processSlashBrackets || + jsMath.Easy.processLaTeXenvironments || jsMath.Easy.fixEscapedDollars || jsMath.Easy.customDelimiters); @@ -117,6 +119,7 @@ } jsMath.Easy.onload = function () { + if (jsMath.Easy.loaded) {return} else {jsMath.Easy.loaded = 1} if (jsMath.Easy.autoloadCheck) jsMath.Autoload.Check(); if (jsMath.Easy.tex2math) { jsMath.Synchronize(function () { Index: jsMath.js =================================================================== RCS file: /webwork/cvs/system/webwork2/htdocs/jsMath/jsMath.js,v retrieving revision 1.36.2.1 retrieving revision 1.36.2.1.2.1 diff -Lhtdocs/jsMath/jsMath.js -Lhtdocs/jsMath/jsMath.js -u -r1.36.2.1 -r1.36.2.1.2.1 --- htdocs/jsMath/jsMath.js +++ htdocs/jsMath/jsMath.js @@ -40,11 +40,12 @@ //start = new Date().getTime(); jsMath.Script.Uncompress([ - ['if(!','window','.','jsMath','||!',1,'.','jsMath.','loaded','){var ','jsMath_old','=',1,'.',3,';',0,'document.','getElementById','||!',17,'childNodes||!',17,'createElement','){','alert("','The',' mathematics ','on this page requires W3C DOM support in its JavaScript. "+"Unfortunately, your ','browser',' doesn\'t seem to have this.");}','else{',1,'.',3,'={version:"3.4c",document:document,',1,':',1,',','platform',':(','navigator.',40,'.match(/','Mac/)?"mac":',42,40,44,'Win/)?"pc":"unix"),sizes:[50,60,70,85,100,120,144,173,207,249],','styles',':{".math','":"font-family',':serif; font-style:normal; font-weight:normal','",".typeset',52,53,'; ','line-height:normal','","div.','typeset','":"text-align',':center; margin:1em 0px;","span.',60,61,':left',54,' span',61,65,'; border:','0px; margin:0px; ','padding:0px','",".typeset .','normal',52,53,73,'size0','":"font-size:','50','%",".typeset .','size1',79,'60',81,'size2',79,'70',81,'size3',79,'85',81,'size4',79,'100',81,'size5',79,'! 120',81,'size6',79,'144',81,'size7',79,'173',81,'size8',79,'207',81,'size9',79,'249',81,'cmr10',52,':',3,'-cmr10',', serif',73,'cmbx10',52,':',3,'-',125,', ',3,122,73,'cmti10',52,':',3,'-',135,', ',3,122,73,'cmmi10',52,':',3,'-',145,73,'cmsy10',52,':',3,'-',152,73,'cmex10',52,':',3,'-cmex10',73,'textit',52,':serif; ','font-style:italic',73,'textbf',52,':serif; font-weight:bold',73,'link":"','text-decoration:none',73,'error',79,'10pt; ',168,'; "+"','background-color',':#FFFFCC; padding:1px',181,'border:','1px solid',' #CC0000',73,'blank','":"','display:inline-block','; ','overflow:hidden',70,'0px none; width:0px','; height:','0px;",".',60,' .','spacer','":"',191,'","#jsMath_hiddenSpan":"','visibility',':','hidden','; ','position:absolute','; top:0px',';left:0px',181,58,'; text-indent:0px","#','jsMath_message','":"','position:fixed','; bottom:','1px; left:2px; ',182,':#E6E6E6','; "+"border:solid 1px #959595; margin:0px; padding:','1px 8px','; "+"z-index:102; color',': black',! '; font-size:','small; ','width:auto',';","#','jsMath_panel','! ":"',216 ,217,'1.5em; right:1.5em','; padding:.8em 1.6em',181,182,':#DDDDDD',70,'outset 2px',181,'z-index:103; ',227,'; color:black',225,'10pt; font-style:normal","#',229,' .disabled":"color:#888888","#',229,' .infoLink',79,'85%","#',229,' *":"','font-size:inherit; font-style:inherit; font-family:inherit','; ',58,'","#',229,' div":"',182,':inherit; color:inherit;","#',229,' span":"',182,261,229,' td','":"border:0px; padding:0px; margin:0px; background-color:inherit; color:inherit;","#',229,' tr',268,229,' table',268,'jsMath_button','":"',216,217,'1px; right:2px; ',182,':white',221,'0px 3px 1px 3px',223,':black; ',175,225,'x-small',181,227,'; cursor:hand;","#',275,253,72,70,71,58,181,254,'","#jsMath_global":"',168,';","#jsMath_float','":"',208,209,'; left:0px; max-width:80%; "+"z-index:101; ',227,'; height:auto',302,' .drag":"',182,':#DDDDDD',70,'outset 1px',196,'12px',225,'1px',302,' .close":"',182,220,70,'inset 1px; width:8px',196,'8px; margin:1px 2px',302,' .source":"',182,':#E2E2E! 2',70,314,181,227,308,'; padding:8px 15px',181,'font-family:courier, fixed',225,'90%","#jsMath_noFont .message',61,': center',234,70,'3px solid #DD0000',181,182,':#FFF8F8; color: #AA0000',225,226,227,228,'jsMath_noFont .link','":"',72,' 5px 2px 5px',70,'2px outset; ',182,':#E8E8E8',181,'color:black',225,'80%; ',227,291,'jsMath_PrintWarning',' .message',61,':center',234,70,'3px solid #DD0000',181,182,': #FFF8F8; color: #AA0000',225,'x-',226,227,';","@media print":"#',275,' {display:none','}\\n"+"#jsMath_Warning',383,'}","@media screen":"#',367,383,'}"},Element',':function(','_1){return ',7,17,18,'("jsMath_"+_1);},','BBoxFor',390,'s','){this.','hidden.innerHTML','="<nobr><','span class=\\"',60,'\\"><',402,'scale\\">"+s+"</span></span></nobr>";var _3={w:this.',206,'.offsetWidth',',h:this.',206,'.offsetHeight','};this.',400,'="";return _3;},EmBoxFor',390,'s',9,'_5=',7,'Global.cache','.R;',0,'_5[this.em]){_5[this.em]={};}',0,'_5','[this.em][s',']){var _6','=this.BBoxFor','(s);_5! ',426,']={w:_6.w/this.em,h:_6','.h/this.em};}return ','_5',426! ,'];},', 'EmBoxForItalics',390,'s',9,'_8=',7,420,'.R;',0,'_8[this.em]){_8[this.em]={};}',0,'_8',426,']){var _9',428,'(s);if(s.match(/<i>|class=\\"(icm|italic|igreek|iaccent)/i)){_9.w',428,'(s+',7,'Browser.','italicString',').w-',7,455,'italicCorrection',';}_8',426,']={w:_9.w/this.em,h:_9',432,'_8',426,'];},Init',':function(){','if(',7,'Setup.inited','!=1){',0,7,471,'){',7,'Setup.','Body();}if(',7,471,'!=1){if(',7,471,'==-100','){return;}',25,'It looks like ',3,' failed to set up properly (error code "+',7,471,'+"). "+"I will try to keep going, but it could get ugly.");',7,471,'=1;}}this.em',428,'("<span style=\\""+',7,455,'block+";','width:13em;height:1em','\\"></span','>").w/13;if(this.em==0',399,'em',428,'("<img src=\\""+',7,189,'+"\\" style=\\"',502,'\\"/>").w/13;}var _a=',7,420,'.B;',0,'_a[this.em]){_a[this.em]={};','_a[this.em].','bb',428,'("x");var hh=',519,'bb.h;',519,'d',428,'("x"+',7,'HTML.Rule(1,','hh/',7,'em)).h-hh;if(',7,455,456,'){',519,'ic=',7,396,'(',7,455,456,').w;}}! ',7,455,460,'=',519,'ic;var bb=',519,'bb;var h=bb.h;var d=',519,'d;this.h=(h-d)/this.em;this.d=d/this.em;this.hd=this.h+this.d;this.xWidth=bb.w;this.',478,'TeXfonts','();var _f=this.EmBoxFor("<',402,118,'\\">M</span>").w/2;this.TeX.M_height=_f*(26/14);this.TeX.h=this.h;this.TeX.d=this.d;this.TeX.hd=this.hd;this.Img.Scale();',0,'this.initialized',399,478,'Sizes','();this.','Img.UpdateFonts();}this.p_height=(','this.TeX.cmex10[0].','h+',570,'d)/0.85;',564,'=1;},ReInit',468,'var w',428,'("x").w;if(w!=this.xWidth',399,'Init();}},Loaded',468,'if(',10,9,'_11=["Process","ProcessBeforeShowing","ConvertTeX","ConvertTeX2","ConvertLaTeX","ConvertCustom","CustomSearch","Synchronize","Macro","document"];','for(var i=0;i<','_11','.length;i++){if(',10,'[_11[i]]){delete ',10,'[_11[i]];}}}if(',10,'){this.Insert(',3,',',10,');}',10,'=null;',7,8,'=1;},Add',390,'dst,src){for(var id in src){','dst[id]=src[id','];}},Insert',390,606,'if(dst[id]&&typeof (src[id])=="object"&&(','typeof (dst[id])=="! ','object"||',612,'function")){this.Insert(dst[id],src[id]);}'! ,31,607, '];}}},Package',390,'obj,def',595,'obj.prototype,def);}};',7,'Global={isLocal:1,cache:{','T:{},D:{},R:{},B',':{}},ClearCache',468,7,420,'={',625,':{}};},GoGlobal',390,'_1b',9,'url=String(',7,1,'.','location);','var c=(',7,'isCHMmode','?"#":"?");if(_1b){url=url.replace(/\\?.*/,"")+"?"+_1b;}',7,'Controls.','Reload(',7,'root+"',3,'-global.html"+c+escape(url));},Init',468,'if(',7,'Controls.cookie.','global=="always"&&!',7,'noGoGlobal','){','if(navigator.','accentColorName',486,0,7,1,'){',7,1,'=',1,';}',7,646,8,'=1;',7,646,'defaults.hiddenGlobal',601,'this.GoGlobal(',7,646,'SetCookie(2));}},Register',468,'var _1e=',7,1,'.parent;',0,7,'isCHMode){',7,643,'=(',7,1,'.','location.protocol','=="mk:");}try{',0,7,643,399,'Domain();}if(_1e.',3,'&&_1e.',7,'isGlobal){_1e.',7,'Register(',7,1,');}}','catch(err){',7,658,'=1;}},Domain',468,660,'appName=="Microsoft Internet Explorer"&&',7,40,'=="mac"&&',42,'userProfile','!=null',486,'if(',1,'==parent',486,'var _1f=',7,17,'domain;try{while(true){! try{if(parent.',17,'title',726,'){return;}}','catch(err){}',0,17,'domain.match(/\\..*\\./)){break;}',7,17,'domain=',7,17,'domain.replace(/^[^.]*\\./,"");}}',740,7,17,746,'_1f;}};',7,'Script={request:null,Init',468,'if(!(',7,655,'asynch&&',7,655,'progress',')){if(',1,'.XMLHttpRequest','){try{','this.request','=new XMLHttpRequest;}catch(err){}}',0,769,'&&',1,'.','ActiveXObject',9,'xml=["MSXML2.XMLHTTP.5','.0","MSXML2.XMLHTTP','.4',779,'.3',779,'","Microsoft.XMLHTTP"];',587,'xml.length&&!',769,';i++){try{',769,'=new ',776,'(xml[i]);}catch(err){}}}}',0,769,'||',7,478,'domainChanged',399,'Load=this.delayedLoad;this.needsBody=1;}},Load',390,'url,_23){if(_23){',7,'Message.Set("Loading "+url);',7,'Script.','Delay(1);',7,'Script.Push(','this,"xmlRequest",url',');',7,809,7,'Message',',"Clear");}',31,7,809,810,');}},xmlRequest',390,'url){','this.blocking','=1;try{',769,'.open("GET",url,false);',769,'.send(null);}',714,824,'=0;if(',7,'Translate.','restart&&',7,'Translate.asynchronous){! return "";}throw "jsMath can\'t load the file \'"+url+"\'\\n"+! "',815,' : "+err.message;}if(',769,'.status','&&',769,841,'>=400){',824,832,7,834,'restart&&',7,837,'Error status: "+',769,841,';}',0,'url.match(/\\.js$/)){','return (',769,'.responseText',');}var _25=','this.queue',';',863,'=[];',7,1,'.eval(',769,861,');',824,'=0;','this.queue=this.queue.concat(','_25);this.Process();return "";},cancelTimeout:30*1000,iframe:null,blocking:0,cancelTimer:null,needsBody:0,queue:[],Synchronize',390,'_26,_27){','if(typeof (','_26)!="string"){',7,809,'null,_26,_27);}',31,7,809,7,1,',"eval",_26);}},Push',390,'_28,_29,_2a){',863,'[',863,'.length]=[_28,_29,_2a];if(!(',824,'||(this.needsBody&&!',7,17,'body))){this.Process();}},Process',468,'while(',863,'.length&&!',824,9,'_2b=',863,'[0];var _2c=',863,'.slice(1);',863,'=[];var _2d=_2b[0];var _2e=_2b[1];var _2f=_2b[2];if(_2d){_2d[_2e](_2f);}',31,'if(_2e){_2e(_2f);}}',875,'_2c);}},delayedLoad',390,'url',399,'Push(this,"startLoad",url);},startLoad',390,'url){','this.iframe','=',7,17,23,'("iframe");','this.iframe.s! tyle.',204,'="',206,'";',930,'position="absolute";',930,'width="0px";',930,'height="0px";if(',7,17,'body.firstChild','){',7,17,'body.insertBefore(',924,',',7,17,943,');}',31,7,17,'body','.appendChild(',924,');}',824,'=1;this.','url=url;',0,858,924,'.src=url;}',31,924,'.src=',7,649,3,'-loader.html";}if(url.substr(0,',7,'root.length',')==',7,'root){url=url.substr(',7,976,');}',7,804,'this.cancelTimer','=setTimeout("',7,806,'cancelLoad','()",this.cancelTimeout);},endLoad',390,'_32){if(',985,'){clearTimeout(',985,');',985,'=null;}',7,815,'.Clear();if(_32!="cancel"){',824,'=0;this.Process','();}},Start',468,'this.tmpQueue','=',863,';',863,'=[];},End',468,875,1006,');delete ',1006,';},',989,468,985,601,7,815,'.Set("Can\'t load file");this.endLoad("cancel");},Delay',390,'_33){',824,'=1;setTimeout("',7,806,'endDelay','()",_33);},',1031,468,824,1003,'();},','imageCount',':0,WaitForImage',390,'_34){',824,962,1038,'++;if(this.img==null',399,'img=[];}var img=new Image',568,'img[this.im! g.length]=img;img.onload=function(){if(--',7,806,1038,'==0){',! 7,806,10 31,'();}};img.onerror','=img.onload;img.','onabort',1058,'src=_34;},Uncompress',390,'_36){','for(var k=0;k<','_36.length;k++){var d=_36[k];var n=d.length;',587,'n;i++){',879,'d[i])=="number"){d[i]=d[d[i]];}}_36[k]=d.join("");}',1,869,'_36.join(""));}};',7,815,'={',189,':null,message:null,text:null,clear:null,Init',468,0,7,17,'body||!',7,655,764,486,'if(',7,478,'stylesReady){','this.message','=',7,'Setup.DIV("message",{visibility:"hidden','"});}',31,1091,'=',7,1094,'",position:"absolute",','bottom:"1px",left:"2px",','backgroundColor',':"#E6E6E6",border:"solid 1px #959595",margin:"0px",padding:"1px 8px",zIndex:102,color:"black",fontSize:"small",width:"auto"});}','this.text','=',7,17,'createTextNode','("");',1091,958,1105,');',1091,'.onmousedown=',7,834,'Cancel;},Set',390,'_3b,_3c){','if(this.clear){clearTimeout(this.clear',');','this.clear',998,'if(',7,655,764,'){',0,1105,399,'Init();',0,1105,739,'if(',7,455,'textNodeBug','){',1091,'.innerHTML','=_3b;}',31,1105,'.nodeValue',11! 45,'this.message.style.',204,'="visible";if(_3c){',1150,'cursor="pointer";',0,1150,'cursor){',1150,'cursor="hand";}',1091,'.title=" Cancel Processing of Math ";}',31,1150,'cursor="";',1091,'.title="";}}',31,'if(_3b.substr(0,8)!="Loading "){',7,1,841,'=_3b;}}},Clear',468,1122,');}',1124,'=setTimeout("',7,815,'.doClear()",1000);},doClear',468,'if(',1124,399,'clear',601,7,1,841,'="";if(',1105,'){',1105,1148,'="";}if(',1091,'){',1150,204,'="',206,'";}}},Blank',468,'if(','this.blank','||!',7,17,'body',486,1205,'=',7,478,'DIV("',189,'",{position:(',7,455,'msiePositionFixedBug','?"absolute":"fixed"),top:"0px",left:"0px",bottom:"0px",right:"0px",zIndex:101,',1103,':"white"});if(',7,455,'msieBlankBug','){',1205,1144,'=" ";',1205,'.style.width="110%";',1205,'.style.height="110%";}},UnBlank',468,'if(',1205,'){',7,17,'body.removeChild(',1205,');}',1205,'=null;}};',7,'Setup={',8,':[],DIV',390,'id,_3e',9,'div=',7,17,23,'("div");div.id="jsMath_"+id;','for(var i in ','_3e){div.style[i! ]=_3e[i];}',0,7,17,'body.hasChildNodes){',7,17,'body',958,'div! );}',31, 7,17,947,'div,',7,17,943,');}return div;},Script',390,'_41,_42){if(','this.loaded[_41',']){return;}',31,1280,']=1;}',0,'_41.match("^([a-zA-Z]+:/?)?/")){_41=',7,'root+_41;}',7,806,'Load(_41,_42);},Hidden',468,7,206,'=this.DIV("Hidden",{',204,':"',206,1101,'top:0,left:0,border:0,padding:0,margin:0});',7,'hiddenTop=',7,206,';return;},Source',468,'if(',7,'Autoload&&',7,'Autoload.root','){',7,'root=',7,1311,';}',31,7,'root="";var _43=',7,17,'getElementsByTagName("','script");if(_43){',587,'_43','.length;i++){var ','src=_43[i].src;if(src&&src.match("(^|/)',7,'js$")){',7,1314,'src.','replace(/',7,'js$/,"");i=_43.length;}}}}if(',7,'root.charAt(0)=="/"){',7,1314,7,17,698,'+"//"+',7,17,'location.host+',7,'root;}',31,0,7,'root.match','(/^[a-z]+:/i)){src','=new String(',7,17,640,7,1314,'src','.replace(new RegExp','("[^/]*$"),"")+',7,'root;while(',7,1353,'("/[^/]*/\\\\.\\\\./")){',7,1314,7,'root',1362,'("/[^/]*/\\\\.\\\\./"),"/");}}}',7,'Img.',1314,7,649,'fonts/";',7,189,'=',7,649,189,'.! gif";this.Domain();},Domain',468,'try{',7,17,'domain;}catch(err',486,'var _46="";var _47=',7,17,'domain;if(',7,1353,'("://([^/]*)/")){_46=RegExp.$1;}_46=_46.replace(/:\\d+$/,"");if(_46==""||_46==_47',486,660,'appName=="Microsoft Internet Explorer"&&',7,40,'=="mac"&&',42,'onLine&&',42,725,'&&',7,17,'all',486,'_46=_46.split(/\\./);_47=_47.split(/\\./);if(_46.length<2||_47.length<2||','_46[_46.length-','1',']!=_47[_47.length-','1]||',1417,'2',1419,'2]){this.','DomainWarning','();return;}var _48=',1417,'2]+"."+',1417,'1];for(var i=3;i<=_46.length&&i<=_47',589,1417,'i',1419,'i]){break;}_48=',1417,'i]+"."+_48;}',7,17,746,'_48;this.',798,'=1;},',1425,468,25,'In order for ',3,' to be able to load the additional "+"components that it may need, the ',7,'js file must be "+"',8,' from a server in the same domain as the page that "+"contains it. Because that is not the case for this page, "+"the',27,'displayed here may not appear correctly.");},','EncodeFont',390,'_4a',9,'_4b=',7,'TeX[! _4a];if(_4b[0].c',726,486,1064,'128;k++){var _4d=_4b[k];_4b[k]! =_4d[3]; if(_4b[k]==null){_4b[k]={};}_4b[k].w=_4d[0];_4b[k].h=_4d[1];if(_4d[2]!=null){_4b[k].d=_4d[2];}_4b[k].c=',7,'TeX.encoding[k];}},Fonts',468,587,7,'TeX.fam',1327,'_4f=',7,1472,'[i];if(_4f',399,1456,'(_4f);}}},TeXfont',390,'_50',9,'_51=',7,'TeX[_50];if(_51==null',486,'var WH=',7,'EmBoxFor("<span class=\\""+_50+"\\">"+_51[65].c','+"</span>");_51.hd=WH.h;_51.dh=0.05;_51.d=',7,1490,'+',7,530,'_51.hd)+"</span>").h-_51.hd;_51.h=_51.hd-_51.d;','if(_50=="',145,'"){_51.skewchar=','127;}',31,1498,152,1500,'48;}}},',558,468,587,7,1472,589,7,1472,'[i]){this.TeXfont(',7,1472,'[i]);}}},Sizes',468,7,'TeXparams','=[];for(var j=0;j<',7,'sizes.length;j++){',7,1521,'[j]={};}',1258,7,'TeX){',879,7,'TeX[i])!="object"){for(var j=0;j<',7,'sizes.length;j++){',7,1521,'[j][i]=',7,'sizes[j]*',7,'TeX[i]/100;}}}},Styles',390,'_57){',0,'_57){_57=',7,50,';_57[".',60,' .scale"]="font-size:"+',7,655,'scale+"%";this.stylesReady=1;}',7,809,'this,"','AddStyleSheet','",_57);if(',7,455,'styleChangeDelay','){',7,809! ,7,'Script,"Delay",1);}},',1558,390,'_58',9,'_59=',7,17,1323,'head")[0];var _5a="";for(var id in _58){_5a+=id+" {"+_58[id]+"}\\n";}if(',7,17,'createStyleSheet){_59.insertAdjacentHTML("beforeEnd","<span',' style=\\"','display:none\\">x</span>"+"<style type=\\"text/css\\">"+_5a+"</style>");}',31,'var _5c=',7,17,23,'("style");_5c.type="text/css";_5c',958,7,17,1109,'(_5a));_59',958,'_5c);}},Body',468,'if(this.inited',486,'this.inited=-','1;',7,478,'Hidden();',1598,'2;',7,455,1134,1598,'3;if(',7,655,189,'){',7,815,'.Blank();}',1598,'4;',7,478,'Styles();',1598,'5;',7,646,1134,1598,'6;',7,809,7,'Setup,"User","pre-font");',1598,'7;',7,809,7,'Font,"Check");if(',7,'Font.register.length){',7,809,7,'Font,"LoadRegistered");}this.inited=1;},User',390,'_5d){if(',7,'Setup.UserEvent[_5d',']){(',7,1648,'])();}},UserEvent:{"pre-font":null,"onload":null}};',7,'Update={',558,390,'_5e){for(var ','_5f in ',1657,'_60 in _5e[_5f]){for(var id in _5e[_5f][_60]){',7,'TeX[_5f][_60][id]=_5e[_5f][_60][id! ];}}}},TeXfontCodes',390,'_62){for(var _63 in _62){',587,'_62[! _63].len gth;i++){',7,'TeX[_63][i].c=_62[_63][i];}}}};',7,'Browser={allowAbsolute:1,allowAbsoluteDelim:0,separateSkips:0,valignBug:0,operaHiddenFix:"",','msieCenterBugFix',':"",','msieInlineBlockFix',':"",','msieSpaceFix',':"",imgScale:1,renameOK:1,',1562,':0,delay:1,version:0,','TestSpanHeight',468,7,400,'="<span','><','span style=\\""+this.block+";','height:2em;width:','1px',503,'></span>";var ','_65=',7,'hidden.firstChild;','var img=_65.firstChild;','this.spanHeightVaries','=(_65',411,'>=img',411,'&&_65',411,'>0);','this.spanHeightTooBig','=(_65',411,'>img',411,');',7,400,'="";},','TestInlineBlock',468,'this.block','="display:-moz-inline-box";','this.hasInlineBlock','=',7,'BBoxFor("<span style=\\""+this.block+";','width:10px;height:5px\\"></span>").w>0;if','(',1715,'){',7,'styles[".typeset .',189,'"]=',7,1724,189,'"].replace(/',191,'/,',1713,');',7,1724,200,'"]=',7,1724,200,1730,191,'/,"");}',31,1713,'="',191,'";',1715,'=',7,1718,1719,'(!',1715,739,1713,'+=";',193,'";var h=',7,396! ,'("x").h;this.mozInlineBlockBug=',7,1718,'height:"+h+"px;width:1px',503,'>x"+"<',1685,1767,';vertical-align:-"+h+"px',503,'>").h>2*h;this.widthAddsBorder=',7,1718,193,';height:1px;width:10px',';border-left:','10px solid',503,'>").w>10;','this.msieBorderBug','=',7,1718,1767,503,'>x").h!=',7,1718,1767,1779,186,503,'>x").h;this.blankWidthBug=',1783,'||',7,1718,1686,'0px',503,'>").h==0;},','TestRenameOK',468,7,400,1683,1689,'_68=',7,1692,'_68.setAttribute("name","','jsMath_test','");this.renameOK=(',7,17,'getElementsByName("',1815,'").length>0);',7,400,1710,'TestStyleChange',468,7,400,1683,' ID=\\"',1815,'\\">x</span>";var _69=',7,1692,'var w=_69',408,';',7,478,1558,'({"#',1815,79,'200%"});this.',1562,'=(_69',408,'==w);',7,400,1710,'VersionAtLeast',390,'v',9,'bv',1355,'this.version',').split(".");','v',1355,'v',1859,'if(v[1]==null){v[1]="0";}return bv[0]>v[0]||(bv[0]==v[0]&&bv[1]>=v[1]);},Init',468,7,29,'="unknown";this.',1711,568,1679,568,1805,568,1825,568,'MSIE',568,'Mozilla! ',568,'Opera',568,'OmniWeb',568,'Safari',568,'Konqueror','();i! f(','thi s.allowAbsoluteDelim','){',7,'Box.DelimExtend=',7,'Box.DelimExtendAbsolute;',7,'Box.Layout=',7,'Box.LayoutAbsolute;}',31,7,'Box.DelimExtend=',7,'Box.DelimExtendRelative;',7,'Box.Layout=',7,'Box.LayoutRelative;}if(','this.separateSkips','){',7,'HTML.Place=',7,'HTML.','PlaceSeparateSkips',';',7,'Typeset.prototype.','Place=',7,1917,1914,';}},MSIE',468,'if(',1694,'&&!',1702,'){',7,29,'="MSIE";if(',7,40,'=="pc"){this.','IE7=(',1,767,726,');this.quirks=(',7,17,'compatMode=="BackCompat");',1889,'=1;',1908,'=1',';this.buttonCheck=1;this.',1226,'=1;this.msieDivWidthBug=1;this.',1220,962,'msieIntegralBug',962,'waitForImages',962,'msieAlphaBug=!','this.IE7',';this.','alphaPrintBug','=!',1957,';this.',1671,'="position:relative; ";this.',1673,'=" ',191,';";',0,1957,399,1675,1683,1580,191,503,'>";}',7,'Macro("joinrel","\\\\mathrel{\\\\kern-5mu}"),',7,1724,'arial"]="font-family: \'Arial unicode MS\'";',0,1957,'||this.quirks){',7,'styles["#',214,'"]=',7,1987,214,1730,216,'/,"',208,'").',133! 4,227,'/,"");',7,1987,229,'"]=',7,1987,229,1730,216,'/,"',208,'").',1334,227,'/,"");',7,1987,275,'"]="width:','1px; "+',7,1987,275,1730,216,'/,"',208,'").',1334,227,'/,"");',7,1,'.attachEvent("','onscroll",',7,646,'MoveButton',');if(',1957,'){',7,1,2034,'onresize",',7,646,2038,');}this.msieMoveButtonHack=',1957,';}',7,1987,353,'"]+=" ','display: inline-block',';";',7,1724,200,'"]=',7,1724,200,1730,191,'/,"");',7,50,'[".tex2math_div"]=',7,50,'["div.',60,'"]+"; width: 100%; ',2056,'";if(','screen.deviceXDPI','&&','screen.logicalXDPI','&&',2078,'!=',2080,399,'imgScale*=',2080,'/',2078,';',7,655,'alpha=0;}this.',456,'="<i>x</i>";',7,'EmBoxFor=',7,436,';}',31,'if(',7,40,'=="mac"){this.msieAbsoluteBug',962,'msieButtonBug',1949,1226,962,'quirks=1;',7,478,'Script("',3,'-msie-mac.js");',7,'Parser.prototype.macros.angle=["Replace","ord","<font face=\\"Symbol\\">‹</font>","normal"];',7,1987,229,2019,'42em; "+',7,1987,229,1730,227,'/,"");',7,655,'printwarn=0;}}',7,'Macro("not","\\! \\mathrel{\\\\rlap{\\\\kern3mu','/}}");}},',1879,468,'if(',7,2! 06,'.ATT RIBUTE_NODE){',7,29,'="',1879,'";if(',7,40,1934,1959,'=1;}',1889,'=1;',7,1987,275,'"]=',7,1987,275,1730,'cursor:hand','/,"cursor:pointer");',7,1987,353,'"]=',7,1987,353,1730,2162,'/,"cursor:pointer");',7,2134,'/}}");',660,'vendor=="Firefox"){',1858,'=',42,'vendorSub;}',31,660,'userAgent.match','(" Firefox/([0-9.]+)( |$)")){',1858,'=RegExp.$1;}}}},',1883,468,660,'accentColorName){',7,29,'="',1883,'";','this.allowAbsolute','=',1715,';',1889,'=',2198,';this.valignBug=!',2198,1947,1141,'=1;',7,'noChangeGlobal=1;',0,1715,'){',7,'Setup.Script("jsMath-old-browsers.js','");}}},Opera',468,'if(',1702,'){',7,29,'="Opera";var _6d=',42,2185,'("Opera 7");',2198,'=0;this.delay=10;this.operaHiddenFix="[Processing]";if(_6d){',7,2216,'");}}},Safari',468,660,'appVersion',44,'Safari\\//)){',7,29,'="Safari";var _6e=',42,2185,'("Safari/([0-9]+)");_6e=(_6e)?_6e[1]:400;',587,7,1472,589,7,1472,'[i]&&',7,'TeX[',7,1472,'[i]]){',7,'TeX[',7,1472,'[i]].dh=0.1;}}',7,'TeX.axis_height+=0.05;',7,'TeX.default! _rule_thickness+=0.025;',1889,'=_6e>=125;this.safariIFRAMEbug=_6e>=312&&_6e<412;this.safariButtonBug=_6e<412;this.safariImgBug',962,1141,'=1',1947,1562,'=1;}},',1887,468,660,'product&&',42,'product.match("',1887,'")){',7,29,'="',1887,'";',2198,'=0;',1889,'=0;',660,2185,'(/',1887,'\\/(\\d+)\\.(\\d+)/)){if(RegExp.$1<3||(RegExp.$1==3&&RegExp.$2<3)){',1908,962,'valignBug=1;',7,2216,'");}}',7,'Add(',7,50,',{".',60,' .',118,52,': ','jsMath-cmr10, jsMath cmr10',', serif',73,125,52,': ',3,'-',125,', ',3,' ',125,', ',2311,73,135,52,': ',3,'-',135,', ',3,' ',135,', ',2311,73,145,52,': ',3,'-',145,', ',3,' ',145,73,152,52,': ',3,'-',152,', ',3,' ',152,73,159,52,': ',3,163,', ',3,' ',159,'"});',7,'Font.testFont="',3,163,', ',3,' ',159,'";}}};',7,'Font={testFont:"',3,163,'",fallback:"symbol",register:[],message:"<b>No ',3,' TeX fonts found</b> -- using',' image fonts instead','.<br/>\\n"+"These',' may be slow and might not print well.<br/>\\n"+"Use the jsMath control panel to get additi! onal information.",','extra_message:"Extra TeX fonts not found! : <b><sp an id=\\"jsMath_ExtraFonts',503,'></b><br/>"+"Using',2388,'. This',2390,'print_message:"To print higher-resolution math symbols, click the<br/>\\n"+"<b>Hi-Res Fonts for Printing</b> button on the ',3,' control panel.<br/>\\n",','alpha_message:"If the math symbols print as black boxes, turn off <b>image alpha channels</b><br/>\\n"+"using the <B>Options</B> pane of the ',3,2399,'Test1',390,'_70,n,_72,_73','){if(n==null){n=124;}if(','_72==null){_72=2;}if(_73==null){_73="";}var wh1=',7,'BBoxFor("<span style=\\"font-family',': "+_73+_70+", serif\\">"+',7,'TeX[_70][n].c+"</span>");','var wh2=',7,2409,': serif\\">"+',7,2412,859,'wh1.w>_72*wh2.w&&wh1.h!=0);},Test2',390,'_76,n,_78,_79',2406,'_78==null){_78=2;}if(_79==null){_79="";}var'], - [' wh1=','jsMath.','BBoxFor("<span style=\\"font-family',': "+','_79+_76','+", serif','\\">"+',1,'TeX[_76][n','].c+"</span>");','var wh2=',1,2,': serif',6,1,'TeX[_76][n',9,'return (wh2.w>_78*wh1.w&&wh1.h!=0);},CheckTeX',':function','(){var ','wh=',1,2,3,1,'Font.','testFont',5,6,1,'TeX.cmex10[1',9,1,'nofonts=((wh.w*3>wh.h||wh.h==0)&&!this.Test1("cmr10','",null,null,"jsMath-"));if(',1,'nofonts&&(',1,'platform','!="mac"||',1,'browser!="Mozilla"||!',1,'Browser.','VersionAtLeast(1.5))){wh=',1,2,': cmex10, serif',6,1,'TeX.cmex10[1',9,1,34,'"));if(!',1,'nofonts){',1,'Setup.Script("jsMath-','BaKoMa-fonts.js");}}},Check',19,20,'_7d=',1,'Controls.','cookie;this.CheckTeX();if(',1,57,'if(_7d.autofont','||_7d','.font=="tex"){','_7d.font','=this.','fallback',';if(_7d.warn){',1,'nofontMessage=1;_7d.warn=0;',1,65,'SetCookie(0);if','(',1,'window.NoFontMessage','){',1,83,'();}else{','this.Message(this.','message);}}}}else{',69,'){',72,'="tex";}if(_7d',71,'return;}}if(',1,'noImgFonts){',72,! '="unicode";}if(',72,'=="unicode"){',1,59,74,'-"+',1,39,'+".js");',1,'Box.TeXnonfallback=',1,'Box.TeX',';',1,112,'=',1,'Box.TeXfallback;return;}','if(!_7d.print&&_7d.printwarn){this.','PrintMessage','((',1,44,'alphaPrintBug&&',1,65,'cookie.alpha)?','this.print_message','+this.alpha_message:',128,');}if(',1,44,'waitForImages){',1,'Script.','Push(',1,'Script,"WaitForImage",',1,'blank',131,72,'=="symbol"){',1,59,74,'-symbols.js");',1,'Box.TeXnonfallback=',1,112,';',1,112,'=',1,118,1,'Img.SetFont','({cmr10',':["all"],','cmmi10',162,'cmsy10',162,'cmex10',162,'cmbx10',162,'cmti10:["all"]});',1,'Img.LoadFont','("cm-fonts");},Message',19,'(_7e','){if(',1,'Element("','Warning','")){','return;}var ','div=',1,'Setup.DIV("',180,'",{});div.innerHTML="<center><table><tr><td>"+"<div ','id=\\"jsMath_noFont\\"><div ','class=\\"message\\">"+','_7e+"<div style=\\"text-align:left\\"><span style=\\"float:left; margin: 8px 0px 0px 20px\\">"+"<span onclick=\\"',1,65,'Panel','()\\" title=\\" ','Op! en the ','jsMath Control Panel',' \\" class=\\"link\\">',196,'! </span>" +"</span','><span style=\\"margin: 8px 20px 0px 0px; float:right\\">"+"<span onclick=\\"',1,26,'HideMessage',194,'Remove this font warning message',197,'Hide this Message',199,'></div><div style=\\"height:6px\\"></div><br clear=\\"all\\"/></div></','div>"+"<div style=\\"width:22em; height:1px\\"></div>"+"</td></tr></table></center><hr/>";},',203,19,20,'_80=',1,179,180,'");if(_80){_80','.style.display="none";}},',120,19,'(_81',177,1,179,'PrintWarning',181,182,'div=',1,185,226,187,189,'_81+"</',210,'Register',19,'(_83,_84',177,'typeof (_83)=="string"){_83={name:_83};}if(!',1,'Setup.inited','&&!_84){','this.register','[',245,'.length]=_83;',182,'_85=_83.name;var _86=_85.replace(/10$/,"");var _87=',1,'TeX.fam.length;if(','_83.prefix','==null){',253,'="";}if(!_83.style){_83.style="font-family',3,253,'+_85',5,'";}if(!_83.styles){_83.styles={};}if(!_83.macros){_83.macros={};}',1,'TeX.fam[_87]=_85;',1,'TeX.famName[_85]=_87;_83.macros[_86]=["HandleFont",_87];',1,'Add(',1,'Parser.prot! otype.macros,_83.macros);_83.styles[".typeset ."+_85]=_83.style;',1,'Setup.Styles(_83.styles);if(',1,'initialized){',1,136,'Push(',1,'Setup,"TeXfont",_85);}var _88=',1,65,'cookie;var _89=!',1,'nofonts&&_83.test(_85,_83.testChar,_83.testFactor,',253,');if(_89&&_88',71,'if(_83.','tex){_83.tex(_85,_87,_83);}return;}if(!_89&&_88.warn&&_88.font=="tex"&&!',1,57,'if(!_88.fonts.match("/"+_85+"/")){_88.fonts+=_85+"/";',1,65,80,'(!',1,179,180,181,88,'extra_message);}var _8a=',1,179,'ExtraFonts");if(_8a',177,'_8a.innerHTML','!=""){',306,'+=",";}',306,'+=" "+',253,'+_85;}}}if(_88.font=="unicode"||',1,97,287,74,'){_83.',74,'(_85,_87,_83);}',182,'_8b={};_8b[_85]=["all"];',1,160,'(_8b);',1,173,'(_85);if(',1,'initialized){',1,136,'Push(',1,'Img,"Scale");',1,136,'Push(',1,'Img,"UpdateFonts");}},LoadRegistered',19,20,'i=0;while(i<',245,'.length){this.',237,'(',245,'[i++],1);}',245,'=[];},Load',19,'(_8d){',1,'Setup.Script(this.URL(_8d));},URL',19,'(_8e){return ',1,'Img.root+_8e+"/def.js";}};'! ,1,'Controls={cookie:{scale:100,font:"tex",autofont:1,scaleImg! :0,alpha :1,warn:1,fonts:"/",printwarn:1,stayhires:0,button:1,progress:1,asynch:0,blank:0,print:0,keep:"0D",global:"auto",hiddenGlobal:1},cookiePath:"/",','noCookiePattern',':/^(file|mk):$/,Init',19,'(){this.panel=',1,185,'panel",{display:"none"});if(!',1,44,'msieButtonBug){this.Button',87,'setTimeout("',1,65,'Button()",500);}},',193,19,'(){',1,'Translate.Cancel();if(this.loaded){this.Main',87,1,136,'delayedLoad(',1,'root+"jsMath-controls.html");}},Button',19,20,'_8f=',1,185,'button",{});_8f.title=" Open ',196,' ";_8f.innerHTML="<span onclick=\\"',1,65,193,'()\\">jsMath</span>";if(!',1,'Global.','isLocal&&!',1,'noShowGlobal){_8f.innerHTML+="<span id=\\"jsMath_global\\" title=\\" Open jsMath Global ',193,' \\" "+"onclick=\\"',1,401,'Show(1)\\">Global </span>";}if(_8f.offsetWidth<30){_8f.style.width="auto";}if(!','this.cookie','.button){_8f',219,'MoveButton',19,20,'_90=',1,'Controls;if(!','_90.button','){',419,'=',1,179,'button");}if(',419,'){_90.MoveElement(_90.','button,3,2);}va! r dx=20;var dy=20;if(',419,'){dy=',419,'.offsetHeight','+6;dx=dy+5;}if(_90.panel',427,'panel,dx,dy);}},MoveElement',19,'(obj,dx,dy',177,1,44,'IE7){var _96=document.body;obj.style.right','="auto";obj.style.','bottom',442,'left=_96.clientWidth+_96.scrollLeft-obj.offsetWidth-dx+"px";obj.style.top=_96.clientHeight+_96.scrollTop-obj',432,'-dy+"px";}else{','obj.style.visibility="','hidden";',448,'visible";}},GetCookie',19,'(){if(','this.defaults',254,454,'={};}',1,267,454,',',410,');this.userSet={};var _97=',1,'document.cookie',';if(',1,'window.location','.protocol.match(this.',362,')){_97',73,'localGetCookie','();','this.isLocalCookie','=1;}if(_97.match(/jsMath=([^;]+)/)){var _98=unescape(RegExp.$1).split(/,/);for(var i=0;i<_98.length;i++){var x=_98[i].match(/(.*):(.*)/);if(x[2].match(/^\\d+$/)){x[2]=1*x[2];}',410,'[x[1]]=x[2];this.userSet[x[1]]=1;}}},',473,19,'(){return ',1,468,'.search.substr(1);},SetCookie',19,'(_9b){var _9c=[];','for(var id in ',410,177,454,'[id]==null||',41! 0,'[id]!=',454,'[id]){_9c[_9c.length]=id+":"+',410,'[id];}}_9c! =_9c.joi n(",");if(',475,177,'_9b==2){return "','jsMath="+escape(','_9c);}this.','localSetCookie','(_9c,_9b);}else{_9c=escape(_9c);if(_9c==""){_9b=0;}if(','this.cookiePath','){_9c+="; ','path="+',505,';}if(','this.cookieDomain',506,'domain="+',510,';}if(',410,'.keep!="0D"){var ms={D',':1000*60*60*24',',W',517,'*7,M',517,'*30,Y',517,'*365};var exp=new Date;exp.setTime(exp.getTime()+',410,'.keep.substr(','0,1)*ms[',410,526,'1,1)]);_9c+="; expires="+exp.toGMTString();}if(_9c!=""){',1,465,'="jsMath="+_9c;var _a0=',1,465,';if(_9b&&!_a0.match(/jsMath=/)){alert("Cookies must be enabled in order to save jsMath options");}}}return null;},',503,19,'(_a1,_a2){if(!_a2){',182,'_a3=String(',1,468,').replace(/\\?.*/,"");if(_a1!=""){_a3+="?',501,'_a1',131,'_a3!=',1,468,'.href){this.Reload(_a3);}},Reload',19,'(url){if(!this.loaded){return;}this.loaded=0;',1,243,'=-100;',1,401,'ClearCache();if(url){',1,468,'.replace(url);}else{',1,468,'.reload();}}};',1,'Click={CheckClick',19,'(_a5){if(!_a5){_a5=',1,'! window.event;}if','(_a5.altKey){',1,65,193,'();}},CheckDblClick',19,'(_a6){if(!_a6){_a6=',1,571,'(!',1,'Click.DblClick){',1,'Extension.Require("double-click",1);var _a7=_a6;_a6={};',487,'_a7){_a6[id]=_a7[id];}}',1,136,'Push(',1,'Click,"DblClick",[_a6,this.alt]);}};',1,'TeX={thinmuskip:3/18,medmuskip:4/18,thickmuskip:5/18,x_height:0.430554,quad:1,num1:0.676508,num2:0.393732,num3:0.44373,denom1:0.685951,denom2:0.344841,sup1:0.412892,sup2:0.362892,sup3:0.288888,sub1:0.15,sub2:0.247217,sup_drop:0.386108,sub_drop:0.05,delim1:2.39,delim2:1,axis_height:0.25,default_rule_thickness:0.06,big_op_spacing1:0.111111,big_op_spacing2:0.166666,big_op_spacing3:0.2,big_op_spacing4:0.6,big_op_spacing5:0.1,integer:6553.6,scriptspace:0.05,nulldelimiterspace:0.12,delimiterfactor:901,delimitershortfall:0.5,scale:1,atom:["ord","op","bin","rel","open","close","punct","ord"],fam:["cmr10","cmmi10","cmsy10","cmex10","cmti10","","cmbx10",""],famName:{cmr10:0,cmmi10:1,cmsy10:2,cmex10:3,cmti10:4,cmbx10:6}! ,encoding:["À","Á","Â","Ã","Ä","Å! ;"," 6;","Ç","È","É","Ê","Ë","Ì","Í","Î","Ï","°","Ñ","Ò","Ó","Ô","Õ","Ö","·","Ø","Ù","Ú","Û","Ü","µ","¶","ß","ï","!",""","#","$","%","&","'","(",")","*","+",",","-",".","/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?","@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","[","\","]","^","_","`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","{","|","}","~","ÿ"],cmr10:[[0.625',',0.683],[0.','833',595,'778',595,'694',595,'667',595,'75',595,'722',595,'778',595,'722',595,'778',595,'722',595,'583',',0.694,0,{ic:0.','0778,krn:{"39":0.0778,"63":0.0778,"33":0.0778,"41":0.0778,"93":0.0778},lig:{"105":','14,"108":15}}],[0.','556',',0.694],[0.','556',621,'833',621,'833',621,'278',',0.431],[0.','3! 06,0.431',',0.194],[0.','5',621,'5',621,'5,0.628],[0.5',621,'5,0.568],[0.75',621,'444,0,0.17],[0.5',621,'722',629,'778',629,'5,0.528,0.0972],[0.903,0.683],[1.01',595,'778,0.732,0.0486],[','0.278',',0.431,0,{','krn:{"108":-0.','278,"76":-0.319}}],[',649,',0.694,0,{lig:{"96":','60}}],[0.5',621,'833',',0.694,0.194],[','0.5',',0.75,0.0556],[0.','833',660,'778',621,'278',',0.694,0,{krn:{"','63":0.111,"33":0.111','},lig:{"39":34}}],[0.','389',',0.75,0.25],[0.','389',670,'5,0.75],[','0.778,0.583,0.0833],[','0.278,0.106',631,'333',650,'lig:{"45":','123}}],[',675,'],[0.5',670,'5,0.644','],[0.5,0.644],[0.5,0.','644',685,'644',685,'644',685,'644],[0.5,0.644],[',649,629,'278,0.431',631,'278,0.5',631,'778',',0.367,-0.133],[','0.472,0.5',631,'472',654,'62}}],[0.778',621,'75',',0.683,0,{krn:{"','116','":-0.0278,"','67',710,'79',710,'71',710,'85',710,'81',710,'84":-0.0833,"89":-0.0833,"86":-0.111,"87":-0.111}}],[0.','708',595,'722',595,'764',708,'88',710,'87',710,'65',710,'86',710,'89":-',! '0.0278}}],[0.','681',595,'653',',0.683,0,{','krn:{"111":-0.08! 33,"101" :-0.0833,"117":-0.0833,"114":-0.0833,"97":-0.0833,"65":-0.111,"79":-0.0278,"67":-0.0278,"71":-0.0278,"81":-0.0278}}],[','0.785',595,'75',595,'361',708,'73":',737,'514',595,'778',708,'79',710,'67',710,'71',710,'81":-',737,'625',708,721,'917',595,'75',595,'778',708,'88',710,'87',710,'65',710,'86',710,'89":-',737,'681',708,'65','":-0.0833,"','111',710,'101',710,'97',710,'46',785,'44":-0.','0833}}],[0.','778,0.683',631,'736',708,'116',710,'67',710,'79',710,'71',710,'85',710,'81',710,721,'556',595,'722',708,'121',710,'101',785,'111',785,'114',785,'97',785,'65',785,'117":-0.',795,'75',595,'75',',0.683,0,{ic:0.','0139,',742,'1.03',834,'0139,',742,'0.75',708,'79',710,'67',710,'71',710,'81":-',737,'75',834,'025,krn:{"101',785,'111',785,'114',785,'97',785,'65',785,829,795,'611',595,'278',670,'5',621,'278',670,'5',621,'278,0.668],[0.','278',654,'92}}],[0.5',650,'krn:{"118',710,'106":0.0556,"121',710,'119":-',737,'556,0.','694,0',',{krn:{"101":0.0278,"111":0.0278,"120":-0.0278,"100":0.0! 278,"99":0.0278,"113":0.0278,"118":-0.0278,"106":0.0556,"121":-0.0278,"119":-0.0278}}],[0.','444',650,'krn:{"104',710,'107":-',737,'556',621,'444',629,'306',617,618,'12,"102":11,"108":13}}],[0.5',',0.431,0.194,{','ic:0.','0139,krn:{"','106":',737,'556',666,'116',710,'117',710,'98',710,'121',710,'118',710,'119":-',737,875,'306,0.668',631,'528',666,'97','":-0.0556,"','101',710,'97',710,'111',710,'99":-',737,'278',621,'833',650,'krn:{"116',710,'117',710,'98',710,'121',710,'118',710,'119":-',737,'556',650,'krn:{"116',710,'117',710,'98',710,'121',710,'118',710,'119":-',737,'5,0.431',',0',888,886,'431,0.194',888,'528,0.431',631,'392',629,'394',629,'389,0.615,0,{krn:{"121',710,'119":-',737,'556',650,'krn:{"119":-',737,'528',',0.431,0,{ic:0.',905,'97',928,'101',710,'97',710,'111',710,'99":-',737,'722',988,905,'101',710,'97',710,'111',710,'99":-',737,'528',629,'528',903,'ic:0.',905,'111',710,'101',710,'97',710,'46',785,'44":-0.',795,'444',629,'5',988,'0278,',679,'124}}],[1',988,'027! 8}],[0.','5',621,'5,0.668],[0.5,0.668]],cmmi10:[[0.615',834,'1! 39',',kr n:{"61":-0.0556,"59":-0.111,"58":-0.111,"127":0.',795,'833',708,'127":0.167}}],[0.','763',834,1031,'krn:{"127":0.0833}}],[0.','694',708,1045,'742',834,'0757,',1049,'831',834,'0812,krn:{"61',928,'59":-0.0556,"58":-0.0556,"127":0.','0556}}],[0.','78',834,'0576,',1049,'583',834,'139',1041,1062,'667',741,1049,'612',834,'11,krn:{"61',928,1061,1062,'772',834,'0502,',1049,'64',988,'0037,','krn:{"127":',737,'566',',0.694,0.194,{ic:0.','0528,',1049,'518',903,'ic:0.0556}],[0.444',617,'0378,krn:{"',1061,1062,'406',650,'krn:{"127":0.0556}}],[0.','438',1091,'0738,',1049,'497',903,'ic:0.0359',',',1103,'469',617,1031,1049,'354',650,1103,'576',629,'583',621,'603',903,1088,737,'494',988,'0637,krn:{"',1061,'0278}}],[0.','438',1091,'046,',1088,'0.111}}],[0.','57',988,'0359}],[0.','517',903,1049,'571',988,'0359,krn:{"59',928,'58":-0.',1062,'437',988,'113,krn:{"',1061,1132,'54',988,'0359,',1088,737,'596,0.694,0.194,{',1049,'626',903,1103,'651',1091,'0359,',1088,1137,'622',988,1140,'466',650,1049! ,'591',',0.694,0,{',1049,'828',988,1035,'517',903,1049,'363,0.431,0.0972,{ic:0.0799,',1049,'654',903,1088,'0.0833}}],[1',700,'1',700,'1',700,'1',700,649,',0.464,-0.0363],[',649,1199,'0.5,0.465,-0.0347],[',1202,'0.5',629,'5',629,'5',629,967,631,967,631,967,',0.194',685,971,685,'431',631,'278,0.106],[',675,631,'778',',0.539,0.0391],[','0.5,0.75,0.25,{krn:{"1',928,'65',928,'77',928,'78',928,'89":0.0556,"90":-0.',1062,'778',1225,1202,'0.531',617,'0556,',1049,'75',708,'127":','0.','139}}],[0.','759',834,'0502,',1049,'715',834,'0715,krn:{"61',710,1061,795,'828',834,1031,1103,'738',834,'0576,',1049,'643',834,'139',1041,795,'786',741,1049,'831',834,'0812,krn:{"61',928,1061,1062,'44',834,'0785,',1088,1137,'555',834,'0962',1041,'167}}],[0.','849',834,'0715,krn:{"61',928,1061,1062,'681',708,1245,737,'97',834,'109,krn:{"','61',928,1061,795,'803',834,1302,'61',785,'61',710,1061,795,'763',834,1031,1049,'642',834,'139',1041,795,'791,0.683,0.194,{',1049,'759',834,'00773,',1049,'613',834,'0! 576,krn:{"61',928,1061,795,'584',834,'139,krn:{"61',710,1061,7! 95,'683' ,834,1302,'59":-0.111,"',1148,'111,"61',928,1245,737,'583',834,'222',',krn:{"59":-0.167,"58":-0.167,"61":-0.111}}],[0.','944',834,'139',1355,'828',834,'0785,krn:{"61',785,'61',710,1061,795,'581',834,'222',1355,'683',834,'0715,krn:{"61',928,1061,795,'389,0.75],[0.389',658,'0.389',658,'1,0.358,-0.142],[',1382,'0.417',1177,1088,1137,'529',629,'429',621,'433',650,1103,'52',666,'89":0.0556,"90',928,'106":-0.111,"102":-0.167,"',1045,'466',650,1103,'49',1091,'108,krn:{"',1061,1289,'477',903,1110,',',1088,737,'576',666,'127":-',737,'345,0.66],[0.412,0.66,0.194,{ic:0.0572,krn:{"59',928,1148,1062,'521',617,'0315}],[0.298',617,'0197,',1049,'878',629,'6',629,'485',650,1103,'503',903,1049,'446',903,1110,',',1049,'451',988,1031,'krn:{"',1061,1062,'469',650,1103,'361,0.615,0,{',1049,'572',650,1088,737,'485',988,'0359,',1088,737,'716',988,'0269,',1049,'572',650,1088,737,'49',903,1110,',',1103,'465',988,'044,',1103,'322',650,1088,737,'384',903,1049,'636',903,1088,1137,'5,0.714,0,{ic:0.154}],! [',649,617,'399}]],cmsy10:[[',674,649,',0.444,-0.0556],[',674,1202,674,'0.5,0.444,-0.0556],[',674,674,674,674,674,674,674,'1',658,1502,1502,'0.778',1199,'0.778,0.464,-0.0363','],[0.778,0.636,0.136',1517,1517,1517,1517,1517,'],[0.778',700,'0.778,0.483,-0.0169],[0.778',1225,'0.778',1225,'1',1225,'1',1225,'0.778',1225,'0.778',1225,'1',700,'1',700,'0.5',658,'0.5',658,'1',700,'1',658,'1',658,'0.778',1199,'1',700,'1',700,'0.611',658,'0.611',658,'1',700,'1',658,'1',658,'0.778',629,'275,0.556],[1',629,'667',1225,'0.667',1225,'0.889',658,'0.889',658,'0',658,'0',700,'0.556',621,'556',621,'667',629,'5',660,'722',621,'722',621,'778',621,'778',621,'611',621,'798',708,'48":0.','194}}],[0.657',834,'0304',',krn:{"48":0.',1247,'527',834,'0583',1607,1247,'771',834,'0278',1607,795,'528',834,'0894',1607,'111}}],[0.','719',834,'0993',1607,1623,'595',',0.683,0.0972,{ic:0.','0593',1607,1623,'845',834,'00965',1607,1623,'545',834,'0738,krn:{"48":',737,'678',1630,'185',1607,1289,'762',834,'0144',160! 7,1062,'69',708,1603,'139}}],[1.2',708,1603,1247,'82',834,'147! ',1607,7 95,'796',834,1616,1607,1623,'696',834,'0822',1607,795,'817,0.683,0.0972,{krn:{"48":',1137,'848',708,1603,795,'606',834,'075',1607,1247,'545',834,'254,krn:{"48":',737,'626',834,'0993',1607,795,'613',834,'0822,krn:{"48":',737,'988',834,'0822',1607,795,'713',834,'146',1607,1247,'668',1630,'0822',1607,795,'725',834,'0794',1607,1247,'667,0.556],[0.',1719,1719,1719,1719,'611',621,'611',621,'444',670,'444',670,'444',670,'444',670,'5',670,'5',670,'389',670,'389',670,'278',670,'5',670,'5',670,'611',670,'5',670,'278',658,'0.833,0.04,0.96],[0.75',595,'833',595,'417',1091,'111}],[0.',1719,'667,0.556',1517,1517,'],[0.444',658,'0.444',658,'0.444',658,'0.611',658,'0.778,0.694,0.13','],[',1775,'],[',1775,'],[',1775,']],cmex10:[[0.458',',0.04,1.16,{n:','16}],[0.458',1783,'17}],[0.417',1783,'104}],[0.417',1783,'105','}],[0.472,0.04,1.16,{n:','106',1791,'107',1791,'108',1791,'109}],[0.583',1783,'110}],[0.583',1783,'111',1791,'68',1791,'69}],[0.333',',0,0.6,{delim:{','rep:12}}],[0.556',1807,'re! p:13}}],[0.578',1783,'46}],[0.578',1783,'47}],[0.597',',0.04,1.76,{n:','18}],[0.597',1815,'19}],[0.736',',0.04,2.36,{n:','32}],[0.736',1819,'33}],[0.528',1819,'34}],[0.528',1819,'35}],[0.583',1819,'36}],[0.583',1819,'37}],[0.583',1819,'38}],[0.583',1819,'39}],[0.75',1819,'40}],[0.75',1819,'41}],[0.75',1819,'42}],[0.75',1819,'43}],[1.04',1819,'44}],[1.04',1819,'45}],[0.792',',0.04,2.96,{n:','48}],[0.792',1847,'49}],[0.583',1847,'50}],[0.583',1847,'51}],[0.639',1847,'52}],[0.639',1847,'53}],[0.639',1847,'54}],[0.639',1847,'55}],[0.806',1847,'56}],[0.806',1847,'57}],[0.806',',0.04,2.96],[','0.806',1867,'1.28',1867,'1.28',1867,'0.811',1815,'30}],[0.811',1815,'31}],[0.875',',0.04,1.76,{delim:{top:','48,bot:64,rep:66}}],[0.875',1879,'49,bot:65,','rep:67}}],[0.','667',1879,'50,bot:52,rep:54}}],[0.667',1879,'51,bot:53,rep:55','}}],[0.667,0.04,1.76,{delim:{bot:','52,rep:54',1889,'53,rep:55}}],[0.667',1807,'top:50,rep:54}}],[0.667',1807,'top:51,rep:55','}}],[0.889,0,0.9,{delim:{top:'! ,'56,mid:60,bot:58,rep:62',1897,'57,mid:61,bot:59,rep:62',1897! ,'56,bot :58,rep:62',1897,'57,bot:59,rep:62','}}],[0.889,0,1.8,{delim:{rep:','63',1905,'119}}],[0.889,0,0.3,{delim:{','rep:62}}],[0.','667',1807,'top:120,','bot:121,rep:63}}],[0.','875',1879,'56,bot:59,',1909,'875',1879,'57,bot:58,',1909,'875',1807,'rep:66}}],[0.875',1807,1883,'611',1815,'28}],[0.611',1815,'29','}],[0.833,0,1,{n:','71}],[1.11',',0.1,1.5],[','0.472,0,1.11,{ic:0.194,n:','73}],[','0.556,0,2.22,{ic:0.444}],[1.11,0',',1,{n:75}],[1.51,0','.1,1.5],[1.11,0',',1,{n:77}],[1.51,0',1939,',1,{n:79}],[1.51',1934,'1.06,0,1,{n:88}],[0.944,0,1,{n:89}],[',1935,'90',1932,'91',1932,'92',1932,'93',1932,'94',1932,'95}],[1.44',1934,'1.28',1934,1937,1939,1939,1939,1939,'.1,1.5],[0.944,0,1,{n:97}],[1.28',1934,'0.556,0.722,0,{n:','99','}],[1,0.75,0,{n:','100}],[1.44,0.75],[',1967,'102',1969,'103}],[1.44,0.75],[0.472',1815,'20}],[0.472',1815,'21}],[0.528',1815,'22}],[0.528',1815,'23}],[0.528',1815,'24}],[0.528',1815,'25}],[0.667',1815,'26}],[0.667',1815,'27}],[1',1783,'113}],[1',1815,'114}],[1! ',1819,'115}],[1',1847,'116}],[1.06,0,1.8,{delim:{top:118,bot:116,rep:117}}],[1.06,0,0.6],[1.06,0.04,0.56],[0.778',1807,'top:126,','bot:127,rep:119','}}],[0.667',1807,1912,'rep:63}}],[0.667',1807,1913,'45,0.12],[0.',2008,2008,2008,'778',1807,2000,'rep:119}}],[0.778',1807,2001,'}}]],cmti10:[[0.627',834,'133}],[0.818',595,'767',834,'094}],[0.692',595,'664',834,'153}],[0.743',834,'164}],[0.716',834,'12}],[0.','767',834,1762,'716',834,'0599}],[0.767',834,1762,'716',834,'103}],[0.','613',1091,'212,krn:{"39":0.104,"63":0.104,"33":0.104,"41":0.104,"93":0.104},lig:{"105":',619,'562',1091,2043,'588',1091,2043,'882',1091,2043,'894',1091,2043,'307',988,'0767}],[0.332',903,'ic:0.0374}],[0.511',621,'511',617,'0969','}],[0.511,0.','628,0,{ic:0.083}],[0.511',617,'108',2069,'562,0,{ic:0.',2043,'831',621,'46,0,0.17],[0.537',1091,'105}],[0.716',988,'0751}],[0.716',988,'0751',2069,'528,0.0972,{ic:0.0919}],[0.883',834,2032,'985',834,2032,'767,0.732,0.0486,{ic:0.094}],[0.256',650,651,'256,"76":! -0.321}}],[0.307',617,'124,lig:{"96":60}}],[0.514',617,'0696}]! ,[0.818' ,1091,'0662}],[0.769',621,'818,0.75,0.0556',',{ic:0.136}],[0.','767',617,'0969}],[0.307',617,'124,krn:{"63":0.102,"33":0.102',668,'409',',0.75,0.25,{ic:0.162}],[0.','409,0.75,0.25,{ic:0.0369',2069,'75,0,{ic:0.149}],[0.767,0.562,0.0567,{ic:0.0369}],[0.307,0.106',631,'358',988,'0283,',679,'123}}],[0.307,0.106],[0.511',2112,'511,0.644,0',',{ic:0.136}],[0.511,0.644,0',2124,2124,2124,'.194',2124,2124,2124,'.194',2124,2124,2104,'307',988,'0582}],[0.307',903,'ic:0.0582}],[0.307,0.5,0.194,{ic:0.0756}],[0.767,0.367,-0.133,{ic:0.0662',2069,'5',631,'511',617,'122,lig:{"96":62}}],[0.767',617,'096}],[0.743',708,'110','":-0.0256,"','108',2151,'114',2151,'117',2151,'109',2151,'116',2151,'105',2151,'67',2151,'79',2151,'71',2151,'104',2151,'98',2151,'85',2151,'107',2151,'118',2151,'119',2151,'81',2151,'84":-0.0767,"89":-0.0767,"86":-0.102,"87":-0.102,"101','":-0.0511,"','97',2185,'111',2185,'100',2185,'99',2185,'103',2185,'113":-0.0511}}],[0.704',834,2043,'716',834,'145}],[0.755',834,'094,kr! n:{"88',2151,'87',2151,'65',2151,'86"'], - [':-0.0256,"89','":-0.0256}}],[0.','678,0.683',',0,{ic:0.','12}],[0.','653,0.683',3,'133',',krn:{"','111','":-0.0767,"','101',10,'117',10,'114',10,'97',10,'65','":-0.102,"','79','":-0.0256,"','67',22,'71',22,'81',1,'774,0.683',3,'0872}],[0.743,0.683',3,'164}],[0.','386,0.683',3,'158}],[0.525,0.683',3,'14}],[0.769,0.683',3,'145',8,'79',22,'67',22,'71',22,'81',1,'627,0.683,0,{krn:{"84',10,'89',10,'86',20,'87',20,'101":-0.0511,"97":-0.0511,"111":-0.0511,"100":-0.0511,"99":-0.0511,"103":-0.0511,"113":-0.0511}}],[0.','897,0.683',3,33,'743,0.683',3,33,'767,0.683',3,'094',8,'88',22,'87',22,'65',22,'86',22,'89',1,'678,0.683',3,'103',8,'65":-0.0767}}],[0.','767,0.683',',0.194,{ic:0.','094}],[0.729,0.683',3,'0387',8,'110',22,'108',22,'114',22,'117',22,'109',22,'116',22,'105',22,'67',22,'79',22,'71',22,'104',22,'98',22,'85',22,'107',22,'118',22,'119',22,'81',22,'84',10,'89',10,'86',20,'87',20,58,'562,0.683',3,4,'716,0.683',3,'133',8,'121',10,'101',10,'111',10,'114',10,'97',10,'117',! 10,83,'743,0.683',3,33,'743,0.683',3,'184',8,'111',10,'101',10,'117',10,'114',10,'97',10,'65',20,'79',22,'67',22,'71',22,'81',1,'999,0.683',3,'184',8,83,'743,0.683',3,'158',8,'79',22,'67',22,'71',22,'81',1,'743,0.683',3,'194',8,'101',10,'111',10,'114',10,'97',10,'117',10,83,'613,0.683',3,'145','}],[0.307,0.','75,0.25',',{ic:0.188}],[0.514',',0.694',3,'169',215,216,',{ic:0.105','}],[0.511,0.','694',3,'0665',215,'668',3,'118',215,'694',3,'124,lig:{"96":92}}],[0.511,0.431',3,'0767}],[0.','46',218,3,'0631',8,58,'46,0.431',3,'0565',8,58,'511',218,3,'103',8,'108":0.0511}}],[0.','46,0.431',3,'0751',8,58,'307',218,85,'212',8,'39":0.104,"63":0.104,"33":0.104,"41":0.104,"93":0.104},lig:{"105":','12,"102":11,"108":13}}],[0.','46,0.431',85,'0885',224,'694',3,'0767',215,'655',3,'102',215,'655',85,'145}],[0.46',218,3,'108}],[0.','256',218,3,'103',8,254,'818,0.431',3,237,'562,0.431',3,273,8,'39":-0.102}}],[0.511,0.431',3,'0631',8,58,'511,0.431',85,'0631',8,58,'46,0.431',85,'0885}],[0.','4! 22,0.431',3,'108',8,58,'409,0.431',3,'0821}],[0.332,0.615',3,'! 0949}],[ 0.537,0.431',3,237,'46,0.431',3,284,'664,0.431',3,'108',8,254,'464,0.431',3,4,'486,0.431',85,310,'409,0.431',3,'123',224,'431',3,'0921',',lig:{"45":124}}],[1.','02,0.431',3,343,224,'694',3,'122',224,'668',3,'116',224,'668',3,'105}]],cmbx10:[[0.692',',0.686],[0.','958',360,'894',360,'806',360,'767',360,'9',360,'831',360,'894',360,'831',360,'894',360,'831',360,'671',218,3,'109,krn:{"39":0.109,"63":0.109,"33":0.109,"41":0.109,"93":0.109},lig:{"105":','14,"108":15}}],[0.639',',0.694],[0.','639',386,'958',386,'958',386,'319',',0.444],[0.','351',',0.444,0.194','],[0.575,0.','694',397,'694',397,'632',397,'694',397,'596],[0.869',386,'511,0,0.17],[0.597',386,'831',394,'894,0.444',397,'542,0.0972],[1.04,0.686],[1.17',360,'894,0.735,0.0486],[0.319',',0.444,0,{krn:{"','108":-0.319,"76":-0.378}}],[0.35',',0.694,0,{lig:{"96":','60}}],[0.603',386,'958',218,',0.194',397,'75,0.0556],[0.','958,0.',426,'894',386,'319',',0.694,0,{krn:{"','63":0.128,"33":0.128},lig:{"39":34}}],[0.447,0.',216,'],! [0.447,0.',216,397,'75],[0.894,0.633,0.133],[','0.319,0.156',',0.194],[0.','383,0.444,0,{lig:{"45":123}}],[',439,397,216,397,'644',397,'644',397,'644',397,'644',397,'644',397,'644',397,'644',397,'644',397,'644',397,'644],[0.319',394,'319',396,'],[0.35,0.5',440,'894,0.391,-0.109],[0.543,0.5',440,'543',419,'62}}],[0.894',386,'869',',0.686,0,{krn:{"','116','":-0.0319,"','67',479,'79',479,'71',479,'85',479,'81',479,'84":-0.0958,"89":-0.0958,"86":-0.128,"87":-0.128}}],[','0.818',360,'831',360,'882',477,'88',479,'87',479,'65',479,'86',479,'89','":-0.0319}}],[0.','756',360,'724,0.686,0,{','krn:{"111":-0.0958,"101":-0.0958,"117":-0.0958,"114":-0.0958,"97":-0.0958,"65":-0.128,"79":-0.0319,"67":-0.0319,"71":-0.0319,"81":-0.0319}}],[','0.904',360,'9',360,'436',477,'73','":0.0319}}],[0.','594',360,'901',477,'79',479,'67',479,'71',479,'81',506,'692',477,490,'1.09',360,'9',360,'864',477,'88',479,'87',479,'65',479,'86',479,'89',506,'786',477,'65":-0.0958,"111',479,'101',479,'97',479,'46":! -0.0958,"44":-0.0958}}],[0.','864,0.686',440,'862',477,'116',4! 79,'67', 479,'79',479,'71',479,'85',479,'81',479,490,'0.639',360,'8',477,'121',479,'101":-0.0958,"111":-0.0958,"114":-0.0958,"97":-0.0958,"65":-0.0958,"117":-0.0958}}],[0.','885',360,'869,0.686',3,'016,',510,'1.19,0.686',3,'016,',510,'0.869',477,'79',479,'67',479,'71',479,'81',506,'869,0.686',3,'0287',8,582,'703',360,'319,0.',216,'],[0.603',386,610,216,397,'694],[0.319',386,'319',419,'92}}],[0.559',417,'118',479,'106":0.0639,"121',479,'119',506,'639',218,',0',',{krn:{"101":0.0319,"111":0.0319,"120":-0.0319,"100":0.0319,"99":0.0319,"113":0.0319,"118":-0.0319,"106":0.0639,"121":-0.0319,"119":-0.0319}}],[0.','511',417,'104',479,'107',506,'639',386,'527',394,'351',218,3,384,266,'575,0.444',85,'016',8,'106',518,'639',432,'116',479,'117',479,'98',479,'121',479,'118',479,'119',506,'319',386,'351',218,440,'607',432,'97":-0.0639,"101',479,'97',479,'111',479,'99',506,'319',386,'958',417,'116',479,'117',479,'98',479,'121',479,'118',479,'119',506,'639',417,'116',479,'117',479,'98',479,'121',479,! '118',479,'119',506,'575,0.444,0',632,'639',396,632,'607',396,'],[0.474',394,'454',394,'447,0.635,0,{krn:{"121',479,'119',506,'639',417,'119',506,'607,0.444',3,'016',8,'97":-0.0639,"101',479,'97',479,'111',479,'99',506,'831,0.444',3,'016',8,'101',479,'97',479,'111',479,'99',506,'607',394,732,85,'016',8,'111',479,'101',479,'97',479,558,'511,0.444',397,'444',3,'0319',344,'15,0.444',3,'0319}],[0.575',218,397,'694',397,'694]]};','jsMath.Img','={fonts:[50,60,70,85,100,120,144,173,207,249,298,358,430],w:{"50":6.9,"60":8.3,"70":9.7,"85":11.8,"100":13.9,"120":16.7,"144":20,"173":24,"207":28.8,"249":34.6,"298":41.4,"358":49.8,"430":59.8},best:4,update:{},factor:1,loaded:0,SetFont',':function(','_a9){for(var _aa in _a9){if(!','this.update[_aa',']){',787,']=[];}',787,']=',787,'].concat(_a9[_aa]);}},AddFont',785,'_ab,def){if(!',783,'[_ab]){',783,'[_ab]={};}','jsMath.Add(jsMath.','Img[_ab],def);},UpdateFonts',':function(){','var _ad=this.update;','if(!this.loaded){','return;}var ','_ae=! this[','jsMath.Img.fonts','[this.best]];','for(var _af in _ad)! {','for( var i=0;i<','_ad[_af].length;i++){var c=_ad[_af][i];if(c=="all"){for(c in ','jsMath.TeX[','_af]){',813,'_af][c].img','={};}}else{',813,816,'={};}}}this.update={};},BestSize',803,'var w=jsMath.em*this.factor;var m=','this.w[this.fonts[','0]];for(var i=1;i<','this.fonts','.length;i++){','if(w<(',823,'i]]+2*m)/3){return i-1;}m=',823,'i]];}return i-1;},Scale',803,805,'return;}this.best=this.BestSize();this.em=',783,'.w[',825,809,'this.scale','=(jsMath.em/this.em);','if(Math.abs(',839,'-1)<0.12){',839,'=1;}},URL',785,'_b5,_b6,C){var _b8=(','jsMath.Controls.cookie.','alpha)?"/alpha/":"/plain/";if(C==null){C="def.js";}else{C="char"+C+".png";}if(_b6!=""){_b6+="/";}','return this.','root+_b5+_b8+_b6+C;},LoadFont',785,'_b9){',805,'this.Init();}jsMath.Setup.Script(this.URL(_b9,""));},Init',803,'if(',848,'print||',848,'stayhires','){',848,'print=',848,861,';this.factor*=3;if(!','jsMath.Controls.','isLocalCookie||!jsMath.Global.isLocal){',868,'SetCookie(0);}if(','jsMath.Browser.','alphaP! rintBug){',848,'alpha=0;}}var _ba="0123456789ABCDEF";this.HexCode=[];',811,'128;i++){var h=Math.floor(i/16);var l=i-16*h;this.HexCode[i]=_ba.charAt(h)+_ba.charAt(l);}this.loaded=1;}};jsMath.HTML={Em',785,'m){var n=5;if(m<0){n++;}',841,'m)<0.000001){m=0;}var s=String(m);s=s.replace(/(\\.\\d\\d\\d).+/,"$1");return s+"em";},Spacer',785,'w){if(w==0){return "";}return ',872,'msieSpaceFix+"<','span class=\\"spacer\\" style=\\"margin-','left:"+this.Em(','w)+"\\"></span>";},Blank',785,'w,h,d,_c5){var _c6="";var _c7="";if(_c5){_c7+="border-',887,'w)+" solid;";if(',872,'widthAddsBorder){w=0;}}if(w==0){if(',872,'blankWidthBug){_c7+="width:1px;";_c6="<',886,'right:-1px\\"></span>";}}else{_c7+="width:"+this.Em(w)+";";}if(d==null){d=0;}if(h){var H=this.Em(h+d);if(_c5&&h*jsMath.em<1.5){H="1px";h=1/jsMath.em;}_c7+="height:"+H+";";}if(',872,'mozInlineBlockBug){d=-h;}if(',872,'msieBorderBug&&!_c5){d-=jsMath.d;}if(d){_c7+="','vertical-align:"+','this.Em(-d);}return _c6+"<span class=\\"blank\\! " ','style=\\""+','_c7+"\\"></span>";},Rule',785,'w,h){if(h==n! ull){h=j sMath.TeX.default_rule_thickness;}',850,'Blank(w,h,0,1);},Class',785,'_cb,_cc){return "<span class=\\""+_cb+"\\">"+_cc+"</span>";},Place',785,'_cd',',x,y){if(Math.abs(x)<0.0001){x=0;}if(Math.abs(y)<0.0001){y=0;}','if(x||y){var _d0','="<span style=\\"position',': relative',';";if(x){_d0+=" margin-',887,'x)+";";}if(y){_d0+=" ','top:"+this.Em','(-y)+";";}_cd=_d0+"\\">"+_cd','+"</span>";}','re... [truncated message content] |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 17:36:22
|
Log Message: ----------- Adding union theme to templates Tags: ---- rel-2-4-patches Added Files: ----------- webwork2/conf/templates/union: gateway.template system.template Revision Data ------------- --- /dev/null +++ conf/templates/union/gateway.template @@ -0,0 +1,279 @@ +<!DOCTYPE html + PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<!-- +################################################################################ +# WeBWorK Online Homework Delivery System +# Copyright © 2000-2006 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader: webwork2/conf/templates/union/gateway.template,v 1.1.2.1 2008/06/24 17:19:06 gage Exp $ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. +################################################################################ +--> + +<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US"> +<head> +<title><!--#path style="text" text=" : " textonly="1"--></title> +<!--#head--> +<style type="text/css" media="all">@import "<!--#url type="webwork" name="stylesheet"-->";</style> + +<style type="text/css"> +/******************/ +/* gateway styles */ +/******************/ + +.LoginStatus {position:absolute; right:0px; top:-.5em} + +div.gwMessage { background-color:#dddddd; color: black; } +div.gwTiming { + background-color:#EECCCC; + color: black; + padding: .5em 2em; + float: right; +} +div.gwTiming form {margin:0px} +div.gwWarning { background-color:#ffffdd; color: black; } + +span.resultsWithError { + background-color: #ffcccc; + color: black; + padding: 1px 2em; + margin-left: 1em; +} +span.resultsWithoutError { + background-color: #66ff99; + color: black; + padding: 1px 2em; + margin-left: 1em; +} + +div.gwCorrect { + background-color: #66ff99; + color: black; + padding: 1px 2em; + margin-left: 1em; +} +div.gwIncorrect { + background-color: #ff9999; + color: black; + padding: 1px 2em; + margin-left: 1em; +} + +div.gwProblem { + clear: both; + background-color: white; + color: black; + padding: 1em 2em; + border-top-style: solid; border-bottom-style: solid; + border-width: 2px; border-color: #DDBBBB; +} +hr {display: none} +.div.gwProblem hr {display:block} + +div.gwSoln { +/* background-color: #e0e0ff; */ + background-color: transparent; + color: black; +/* padding: 2px; */, +/* border: dashed black 1px; */ +} +div.gwSoln b { color: navy; } + +p.gwPreview { + font-size: smaller; + text-align: right; + margin-top: 0px; + margin-bottom: 0px; +} + +table.gwAttemptResults { + border-width: 0px; +} +table.gwAttemptResults td.label { + font-weight: bold; + background-color: transparent; + color: navy; +} +table.gwAttemptResults td.output { + padding: 2px; + border: solid black 1px; + background-color: #eeeeee; +} + +</style> +<script language="javascript" type="text/javascript"> +function jumpTo(ref) { // scrolling javascript function + if ( ref ) { + var pn = ref - 1; // we start anchors at 1, not zero + if ( navigator.appName == "Netscape" && + parseFloat(navigator.appVersion) < 5 ) { + var xpos = document.anchors[pn].x; + var ypos = document.anchors[pn].y; + } else { + var xpos = document.anchors[pn].offsetLeft; + var ypos = document.anchors[pn].offsetTop; + } + if ( window.scrollTo == null ) { // cover for anyone + window.scroll(xpos,ypos); // lacking js1.2 + } else { + window.scrollTo(xpos,ypos); + } + } + return false; // prevent link from being followed +} + +// timer for gateway +var theTime = -1; // -1 before we've initialized +var alerted = -1; // -1 = no alert set; 1 = 1st alert set + // this shouldn't really be needed + +function runtimer() { +// aesthetically this is displeasing: we're assuming that the +// ContentGenerator will put the appropriate form elements in that +// page for us to manipulate. even with error checking, it seems sort +// of odd. + if ( document.gwtimer == null ) { // no timer + return; + } else { + var tm = document.gwtimer.gwtime; + var st = document.gwtimer.gwpagetimeleft.value; + + if ( st == 0 ) { // no time limit + return; + } else { + if ( theTime == -1 ) { + theTime = st; + tm.value = toMinSec(theTime); + setTimeout("runtimer()", 1000); // 1000 ms = 1 sec + } else if ( theTime == 0 && alerted != 3 ) { + alert("* You are out of time! *"); + alerted = 3; + } else if ( alerted != 3 ) { + theTime--; + tm.value = toMinSec(theTime); + setTimeout("runtimer()", 1000); // 1000 ms = 1 sec + if ( theTime == 35 && alerted != 2 ) { // time is in seconds + alert("* You have only about 30 seconds to complete " + + "this assignment. Press Grade very soon! *\n" + + "* The timer stops while this alert box is open. *"); + alerted = 2; + theTime -= 5; + } else if ( theTime == 75 && alerted != 1) { + alert("* You have only about a minute left " + + "to complete this assignment! *\n" + + "* The timer stops while this alert box is open. *"); + alerted = 1; + theTime -= 5; + } + } + } + } +} +function toMinSec(t) { +// convert to min:sec + mn = Math.floor(t/60); + sc = t - 60*mn; + if ( mn < 10 && mn > -1 ) { + mn = "0" + mn; + } + if ( sc < 10 ) { + sc = "0" + sc; + } + return mn + ":" + sc; +} +</script> +</head> +<body onload="runtimer();"> +<table width="100%" cellpadding="10" cellspacing="0" border="0"> + <tr valign="top"> +<!-- removed left sidebar --> + <!--#if can="info"--> + <td class="TopPanel" colspan="2"> + <!--#else--> + <td class="TopPanel" > + <!--#endif--> + <div style="position:relative; width:100%;"> + <!--#if can="path"--> + <span class="Path"> + <!--#path style="text" image="/webwork2_files/images/right_arrow.png" text=" > "--> + </span> + <!--#endif--> + + <!--#if loggedin="1"--> + <!--#if can="loginstatus"--> + + <span class="LoginStatus"> + + <!--#loginstatus--> + </span> + <!--#endif--> + <!--#endif--> + </div> + </td> + </tr> + <tr valign="top"> + <!--#if warnings="1"--> + <td class="ContentPanelError" bgcolor="#ffcccc"> + <!--#else--> + <td class="ContentPanel" bgcolor="#ffffff"> + <!--#endif--> +<!-- removed nav button to go up --> + <!--#if can="title"--> + <div class="Title"> + <!--#title--> + </div> + <!--#endif--> + <!--#if can="message"--> + <div class="Message"> + <!--#message--> + </div> + <!--#endif--> + + <!--#if can="submiterror"--> + <div class="SubmitError"> + <!--#submiterror--> + </div> + <!--#endif--> + <!--#if can="body"--> + <div class="Body"> + <!--#body--> + </div> + <!--#endif--> + <!--#if warnings="1"--> + <hr> + <div class="Warnings"> + <!--#warnings--> + </div> + <!--#endif--> + <!--#if can="message"--> + <div class="Message"> + <!--#message--> + </div> + <!--#endif--> + </td> + <!--#if can="info"--> + <td class="InfoPanel"> + <div class="Info"> + <!--#info--> + </div> + </td> + <!--#endif--> + </tr> + <tr> + <td class = "Timestamp", colspan=3> + Updated: <!--#timestamp--> + </td> + </tr> +</table> +</body> +</html> --- /dev/null +++ conf/templates/union/system.template @@ -0,0 +1,159 @@ +<!DOCTYPE html + PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<!-- +################################################################################ +# WeBWorK Online Homework Delivery System +# Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader: webwork2/conf/templates/union/system.template,v 1.1.2.1 2008/06/24 17:19:06 gage Exp $ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. +################################################################################ +--> + +<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US"> +<head> +<title><!--#path style="text" text=" : " textonly="1"--></title> +<!--#head--> +<style type="text/css" media="all">@import "<!--#url type="webwork" name="stylesheet"-->";</style> +</head> +<body> +<table width="100%" cellpadding="10" cellspacing="0" border="0"> + <tr valign="top"> + <td align="left" valign="top" rowspan="2" class="LeftPanel"> + <a href="http://webwork.math.rochester.edu"> + <img src="/webwork2_files/images/webwork_square.gif" alt="WeBWorK" height="64" width="66" border="0" /><! + ></a> + <br /> + + <!--#if loggedin="1"--> + <!--#if can="links"--> + <hr /> + <div class="Links"> + <!--#links--> + </div> + <!--#if can="siblings"--> + <hr /> + <!--#endif--> + <!--#endif--> + <div class="Siblings"> + <!--#siblings--> + </div> + <!--#if can="options"--> + <div class="Options"> + <!--#options--> + </div> + <!--#endif--> + <!--#endif--> + </td> + <!--#if can="info"--> + <td class="TopPanel" colspan="2"> + <!--#else--> + <td class="TopPanel"> + <!--#endif--> + <table border="0" cellpadding="0" cellspacing="0" width="100%"> + <tr> + + <!--#if can="path"--> + <td align="left" class="TopPanel" nowrap> + <span class="Path"> + <!--#path style="text" image="/webwork2_files/images/right_arrow.png" text=" > "--> + </span> + </td> + <!--#endif--> + + <!--#if can="time_left"--> + <td align="center" class="TopPanel" width="100%" nowrap> + <span class="TimeLeft"> + <!--#time_left--> + </span> + </td> + <!--#endif--> + + <!--#if loggedin="1"--> + <!--#if can="loginstatus"--> + <td align="right" class="TopPanel" nowrap> + <span class="LoginStatus"> + <!--#loginstatus--> + </span> + </td> + <!--#endif--> + <!--#endif--> + + </tr> + </table> + </td> + </tr> + + <tr valign="top"> + <!--#if warnings="1"--> + <td class="ContentPanelError" bgcolor="#ffcccc"> + <!--#else--> + <td class="ContentPanel" bgcolor="#ffffff"> + <!--#endif--> + <!--#if can="nav"--> + <div class="Nav"> + <!--#nav style="images" imageprefix="/webwork2_files/images/nav" imagesuffix=".gif" separator=" "--> + </div> + <!--#endif--> + <!--#if can="title"--> + <div class="Title"> + <!--#title--> + </div> + <!--#endif--> + <!--#if can="message"--> + <div class="Message"> + <!--#message--> + </div> + <!--#endif--> + + <!--#if can="submiterror"--> + <div class="SubmitError"> + <!--#submiterror--> + </div> + <!--#endif--> + <!--#if can="body"--> + <div class="Body"> + <!--#body--> + </div> + <!--#endif--> + <!--#if warnings="1"--> + <hr> + <div class="Warnings"> + <!--#warnings--> + </div> + <!--#endif--> + <!--#if can="message"--> + <div class="Message"> + <!--#message--> + </div> + <!--#endif--> + </td> + + <!--#if can="info"--> + <td class="InfoPanel"> + <div class="Info"> + <!--#info--> + </div> + </td> + <!--#endif--> + </tr> + + <tr> + <td class="Timestamp", colspan="3"> + Updated: <!--#timestamp--> + </td> + </tr> + +</table> +</body> +</html> |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 17:34:53
|
Log Message: ----------- Adding files for math2 theme Tags: ---- rel-2-4-patches Added Files: ----------- webwork2/conf/templates/math2: gateway.template math2.css system.template Revision Data ------------- --- /dev/null +++ conf/templates/math2/gateway.template @@ -0,0 +1,100 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<!-- +################################################################################ +# WeBWorK Online Homework Delivery System +# Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader: webwork2/conf/templates/math2/gateway.template,v 1.1.2.1 2008/06/24 17:17:36 gage Exp $ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. +################################################################################ +--> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta http-equiv="content-type" content="text/html; charset=utf-8" /> +<meta http-equiv="Pragma" content="no-cache"/> +<meta http-equiv="expires" content="Wed, 21 Dec 2005 00:00:01 GMT"/> +<link rel="stylesheet" type="text/css" href="<!--#url type="webwork" name="htdocs"-->/css/math.css"/> +<!-- [gateway] since the left-side menus are gone, don't indent the main content area --> +<link rel="stylesheet" type="text/css" href="<!--#url type="webwork" name="htdocs"-->/css/gateway.css"/> +<title><!--#path style="text" text=" : " textonly="1"--></title> +<!--#head--> +<script language="javascript" type="text/javascript" + src="<!--#url type="webwork" name="htdocs"-->/js/gateway.js"></script> +</head> +<body bgcolor="white"> +<div id="masthead"> + <div id="loginstatus"> + <!--#loginstatus--> + </div> + <div id="logo"> + <img src="<!--#url type="webwork" name="htdocs"-->/images/webwork_rectangle.png" alt="WeBWorK" height="51" width="267" /> + </div> +</div> +<hr class="for-broken-browsers"/> +<div id="big-wrapper"> + <div id="breadcrumbs"> + <!--#path style="text" text=" → "--> + </div> + <div id="content"> + + <!--#if can="info"--> + <!--<div id="page-info">--> + <!--<div class="info-box" id="fisheye">--> + <!--#info--> + <!--</div>--> + <!--</div>--> + <!--#endif--> + + <!-- [gateway] removed nav button to go up --> + + <!--#if can="title"--> + <h1><!--#title--></h1> + <!--#endif--> + + <!--#if can="message"--> + <div class="Message"> + <!--#message--> + </div> + <!--#endif--> + + <!--#if can="body"--> + <div class="Body"> + <!--#body--> + </div> + <!--#endif--> + + <!--#if warnings="1"--> + <hr> + <div class="Warnings"> + <!--#warnings--> + </div> + <!--#endif--> + + <!--#if can="message"--> + <div class="Message"> + <!--#message--> + </div> + <!--#endif--> + + </div> <!-- content --> + <hr class="for-broken-browsers"/> + <div id="footer"> + <p id="last-modified">Page generated at <!--#timestamp--></p> + <div id="copyright"> + WeBWorK © 2000-2007 <a href="http://openwebwork.sf.net/">The WeBWorK Project</a> + </div> + </div> + <!-- [gateway] removed left sidebar --> +</div> <!-- big-wrapper --> + +</body> +</html> --- /dev/null +++ conf/templates/math2/math2.css @@ -0,0 +1,507 @@ +/* WeBWorK Online Homework Delivery System + * Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ + * $CVSHeader: webwork2/conf/templates/math2/math2.css,v 1.1.2.1 2008/06/24 17:17:36 gage Exp $ + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of either: (a) the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any later + * version, or (b) the "Artistic License" which comes with this package. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the + * Artistic License for more details. + */ + +/* --- Standard elements ---------------------------------------------------- */ + +body { + background: white; + color: black; + margin: .5em .5em 0 .5em; /* MSIE ignores bottom margin; Gecko doesn't */ + padding: 0; + font-family: Times, serif; + min-width: 25em; +} + +h1, h2, h3, h4, h5, h6 { + font-family: "Trebuchet MS", "Arial", "Helvetica", sans-serif; + /* FIXME "You have no background-color with your color" */ + color: #225; + background: transparent; +} +h1 { font-size: 170%; } +h2 { font-size: 140%; padding-bottom: 0; margin-bottom: .5ex } +h3 { font-size: 120%; } +h4 { font-size: 110%; } +h5 { font-size: 105%; } +h6 { font-size: 105%; } + +a:link { color: #00e; background-color: inherit; } +a:visited { color: #808; background-color: inherit; } + +/* --- Miscellaneous classes ---------------------------------------------- */ + +/* show only to CSS-ignorant browsers */ +.for-broken-browsers { display: none } + +/* for hiding floats from Netscape 4.x */ +.float-left { float: left; } +.float-right { float: right; } + +/* --- Compound titles (class) ---------------------------------------------- */ + +/* WeBWorK is not using this, but it might be nice to have it around later */ + +/* "Split" title, with main heading left-aligned above a horizontal line, + * and subheading right-aligned below the line. Usage: + * + * <h1 class="compound">Alumni Newsletter</h1> + * <h2 class="compound">Spring '00</h2> + */ + +/*h1.compound { + border-bottom: 1px solid #559; + text-align: left; + padding: .5ex 0 0 0; + margin: 0; +} +h2.compound { float: right; margin: 0; padding: 0 }*/ + +/* --- Info box (class) ----------------------------------------------------- */ + +/* FIXME as a quick hack, the info() escape outputs a DIV with this class. + * don't let the placement of these styles fool you -- <div style="info-box"> + * is output by WeBWorK! */ + +/* Common style for a small box to hold supplemental info; typically this + * box will appear in a sidebar. Sample usage: + * + * <div class="info-box"> + * <h2>Announcements</h2> + * <ul> + * <li>foo</li> + * </ul> + * <a class="more" href="bar">Older announcements...</a> + * </div> + */ + +.info-box { + border: 1px solid #559; + /* FIXME: these aren't valid CSS, but they sure look nice :-P */ + border-radius-topright: 1.5ex; border-radius-topleft: 1.5ex; + -moz-border-radius-topright: 1.5ex; -moz-border-radius-topleft: 1.5ex; + margin-bottom: 1ex; + margin-top: 0; + overflow: hidden; +} +.info-box h2, +.info-box h3, +.info-box h4, +.info-box h5, +.info-box h6 { + /* FIXME: these aren't valid CSS, but they sure look nice :-P */ + border-radius-topright: 1.5ex; border-radius-topleft: 1.5ex; + -moz-border-radius-topright: 1.5ex; -moz-border-radius-topleft: 1.5ex; + border-bottom: 1px solid #559; + font-size: 100%; + text-align: center; + background: #88d; + color: white; + margin: 0; + padding: 0 .5em 0 .5em; +} +.info-box h2 a, +.info-box h3 a, +.info-box h4 a, +.info-box h5 a, +.info-box h6 a { + color: #fff; + background: inherit; +} +.info-box ul, +.info-box ol { + margin: 1ex .5em 1ex 0; + padding-left: 3.5em; + font-size: 80%; +} +.info-box dl { + margin: 1ex .5em 1ex 1ex; + padding: 0; + font-size: 80%; +} +.info-box li, +.info-box dt { + margin: 0 0 .5ex 0; + padding: 0; + line-height: 2.2ex; +} +.info-box dt { font-weight: bold } +.info-box dd { + margin: 0 0 .5ex 1em; + padding: 0; + line-height: 2.2ex; +} +.info-box dd p { + margin-top: 0; +} +.info-box a.more { + float: right; + font-size: 80%; + font-style: italic; + margin-bottom: 1ex; + margin-right: .5em; +} + +.Message { +background-color:#ddd; +} +/* --- Fisheye view (id) ---------------------------------------------------- */ + +/* The "fisheye" view: a hierarchical view of the website to show the + * user where they are in the document hierarchy. Provides more "lateral" + * information than breadcrumbs, but not as much as a full sitemap. To + * appear within the #site-navigation div. Inherits many of its attributes + * from class info-box, and overrides some. + */ + +#mini-sitemap, +#fisheye { + font-family: "Trebuchet MS", "Arial", "Helvetica", sans-serif; + padding: 0 0 1ex 0; +} +#mini-sitemap a, +#fisheye a { + text-decoration: none; +} +#mini-sitemap a:hover, +#fisheye a:hover { + text-decoration: underline; +} +#mini-sitemap li, +#fisheye li { + line-height: 2.5ex; + margin: 0; +} +#mini-sitemap ul, +#fisheye ul { + font-size: 90%; + list-style-type: none; + margin: 0 .1em .3ex .3em; + padding: 0; +} +#mini-sitemap ul ul, +#fisheye ul ul { + font-size: 90%; + margin-left: 0; +} +#mini-sitemap ul li, +#fisheye ul li { + font-weight: bold; +} +#mini-sitemap ul ul ul, +#fisheye ul ul ul { + font-size: 95%; + margin-left: .3em; + padding-left: .5em; + border-left: 1px dotted gray; +} +#mini-sitemap ul ul li a.active, +#fisheye ul ul li a.active { + font-weight: bold; + color: black; + background-color: inherit; +} +#mini-sitemap ul ul ul li, +#fisheye ul ul ul li { + font-weight: normal; +} +#mini-sitemap ul ul ul ul, +#fisheye ul ul ul ul { + font-size: 90%; +} +#mini-sitemap ul ul ul ul ul, +#fisheye ul ul ul ul ul { + font-size: 90%; +} + +/* --- Common layout elements for documents using templates ----------------- */ + +/* The "masthead" of our document that tells users what site they're on. + * It contains a logo-ish title and some basic site navigation. The + * masthead should appear at the top of the page, but we're not positioning + * it absolutely because we can't know its height in advance. Therefore this + * element should be placed at the very top of the <body> of our HTML document. + */ +#masthead { + font-family: "Trebuchet MS", "Arial", "Helvetica", sans-serif; + font-size: 100%; + margin: 0; + padding: 0; + color: #fff; + border: 1px solid #000; + background-color: #038; + /* [ww] we could have some sort of spider web image here. */ + /*background-image: url("/images/mandel-wide.jpg");*/ + background-repeat: repeat-x; + background-position: top left; +} +#masthead a { + /* FIXME "You have no background-color with your color" */ + color: #fff; + background: transparent; +} +/* [ww] since this is a logo and not text, we need borders that are the same + * width all the way around. after we find a nice background image, we can + * turn these back on. */ +/*#masthead #logo { padding: .5ex .2em .1ex .5em }*/ +#masthead #logo { padding: 1ex } +/* [ww] don't need these -- logo itself an image */ +/*#masthead #logo h1 { + background-image: none; + background-color: transparent; + font-size: 100%; + font-weight: normal; + padding: 0; + margin: 0; + white-space: nowrap; + line-height: 1.9ex; +}*/ +/*#masthead #logo h2 { + background-color: transparent; + background-image: none; + font-weight: bold; + font-size: 210%; + line-height: 1.9ex; + margin: 0; + padding: 0; +}*/ +/* [ww] instead of a search form, we want the loginstatus there */ +/*#masthead form {*/ +#masthead #loginstatus { + float: right; + padding: 0; + margin: 1ex .5em .1ex .1em; + font-size: smaller; +} +#masthead #loginstatus #Nav { + padding: 1ex; +} + +/* "big-wrapper" contains everything other than the masthead. It's merely + * a relatively positioned div that allows us to use absolute positioning + * on elements within it -- and because it's relatively positioned, + * absolutely positioned objects *stay* within it. + */ +#big-wrapper { + position: relative; + top: 1ex; + width: 100%; + min-width: 18em; + margin: 0; + border: 0; +} + +/* + * A simple list of "breadcrumbs" showing a path of links from the root of + * the site's hierarchy to our present location. We are not positioning + * this element absolutely, because we don't know in advance how tall it + * will be, and we might want to place content under it. So when coding + * our HTML document, we'll probably want to include this element right + * before the main content. + */ + +#breadcrumbs { + margin-left: 10.4em; + margin-right: 0; + padding: 0 .4em; + border: 1px solid #559; + background: #88d; + color: #fff; + text-align: left; + font-size: 100%; + font-family: "Trebuchet MS", "Arial", sans-serif; +} +#breadcrumbs a { + font-size: 100%; + white-space: nowrap; + background-color: inherit; + color: #fff; + text-decoration: none; +} +#breadcrumbs a.active { font-weight: bold; } +#breadcrumbs a:hover { text-decoration: underline; } + + +/* For the more CSS-compliant browsers, we'd like to provide site-wide + * navigation links (e.g., a mini site map) to appear in a column along + * the left side of the page, just below the masthead. This column is + * absolutely positioned, so that ideally we should be able to include its + * contents anywhere within the body of our HTML documents. However, we + * probably want to include this data at the END of our documents -- after + * the main content -- so that it doesn't interfere with document flow in + * browsers that don't understand CSS (e.g., lynx) -- or in browsers for + * which we've disabled CSS via some hack (e.g. Netscape Navigator 4.x). + * + * We consider this meta-information to be non-essential; it is NOT part of + * the content, and may not be displayed in some circumstances. + */ +#site-navigation { + position: absolute; + left: 0; + top: 0; + margin: 0; + padding: 0; + width: 9.8em; +} + +/* The primary information content of the document, excluding masthead and + * site navigation. We want to leave a wide left margin to prevent overlap + * with our site map, which will be displayed on the left-hand side of the + * screen. + */ +#content { + margin: .5em 0 0 10.4em; + padding: 0 0 0 0; + font-family: "Times", serif; + /* border-left: 1px dotted #bbf; */ +} +#content h1 { margin: .4ex 0; } /* for crappy MSIE */ + + +#footer { + /* white-space: nowrap; */ + clear: both; + /* border-top: 1px solid #559; */ + margin: 0 .5em .2ex 10.4em; + padding: 0; + font-family: "Trebuchet MS", "Arial", "Helvetica", sans-serif; +} +#copyright { font-size: 75%; margin: 0;} +#last-modified { + clear: both; + font-family: "Trebuchet MS", "Arial", "Helvetica", sans-serif; + font-size: 75%; + background-color: inherit; + color: #444; + margin: 1ex 0 0 0; + padding: 0; + border-bottom: 1px solid #559; +} + +/* --- WeBWorK classes ------------------------------------------------------ */ + +/* These classes are emitted by WeBWorK code and should appear in ANY WeBWorK + * template. they need not be implemented the same way in each template though. + * (These are mostly copied from ur.css right atm.) + */ + +/* the info escape emits a DIV with this id. (note that the same DIV has class + * "info-box" which is given above in the "template styles" section. Regardless, + * it is emitted by WW code in ProblemSet.pl (not in system.template) ! */ +#InfoPanel { + font-size:100%; + float: right; + width: 40%; + overflow: auto; + margin-right: -1px; + background-color: #fff; +} +#InfoPanel ol { + font-size:100%; +} + +/* tables used for laying out form fields shouldn't have a border */ +table.FormLayout { border: 0; } +table.FormLayout tr { vertical-align: top; } +table.FormLayout th.LeftHeader { text-align: right; white-space: nowrap; } +table.FormLayout tr.ButtonRow { text-align: left; } +table.FormLayout tr.ButtonRowCenter { text-align: center; } + +/* for problems which are rendered by themselves, e.g., by Set Maker */ +div.RenderSolo { background-color: #E0E0E0; color: black; } +div.AuthorComment { background-color: #00E0E0; color: black; } + +/* minimal style for lists of links (generated by the links escape) */ +/*ul.LinksMenu { list-style: none; margin-left: 0; padding-left: 0; }*/ +/*ul.LinksMenu ul { list-style: none; margin-left: 0.5em; padding-left: 0; }*/ + +/* background styles for success and failure messages */ +div.WarningMessage { background-color: #ffcccc; padding: 3px 3px 3px 3px; } +div.ResultsWithoutError { color: inherit; background-color: #8F8; } /* green */ +div.ResultsWithError { color: #C33; background-color: inherit; } /* red */ +div.ResultsAlert { color: #F60; background-color: inherit; } /* orange */ + +/* styles used by WeBWorK::HTML::ScrollingRecordList */ +div.ScrollingRecordList { padding: 1em; white-space: nowrap; border: thin solid gray; } +div.ScrollingRecordList select.ScrollingRecordList { width: 99%; } + +/* wraps the View Options form (generated by &optionsMacro) */ +/* FIXME: can't this style information just go in div.Options above? */ +div.viewOptions { font-size: small } + +/* messages, attempt results, answer previews, etc. go in this DIV */ +/* this used to be "float:left", but that was suspected of causing MSIE peekaboo bug */ +div.problemHeader {} + +/* styles for the attemptResults table */ +table.attemptResults { + border-style: outset; + border-width: 1px; + margin: 0px 10pt; + border-spacing: 1px; +} +table.attemptResults td, +table.attemptResults th { + border-style: inset; + border-width: 1px; + text-align: center; + /*width: 15ex;*/ /* this was erroniously commented out with "#" */ + padding: 2px 5px 2px 5px; + color: inherit; + background-color: #DDDDDD; +} +/* override above settings in tables used to display ans_array results */ +table.attemptResults td td, +table.attemptResults td th, +table.ArrayLayout td { + border-style: none; + border-width: 0px; + padding: 0px; +} +table.attemptResults td.Message { + text-align: left; + padding: 2px 5px 2px 5px; + width: auto; +} +.attemptResultsSummary { font-style: italic; } +.parsehilight { color: inherit; background-color: yellow; } + +/* the problem TEXT itself does in this box */ +/* we used to make this a grey box, but surprise, MSIE is bug-ridden. */ +div.problem { } + +/* jsMath emits this class when appropriate math fonts aren't available */ +div.NoFontMessage { + padding: 10px; + border-style: solid; + border-width: 3px; + border-color: #DD0000; + color: inherit; + background-color: #FFF8F8; + width: 75%; + text-align: left; + margin: 10px auto 10px 12%; +} + +/* text colors for published and unpublished sets */ +font.Published { font-style: normal; font-weight: normal; color: #000000; background-color: inherit; } /* black */ +font.Unpublished { font-style: italic; font-weight: normal; color: #aaaaaa; background-color: inherit; } /* light grey */ + +/* styles used when editing a temporary file */ +.temporaryFile { font-style: italic; color: #F60; background-color: inherit; } + +/* text colors for Auditing, Current, and Dropped students */ +.Audit { font-style: normal; color: purple; background-color: inherit; } +.Enrolled { font-weight: normal; color: black; background-color: inherit; } +.Drop { font-style: italic; color: gray; background-color: inherit; } --- /dev/null +++ conf/templates/math2/system.template @@ -0,0 +1,123 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<!-- +################################################################################ +# WeBWorK Online Homework Delivery System +# Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader: webwork2/conf/templates/math2/system.template,v 1.1.2.1 2008/06/24 17:17:36 gage Exp $ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. +################################################################################ +--> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta http-equiv="content-type" content="text/html; charset=utf-8" /> +<link rel="stylesheet" type="text/css" href="<!--#url type="webwork" name="htdocs"-->/css/math.css"/> +<title><!--#path style="text" text=" : " textonly="1"--></title> +<!--#head--> +</head> +<body bgcolor="white" onload="if (typeof(initializeAction) == 'function') {initializeAction()}"> + +<div id="masthead"> + <div id="loginstatus"> + <!--#loginstatus--> + <!--#if can="nav"--> + <div id="Nav"> + <!--#nav style="images" imageprefix="/webwork2_files/images/nav" imagesuffix=".gif" separator=" "--> + </div> + <!--#endif--> + + </div> + <div id="logo"> + <img src="<!--#url type="webwork" name="htdocs"-->/images/webwork_rectangle.png" alt="WeBWorK" height="51" width="267" /> + </div> +</div> +<hr class="for-broken-browsers"/> +<div id="big-wrapper" > + <div id="breadcrumbs"> + <!--#path style="text" text=" → "--> + </div> + <div id="content" > + + <!--#if can="title"--> + <span style="font-size:larger; color:#00F; float:left; width:60%; "><!--#title--></span> + <!--#endif--> + <!--#if can="message"--> + <span class="Message" style=" float:right; width:40%; right:0;"> + <!--#message--> + </span> + <!--#endif--> + + <hr style="clear:both"/> + <!--#if can="info"--> + <!-- styles could be different for different pages so they are not set here --> + <!--#info--> + <!--#endif--> + <!--#if can="body"--> + <!--#if warnings="1"--> + <div class="Body" style="background-color:#ffcccc"> + <p style="font-size:larger"> + Warning -- there may be something wrong with this question. Please inform your instructor + including the warning messages below. + </p> + <!--#else--> + <div class="Body" style="background-color:#ffffff"> + <!--#endif--> + + <!--#body--> + </div> + <!--#endif--> + + <!--#if warnings="1"--> + + <hr/> + <div class="Warnings"> + <!--#warnings--> + </div> + <!--#endif--> + + <!--#if can="message"--> + <div class="Message"> + <!--#message--> + </div> + <!--#endif--> + + + <hr class="for-broken-browsers"/> + <div id="footer"> + <p id="last-modified">Page generated at <!--#timestamp--></p> + <div id="copyright"> + WeBWorK © 2000-2007 <a href="http://openwebwork.sf.net/">The WeBWorK Project</a> + </div> + </div> + <div id="site-navigation"> + <!--#if can="links"--> + <div class="info-box" id="fisheye"> + <h2>Main Menu</h2> + <!--#links--> + </div> + <!--#endif--> + <!--#if can="siblings"--> + <!--#siblings--> + <!--#endif--> + <!--#if can="options"--> + <div class="info-box" id="fisheye"> + <h2>Display Options</h2> + <!--#options--> + </div> + <!--#endif--> + </div> + +</div><!--content--> +</div> <!-- big-wrapper --> + +</body> +</html> |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 17:33:37
|
Update of /webwork/cvs/system/webwork2/conf/templates/math2 In directory devel.webwork.rochester.edu:/tmp/cvs-serv36214/math2 Log Message: Directory /webwork/cvs/system/webwork2/conf/templates/math2 added to the repository --> Using per-directory sticky tag `rel-2-4-patches' |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 17:32:09
|
Log Message: ----------- updated version of template Modified Files: -------------- webwork2/conf/templates/math: system.template Revision Data ------------- Index: system.template =================================================================== RCS file: /webwork/cvs/system/webwork2/conf/templates/math/system.template,v retrieving revision 1.7 retrieving revision 1.8 diff -Lconf/templates/math/system.template -Lconf/templates/math/system.template -u -r1.7 -r1.8 --- conf/templates/math/system.template +++ conf/templates/math/system.template @@ -24,55 +24,61 @@ <title><!--#path style="text" text=" : " textonly="1"--></title> <!--#head--> </head> -<body bgcolor="white"> +<body bgcolor="white" onload="if (typeof(initializeAction) == 'function') {initializeAction()}"> <div id="masthead"> <div id="loginstatus"> <!--#loginstatus--> + <!--#if can="nav"--> + <div id="Nav"> + <!--#nav style="images" imageprefix="/webwork2_files/images/nav" imagesuffix=".gif" separator=" "--> + </div> + <!--#endif--> + </div> <div id="logo"> <img src="<!--#url type="webwork" name="htdocs"-->/images/webwork_rectangle.png" alt="WeBWorK" height="51" width="267" /> </div> </div> <hr class="for-broken-browsers"/> -<div id="big-wrapper"> +<div id="big-wrapper" > <div id="breadcrumbs"> <!--#path style="text" text=" → "--> </div> - <div id="content"> - - <!--#if can="info"--> - <!--<div id="page-info">--> - <!--<div class="info-box" id="fisheye">--> - <!--#info--> - <!--</div>--> - <!--</div>--> - <!--#endif--> - - <!--#if can="nav"--> - <div class="Nav"> - <!--#nav style="images" imageprefix="/webwork2_files/images/nav" imagesuffix=".gif" separator=" "--> - </div> - <!--#endif--> - - <!--#if can="title"--> - <h1><!--#title--></h1> - <!--#endif--> - - <!--#if can="message"--> - <div class="Message"> - <!--#message--> - </div> - <!--#endif--> + <div id="content" > - <!--#if can="body"--> - <div class="Body"> - <!--#body--> - </div> - <!--#endif--> + <!--#if can="title"--> + <span style="font-size:larger; color:#00F; float:left; width:60%; "><!--#title--></span> + <!--#endif--> + <!--#if can="message"--> + <span class="Message" style=" float:right; width:40%; right:0;"> + <!--#message--> + </span> + <!--#endif--> + + <hr style="clear:both"/> + <!--#if can="info"--> + <!-- styles could be different for different pages so they are not set here --> + <!--#info--> + <!--#endif--> + <!--#if can="body"--> + <!--#if warnings="1"--> + <div class="Body" style="background-color:#ffcccc"> + <p style="font-size:larger"> + Warning -- there may be something wrong with this question. Please inform your instructor + including the warning messages below. + </p> + <!--#else--> + <div class="Body" style="background-color:#ffffff"> + <!--#endif--> + + <!--#body--> + </div> + <!--#endif--> <!--#if warnings="1"--> - <hr> + + <hr/> <div class="Warnings"> <!--#warnings--> </div> @@ -84,7 +90,7 @@ </div> <!--#endif--> - </div> <!-- content --> + <hr class="for-broken-browsers"/> <div id="footer"> <p id="last-modified">Page generated at <!--#timestamp--></p> @@ -109,6 +115,8 @@ </div> <!--#endif--> </div> + +</div><!--content--> </div> <!-- big-wrapper --> </body> |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 17:26:23
|
Log Message: ----------- Adding math.css in conf/templates directory. I'll link to this from webwork2/htdocs This keeps the math.css and the math.templates files together Tags: ---- rel-2-4-patches Added Files: ----------- webwork2/conf/templates/math: math.css Revision Data ------------- --- /dev/null +++ conf/templates/math/math.css @@ -0,0 +1,504 @@ +/* WeBWorK Online Homework Delivery System + * Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ + * $CVSHeader: webwork2/conf/templates/math/math.css,v 1.1.2.1 2008/06/24 17:09:07 gage Exp $ + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of either: (a) the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any later + * version, or (b) the "Artistic License" which comes with this package. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the + * Artistic License for more details. + */ + +/* --- Standard elements ---------------------------------------------------- */ + +body { + background: white; + color: black; + margin: .5em .5em 0 .5em; /* MSIE ignores bottom margin; Gecko doesn't */ + padding: 0; + font-family: Times, serif; + min-width: 25em; +} + +h1, h2, h3, h4, h5, h6 { + font-family: "Trebuchet MS", "Arial", "Helvetica", sans-serif; + /* FIXME "You have no background-color with your color" */ + color: #225; + background: transparent; +} +h1 { font-size: 170%; } +h2 { font-size: 140%; padding-bottom: 0; margin-bottom: .5ex } +h3 { font-size: 120%; } +h4 { font-size: 110%; } +h5 { font-size: 105%; } +h6 { font-size: 105%; } + +a:link { color: #00e; background-color: inherit; } +a:visited { color: #808; background-color: inherit; } + +/* --- Miscellaneous classes ---------------------------------------------- */ + +/* show only to CSS-ignorant browsers */ +.for-broken-browsers { display: none } + +/* for hiding floats from Netscape 4.x */ +.float-left { float: left; } +.float-right { float: right; } + +/* --- Compound titles (class) ---------------------------------------------- */ + +/* WeBWorK is not using this, but it might be nice to have it around later */ + +/* "Split" title, with main heading left-aligned above a horizontal line, + * and subheading right-aligned below the line. Usage: + * + * <h1 class="compound">Alumni Newsletter</h1> + * <h2 class="compound">Spring '00</h2> + */ + +/*h1.compound { + border-bottom: 1px solid #559; + text-align: left; + padding: .5ex 0 0 0; + margin: 0; +} +h2.compound { float: right; margin: 0; padding: 0 }*/ + +/* --- Info box (class) ----------------------------------------------------- */ + +/* FIXME as a quick hack, the info() escape outputs a DIV with this class. + * don't let the placement of these styles fool you -- <div style="info-box"> + * is output by WeBWorK! */ + +/* Common style for a small box to hold supplemental info; typically this + * box will appear in a sidebar. Sample usage: + * + * <div class="info-box"> + * <h2>Announcements</h2> + * <ul> + * <li>foo</li> + * </ul> + * <a class="more" href="bar">Older announcements...</a> + * </div> + */ + +.info-box { + border: 1px solid #559; + /* FIXME: these aren't valid CSS, but they sure look nice :-P */ + border-radius-topright: 1.5ex; border-radius-topleft: 1.5ex; + -moz-border-radius-topright: 1.5ex; -moz-border-radius-topleft: 1.5ex; + margin-bottom: 1ex; + margin-top: 0; + overflow: hidden; +} +.info-box h2, +.info-box h3, +.info-box h4, +.info-box h5, +.info-box h6 { + /* FIXME: these aren't valid CSS, but they sure look nice :-P */ + border-radius-topright: 1.5ex; border-radius-topleft: 1.5ex; + -moz-border-radius-topright: 1.5ex; -moz-border-radius-topleft: 1.5ex; + border-bottom: 1px solid #559; + font-size: 100%; + text-align: center; + background: #88d; + color: white; + margin: 0; + padding: 0 .5em 0 .5em; +} +.info-box h2 a, +.info-box h3 a, +.info-box h4 a, +.info-box h5 a, +.info-box h6 a { + color: #fff; + background: inherit; +} +.info-box ul, +.info-box ol { + margin: 1ex .5em 1ex 0; + padding-left: 3.5em; + font-size: 80%; +} +.info-box dl { + margin: 1ex .5em 1ex 1ex; + padding: 0; + font-size: 80%; +} +.info-box li, +.info-box dt { + margin: 0 0 .5ex 0; + padding: 0; + line-height: 2.2ex; +} +.info-box dt { font-weight: bold } +.info-box dd { + margin: 0 0 .5ex 1em; + padding: 0; + line-height: 2.2ex; +} +.info-box dd p { + margin-top: 0; +} +.info-box a.more { + float: right; + font-size: 80%; + font-style: italic; + margin-bottom: 1ex; + margin-right: .5em; +} + +.Message { +background-color:#ddd; +} +/* --- Fisheye view (id) ---------------------------------------------------- */ + +/* The "fisheye" view: a hierarchical view of the website to show the + * user where they are in the document hierarchy. Provides more "lateral" + * information than breadcrumbs, but not as much as a full sitemap. To + * appear within the #site-navigation div. Inherits many of its attributes + * from class info-box, and overrides some. + */ + +#mini-sitemap, +#fisheye { + font-family: "Trebuchet MS", "Arial", "Helvetica", sans-serif; + padding: 0 0 1ex 0; +} +#mini-sitemap a, +#fisheye a { + text-decoration: none; +} +#mini-sitemap a:hover, +#fisheye a:hover { + text-decoration: underline; +} +#mini-sitemap li, +#fisheye li { + line-height: 2.5ex; + margin: 0; +} +#mini-sitemap ul, +#fisheye ul { + font-size: 90%; + list-style-type: none; + margin: 0 .1em .3ex .3em; + padding: 0; +} +#mini-sitemap ul ul, +#fisheye ul ul { + font-size: 90%; + margin-left: 0; +} +#mini-sitemap ul li, +#fisheye ul li { + font-weight: bold; +} +#mini-sitemap ul ul ul, +#fisheye ul ul ul { + font-size: 95%; + margin-left: .3em; + padding-left: .5em; + border-left: 1px dotted gray; +} +#mini-sitemap ul ul li a.active, +#fisheye ul ul li a.active { + font-weight: bold; + color: black; + background-color: inherit; +} +#mini-sitemap ul ul ul li, +#fisheye ul ul ul li { + font-weight: normal; +} +#mini-sitemap ul ul ul ul, +#fisheye ul ul ul ul { + font-size: 90%; +} +#mini-sitemap ul ul ul ul ul, +#fisheye ul ul ul ul ul { + font-size: 90%; +} + +/* --- Common layout elements for documents using templates ----------------- */ + +/* The "masthead" of our document that tells users what site they're on. + * It contains a logo-ish title and some basic site navigation. The + * masthead should appear at the top of the page, but we're not positioning + * it absolutely because we can't know its height in advance. Therefore this + * element should be placed at the very top of the <body> of our HTML document. + */ +#masthead { + font-family: "Trebuchet MS", "Arial", "Helvetica", sans-serif; + font-size: 100%; + margin: 0; + padding: 0; + color: #fff; + border: 1px solid #000; + background-color: #038; + /* [ww] we could have some sort of spider web image here. */ + /*background-image: url("/images/mandel-wide.jpg");*/ + background-repeat: repeat-x; + background-position: top left; +} +#masthead a { + /* FIXME "You have no background-color with your color" */ + color: #fff; + background: transparent; +} +/* [ww] since this is a logo and not text, we need borders that are the same + * width all the way around. after we find a nice background image, we can + * turn these back on. */ +/*#masthead #logo { padding: .5ex .2em .1ex .5em }*/ +#masthead #logo { padding: .5ex } +/* [ww] don't need these -- logo itself an image */ +/*#masthead #logo h1 { + background-image: none; + background-color: transparent; + font-size: 100%; + font-weight: normal; + padding: 0; + margin: 0; + white-space: nowrap; + line-height: 1.9ex; +}*/ +/*#masthead #logo h2 { + background-color: transparent; + background-image: none; + font-weight: bold; + font-size: 210%; + line-height: 1.9ex; + margin: 0; + padding: 0; +}*/ +/* [ww] instead of a search form, we want the loginstatus there */ +/*#masthead form {*/ +#masthead #loginstatus { + float: right; + padding: 0; + margin: 1ex .5em .1ex .1em; + font-size: smaller; +} +#masthead #loginstatus #Nav { + padding: 1ex; +} + +/* "big-wrapper" contains everything other than the masthead. It's merely + * a relatively positioned div that allows us to use absolute positioning + * on elements within it -- and because it's relatively positioned, + * absolutely positioned objects *stay* within it. + */ +#big-wrapper { + position: relative; + top: 1ex; + width: 100%; + min-width: 18em; + margin: 0; + border: 0; +} + +/* + * A simple list of "breadcrumbs" showing a path of links from the root of + * the site's hierarchy to our present location. We are not positioning + * this element absolutely, because we don't know in advance how tall it + * will be, and we might want to place content under it. So when coding + * our HTML document, we'll probably want to include this element right + * before the main content. + */ + +#breadcrumbs { + margin-left: 10.4em; + margin-right: 0; + padding: 0 .4em; + border: 1px solid #559; + background: #88d; + color: #fff; + text-align: left; + font-size: 100%; + font-family: "Trebuchet MS", "Arial", sans-serif; +} +#breadcrumbs a { + font-size: 100%; + white-space: nowrap; + background-color: inherit; + color: #fff; + text-decoration: none; +} +#breadcrumbs a.active { font-weight: bold; } +#breadcrumbs a:hover { text-decoration: underline; } + + +/* For the more CSS-compliant browsers, we'd like to provide site-wide + * navigation links (e.g., a mini site map) to appear in a column along + * the left side of the page, just below the masthead. This column is + * absolutely positioned, so that ideally we should be able to include its + * contents anywhere within the body of our HTML documents. However, we + * probably want to include this data at the END of our documents -- after + * the main content -- so that it doesn't interfere with document flow in + * browsers that don't understand CSS (e.g., lynx) -- or in browsers for + * which we've disabled CSS via some hack (e.g. Netscape Navigator 4.x). + * + * We consider this meta-information to be non-essential; it is NOT part of + * the content, and may not be displayed in some circumstances. + */ +#site-navigation { + position: absolute; + left: 0; + top: 0; + margin: 0; + padding: 0; + width: 9.8em; +} + +/* The primary information content of the document, excluding masthead and + * site navigation. We want to leave a wide left margin to prevent overlap + * with our site map, which will be displayed on the left-hand side of the + * screen. + */ +#content { + margin: .5em 0 0 10.4em; + padding: 0 0 0 0; + font-family: "Times", serif; + /* border-left: 1px dotted #bbf; */ +} +#content h1 { margin: .4ex 0; } /* for crappy MSIE */ + + +#footer { + /* white-space: nowrap; */ + clear: both; + /* border-top: 1px solid #559; */ + margin: 0 .5em .2ex 10.4em; + padding: 0; + font-family: "Trebuchet MS", "Arial", "Helvetica", sans-serif; +} +#copyright { font-size: 75%; margin: 0;} +#last-modified { + clear: both; + font-family: "Trebuchet MS", "Arial", "Helvetica", sans-serif; + font-size: 75%; + background-color: inherit; + color: #444; + margin: 1ex 0 0 0; + padding: 0; + border-bottom: 1px solid #559; +} + +/* --- WeBWorK classes ------------------------------------------------------ */ + +/* These classes are emitted by WeBWorK code and should appear in ANY WeBWorK + * template. they need not be implemented the same way in each template though. + * (These are mostly copied from ur.css right atm.) + */ + +/* the info escape emits a DIV with this id. (note that the same DIV has class + * "info-box" which is given above in the "template styles" section. Regardless, + * it is emitted by WW code in ProblemSet.pl (not in system.template) ! */ +#InfoPanel { + font-size: smaller; + float: right; + width: 40%; + overflow: auto; + margin-right: -1px; + background-color: #fff; +} + +/* tables used for laying out form fields shouldn't have a border */ +table.FormLayout { border: 0; } +table.FormLayout tr { vertical-align: top; } +table.FormLayout th.LeftHeader { text-align: right; white-space: nowrap; } +table.FormLayout tr.ButtonRow { text-align: left; } +table.FormLayout tr.ButtonRowCenter { text-align: center; } + +/* for problems which are rendered by themselves, e.g., by Set Maker */ +div.RenderSolo { background-color: #E0E0E0; color: black; } +div.AuthorComment { background-color: #00E0E0; color: black; } + +/* minimal style for lists of links (generated by the links escape) */ +/*ul.LinksMenu { list-style: none; margin-left: 0; padding-left: 0; }*/ +/*ul.LinksMenu ul { list-style: none; margin-left: 0.5em; padding-left: 0; }*/ + +/* background styles for success and failure messages */ +div.WarningMessage { background-color: #ffcccc; padding: 3px 3px 3px 3px; } +div.ResultsWithoutError { color: inherit; background-color: #8F8; } /* green */ +div.ResultsWithError { color: #C33; background-color: inherit; } /* red */ +div.ResultsAlert { color: #F60; background-color: inherit; } /* orange */ + +/* styles used by WeBWorK::HTML::ScrollingRecordList */ +div.ScrollingRecordList { padding: 1em; white-space: nowrap; border: thin solid gray; } +div.ScrollingRecordList select.ScrollingRecordList { width: 99%; } + +/* wraps the View Options form (generated by &optionsMacro) */ +/* FIXME: can't this style information just go in div.Options above? */ +div.viewOptions { font-size: small } + +/* messages, attempt results, answer previews, etc. go in this DIV */ +/* this used to be "float:left", but that was suspected of causing MSIE peekaboo bug */ +div.problemHeader {} + +/* styles for the attemptResults table */ +table.attemptResults { + border-style: outset; + border-width: 1px; + margin: 0px 10pt; + border-spacing: 1px; +} +table.attemptResults td, +table.attemptResults th { + border-style: inset; + border-width: 1px; + text-align: center; + /*width: 15ex;*/ /* this was erroniously commented out with "#" */ + padding: 2px 5px 2px 5px; + color: inherit; + background-color: #DDDDDD; +} +/* override above settings in tables used to display ans_array results */ +table.attemptResults td td, +table.attemptResults td th, +table.ArrayLayout td { + border-style: none; + border-width: 0px; + padding: 0px; +} +table.attemptResults td.Message { + text-align: left; + padding: 2px 5px 2px 5px; + width: auto; +} +.attemptResultsSummary { font-style: italic; } +.parsehilight { color: inherit; background-color: yellow; } + +/* the problem TEXT itself does in this box */ +/* we used to make this a grey box, but surprise, MSIE is bug-ridden. */ +div.problem { } + +/* jsMath emits this class when appropriate math fonts aren't available */ +div.NoFontMessage { + padding: 10px; + border-style: solid; + border-width: 3px; + border-color: #DD0000; + color: inherit; + background-color: #FFF8F8; + width: 75%; + text-align: left; + margin: 10px auto 10px 12%; +} + +/* text colors for published and unpublished sets */ +font.Published { font-style: normal; font-weight: normal; color: #000000; background-color: inherit; } /* black */ +font.Unpublished { font-style: italic; font-weight: normal; color: #aaaaaa; background-color: inherit; } /* light grey */ + +/* styles used when editing a temporary file */ +.temporaryFile { font-style: italic; color: #F60; background-color: inherit; } + +/* text colors for Auditing, Current, and Dropped students */ +.Audit { font-style: normal; color: purple; background-color: inherit; } +.Enrolled { font-weight: normal; color: black; background-color: inherit; } +.Drop { font-style: italic; color: gray; background-color: inherit; } |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 17:22:39
|
Log Message: ----------- Adding macros to support live.jar Tags: ---- rel-2-4-patches Added Files: ----------- pg/macros: LiveGraphics3D.pl Revision Data ------------- --- /dev/null +++ macros/LiveGraphics3D.pl @@ -0,0 +1,190 @@ +sub _LiveGraphics3D_init {}; # don't reload this file + +########################################################################### +# +# Macros for handling interactive 3D graphics via the LiveGraphics3D +# Java applet. The applet needs to be in the course html directory. +# (If it is in the system html area, you will need to change the +# default below or supply the jar option explicitly). +# +# The LiveGraphics3D applet displays a mathematica Graphics3D object +# that is stored in a .m file (or a compressed one). Use Mathematica +# to create one. (In the future, I plan to write a perl class that +# will create these for you on the fly. -- DPVC) +# +# The main routines are +# +# Live3Dfile load a data file +# Live3Ddata load raw Graphics3D data +# LiveGraphics3D access to all parameters +# + +# +# LiveGraphics3D(options) +# +# Options are from: +# +# file => name name of .m file to load +# +# archive => name name of a .zip file to load +# +# input => 3Ddata string containing Graphics3D data to +# be displayed by the applet +# +# size => [w,h] width and height of applet +# +# vars => [vars] hash of variables to pass as independent +# variables to the applet, togther with +# their initial values +# e.g., vars => [a=>1,b=>1] +# +# depend => [list] list of dependent variables to pass to +# the applet with their replacement strings +# (see LiveGraphics3D documentation) +# +# jar => URL where to find the live.jar file +# +# background=>"#RRGGBB" the background color to use (default is white) +# +# scale => n scaling factor for applet (default is 1.) +# +# image => file a file containing an image to use in TeX mode +# or when Java is disabled +# +# tex_size => ratio a scaling factor for the TeX image (as a portion +# of the line width). +# 1000 is 100%, 500 is 50%, etc. +# +# tex_center => 0 or 1 center the image in TeX mode or not +# +# Live3D => [params] hash of additional parameters to pass to +# the Live3D applet. +# e.g. Live3D => [VISIBLE_FACES => "FRONT"] +# + +sub LiveGraphics3D { + my %options = ( + size => [250,250], + jar => findAppletCodebase("live.jar")."/live.jar", + background => "#FFFFFF", + scale => 1., + tex_size => 500, + tex_cener => 0, + @_ + ); + my $out = ""; my $p; my %pval; + my $ratio = $options{tex_size} * (.001); + + if ($main::displayMode eq "TeX") { + # + # In TeX mode, include the image, if there is one, or + # else give the user a message about using it on line + # + if ($options{image}) { + $out = "\\includegraphics[width=$ratio\\linewidth]{$options{image}}"; + $out = "\\centerline{$out}" if $options{tex_center}; + $out .= "\n"; + } else { + $out = "\\vbox{ + \\hbox{[ This image is created by} + \\hbox{\\quad an interactive applet;} + \\hbox{you must view it on line ]} + }"; + } + } else { + my ($w,$h) = @{$options{size}}; + $out .= $bHTML if ($main::displayMode eq "Latex2HTML"); + # + # Put the applet in a table + # + $out .= qq{\n<TABLE BORDER="1" CELLSPACING="2" CELLPADDING="0">\n<TR>}; + $out .= qq{<TD WIDTH="$w" HEIGHT="$h" ALIGN="CENTER">}; + # + # start the applet + # + $out .= qq{ + <APPLET ARCHIVE="$options{jar}" CODE="Live.class" WIDTH="$w" HEIGHT="$h"> + <PARAM NAME="BGCOLOR" VALUE="$options{background}"> + <PARAM NAME="MAGNIFICATION" VALUE="$options{scale}"> + }; + # + # include the file or data + # + $out .= qq{<PARAM NAME="INPUT_ARCHIVE" VALUE="$options{archive}">\n} + if ($options{archive}); + $out .= qq{<PARAM NAME="INPUT_FILE" VALUE="$options{file}">\n} + if ($options{file}); + $out .= qq{<PARAM NAME="INPUT" VALUE="$options{input}">\n} + if ($options{input}); + # + # include any independent variables + # + if ($options{vars}) { + my @vars = (); %pval = @{$options{vars}}; + foreach $p (lex_sort(keys(%pval))) {push(@vars,"${p}->$pval{$p}");} + $out .= + '<PARAM NAME="INDEPENDENT_VARIABLES" VALUE="{'.join(',',@vars).'}">'; + $out .= "\n"; + } + # + # include dependent variables + # + if ($options{depend}) { + my @depend = (); $pval = @{$options{depend}}; + foreach $p (lex_sort(keys(%pval))) {push(@depend,"${p}->$pval{$p}");} + $out .= + '<PARAM NAME="DEPENDENT_VARIABLES" VALUE="{'.join(',',@depend).'}">'; + $out .= "\n"; + } + # + # include any extra Live3D parameters + # + if ($options{Live3D}) { + my %pval = @{$options{Live3D}}; + foreach $p (lex_sort(keys(%pval))) { + $out .= qq{<PARAM NAME="$p" VALUE="$pval{$p}">\n}; + } + } + # + # End the applet and table + # + $out .= qq{<IMG SRC="$options{image}" BORDER="0">} if ($options{image}); + $out .= "<SMALL>[Enable Java to make this image interactive]</SMALL><BR>"; + $out .= "</APPLET>"; + $out .= "</TD></TD>\n</TABLE>\n"; + $out .= $eHTML if ($main::displayMode eq "Latex2HTML"); + } + + return $out; +} + +# +# Syntactic sugar to make it easier to pass files and data to +# LiveGraphics3D. +# +sub Live3Dfile { + my $file = shift; + LiveGraphics3D(file => $file, @_); +} + +# +# Syntactic sugar to make it easier to pass raw Graohics3D data +# to LiveGraphics3D. +# +sub Live3Ddata { + my $data = shift; + LiveGraphics3D(input => $data, @_); +} + + +# +# A message you can use for a caption under a graph +# +$LIVEMESSAGE = MODES( + TeX => '', + Latex2HTML => + $BCENTER.$BSMALL."Drag the surface to rotate it".$ESMALL.$ECENTER, + HTML => $BCENTER.$BSMALL."Drag the surface to rotate it".$ESMALL.$ECENTER +); + +1; |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 16:25:48
|
Log Message: ----------- Corrective updates to rel-2-4-patches Tags: ---- rel-2-4-patches Modified Files: -------------- webwork2: README webwork2/bin: NPL-update remove_stale_images webwork2/conf: database.conf.dist global.conf.dist webwork.apache-config.dist webwork2/conf/snippets: blankProblem2.pg webwork2/doc: Copying webwork2/htdocs/helpFiles: InstructorUserList.html webwork2/htdocs/jsMath/test: index-images.html webwork2/lib: WeBWorK.pm webwork2/lib/WeBWorK: Constants.pm ContentGenerator.pm Form.pm PG.pm Request.pm Utils.pm webwork2/lib/WeBWorK/ContentGenerator: CourseAdmin.pm Feedback.pm Hardcopy.pm Problem.pm ProblemSet.pm webwork2/lib/WeBWorK/ContentGenerator/Instructor: AddUsers.pm Config.pm ProblemSetList.pm SendMail.pm SetMaker.pm Stats.pm webwork2/lib/WeBWorK/DB/Driver: SQL.pm webwork2/lib/WeBWorK/DB/Record: SetLocations.pm webwork2/lib/WeBWorK/File: Classlist.pm webwork2/lib/WeBWorK/PG: Local.pm webwork2/lib/WeBWorK/Utils: CourseManagement.pm DelayedMailer.pm RestrictedClosureClass.pm Tasks.pm webwork2/lib/WeBWorK/Utils/CourseManagement: sql_single.pm Revision Data ------------- Index: Stats.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm,v retrieving revision 1.67.4.1 retrieving revision 1.67.4.1.2.1 diff -Llib/WeBWorK/ContentGenerator/Instructor/Stats.pm -Llib/WeBWorK/ContentGenerator/Instructor/Stats.pm -u -r1.67.4.1 -r1.67.4.1.2.1 --- lib/WeBWorK/ContentGenerator/Instructor/Stats.pm +++ lib/WeBWorK/ContentGenerator/Instructor/Stats.pm @@ -337,6 +337,7 @@ # DBFIXME use an iterator my @problemRecords = sort {$a->problem_id <=> $b->problem_id } $db->getAllUserProblems( $student, $setName ); debug("End obtaining problem records for user $student set $setName"); + my $num_of_problems = @problemRecords; $max_num_problems = ($max_num_problems>= $num_of_problems) ? $max_num_problems : $num_of_problems; ######################################## Index: SendMail.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/SendMail.pm,v retrieving revision 1.63.2.1 retrieving revision 1.63.2.1.2.1 diff -Llib/WeBWorK/ContentGenerator/Instructor/SendMail.pm -Llib/WeBWorK/ContentGenerator/Instructor/SendMail.pm -u -r1.63.2.1 -r1.63.2.1.2.1 --- lib/WeBWorK/ContentGenerator/Instructor/SendMail.pm +++ lib/WeBWorK/ContentGenerator/Instructor/SendMail.pm @@ -496,6 +496,11 @@ my $recipients = join(" ",@{$self->{ra_send_to} }); my $errorMessage = defined($self->{submit_message}) ? CGI::i($self->{submit_message} ) : '' ; + + # Format message keeping the preview_header lined up + $errorMessage = wrap("","",$errorMessage); + $msg = wrap("","",$msg); + $msg = join("", $errorMessage, $preview_header, @@ -506,7 +511,8 @@ $msg , "\n" ); - return join("", '<pre>',wrap("","",$msg),"\n","\n", +# return join("", '<pre>',wrap("","",$msg),"\n","\n", + return join("", '<pre>',$msg,"\n","\n", '</pre>', CGI::p('Use browser back button to return from preview mode'), CGI::h3('Emails to be sent to the following:'), @@ -633,7 +639,7 @@ -labels=>{all_students=>'All students in course',studentID => 'Selected students'}, -default=>'studentID', -linebreak=>0), CGI::br(),$scrolling_user_list, - CGI::i("Preview set to: "), $preview_record->last_name, + CGI::i("Preview set to: "), $preview_record->last_name,'(', $preview_record->user_id,')', CGI::submit(-name=>'action', -value=>'preview',-label=>'Preview message'),' ', ), ); # end Tr @@ -933,7 +939,7 @@ if ($for_preview) { my @preview_COL = @COL; shift @preview_COL; ## shift back for preview - my $preview_header = CGI::pre({},data_format(1..($#COL)),"<br>", data_format2(@preview_COL)). + my $preview_header = CGI::p('',data_format(1..($#COL)),"<br>", data_format2(@preview_COL)). CGI::h3( "This sample mail would be sent to $EMAIL"); return $msg, $preview_header; } else { Index: SetMaker.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm,v retrieving revision 1.77.2.4 retrieving revision 1.77.2.4.2.1 diff -Llib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm -Llib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm -u -r1.77.2.4 -r1.77.2.4.2.1 --- lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm +++ lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm @@ -747,7 +747,7 @@ } $libs = CGI::br()."or Problems from".$libs if $libs ne ''; - my $these_widths = "width: 23ex"; + my $these_widths = "width: 25ex"; if($have_local_sets ==0) { $list_of_local_sets = [NO_LOCAL_SET_STRING]; @@ -786,7 +786,7 @@ print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"center"}, "Browse ", - CGI::submit(-name=>"browse_library", -value=>"Problem Library", -style=>$these_widths, @dis1), + CGI::submit(-name=>"browse_library", -value=>"National Problem Library", -style=>$these_widths, @dis1), CGI::submit(-name=>"browse_local", -value=>"Local Problems", -style=>$these_widths, @dis2), CGI::submit(-name=>"browse_mysets", -value=>"From This Course", -style=>$these_widths, @dis3), CGI::submit(-name=>"browse_setdefs", -value=>"Set Definition Files", -style=>$these_widths, @dis4), @@ -981,7 +981,7 @@ ############# Default of which problem selector to display - my $browse_which = $r->param('browse_which') || 'browse_local'; + my $browse_which = $r->param('browse_which') || 'browse_library'; @@ -1373,7 +1373,9 @@ } if (scalar(@pg_files)>0) { print CGI::p(($first_shown+1)."-".($last_shown+1)." of ".scalar(@pg_files). - " shown.", $prev_button, " ", $next_button); + " shown.", $prev_button, " ", $next_button, + CGI::submit(-name=>"update", -style=>"width:15ex; font-weight:bold", + -value=>"Update Set")); } # } print CGI::endform(), "\n"; Index: Config.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Config.pm,v retrieving revision 1.9.6.1 retrieving revision 1.9.6.1.2.1 diff -Llib/WeBWorK/ContentGenerator/Instructor/Config.pm -Llib/WeBWorK/ContentGenerator/Instructor/Config.pm -u -r1.9.6.1 -r1.9.6.1.2.1 --- lib/WeBWorK/ContentGenerator/Instructor/Config.pm +++ lib/WeBWorK/ContentGenerator/Instructor/Config.pm @@ -123,7 +123,7 @@ my $displayoldval = $self->comparison_value($oldval); return '' if($displayoldval eq $newval); # Remove quotes from the string, we will have a new type for text with quotes - $newval =~ s/['"`]//g; + $newval =~ s/['"`]//g; #`"'geditsucks return('$'. $varname . " = '$newval';\n"); } @@ -137,7 +137,7 @@ my $newval = $self->convert_newval_source($newvalsource); my $displayoldval = $self->comparison_value($oldval); # Remove quotes from the string, we will have a new type for text with quotes - $newval =~ s/['"`]//g; + $newval =~ s/['"`]//g; #`"'geditsucks my $newval2 = eval($newval); if($@) { $self->{Module}->addbadmessage("Syntax error in numeric value '$newval' for variable \$$self->{var}. Reverting to the system default value."); @@ -256,7 +256,7 @@ return '' if($newval eq $oldval); # ok we really have a new value, now turn it back into a string my @parts = split ',', $newval; - map { $_ =~ s/['"`]//g } @parts; + map { $_ =~ s/['"`]//g } @parts; #`"'geditsucks @parts = map { "'". $_ ."'" } @parts; $str = join(',', @parts); $str = '$'. $varname . " = [$str];\n"; @@ -482,17 +482,20 @@ my $ce = $r->ce; # Get a course environment without course.conf - $self->{default_ce} = WeBWorK::CourseEnvironment->new( - { webwork_dir => $ce->{webworkDirs}->{root} }); + $self->{default_ce} = WeBWorK::CourseEnvironment->new({ + %WeBWorK::SeedCE, + }); $self->{ce_file_dir} = $ce->{courseDirs}->{root}; # Get a copy of the course environment which does not have simple.conf loaded - my $ce3 = eval { WeBWorK::CourseEnvironment->new( - { webwork_dir => $ce->{webworkDirs}->{root}, - courseName => $ce->{courseName}, - web_config_filename => 'noSuchFilePlease', - }) }; + my $ce3 = eval { + new WeBWorK::CourseEnvironment({ + %WeBWorK::SeedCE, + courseName => $ce->{courseName}, + web_config_filename => 'noSuchFilePlease', + }) + }; if($r->param("make_changes")) { my $widget_count = 0; my $fileoutput = "#!perl @@ -571,12 +574,12 @@ my $default_ce = $self->{default_ce}; # Get the current course environment again in case we just saved changes - my $ce4 = eval { WeBWorK::CourseEnvironment->new( - { webwork_dir => $ce->{webworkDirs}->{root}, - webwork_url => $ce->{webwork_url}, - pg_dir => $ce->{pg_dir}, - courseName => $ce->{courseName}, - }) }; + my $ce4 = eval { + new WeBWorK::CourseEnvironment({ + %WeBWorK::SeedCE, + courseName => $ce->{courseName}, + }) + }; my $widget_count = 0; if(scalar(@$ConfigValues) == 0) { Index: ProblemSetList.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm,v retrieving revision 1.101.2.4 retrieving revision 1.101.2.4.2.1 diff -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm -Llib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm -u -r1.101.2.4 -r1.101.2.4.2.1 --- lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm +++ lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm @@ -1733,8 +1733,10 @@ $curr .= $c; } } - ($name, $value, $attemptLimit, $continueFlag) = @line; + ## anything left? + push(@line, $curr) if ( $curr ); + ($name, $value, $attemptLimit, $continueFlag) = @line; ##################### # clean up problem values ########################### Index: AddUsers.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AddUsers.pm,v retrieving revision 1.23.6.1 retrieving revision 1.23.6.1.2.1 diff -Llib/WeBWorK/ContentGenerator/Instructor/AddUsers.pm -Llib/WeBWorK/ContentGenerator/Instructor/AddUsers.pm -u -r1.23.6.1 -r1.23.6.1.2.1 --- lib/WeBWorK/ContentGenerator/Instructor/AddUsers.pm +++ lib/WeBWorK/ContentGenerator/Instructor/AddUsers.pm @@ -28,7 +28,7 @@ use warnings; #use CGI qw(-nosticky ); use WeBWorK::CGI; -use WeBWorK::Utils qw/cryptPassword/; +use WeBWorK::Utils qw/cryptPassword trim_spaces/; sub initialize { my ($self) = @_; @@ -208,12 +208,7 @@ } -## Utility function to trim whitespace off the start and end of its input -sub trim_spaces { - my $in = shift; - $in =~ s/^\s*(.*?)\s*$/$1/; - return($in); -} + 1; Index: SQL.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/DB/Driver/SQL.pm,v retrieving revision 1.14.4.1 retrieving revision 1.14.4.1.2.1 diff -Llib/WeBWorK/DB/Driver/SQL.pm -Llib/WeBWorK/DB/Driver/SQL.pm -u -r1.14.4.1 -r1.14.4.1.2.1 --- lib/WeBWorK/DB/Driver/SQL.pm +++ lib/WeBWorK/DB/Driver/SQL.pm @@ -103,3 +103,4 @@ } 1; + Index: README =================================================================== RCS file: /webwork/cvs/system/webwork2/README,v retrieving revision 1.17.4.3 retrieving revision 1.17.4.3.2.1 diff -LREADME -LREADME -u -r1.17.4.3 -r1.17.4.3.2.1 --- README +++ README @@ -1,156 +1,7 @@ WeBWorK Online Homework Delivery System - Version 2.4.1 + Version 2.4.5 Copyright 2000-2007, The WeBWorK Project All rights reserved. -Details -------- - -Release date: 25-August-2007 -CVS tag: rel-2-4-1 -CVS branch: rel-2-4-dev - -Changes since 2.4.0 -------------------- - -* Fixed a "Duplicate entry" error that occurred when WeBWorK attempted to assign - a set to a user to whom it was already assigned, for example with the "Assign - Set to All Users" button. (Bug #1293) - -* Fixed a problem that occurred when viewing the set details for a set that had - not been assigned to any users. - -* Added the ability to unarchive .tar.gz and .tar files to the File Manager. - -* Worked around an IE bug in the File Manager where pressing return submits a - form but does not set the submit button's value properly in some - circumstances. - -* Fixed a problem where the "over time: closed." status message would appear in - incorrect circumstances in the problem set list. - -* Improved handling of textbook chapters and sections in the NPL-update script. - -* Improved handling in the NPL-update script for problems which are tagged to a - chapter, but not to a particular section in the chapter. - -* Show the numbers for textbook chapters and sections in the Library Browser. - -* Improve speed of browsing the National Problem Library in the Library Browser. - -* Ignore .svn directories when browsing file-based problem libraries in the - Library browser. - -* Extended the set definition file format to support commas in the source_file, - value, and max_attempts fields. Literal commas and backslashes are backslash- - escaped. - -Installation & Upgrade ----------------------- - -Comprehensive installation and upgrade instructions are located at: -http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/InstallationManualV2pt4 - -Read the sections below for specific information about upgrading from various -versions of WeBWorK. - -Upgrading from 2.4.0 --------------------- - -Before beginning, back up your WeBWorK database and course directories. - -To update WeBWorK to exactly 2.4.1, use the following commands: - -cd /opt/webwork/webwork2 -cvs -q up -dP -rrel-2-4-1 - -To update WeBWorK to the "tip" of the 2.4.x branch, which is mostly stable and -includes bug fixes and new features before they are officially released, use the -following commands: - -cd /opt/webwork/webwork2 -cvs -q up -dP -rrel-2-4-dev - -If you are using the National Problem Library, re-run bin/NPL-update to update -the database format to the latest version. - -No database changes occurred between 2.4.0 and 2.4.1, so running bin/wwdb_upgrade -is not necessary. No configuration file changes occurred between - -Upgrading from 2.3.x --------------------- - -Before beginning, back up your WeBWorK database and course directories. - -To update WeBWorK to exactly 2.4.1, use the following commands: - -cd /opt/webwork/webwork2 -cvs -q up -dP -rrel-2-4-1 - -To update WeBWorK to the "tip" of the 2.4.x branch, which is mostly stable and -includes bug fixes and new features before they are officially released, use the -following commands: - -cd /opt/webwork/webwork2 -cvs -q up -dP -rrel-2-4-dev - -Merge changes from global.conf.dist, database.conf.dist, and -webwork.apache-config (if you are using Apache 1) or webwork.apache2-config (if -you are using Apache 2) into your configuration files. - -Run bin/wwdb_upgrade -v to upgrade your database. If you receive errors about -modelCourse it is OK to go on -- modelCourse is not a real course. - -If you are using the National Problem Library, the loadDB2 script in the -database_problems directory has been replaced with a new bin/NPL-update script -in the main webwork2 distribution. The problem library metadata is now stored -within the main webwork database. Run bin/NPL-update to load the problem -metadata into the its new location. It is safe to remove the separate -ProblemLibrary database. - -Upgrading from 2.2.x --------------------- - -Make sure you are using the sql_single database layout for all the courses you -wish to continue to use. After you upgrade, courses using other database -layouts will be inaccessible. Move non-sql_single courses out of your courses -directory. - -The standard directory layout of WeBWorK has changed since 2.2.x. We now suggest -that you place the webwork2 directory, as well as the pg, courses, and -libraries, directories in /opt/webwork rather than in /opt. - -To update WeBWorK to exactly 2.4.1, use the following commands: - -cd /opt/webwork/webwork2 -cvs -q up -dP -rrel-2-4-1 - -To update WeBWorK to the "tip" of the 2.4.x branch, which is mostly stable and -includes bug fixes and new features before they are officially released, use the -following commands: - -cd /opt/webwork/webwork2 -cvs -q up -dP -rrel-2-4-dev - -Merge changes from global.conf.dist, database.conf.dist, and -webwork.apache-config into your configuration files. - -Run bin/wwdb_check -v to verify that your database is up-to-date for version -2.3.0 (the first version that included automated database upgrades). Then run -bin/wwdb_upgrade -v to upgrade to bring your database up-to-date for version -2.4.1. - -Getting help ------------- - -The best place to get support is in the WeBWorK discussion forums located at: -http://webwork.maa.org/moodle/course/view.php?id=2 - -To report bugs: -http://bugs.webwork.rochester.edu/ - -Lots of WeBWorK documentation: -http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/WeBWorKDocs - Index: remove_stale_images =================================================================== RCS file: /webwork/cvs/system/webwork2/bin/remove_stale_images,v retrieving revision 1.4.4.1 retrieving revision 1.4.4.1.2.1 diff -Lbin/remove_stale_images -Lbin/remove_stale_images -u -r1.4.4.1 -r1.4.4.1.2.1 --- bin/remove_stale_images +++ bin/remove_stale_images @@ -65,6 +65,7 @@ use Getopt::Long; use Pod::Usage; use File::Find; +use DBI; BEGIN { die "WEBWORK_ROOT not found in environment.\n" @@ -87,7 +88,9 @@ my %kept = (); my %days=(); my %week=(); +my %depths=(); my $grandtotal=0; +my $depthConnection; ##### get command-line options ##### @@ -155,6 +158,12 @@ } if($stat[$type]<$start or $stat[$type]>$end) { $kept{$fullmd5} = ''; + if($depthConnection) { # hold dvipng depths + my $fetchdepth = $depthConnection->selectall_arrayref(" + SELECT depth FROM depths WHERE md5=\"$fullmd5\""); + my $fetchdepthval = $fetchdepth->[0]->[0]; + $depths{$fullmd5} = $fetchdepthval if($fetchdepthval); + } } else { my $result = unlink($File::Find::name); if($result) { @@ -211,11 +220,36 @@ my $tmpdir = $ce->{webworkDirs}->{tmp}; my $tmpfile = "$tmpdir/equationcache.tmp"; +# Prepare to handle depths database table +my $alignType = $ce->{pg}->{displayModeOptions}->{images}->{dvipng_align}; +if($alignType eq 'mysql' and $deloption) { + my $dbinfo = $ce->{pg}->{displayModeOptions}->{images}->{dvipng_depth_db}; + $depthConnection = DBI->connect_cached( + $dbinfo->{dbsource}, + $dbinfo->{user}, + $dbinfo->{passwd}, + { PrintError => 0, RaiseError => 1 }, + ); + print "Could not make database connection for dvipng image depths.\n" unless defined $depthConnection; +} + find({wanted => \&wanted, follow_fast => 1}, $dirHead); print "Removed $num_removed images.\n\n" if($deloption); count_report() if($reportoption); + +# For depth database, empty it and insert only values for the images +# we kept. +my $ent; +if($depthConnection) { # clean out database and put back in good values + $depthConnection->do("TRUNCATE depths"); + for my $ent (keys %depths) { + $depthConnection->do("INSERT INTO `depths` VALUES( + \"$ent\", \"$depths{$ent}\")"); + } +} + ## The rest is updating the equation cache if we deleted images and there is a cache exit() unless($deloption and $num_removed); exit() unless ($cachePath); @@ -223,7 +257,6 @@ my ($perms, $uid, $groupID) = (stat $cachePath)[2,4,5]; #Get values from current cache file my $cachevalues = readFile($cachePath); my @cachelines = split "\n", $cachevalues; -my $ent; for $ent (@cachelines) { chomp($ent); my $entmd5 = $ent; @@ -251,4 +284,4 @@ - +1; \ No newline at end of file Index: NPL-update =================================================================== RCS file: /webwork/cvs/system/webwork2/bin/NPL-update,v retrieving revision 1.1.2.5 retrieving revision 1.1.2.5.2.1 diff -Lbin/NPL-update -Lbin/NPL-update -u -r1.1.2.5 -r1.1.2.5.2.1 --- bin/NPL-update +++ bin/NPL-update @@ -18,6 +18,9 @@ use Cwd; use DBI; + #(maximum varchar length is 255 for mysql version < 5.0.3. + #You can increase path length to 4096 for mysql > 5.0.3) + BEGIN { die "WEBWORK_ROOT not found in environment.\n" unless exists $ENV{WEBWORK_ROOT}; @@ -59,7 +62,7 @@ '], ['NPL-path', ' path_id int(15) NOT NULL auto_increment, - path varchar(4096) NOT NULL, + path varchar(255) NOT NULL, machine varchar(127), user varchar(127), KEY (path), @@ -200,7 +203,7 @@ #### First read in textbook information if(open(IN, "$libraryRoot/Textbooks")) { - print "Reading in textbook data.\n"; + print "Reading in textbook data from Textbooks in the library $libraryRoot.\n"; my %textinfo = ( TitleText => '', EditionText =>'', AuthorText=>''); my $bookid = undef; while (my $line = <IN>) { @@ -307,7 +310,9 @@ } close(IN); } else{ - print "Textbooks file was not found. Updating from cvs should fix this problem.\n"; + print "Textbooks file was not found in library $libraryRoot. If the path to the problem library doesn't seem + correct, make modifications in webwork2/conf/global.conf (\$problemLibrary{root}). If that is correct then + updating from cvs should download the Textbooks file.\n"; } print "Converting data from tagged pgfiles into mysql.\n"; Index: webwork.apache-config.dist =================================================================== RCS file: /webwork/cvs/system/webwork2/conf/webwork.apache-config.dist,v retrieving revision 1.16.2.4 retrieving revision 1.16.2.4.2.1 diff -Lconf/webwork.apache-config.dist -Lconf/webwork.apache-config.dist -u -r1.16.2.4 -r1.16.2.4.2.1 --- conf/webwork.apache-config.dist +++ conf/webwork.apache-config.dist @@ -20,8 +20,14 @@ # # Include /path/to/webwork.apache-config # -# Customize the variable $webwork_dir below to match the location of your -# WeBWorK installation. +# Customize the variables below to match your WeBWorK installation. + +# Uncomment the ScriptAliasMatch to allow access to show-source.cgi +# This allows the "show source" button to work for demonstration "courses" +# See for example Davide Cervone's Knoxville lectures on math objects + +#ScriptAliasMatch /webwork2_course_files/([^/]*)/show-source.cgi/(.*) /opt/webwork/courses/$1/html/show-source.cgi/$2 + <Perl> @@ -94,5 +100,87 @@ $Location{$webwork_htdocs_url} = { SetHandler => "none" }; } + +# The following stanzas can be uncommented to enable various experimental +# WeBWorK web services. These are still in testing and have not been audited +# for security. + +# uncomment the line below if you use the XMLRPC, RQP, or SOAP installations below + +$ENV{WEBWORK_ROOT} = $webwork_dir; + +#$PerlConfig .= <<EOF; +# ##### Sam's WeBWorK::Request-based XML-RPC testbed ##### +# # +# #PerlModule WeBWorK::RPC +# #<Location /webwork2_rpc> +# # SetHandler perl-script +# # PerlHandler Apache::XMLRPC::Lite +# # PerlSetVar dispatch_to "WeBWorK::RPC WeBWorK::RPC::CourseManagement" +# #</Location> +# +# ########## XMLRPC installation ########## +# # +# #PerlModule WebworkWebservice +# #<Location /mod_xmlrpc> +# # SetHandler perl-script +# # PerlHandler Apache::XMLRPC::Lite +# # PerlSetVar dispatch_to "WebworkXMLRPC" +# # PerlSetVar options "compress_threshold => 10000" +# # Order Allow,Deny +# # Allow from All +# #</Location> +# +# ########## RQP installation ########## +# # +# #PerlModule RQP +# ##<Location /rqp> +# ## SetHandler perl-script +# ## PerlHandler Apache::SOAP +# ## PerlSetVar dispatch_to "RQP" +# ## PerlSetVar options "compress_threshold => 10000" +# ## Order Allow,Deny +# ## Allow from All +# ##</Location> +# #<Location /rqp> +# # SetHandler perl-script +# # PerlHandler MySOAP +# # Order Allow,Deny +# # Allow from All +# #</Location> +# +# ########## SOAP installation ########## +# # +# #PerlModule WebworkWebservice +# #<Location /mod_soap> +# # SetHandler perl-script +# # PerlHandler Apache::SOAP +# # PerlSetVar dispatch_to "WebworkXMLRPC" +# # PerlSetVar options "compress_threshold => 10000" +# # Order Allow,Deny +# # Allow from All +# #</Location> +# +# PerlModule WebworkSOAP +# #WEBWORK SOAP CONFIGURATION +# <Location /webwork2_rpc> +# PerlHandler Apache::SOAP +# SetHandler perl-script +# PerlSetVar dispatch_to "WebworkSOAP" +# PerlSetVar options "compress_threshold => 10000" +# Order Allow,Deny +# Allow from All +# </Location> +# #WEBWORK SOAP WSDL HANDLER :: TO BE REPLACED WITH A FILE FOR PRODUCTION SERVERS +# <Location /webwork2_wsdl> +# PerlSetVar dispatch_to "WebworkSOAP::WSDL" +# PerlSetVar options "compress_threshold => 10000" +# PerlHandler WebworkSOAP::WSDL +# SetHandler perl-script +# Order Allow,Deny +# Allow from All +# </Location> +#EOF + </Perl> Index: global.conf.dist =================================================================== RCS file: /webwork/cvs/system/webwork2/conf/global.conf.dist,v retrieving revision 1.189.2.7.2.1 retrieving revision 1.189.2.7.2.2 diff -Lconf/global.conf.dist -Lconf/global.conf.dist -u -r1.189.2.7.2.1 -r1.189.2.7.2.2 --- conf/global.conf.dist +++ conf/global.conf.dist @@ -42,7 +42,7 @@ # URL and path to courses directory. $webwork_courses_url = "/webwork2_course_files"; -$webwork_courses_dir = "/opt/webwork/courses"; +$webwork_courses_dir = "/opt/webwork/courses"; #(a typical place to put the course directory ################################################################################ # Paths to external programs @@ -98,6 +98,9 @@ # a valid mail domain, or at least be well-formed. $mail{smtpSender} = 'we...@yo...'; +# Seconds to wait before timing out when connecting to the SMTP server. +$mail{smtpTimeout} = 30; + # AllowedRecipients defines addresses that the PG system is allowed to send mail # to. this prevents subtle PG exploits. This should be set in course.conf to the # addresses of professors of each course. Sending mail from the PG system (i.e. @@ -142,6 +145,7 @@ # %r = recitation # %% = literal percent sign # + $mail{feedbackSubjectFormat} = "[WWfeedback] course:%c user:%u set:%s prob:%p sec:%x rec:%r"; # feedbackVerbosity: @@ -159,6 +163,10 @@ # Use this to customize the text of the feedback button. $feedback_button_name = "Email instructor"; +# If this value is true, feedback will only be sent to users with the same +# section as the user initiating the feedback. +$feedback_by_section = 0; + ################################################################################ # Theme ################################################################################ @@ -203,7 +211,9 @@ # $webworkDirs{valid_symlinks} = ["$webworkDirs{courses}/modelCourse/templates","/ww2/common/sets"]; $webworkDirs{valid_symlinks} = []; +################################################################################ ##### The following locations are web-accessible. +################################################################################ # The root URL (usually /webwork2), set by <Location> in Apache configuration. $webworkURLs{root} = "$webwork_url"; @@ -226,7 +236,7 @@ $webworkURLs{local_help} = "$webworkURLs{htdocs}/helpFiles"; # URL of general WeBWorK documentation. -$webworkURLs{docs} = "http://webhost.math.rochester.edu/webworkdocs/docs"; +$webworkURLs{docs} = "http://webwork.maa.org"; # URL of WeBWorK Bugzilla database. $webworkURLs{bugReporter} = "http://bugs.webwork.rochester.edu/"; @@ -306,9 +316,10 @@ # don't want to use the equation cache file. $webworkFiles{equationCacheDB} = ""; # "$webworkDirs{DATA}/equationcache"; -##### Hardcopy snippets are used in constructing a TeX file for hardcopy output. -##### They should contain TeX code unless otherwise noted. - +################################################################################ +# Hardcopy snippets are used in constructing a TeX file for hardcopy output. +# They should contain TeX code unless otherwise noted. +################################################################################ # The preamble is the first thing in the TeX file. $webworkFiles{hardcopySnippets}{preamble} = "$webworkDirs{conf}/snippets/hardcopyPreamble.tex"; @@ -336,7 +347,7 @@ $webworkFiles{screenSnippets}{setHeader} = "$webworkDirs{conf}/snippets/setHeader.pg"; # screenSetHeader.pg" # A PG template for creation of new problems. -$webworkFiles{screenSnippets}{blankProblem} = "$webworkDirs{conf}/snippets/blankProblem.pg"; # screenSetHeader.pg" +$webworkFiles{screenSnippets}{blankProblem} = "$webworkDirs{conf}/snippets/blankProblem2.pg"; # screenSetHeader.pg" # A site info "message of the day" file $webworkFiles{site_info} = "$webworkDirs{htdocs}/site_info.txt"; @@ -623,7 +634,7 @@ proctor_quiz_login => "login_proctor", proctor_quiz_grade => "grade_proctor", - view_proctored_tests => "ta", + view_proctored_tests => "student", view_hidden_work => "ta", view_multiple_sets => "ta", @@ -666,6 +677,8 @@ check_answers_after_open_date_without_attempts => "guest", check_answers_after_due_date => "guest", check_answers_after_answer_date => "guest", + create_new_set_version_when_acting_as_student => undef, + record_set_version_answers_when_acting_as_student => undef, record_answers_when_acting_as_student => undef, # "record_answers_when_acting_as_student" takes precedence # over the following for professors acting as students: Index: database.conf.dist =================================================================== RCS file: /webwork/cvs/system/webwork2/conf/database.conf.dist,v retrieving revision 1.35.2.1 retrieving revision 1.35.2.1.2.1 diff -Lconf/database.conf.dist -Lconf/database.conf.dist -u -r1.35.2.1 -r1.35.2.1.2.1 --- conf/database.conf.dist +++ conf/database.conf.dist @@ -78,6 +78,9 @@ username => $database_username, password => $database_password, debug => $database_debug, + # kinda hacky, but needed for table dumping + mysql_path => $externalPrograms{mysql}, + mysqldump_path => $externalPrograms{mysqldump}, ); $dbLayouts{sql_single} = { @@ -254,6 +257,15 @@ merge => [qw/problem_version problem_user problem/], }, }, + setting => { + record => "WeBWorK::DB::Record::Setting", + schema => "WeBWorK::DB::Schema::NewSQL::Std", + driver => "WeBWorK::DB::Driver::SQL", + source => $database_dsn, + params => { %sqlParams, + tableOverride => "${courseName}_setting" + }, + }, }; =head2 THE SQL_MOODLE DATABASE LAYOUT Index: blankProblem2.pg =================================================================== RCS file: /webwork/cvs/system/webwork2/conf/snippets/blankProblem2.pg,v retrieving revision 1.1.2.1.2.1 retrieving revision 1.1.2.1.2.2 diff -Lconf/snippets/blankProblem2.pg -Lconf/snippets/blankProblem2.pg -u -r1.1.2.1.2.1 -r1.1.2.1.2.2 --- conf/snippets/blankProblem2.pg +++ conf/snippets/blankProblem2.pg @@ -27,7 +27,10 @@ #"PGcourse.pl", # Customization file for the course ); +# Print problem number and point value (weight) for the problem TEXT(beginproblem()); + +# Show which answers are correct and which ones are incorrect $showPartialCorrectAnswers = 1; ############################################################## @@ -35,6 +38,9 @@ # Setup # # +Context("Numeric"); + +$pi = Real("pi"); ############################################################## # @@ -42,9 +48,13 @@ # # +Context()->texStrings; BEGIN_TEXT +Enter a value for \(\pi\) + +\{$pi->ans_rule\} END_TEXT Context()->normalStrings; @@ -54,6 +64,9 @@ # # +ANS($pi->with(tolerance=>.0001)->cmp); +# relative tolerance --3.1412 is incorrect but 3.1413 is correct +# default tolerance is .01 or one percent. ENDDOCUMENT(); Index: Copying =================================================================== RCS file: /webwork/cvs/system/webwork2/doc/Copying,v retrieving revision 1.1 retrieving revision 1.1.26.1 diff -Ldoc/Copying -Ldoc/Copying -u -r1.1 -r1.1.26.1 --- doc/Copying +++ doc/Copying @@ -1,37 +1,41 @@ + GNU GENERAL PUBLIC LICENSE - Version 1, February 1989 + Version 2, June 1991 - Copyright (C) 1989 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble - The license agreements of most software companies try to keep users -at the mercy of those companies. By contrast, our General Public + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. The -General Public License applies to the Free Software Foundation's -software and to any other program whose authors commit to using it. -You can use it for your programs, too. +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. When we speak of free software, we are referring to freedom, not -price. Specifically, the General Public License is designed to make -sure that you have the freedom to give away or sell copies of free -software, that you receive source code or can get it if you want it, -that you can change the software or use pieces of it in new free -programs; and that you know you can do these things. +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. - For example, if you distribute copies of a such a program, whether + For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the -source code. And you must tell them their rights. +source code. And you must show them these terms so they know their +rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, @@ -44,120 +48,208 @@ that any problems introduced by others will not reflect on the original authors' reputations. + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + The precise terms and conditions for copying, distribution and modification follow. - + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - 0. This License Agreement applies to any program or other work which -contains a notice placed by the copyright holder saying it may be -distributed under the terms of this General Public License. The -"Program", below, refers to any such program or work, and a "work based -on the Program" means either the Program or any work containing the -Program or a portion of it, either verbatim or with modifications. Each -licensee is addressed as "you". - - 1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this -General Public License and to the absence of any warranty; and give any -other recipients of the Program a copy of this General Public License -along with the Program. You may charge a fee for the physical act of -transferring a copy. - - 2. You may modify your copy or copies of the Program or any portion of -it, and copy and distribute such modifications under the terms of Paragraph -1 above, provided that you also do the following: - - a) cause the modified files to carry prominent notices stating that - you changed the files and the date of any change; and - - b) cause the whole of any work that you distribute or publish, that - in whole or in part contains the Program or any part thereof, either - with or without modifications, to be licensed at no charge to all - third parties under the terms of this General Public License (except - that you may choose to grant warranty protection to some or all - third parties, at your option). - - c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive use - in the simplest and most usual way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this General - Public License. - - d) You may charge a fee for the physical act of transferring a - copy, and you may at your option offer warranty protection in - exchange for a fee. - -Mere aggregation of another independent work with the Program (or its -derivative) on a volume of a storage or distribution medium does not bring -the other work under the scope of these terms. - - 3. You may copy and distribute the Program (or a portion or derivative of -it, under Paragraph 2) in object code or executable form under the terms of -Paragraphs 1 and 2 above provided that you also do one of the following: + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of - Paragraphs 1 and 2 above; or, + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software + interchange; or, b) accompany it with a written offer, valid for at least three - years, to give any third party free (except for a nominal charge - for the cost of distribution) a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of - Paragraphs 1 and 2 above; or, + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, - c) accompany it with the information you received as to where the - corresponding source code may be obtained. (This alternative is + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you - received the program in object code or executable form alone.) + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) -Source code for a work means the preferred form of the work for making -modifications to it. For an executable file, complete source code means -all the source code for all modules it contains; but, as a special -exception, it need not include source code for modules which are standard -libraries that accompany the operating system on which the executable -file runs, or for standard header files or definitions files that -accompany that operating system. - - 4. You may not copy, modify, sublicense, distribute or transfer the -Program except as expressly provided under this General Public License. -Any attempt otherwise to copy, modify, sublicense, distribute or transfer -the Program is void, and will automatically terminate your rights to use -the Program under this License. However, parties who have received -copies, or rights to use copies, from you under this General Public -License will not have their licenses terminated so long as such parties -remain in full compliance. - - 5. By copying, distributing or modifying the Program (or any work based -on the Program) you indicate your acceptance of this license to do so, -and all its terms and conditions. +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the original -licensor to copy, distribute or modify the Program subject to these -terms and conditions. You may not impose any further restrictions on the -recipients' exercise of the rights granted herein. - - 7. The Free Software Foundation may publish revised and/or new versions +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program -specifies a version number of the license which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -the license, you may choose any version ever published by the Free Software -Foundation. +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a +version number of this License, you may choose any version ever +published by the Free Software Foundation. - 8. If you wish to incorporate parts of the Program into other free + 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes @@ -167,47 +259,48 @@ NO WARRANTY - 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest -possible use to humanity, the best way to achieve this is to make it +possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. - To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey -the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> - Copyright (C) 19yy <name of author> + Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -215,34 +308,37 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19xx name of author + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the -commands you use may be called something other than `show w' and `show -c'; they could even be mouse-clicks or menu items--whatever suits your -program. +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here a sample; alter the names: +necessary. Here is a sample; alter the names: - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (a program to direct compilers to make passes - at assemblers) written by James Hacker. + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice -That's all there is to it! +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. Index: InstructorUserList.html =================================================================== RCS file: /webwork/cvs/system/webwork2/htdocs/helpFiles/InstructorUserList.html,v retrieving revision 1.3.4.2 retrieving revision 1.3.4.2.2.1 diff -Lhtdocs/helpFiles/InstructorUserList.html -Lhtdocs/helpFiles/InstructorUserList.html -u -r1.3.4.2 -r1.3.4.2.2.1 --- htdocs/helpFiles/InstructorUserList.html +++ htdocs/helpFiles/InstructorUserList.html @@ -52,7 +52,7 @@ <dd> Click the "Add x student(s)" radio button and then click "Take action". This will take you to a new page where the data can be entered for one or more students. It is also possible to assign the student to one or more problem sets as they are being entered: simply select the homework sets from the list below the data entry table. U... [truncated message content] |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 15:57:33
|
Log Message: ----------- Fixed errors in implementing BEGIN_HINT and BEGIN_SOLUTION -- Hints and solutions are still not working right -- but I believe this has been an on-going bug not a new one. -- still working Tags: ---- rel-2-4-patches Modified Files: -------------- pg/lib/WeBWorK/PG: Translator.pm Revision Data ------------- Index: Translator.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/WeBWorK/PG/Translator.pm,v retrieving revision 1.18.2.2.2.1 retrieving revision 1.18.2.2.2.2 diff -Llib/WeBWorK/PG/Translator.pm -Llib/WeBWorK/PG/Translator.pm -u -r1.18.2.2.2.1 -r1.18.2.2.2.2 --- lib/WeBWorK/PG/Translator.pm +++ lib/WeBWorK/PG/Translator.pm @@ -1636,11 +1636,11 @@ my $evalString = shift; # BEGIN_TEXT and END_TEXT must occur on a line by themselves. $evalString =~ s/\n\s*END_TEXT[\s;]*\n/\nEND_TEXT\n/g; - $evalString =~ s/\n\s*END_SOLUTION[\s;]*\n/\nEND_TEXT\n/g; - $evalString =~ s/\n\s*END_HINT[\s;]*\n/\nEND_TEXT\n/g; + $evalString =~ s/\n\s*END_SOLUTION[\s;]*\n/\nEND_SOLUTION\n/g; + $evalString =~ s/\n\s*END_HINT[\s;]*\n/\nEND_HINT\n/g; $evalString =~ s/\n\s*BEGIN_TEXT[\s;]*\n/\nTEXT\(EV3\(<<'END_TEXT'\)\);\n/g; - $evalString =~ s/\n\s*BEGIN_SOLUTION[\s;]*\n/\nTEXT\(EV3\(<<'END_SOLUTION'\)\);\n/g; - $evalString =~ s/\n\s*BEGIN_HINT[\s;]*\n/\nTEXT\(EV3\(<<'END_HINT'\)\);\n/g; + $evalString =~ s/\n\s*BEGIN_SOLUTION[\s;]*\n/\nSOLUTION\(EV3\(<<'END_SOLUTION'\)\);\n/g; + $evalString =~ s/\n\s*BEGIN_HINT[\s;]*\n/\nHINT\(EV3\(<<'END_HINT'\)\);\n/g; $evalString =~ s/ENDDOCUMENT.*/ENDDOCUMENT();/s; # remove text after ENDDOCUMENT $evalString =~ s/\\/\\\\/g; # \ can't be used for escapes because of TeX conflict |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 15:39:11
|
Log Message: ----------- Adding missing pages. Tags: ---- rel-2-4-patches Modified Files: -------------- webwork2/conf: global.conf.dist webwork2/conf/snippets: blankProblem2.pg webwork2/conf/templates/math: system.template webwork2/htdocs/css: math.css webwork2/htdocs/helpFiles: instructor_links.html webwork2/htdocs/jsMath: jsMath-ww.js webwork2/lib/WeBWorK/DB: Record.pm Revision Data ------------- Index: global.conf.dist =================================================================== RCS file: /webwork/cvs/system/webwork2/conf/global.conf.dist,v retrieving revision 1.189.2.7 retrieving revision 1.189.2.7.2.1 diff -Lconf/global.conf.dist -Lconf/global.conf.dist -u -r1.189.2.7 -r1.189.2.7.2.1 --- conf/global.conf.dist +++ conf/global.conf.dist @@ -895,6 +895,8 @@ [qw(VectorField)], [qw(Parser Value)], [qw(Parser::Legacy)], +# [qw(SaveFile)], + [qw(Applet FlashApplet)], ]; ##### Answer evaluatior defaults Index: blankProblem2.pg =================================================================== RCS file: /webwork/cvs/system/webwork2/conf/snippets/blankProblem2.pg,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.1.2.1 diff -Lconf/snippets/blankProblem2.pg -Lconf/snippets/blankProblem2.pg -u -r1.1.2.1 -r1.1.2.1.2.1 --- conf/snippets/blankProblem2.pg +++ conf/snippets/blankProblem2.pg @@ -46,6 +46,7 @@ END_TEXT +Context()->normalStrings; ############################################################## # Index: system.template =================================================================== RCS file: /webwork/cvs/system/webwork2/conf/templates/math/system.template,v retrieving revision 1.6.2.1 retrieving revision 1.6.2.1.2.1 diff -Lconf/templates/math/system.template -Lconf/templates/math/system.template -u -r1.6.2.1 -r1.6.2.1.2.1 --- conf/templates/math/system.template +++ conf/templates/math/system.template @@ -24,7 +24,7 @@ <title><!--#path style="text" text=" : " textonly="1"--></title> <!--#head--> </head> -<body bgcolor="white"> +<body bgcolor="white" onload="if (typeof(initializeAction) == 'function') {initializeAction()}"> <div id="masthead"> <div id="loginstatus"> @@ -39,40 +39,47 @@ <div id="breadcrumbs"> <!--#path style="text" text=" → "--> </div> - <div id="content"> - - <!--#if can="info"--> - <!--<div id="page-info">--> - <!--<div class="info-box" id="fisheye">--> + <div id="content" > + + <!--#if can="title"--> + <span style="font-size:larger; color:#00F; float:left; width:60%; "><!--#title--></span> + <!--#endif--> + <!--#if can="message"--> + <span class="Message" style=" float:right; width:40%; right:0;"> + <!--#message--> + </span> + <!--#endif--> + + <hr style="clear:both"/> + <!--#if can="info"--> + <!-- styles could be different for different pages so they are not set here --> <!--#info--> - <!--</div>--> - <!--</div>--> - <!--#endif--> - + <!--#endif--> + <!--#if can="nav"--> <div class="Nav"> <!--#nav style="images" imageprefix="/webwork2_files/images/nav" imagesuffix=".gif" separator=" "--> </div> <!--#endif--> - <!--#if can="title"--> - <h1><!--#title--></h1> - <!--#endif--> - - <!--#if can="message"--> - <div class="Message"> - <!--#message--> - </div> - <!--#endif--> - - <!--#if can="body"--> - <div class="Body"> - <!--#body--> - </div> - <!--#endif--> + <!--#if can="body"--> + <!--#if warnings="1"--> + <div class="Body" style="background-color:#ffcccc"> + <p style="font-size:larger"> + Warning -- there may be something wrong with this question. Please inform your instructor + including the warning messages below. + </p> + <!--#else--> + <div class="Body" style="background-color:#ffffff"> + <!--#endif--> + + <!--#body--> + </div> + <!--#endif--> <!--#if warnings="1"--> - <hr> + + <hr/> <div class="Warnings"> <!--#warnings--> </div> @@ -84,7 +91,7 @@ </div> <!--#endif--> - </div> <!-- content --> + <hr class="for-broken-browsers"/> <div id="footer"> <p id="last-modified">Page generated at <!--#timestamp--></p> @@ -109,6 +116,8 @@ </div> <!--#endif--> </div> + +</div><!--content--> </div> <!-- big-wrapper --> </body> Index: math.css =================================================================== RCS file: /webwork/cvs/system/webwork2/htdocs/css/math.css,v retrieving revision 1.9.4.3 retrieving revision 1.9.4.3.2.1 diff -Lhtdocs/css/math.css -Lhtdocs/css/math.css -u -r1.9.4.3 -r1.9.4.3.2.1 --- htdocs/css/math.css +++ htdocs/css/math.css @@ -153,6 +153,9 @@ margin-right: .5em; } +.Message { +background-color:#ddd; +} /* --- Fisheye view (id) ---------------------------------------------------- */ /* The "fisheye" view: a hierarchical view of the website to show the @@ -237,7 +240,7 @@ padding: 0; color: #fff; border: 1px solid #000; - background-color: #000038; + background-color: #038; /* [ww] we could have some sort of spider web image here. */ /*background-image: url("/images/mandel-wide.jpg");*/ background-repeat: repeat-x; @@ -281,6 +284,9 @@ margin: 1ex .5em .1ex .1em; font-size: smaller; } +#masthead #loginstatus #Nav { + padding: 1ex; +} /* "big-wrapper" contains everything other than the masthead. It's merely * a relatively positioned div that allows us to use absolute positioning @@ -390,9 +396,9 @@ * (These are mostly copied from ur.css right atm.) */ -/* the info escape emits a DIV with this id. (not that the same DIV has class +/* the info escape emits a DIV with this id. (note that the same DIV has class * "info-box" which is given above in the "template styles" section. Regardless, - * it is emitted by WW code! */ + * it is emitted by WW code in ProblemSet.pl (not in system.template) ! */ #InfoPanel { font-size: smaller; float: right; @@ -418,6 +424,7 @@ /*ul.LinksMenu ul { list-style: none; margin-left: 0.5em; padding-left: 0; }*/ /* background styles for success and failure messages */ +div.WarningMessage { background-color: #ffcccc; padding: 3px 3px 3px 3px; } div.ResultsWithoutError { color: inherit; background-color: #8F8; } /* green */ div.ResultsWithError { color: #C33; background-color: inherit; } /* red */ div.ResultsAlert { color: #F60; background-color: inherit; } /* orange */ Index: instructor_links.html =================================================================== RCS file: /webwork/cvs/system/webwork2/htdocs/helpFiles/instructor_links.html,v retrieving revision 1.5.4.2 retrieving revision 1.5.4.2.2.1 diff -Lhtdocs/helpFiles/instructor_links.html -Lhtdocs/helpFiles/instructor_links.html -u -r1.5.4.2 -r1.5.4.2.2.1 --- htdocs/helpFiles/instructor_links.html +++ htdocs/helpFiles/instructor_links.html @@ -27,10 +27,8 @@ <h3>Instructor Links Help Page</h3> -<hr/> -<b>For help with an item on a specific page</b><br/> -click the <a href="instructor_links.html"><img src="/webwork2_files/images/question_mark.png"></a> icon. - +Click the icon <a href="instructor_links.html"><img src="/webwork2_files/images/question_mark.png"></a> for +page and item specific help. <hr/> <dl> Index: jsMath-ww.js =================================================================== RCS file: /webwork/cvs/system/webwork2/htdocs/jsMath/jsMath-ww.js,v retrieving revision 1.6.2.1 retrieving revision 1.6.2.1.2.1 diff -Lhtdocs/jsMath/jsMath-ww.js -Lhtdocs/jsMath/jsMath-ww.js -u -r1.6.2.1 -r1.6.2.1.2.1 --- htdocs/jsMath/jsMath-ww.js +++ htdocs/jsMath/jsMath-ww.js @@ -10,7 +10,7 @@ var jsMath = { styles: { - '.math': 'font-family: serif; font-style: normal; color: grey33; font-size: 75%' + '.math': 'font-family: serif; font-style: normal; color: grey; font-size: 75%' }, Controls: {cookie: {scale: 133}}, Parser: {prototype: {macros: { Index: Record.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/DB/Record.pm,v retrieving revision 1.12.4.1 retrieving revision 1.12.4.1.2.1 diff -Llib/WeBWorK/DB/Record.pm -Llib/WeBWorK/DB/Record.pm -u -r1.12.4.1 -r1.12.4.1.2.1 --- lib/WeBWorK/DB/Record.pm +++ lib/WeBWorK/DB/Record.pm @@ -1,5 +1,3 @@ -################################################################################ -# WeBWorK Online Homework Delivery System # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ # $CVSHeader$ # @@ -164,4 +162,14 @@ } } +sub _initial_records { + my $invocant = shift; + my $class = ref $invocant || $invocant; + my @initializers = @_; + + no strict 'refs'; + *{$class."::INITIAL_RECORDS"} = sub { return @initializers }; +} + 1; + |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 15:00:17
|
Log Message: ----------- Adding WebworkSOAP files to rel-2-4-patches Tags: ---- rel-2-4-patches Modified Files: -------------- webwork2/lib: WebworkWebservice.pm Added Files: ----------- webwork2/lib: WebworkSOAP.pm webwork2/lib/WeBWorK/Utils: DBUpgrade.pm webwork2/lib/WebworkSOAP/Classes: Course.pm GlobalProblem.pm GlobalSet.pm Key.pm Password.pm Permission.pm User.pm UserProblem.pm UserSet.pm Revision Data ------------- Index: WebworkWebservice.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WebworkWebservice.pm,v retrieving revision 1.4 retrieving revision 1.4.10.1 diff -Llib/WebworkWebservice.pm -Llib/WebworkWebservice.pm -u -r1.4 -r1.4.10.1 --- lib/WebworkWebservice.pm +++ lib/WebworkWebservice.pm @@ -4,8 +4,8 @@ BEGIN { $main::VERSION = "2.1"; - my $webwork_directory = $ENV{WEBWORK_ROOT}; - + my $webwork_directory = $ENV{WEBWORK_ROOT}; # doesn't work on Mac OS ? + $webwork_directory='/opt/webwork/webwork2'; eval "use lib '$webwork_directory/lib'"; die $@ if $@; eval "use WeBWorK::CourseEnvironment"; die $@ if $@; my $ce = new WeBWorK::CourseEnvironment({ webwork_dir => $webwork_directory }); --- /dev/null +++ lib/WebworkSOAP.pm @@ -0,0 +1,1073 @@ +package WebworkSOAP; + +use strict; + +use WeBWorK::Utils qw(pretty_print_rh); +use WeBWorK::Utils::CourseManagement qw(addCourse renameCourse deleteCourse listCourses archiveCourse listArchivedCourses unarchiveCourse); +use WeBWorK::DB; +use WeBWorK::DB::Utils qw(initializeUserProblem); +use WeBWorK::CourseEnvironment; +use WeBWorK::ContentGenerator::Instructor; + +use WebworkSOAP::Classes::GlobalSet; +use WebworkSOAP::Classes::UserSet; +use WebworkSOAP::Classes::GlobalProblem; +use WebworkSOAP::Classes::UserProblem; +use WebworkSOAP::Classes::User; +use WebworkSOAP::Classes::Key; +use WebworkSOAP::Classes::Password; +use WebworkSOAP::Classes::Permission; + +#init + +use constant { + SOAPERROR_MAJOR => 1, + SOAPERROR_MINOR => 2, + SOAPERROR_CLASS_NOT_FOUND => 3, + SOAPERROR_USER_NOT_FOUND => 4, + SOAPERROR_SET_NOT_FOUND => 5, + SOAPERROR_PROBLEM_NOT_FOUND => 6, + SOAPERROR_KEY_NOT_FOUND => 7, + SOAPERROR_AUTHEN_FAILED => 8 +}; + +our %SeedCE; +%WebworkSOAP::SeedCE = %WeBWorK::SeedCE; + +$WebworkSOAP::SeedCE{soap_authen_key} = "123456789123456789"; +#$WebworkSOAP::SeedCE{webwork_dir} = $ENV{WEBWORK_ROOT}|| warn "\$ENV{WEBWORK_ROOT} is undefined -- check your httpd configuration. Error caught "; + + +sub new { + my($self,$authenKey,$courseName) = @_; + $self = {}; + #Construct Course + my $ce = eval { new WeBWorK::CourseEnvironment({%SeedCE, courseName => $courseName }) }; + $@ and soap_fault_major("Course Environment cannot be constructed.<br>$@"); + #Authentication Check + if($ce->{soap_authen_key} != $authenKey) { + soap_fault_authen(); + } + #Construct DB handle + my $db = eval { new WeBWorK::DB($ce->{dbLayout}); }; + $@ and soap_fault_major("Failed to initialize database handle.<br>$@"); + $self->{db} = $db; + $self->{ce} = $ce; + bless $self; + return $self; +} + +sub soap_fault_authen { + die SOAP::Fault->faultcode(SOAPERROR_AUTHEN_FAILED) + ->faultstring("SOAP Webservice Authentication Failed!"); +} + +sub soap_fault { + my ($errorCode,$errorMsg) = @_; + die SOAP::Fault->faultcode($errorCode) + ->faultstring($errorMsg); +} + +sub soap_fault_major { + my ($errorMsg) = @_; + soap_fault(SOAPERROR_MAJOR,$errorMsg); +} +#################################################################################### +#SOAP CALLABLE FUNCTIONS +#################################################################################### + +=pod +=begin WSDL +_RETURN $string Hello World! +=cut +sub hello { + return "Hello world!"; +} + +################################################# +#Course +################################################# + +=pod +=begin WSDL +_IN authenKey $string +_RETURN @string +=end WSDL +=cut +sub list_courses { + my ($self,$authenKey) = @_; + my $ce = eval { new WeBWorK::CourseEnvironment({%WeBWorK::SeedCE })}; + $@ and soap_fault_major("Internal Course Environment cannot be constructed."); + if($authenKey != $WebworkSOAP::SeedCE{soap_authen_key}) { + soap_fault_authen; + } + $@ and soap_fault_major("Course Environment cannot be constructed."); + my @test = listCourses($ce); + return \@test; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_RETURN $string +=end WSDL +=cut +sub login_user { + my ($self,$authenKey,$courseName,$userID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $newKey; + my $timestamp = time; + my @chars = @{ $soapEnv->{ce}->{sessionKeyChars} }; + my $length = $soapEnv->{ce}->{sessionKeyLength}; + srand; + $newKey = join ("", @chars[map rand(@chars), 1 .. $length]); + my $Key = $soapEnv->{db}->newKey(user_id=>$userID, key=>$newKey, timestamp=>$timestamp); + eval { $soapEnv->{db}->deleteKey($userID) }; + eval { $soapEnv->{db}->addKey($Key) }; + $@ and soap_fault(SOAPERROR_USER_NOT_FOUND,"User not found."); + return $newKey; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_IN setID $string +_RETURN $string +=end WSDL +=cut +sub assign_set_to_user { + my ($self,$authenKey,$courseName,$userID,$setID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $GlobalSet = eval {$soapEnv->{db}->getGlobalSet($setID)}; + $@ and soap_fault(SOAPERROR_SET_NOT_FOUND,"Set not found."); + my $setID = $GlobalSet->set_id; + my $db = $soapEnv->{db}; + my $UserSet = $db->newUserSet; + $UserSet->user_id($userID); + $UserSet->set_id($setID); + my @results; + my $set_assigned = 0; + eval { $db->addUserSet($UserSet) }; + if ($@) { + if ($@ =~ m/user set exists/) { + push @results, "set $setID is already assigned to user $userID."; + $set_assigned = 1; + } else { + die $@; + } + } + + my @GlobalProblems = grep { defined $_ } $db->getAllGlobalProblems($setID); + foreach my $GlobalProblem (@GlobalProblems) { + my $seed = int( rand( 2423) ) + 36; + my $UserProblem = $db->newUserProblem; + $UserProblem->user_id($userID); + $UserProblem->set_id($GlobalProblem->set_id); + $UserProblem->problem_id($GlobalProblem->problem_id); + initializeUserProblem($UserProblem, $seed); + eval { $db->addUserProblem($UserProblem) }; + } + return @results; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userIDs @string +_IN setID $string +_RETURN @string +=end WSDL +=cut +sub grade_users_sets { + my ($self,$authenKey,$courseName,$userIDs,$setID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @grades; + foreach my $userID (@{$userIDs}) { + my @problemData = $soapEnv->{db}->getAllUserProblems($userID,$setID); + + my $grade = 0; + for(my $i=0;$i<@problemData;$i++) { + $grade += @problemData[$i]->status; + } + push(@grades,$grade); + } + return \@grades; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN setID $string +_RETURN @string +=end WSDL +=cut +sub get_set_data { + my ($self,$authenKey,$courseName,$setID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $setData = $soapEnv->{db}->getGlobalSet($setID); + if(not defined $setData) { + return -1; + } + my $set = new WebworkSOAP::Classes::GlobalSet($setData); + return $set; + + +} + +#################################################################### +##FUNCTIONS DIRECTLY MAPPED TO FUNCTIONS IN DB.pm +#################################################################### +############################################### +##Password +############################################### + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::Password +_RETURN $string +=end WSDL +=cut +sub add_password { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $newPassword = $soapEnv->{db}->newPassword; + %$newPassword = %$record; + return $soapEnv->{db}->addPassword($newPassword); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::Password +_RETURN $string +=end WSDL +=cut +sub put_password { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + return $soapEnv->{db}->putPassword($record); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_RETURN @string +=end WSDL +=cut +sub list_password { + my ($self,$authenKey,$courseName) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @tempArray = $soapEnv->{db}->listPasswords; + return \@tempArray; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userIDs @string +_RETURN @WebworkSOAP::Classes::Password Array of user objects +=end WSDL +=cut +sub get_passwords { + my ($self,$authenKey,$courseName,$userIDs) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @passwordData = $soapEnv->{db}->getPasswords(@$userIDs); + my @passwords; + for(my $i=0;$i<@passwordData;$i++) { + push(@passwords,new WebworkSOAP::Classes::Password(@passwordData[$i])); + } + return \@passwords; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_RETURN $WebworkSOAP::Classes::Password of names objects. +=end WSDL +=cut +sub get_password { + my ($self,$authenKey,$courseName,$userID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $passwordData = $soapEnv->{db}->getPassword($userID); + if(not defined $passwordData) { + return -1; + } + my $password = new WebworkSOAP::Classes::Password($passwordData); + return ($password); +} + +################################################## +##Permission +################################################## + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::Permission +_RETURN $string +=end WSDL +=cut +sub add_permission { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $newPermissionLevel = $soapEnv->{db}->newPermissionLevel; + %$newPermissionLevel = %$record; + return $soapEnv->{db}->addPermissionLevel($newPermissionLevel); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::Permission +_RETURN $string +=end WSDL +=cut +sub put_permission { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + return $soapEnv->{db}->putPermissionLevel($record); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_RETURN @string +=end WSDL +=cut +sub list_permissions { + my ($self,$authenKey,$courseName) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @tempArray = $soapEnv->{db}->listPermissionLevels; + return \@tempArray; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userIDs @string +_RETURN @WebworkSOAP::Classes::Permission Array of user objects +=end WSDL +=cut +sub get_permissions { + my ($self,$authenKey,$courseName,$userIDs) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @permissionData = $soapEnv->{db}->getPermissionLevels(@$userIDs); + my @permissions; + for(my $i=0;$i<@permissionData;$i++) { + push(@permissions,new WebworkSOAP::Classes::Permission(@permissionData[$i])); + } + return \@permissions; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_RETURN $WebworkSOAP::Classes::Permission of names objects. +=end WSDL +=cut +sub get_permission { + my ($self,$authenKey,$courseName,$userID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $permissionData = $soapEnv->{db}->getPermissionLevel($userID); + if(not defined $permissionData) { + return -1; + } + my $permission = new WebworkSOAP::Classes::Permission($permissionData); + return ($permission); +} + +################################################## +##Key +################################################## + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::Key +_RETURN $string +=end WSDL +=cut +sub add_key { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $newKey = $soapEnv->{db}->newKey; + %$newKey = %$record; + return $soapEnv->{db}->addKey($newKey); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::Key +_RETURN $string +=end WSDL +=cut +sub put_key { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + return $soapEnv->{db}->putKey($record); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_RETURN @string +=end WSDL +=cut +sub list_keys { + my ($self,$authenKey,$courseName) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @tempArray = $soapEnv->{db}->listKeys; + return \@tempArray; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userIDs @string +_RETURN @WebworkSOAP::Classes::Key Array of user objects +=end WSDL +=cut +sub get_keys { + my ($self,$authenKey,$courseName,$userIDs) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @keyData = $soapEnv->{db}->getKeys(@$userIDs); + my @keys; + for(my $i=0;$i<@keyData;$i++) { + push(@keys,new WebworkSOAP::Classes::Key(@keyData[$i])); + } + return \@keys; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_RETURN $WebworkSOAP::Classes::Key of names objects. +=end WSDL +=cut +sub get_key { + my ($self,$authenKey,$courseName,$userID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $keyData = $soapEnv->{db}->getKey($userID); + if(not defined $keyData) { + return -1; + } + my $key = new WebworkSOAP::Classes::Key($keyData); + return ($key); +} + +################################################## +##User +################################################## + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::User +_RETURN $string +=end WSDL +=cut +sub add_user { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $newUser = $soapEnv->{db}->newUser; + %$newUser = %$record; + return $soapEnv->{db}->addUser($newUser); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::User +_RETURN $string +=end WSDL +=cut +sub put_user { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + return $soapEnv->{db}->putUser($record); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_RETURN @string of names objects. +=end WSDL +=cut +sub list_users { + my ($self,$authenKey,$courseName) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @tempArray = $soapEnv->{db}->listUsers; + return \@tempArray; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_RETURN $WebworkSOAP::Classes::User of names objects. +=end WSDL +=cut +sub get_user { + my ($self,$authenKey,$courseName,$userID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $userData = $soapEnv->{db}->getUser($userID); + if(not defined $userData) { + return -1; + } + my $user = new WebworkSOAP::Classes::User($userData); + return ($user); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userIDs @string +_RETURN @WebworkSOAP::Classes::User Array of user objects +=end WSDL +=cut +sub get_users { + my ($self,$authenKey,$courseName,$userIDs) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @userData = $soapEnv->{db}->getUsers(@$userIDs); + my @users; + for(my $i=0;$i<@userData;$i++) { + push(@users,new WebworkSOAP::Classes::User(@userData[$i])); + } + return \@users; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_RETURN $string +=end WSDL +=cut +sub delete_user { + my ($self,$authenKey,$courseName,$userID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + return $soapEnv->{db}->deleteUser($userID); +} + +################################################## +##Global Sets +################################################## + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::GlobalSet +_RETURN $string +=end WSDL +=cut +sub add_global_set { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $newGlobalSet = $soapEnv->{db}->newGlobalSet; + %$newGlobalSet = %$record; + return $soapEnv->{db}->addGlobalSet($newGlobalSet); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::GlobalSet +_RETURN $string +=end WSDL +=cut +sub put_global_set { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + return $soapEnv->{db}->putGlobalSet($record); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_RETURN @string of names objects. +=end WSDL +=cut +sub list_global_sets { + my ($self,$authenKey,$courseName) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @tempArray = $soapEnv->{db}->listGlobalSets; + return \@tempArray; +} + + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_RETURN @WebworkSOAP::Classes::GlobalSet Array of user objects +=end WSDL +=cut +sub get_all_global_sets { + my ($self,$authenKey,$courseName) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @tempArray = $soapEnv->{db}->listGlobalSets; + my @setData = $soapEnv->{db}->getGlobalSets(@tempArray); + my @sets; + for(my $i=0;$i<@setData;$i++) { + push(@sets,new WebworkSOAP::Classes::GlobalSet(@setData[$i])); + } + return \@sets; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN setIDs @string +_RETURN @WebworkSOAP::Classes::GlobalSet Array of user objects +=end WSDL +=cut +sub get_global_sets { + my ($self,$authenKey,$courseName,$setIDs) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @setData = $soapEnv->{db}->getGlobalSets(@$setIDs); + my @sets; + for(my $i=0;$i<@setData;$i++) { + push(@sets,new WebworkSOAP::Classes::GlobalSet(@setData[$i])); + } + return \@sets; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN setID $string +_RETURN $WebworkSOAP::Classes::GlobalSet +=end WSDL +=cut +sub get_global_set { + my ($self,$authenKey,$courseName,$setID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $setData = $soapEnv->{db}->getGlobalSet($setID); + if(not defined $setData) { + return -1; + } + my $set = new WebworkSOAP::Classes::GlobalSet($setData); + return ($set); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN setID $string +_RETURN $string +=end WSDL +=cut +sub delete_global_set { + my ($self,$authenKey,$courseName,$setID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + return $soapEnv->{db}->deleteGlobalSet($setID); +} + +################################################## +##Global Problems +################################################## + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::GlobalProblem +_RETURN $string +=end WSDL +=cut +sub add_global_problem { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $newGlobalProblem = $soapEnv->{db}->newGlobalProblem; + %$newGlobalProblem = %$record; + return $soapEnv->{db}->addGlobalProblem($newGlobalProblem); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::GlobalProblem +_RETURN $string +=end WSDL +=cut +sub put_global_problem { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + return $soapEnv->{db}->putGlobalProblem($record); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN setID $string +_RETURN @string of names objects. +=end WSDL +=cut +sub list_global_problems { + my ($self,$authenKey,$courseName,$setID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @tempArray = $soapEnv->{db}->listGlobalProblems($setID); + return \@tempArray; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN setID $string +_RETURN @WebworkSOAP::Classes::GlobalProblem Array of user objects +=end WSDL +=cut +sub get_all_global_problems { + my ($self,$authenKey,$courseName,$setID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @problemData = $soapEnv->{db}->getAllGlobalProblems($setID); + my @problems; + for(my $i=0;$i<@problemData;$i++) { + push(@problems,new WebworkSOAP::Classes::GlobalProblem(@problemData[$i])); + } + return \@problems; +} + +=pod +=begin +_IN authenKey $string +_IN courseName $string +_IN problemIDs @string +_RETURN @WebworkSOAP::Classes::GlobalProblem Array of user objects +=end WSDL +=cut +sub get_global_problems { + my ($self,$authenKey,$courseName,$problemIDs) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @problemData = $soapEnv->{db}->getGlobalProblems(@$problemIDs); + my @problems; + for(my $i=0;$i<@problemData;$i++) { + push(@problems,new WebworkSOAP::Classes::GlobalProblem(@problemData[$i])); + } + return \@problems; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN setID $string +_IN problemID $string +_RETURN $WebworkSOAP::Classes::GlobalProblem of names objects. +=end WSDL +=cut +sub get_global_problem { + my ($self,$authenKey,$courseName,$setID,$problemID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $problemData = $soapEnv->{db}->getGlobalProblem($setID,$problemID); + if(not defined $problemData) { + return -1; + } + my $problem = new WebworkSOAP::Classes::GlobalProblem($problemData); + return ($problem); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN setID $string +_IN problemID $string +_RETURN $string +=end WSDL +=cut +sub delete_global_problem { + my ($self,$authenKey,$courseName,$setID,$problemID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + return $soapEnv->{db}->deleteGlobalProblem($setID,$problemID); +} + +################################################## +##USER PROBLEM +################################################## + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::UserProblem +_RETURN $string +=end WSDL +=cut +sub add_user_problem { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $newUserProblem = $soapEnv->{db}->newUserProblem; + %$newUserProblem = %$record; + return $soapEnv->{db}->addUserProblem($newUserProblem); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::UserProblem +_RETURN $string +=end WSDL +=cut +sub put_user_problem { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + return $soapEnv->{db}->putUserProblem($record); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_RETURN @string of names objects. +=end WSDL +=cut +sub list_user_problems { + my ($self,$authenKey,$courseName,$userID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @tempArray = $soapEnv->{db}->listUserProblems($userID); + return \@tempArray; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_IN setID $string +_RETURN @WebworkSOAP::Classes::UserProblem of names objects. +=end WSDL +=cut +sub get_all_user_problems { + my ($self,$authenKey,$courseName,$userID,$setID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @problemData = $soapEnv->{db}->getAllUserProblems($userID,$setID); + my @problems; + for(my $i=0;$i<@problemData;$i++) { + push(@problems,new WebworkSOAP::Classes::UserProblem(@problemData[$i])); + } + return \@problems; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userProblemIDs @string +_RETURN @WebworkSOAP::Classes::UserProblem of names objects. +=end WSDL +=cut +sub get_user_problems { + my ($self,$authenKey,$courseName,$userProblemIDs) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @problemData = $soapEnv->{db}->getUserProblems(@$userProblemIDs); + my @problems; + for(my $i=0;$i<@problemData;$i++) { + push(@problems,new WebworkSOAP::Classes::UserProblem(@problemData[$i])); + } + return \@problems; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_IN setID $string +_IN problemID $string +_RETURN $WebworkSOAP::Classes::UserProblem of names objects. +=end WSDL +=cut +sub get_user_problem { + my ($self,$authenKey,$courseName,$userID,$setID,$problemID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $problemData = $soapEnv->{db}->getUserProblem($userID,$setID,$problemID); + if(not defined $problemData) { + return -1; + } + my $problem = new WebworkSOAP::Classes::UserProblem($problemData); + return ($problem); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_IN setID $string +_IN problemID $string +_RETURN $string +=end WSDL +=cut +sub delete_user_problem { + my ($self,$authenKey,$courseName,$userID,$setID,$problemID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + return $soapEnv->{db}->deleteUserProblem($userID,$setID,$problemID); +} + +################################################## +##USER SET +################################################## + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::UserSet +_RETURN $string +=end WSDL +=cut +sub add_user_set { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $newUserSet = $soapEnv->{db}->newUserSet; + %$newUserSet = %$record; + return $soapEnv->{db}->addUserSet($newUserSet); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN record $WebworkSOAP::Classes::UserSet +_RETURN $string +=end WSDL +=cut +sub put_user_set { + my ($self,$authenKey,$courseName,$record) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + return $soapEnv->{db}->addUserSet($record); +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_RETURN @string of names objects. +=end WSDL +=cut +sub list_user_sets { + my ($self,$authenKey,$courseName,$userID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @tempArray = $soapEnv->{db}->listUserSets($userID); + return \@tempArray; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_RETURN @WebworkSOAP::Classes::UserSet of names objects. +=end WSDL +=cut +sub get_all_user_sets { + my ($self,$authenKey,$courseName) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @setData = $soapEnv->{db}->getAllUserSets(); + my @sets; + for(my $i=0;$i<@setData;$i++) { + push(@sets,new WebworkSOAP::Classes::UserSet(@setData[$i])); + } + return \@sets; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userSetIDs $string +_RETURN @WebworkSOAP::Classes::UserSet of names objects. +=end WSDL +=cut +sub get_user_sets { + my ($self,$authenKey,$courseName,$userSetIDs) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my @setData = $soapEnv->{db}->getUserSets(@$userSetIDs); + my @sets; + for(my $i=0;$i<@setData;$i++) { + push(@sets,new WebworkSOAP::Classes::UserSet(@setData[$i])); + } + return \@sets; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_IN setID $string +_RETURN $WebworkSOAP::Classes::UserSet of names objects. +=end WSDL +=cut +sub get_user_set { + my ($self,$authenKey,$courseName,$userID,$setID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + my $setData = $soapEnv->{db}->getUserSet($userID,$setID); + if(not defined $setData) { + return -1; + } + my $set = new WebworkSOAP::Classes::UserSet($setData); + return $set; +} + +=pod +=begin WSDL +_IN authenKey $string +_IN courseName $string +_IN userID $string +_IN setID $string +_RETURN $string +=end WSDL +=cut +sub delete_user_set { + my ($self,$authenKey,$courseName,$userID,$setID) = @_; + my $soapEnv = new WebworkSOAP($authenKey,$courseName); + return $soapEnv->{db}->deleteUserSet($userID,$setID); +} + + +1; --- /dev/null +++ lib/WeBWorK/Utils/DBUpgrade.pm @@ -0,0 +1,695 @@ +################################################################################ +# WeBWorK Online Homework Delivery System +# Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader: webwork2/lib/WeBWorK/Utils/DBUpgrade.pm,v 1.4.2.1 2008/06/24 14:42:58 gage Exp $ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. +################################################################################ + +package WeBWorK::Utils::DBUpgrade; + +=head1 NAME + +WeBWorK::Utils::DBUpgrade - upgrade WeBWorK SQL databases. + +=cut + +use strict; +use warnings; +use WeBWorK::Debug; +use WeBWorK::Utils::CourseManagement qw/listCourses/; + +################################################################################ + +# dummy package variable to localize later +our $self; + +my $i = -1; +our @DB_VERSIONS; + +$DB_VERSIONS[++$i]{desc} = "is the initial version of database, identical to database structure in WeBWorK 2.2.x."; + +$DB_VERSIONS[++$i]{desc} = "adds dbupgrade table to facilitate automatic database upgrades."; +$DB_VERSIONS[ $i]{global_code} = sub { + $self->dbh->do("CREATE TABLE `dbupgrade` (`name` VARCHAR(255) NOT NULL PRIMARY KEY, `value` TEXT)"); + $self->dbh->do("INSERT INTO `dbupgrade` (`name`, `value`) VALUES (?, ?)", {}, "db_version", 1); + $self->register_sql_table("dbupgrade"); +}; + +$DB_VERSIONS[++$i]{desc} = "adds problems_per_page field to set and set_user tables of each course."; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + $self->dbh->do("ALTER TABLE `${course}_set` ADD COLUMN `problems_per_page` INT") + if $self->sql_table_exists("${course}_set"); + $self->dbh->do("ALTER TABLE `${course}_set_user` ADD COLUMN `problems_per_page` INT") + if $self->sql_table_exists("${course}_set_user"); +}; + +$DB_VERSIONS[++$i]{desc} = "adds depths table to keep track of dvipng depth information."; +$DB_VERSIONS[ $i]{global_code} = sub { + $self->dbh->do("CREATE TABLE depths (md5 CHAR(33) NOT NULL, depth SMALLINT, PRIMARY KEY (md5))"); + $self->register_sql_table("depths"); +}; + +$DB_VERSIONS[++$i]{desc} = "changes type of key timestamp field to BIGINT"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + return unless $self->sql_table_exists("${course}_key"); + $self->dbh->do("ALTER TABLE `${course}_key` CHANGE COLUMN `timestamp` `timestamp` BIGINT"); +}; + +$DB_VERSIONS[++$i]{desc} = "changes type of problem_user status field to FLOAT"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + return unless $self->sql_table_exists("${course}_problem_user"); + $self->dbh->do("UPDATE `${course}_problem_user` SET `status`=NULL WHERE `status`=''"); + $self->dbh->do("ALTER TABLE `${course}_problem_user` CHANGE COLUMN `status` `status` FLOAT"); +}; + +$DB_VERSIONS[++$i]{desc} = "changes types of alphanumeric keyfields to TINYBLOB NOT NULL"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + $self->dbh->do("ALTER TABLE `${course}_user` CHANGE COLUMN `user_id` `user_id` TINYBLOB NOT NULL") + if $self->sql_table_exists("${course}_user"); + $self->dbh->do("ALTER TABLE `${course}_password` CHANGE COLUMN `user_id` `user_id` TINYBLOB NOT NULL") + if $self->sql_table_exists("${course}_password"); + $self->dbh->do("ALTER TABLE `${course}_permission` CHANGE COLUMN `user_id` `user_id` TINYBLOB NOT NULL") + if $self->sql_table_exists("${course}_permission"); + $self->dbh->do("ALTER TABLE `${course}_key` CHANGE COLUMN `user_id` `user_id` TINYBLOB NOT NULL") + if $self->sql_table_exists("${course}_key"); + $self->dbh->do("ALTER TABLE `${course}_set` CHANGE COLUMN `set_id` `set_id` TINYBLOB NOT NULL") + if $self->sql_table_exists("${course}_set"); + $self->dbh->do("ALTER TABLE `${course}_problem` CHANGE COLUMN `set_id` `set_id` TINYBLOB NOT NULL") + if $self->sql_table_exists("${course}_problem"); + $self->dbh->do("ALTER TABLE `${course}_set_user` CHANGE COLUMN `user_id` `user_id` TINYBLOB NOT NULL") + if $self->sql_table_exists("${course}_set_user"); + $self->dbh->do("ALTER TABLE `${course}_set_user` CHANGE COLUMN `set_id` `set_id` TINYBLOB NOT NULL") + if $self->sql_table_exists("${course}_set_user"); + $self->dbh->do("ALTER TABLE `${course}_problem_user` CHANGE COLUMN `user_id` `user_id` TINYBLOB NOT NULL") + if $self->sql_table_exists("${course}_problem_user"); + $self->dbh->do("ALTER TABLE `${course}_problem_user` CHANGE COLUMN `set_id` `set_id` TINYBLOB NOT NULL") + if $self->sql_table_exists("${course}_problem_user"); +}; + +$DB_VERSIONS[++$i]{desc} = "fixes KEY length, adds UNIQUE KEY for user table"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + return unless $self->sql_table_eixsts("${course}_user"); + $self->dbh->do("ALTER TABLE `${course}_user` DROP KEY `user_id`"); + $self->dbh->do("ALTER TABLE `${course}_user` ADD UNIQUE KEY (`user_id`(255))"); +}; + +$DB_VERSIONS[++$i]{desc} = "fixes KEY length, adds UNIQUE KEY for password table"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + return unless $self->sql_table_exists("${course}_password"); + $self->dbh->do("ALTER TABLE `${course}_password` DROP KEY `user_id`"); + $self->dbh->do("ALTER TABLE `${course}_password` ADD UNIQUE KEY (`user_id`(255))"); +}; + +$DB_VERSIONS[++$i]{desc} = "fixes KEY length, adds UNIQUE KEY for permission table"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + return unless $self->sql_table_exists("${course}_permission"); + $self->dbh->do("ALTER TABLE `${course}_permission` DROP KEY `user_id`"); + $self->dbh->do("ALTER TABLE `${course}_permission` ADD UNIQUE KEY (`user_id`(255))"); +}; + +$DB_VERSIONS[++$i]{desc} = "fixes KEY length, adds UNIQUE KEY for key table"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + return unless $self->sql_table_exists("${course}_key"); + $self->dbh->do("ALTER TABLE `${course}_key` DROP KEY `user_id`"); + $self->dbh->do("ALTER TABLE `${course}_key` ADD UNIQUE KEY (`user_id`(255))"); +}; + +$DB_VERSIONS[++$i]{desc} = "fixes KEY length, adds UNIQUE KEY for set table"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + return unless $self->sql_table_exists("${course}_set"); + $self->dbh->do("ALTER TABLE `${course}_set` DROP KEY `set_id`"); + $self->dbh->do("ALTER TABLE `${course}_set` ADD UNIQUE KEY (`set_id`(255))"); +}; + +$DB_VERSIONS[++$i]{desc} = "fixes KEY length, adds UNIQUE KEY for problem table"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + return unless $self->sql_table_exists("${course}_problem"); + $self->dbh->do("ALTER TABLE `${course}_problem` DROP KEY `set_id`"); + $self->dbh->do("ALTER TABLE `${course}_problem` ADD UNIQUE KEY (`set_id`(255), `problem_id`)"); + $self->dbh->do("ALTER TABLE `${course}_problem` DROP KEY `problem_id`"); + $self->dbh->do("ALTER TABLE `${course}_problem` ADD KEY (`problem_id`)"); +}; + +$DB_VERSIONS[++$i]{desc} = "fixes KEY length, adds UNIQUE KEY for set_user table"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + return unless $self->sql_table_exists("${course}_set_user"); + $self->dbh->do("ALTER TABLE `${course}_set_user` DROP KEY `user_id`"); + $self->dbh->do("ALTER TABLE `${course}_set_user` ADD UNIQUE KEY (`user_id`(255), `set_id`(255))"); + $self->dbh->do("ALTER TABLE `${course}_set_user` DROP KEY `set_id`"); + $self->dbh->do("ALTER TABLE `${course}_set_user` ADD KEY (`set_id`(255))"); +}; + +$DB_VERSIONS[++$i]{desc} = "fixes KEY length, adds UNIQUE KEY for problem_user table"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + return unless $self->sql_table_exists("${course}_problem_user"); + $self->dbh->do("ALTER TABLE `${course}_problem_user` DROP KEY `user_id`"); + $self->dbh->do("ALTER TABLE `${course}_problem_user` ADD UNIQUE KEY (`user_id`(255), `set_id`(255), `problem_id`)"); + $self->dbh->do("ALTER TABLE `${course}_problem_user` DROP KEY `set_id`"); + $self->dbh->do("ALTER TABLE `${course}_problem_user` ADD KEY (`set_id`(255), `problem_id`)"); + $self->dbh->do("ALTER TABLE `${course}_problem_user` DROP KEY `problem_id`"); + $self->dbh->do("ALTER TABLE `${course}_problem_user` ADD KEY (`problem_id`)"); +}; + +$DB_VERSIONS[++$i]{desc} = "changes psvn index from PRIMARY KEY to UNIQUE KEY"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + return unless $self->sql_table_exists("${course}_set_user"); + $self->dbh->do("ALTER TABLE `${course}_set_user` ADD UNIQUE KEY (`psvn`)"); + $self->dbh->do("ALTER TABLE `${course}_set_user` DROP PRIMARY KEY"); +}; + +$DB_VERSIONS[++$i]{desc} = "adds hide_score and hide_work fields to set and set_user"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + if ( $self->sql_table_exists("${course}_set") ) { + $self->dbh->do("ALTER TABLE `${course}_set` ADD COLUMN `hide_score` ENUM('0','1')"); + $self->dbh->do("ALTER TABLE `${course}_set` ADD COLUMN `hide_work` ENUM('0','1')"); + } + if ( $self->sql_table_exists("${course}_set_user") ) { + $self->dbh->do("ALTER TABLE `${course}_set_user` ADD COLUMN `hide_score` ENUM('0','1')"); + $self->dbh->do("ALTER TABLE `${course}_set_user` ADD COLUMN `hide_work` ENUM('0','1')"); + } +}; + +$DB_VERSIONS[++$i]{desc} = "updates hide_score and hide_work in set and set_user tables to allow more (and more descriptive) possible values"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + if ( $self->sql_table_exists("${course}_set") ) { + $self->dbh->do("ALTER TABLE `${course}_set` MODIFY COLUMN `hide_score` ENUM('0','1','2')"); + $self->dbh->do("ALTER TABLE `${course}_set` MODIFY COLUMN `hide_work` ENUM('0','1','2')"); + } + if ( $self->sql_table_exists("${course}_set_user") ) { + $self->dbh->do("ALTER TABLE `${course}_set_user` MODIFY COLUMN `hide_score` ENUM('0','1','2')"); + $self->dbh->do("ALTER TABLE `${course}_set_user` MODIFY COLUMN `hide_work` ENUM('0','1','2')"); + } +}; + +$DB_VERSIONS[++$i]{desc} = "adds time_limit_cap field to set and set_user tables"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + if ( $self->sql_table_exists("${course}_set") ) { + $self->dbh->do("ALTER TABLE `${course}_set` ADD COLUMN `time_limit_cap` ENUM('0','1')"); + } + if ( $self->sql_table_exists("${course}_set_user") ) { + $self->dbh->do("ALTER TABLE `${course}_set_user` ADD COLUMN `time_limit_cap` ENUM('0','1')"); + } +}; + +$DB_VERSIONS[++$i]{desc} = "updates hide_score and hide_work in set and set_user tables to have more descriptive values, set default values"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + if ( $self->sql_table_exists("${course}_set") ) { + $self->dbh->do("ALTER TABLE `${course}_set` MODIFY COLUMN `hide_score` ENUM('N','Y','BeforeAnswerDate') DEFAULT 'N'"); + $self->dbh->do("ALTER TABLE `${course}_set` MODIFY COLUMN `hide_work` ENUM('N','Y','BeforeAnswerDate') DEFAULT 'N'"); + } + if ( $self->sql_table_exists("${course}_set_user") ) { + $self->dbh->do("ALTER TABLE `${course}_set_user` MODIFY COLUMN `hide_score` ENUM('N','Y','BeforeAnswerDate') DEFAULT 'N'"); + $self->dbh->do("ALTER TABLE `${course}_set_user` MODIFY COLUMN `hide_work` ENUM('N','Y','BeforeAnswerDate') DEFAULT 'N'"); + } +}; + +$DB_VERSIONS[++$i]{desc} = "adds locations, location_addresses, set_locations and set_locations_user tables to database, and add restrict_ip to set and set_user."; +$DB_VERSIONS[ $i]{global_code} = sub { + $self->dbh->do("CREATE TABLE locations (location_id TINYBLOB NOT NULL, description TEXT, PRIMARY KEY (location_id(1000)))"); + $self->dbh->do("CREATE TABLE location_addresses (location_id TINYBLOB NOT NULL, ip_mask TINYBLOB NOT NULL, PRIMARY KEY (location_id(500),ip_mask(500)))"); +}; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + + $self->dbh->do("CREATE TABLE `${course}_set_locations` (set_id TINYBLOB NOT NULL, location_id TINYBLOB NOT NULL, PRIMARY KEY (set_id(500),location_id(500)))"); + $self->dbh->do("CREATE TABLE `${course}_set_locations_user` (set_id TINYBLOB NOT NULL, user_id TINYBLOB NOT NULL, location_id TINYBLOB NOT NULL, PRIMARY KEY (set_id(300),user_id(300),location_id(300)))"); + + if ( $self->sql_table_exists("${course}_set") ) { + $self->dbh->do("ALTER TABLE `${course}_set` ADD COLUMN `restrict_ip` enum('No','RestrictTo','DenyFrom') DEFAULT 'No'"); + } + if ( $self->sql_table_exists("${course}_set_user") ) { + $self->dbh->do("ALTER TABLE `${course}_set_user` ADD COLUMN `restrict_ip` enum('No','RestrictTo','DenyFrom')"); + } +}; + +$DB_VERSIONS[++$i]{desc} = "updates defaults for hide_work and hide_score in set_user tables."; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + + if ( $self->sql_table_exists("${course}_set_user") ) { + $self->dbh->do("ALTER TABLE `${course}_set_user` MODIFY COLUMN `hide_score` ENUM('N','Y','BeforeAnswerDate')"); + $self->dbh->do("ALTER TABLE `${course}_set_user` MODIFY COLUMN `hide_work` ENUM('N','Y','BeforeAnswerDate')"); + } +}; + +$DB_VERSIONS[++$i]{desc} = "adds relax_restrict_ip, hide_problem_score columns to set and set_user tables."; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + + if ( $self->sql_table_exists("${course}_set") ) { + $self->dbh->do("ALTER TABLE `${course}_set` ADD COLUMN `relax_restrict_ip` ENUM('No','AfterAnswerDate','AfterVersionAnswerDate') DEFAULT 'No'"); + $self->dbh->do("ALTER TABLE `${course}_set` ADD COLUMN `hide_score_by_problem` ENUM('N','Y') DEFAULT 'N'"); + } + if ( $self->sql_table_exists("${course}_set_user") ) { + $self->dbh->do("ALTER TABLE `${course}_set_user` ADD COLUMN `relax_restrict_ip` ENUM('No','AfterAnswerDate','AfterVersionAnswerDate')"); + $self->dbh->do("ALTER TABLE `${course}_set_user` ADD COLUMN `hide_score_by_problem` ENUM('N','Y')"); + } +}; + +$DB_VERSIONS[++$i]{desc} = "adds set and set_user fields to allow set-level proctor, updates permissions to allow finer-grained regulation of proctoring."; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + if ( $self->sql_table_exists("${course}_permission") ) { + $self->dbh->do("UPDATE `${course}_permission` SET `permission`=3 where `permission`=2"); + } + if ( $self->sql_table_exists("${course}_set") ) { + $self->dbh->do("ALTER TABLE `${course}_set` ADD COLUMN `restricted_login_proctor` ENUM('No','Yes') DEFAULT 'No'"); + } + if ( $self->sql_table_exists("${course}_set_user") ) { + $self->dbh->do("ALTER TABLE `${course}_set_user` ADD COLUMN `restricted_login_proctor` ENUM('No','Yes')"); + } +}; + +$DB_VERSIONS[++$i]{desc} = "adds per-course setting table"; +$DB_VERSIONS[ $i]{course_code} = sub { + my $course = shift; + $self->dbh->do("CREATE TABLE `${course}_setting` (`name` VARCHAR(255) NOT NULL PRIMARY KEY, `value` TEXT)"); + $self->register_sql_table("${course}_setting"); + $self->dbh->do("INSERT INTO `${course}_setting` (`name`, `value`) VALUES (?, ?)", {}, "db_version", $i); +}; +our $FIRST_COURSE_DB_VERSION = $i; + +our $THIS_DB_VERSION = $i; + +################################################################################ + +sub new { + my $invocant = shift; + my $class = ref $invocant || $invocant; + my $self = bless {}, $class; + $self->init(@_); + return $self; +} + +sub init { + my ($self, %options) = @_; + + $self->{dbh} = DBI->connect( + $options{ce}{database_dsn}, + $options{ce}{database_username}, + $options{ce}{database_password}, + { + PrintError => 0, + RaiseError => 1, + }, + ); + $self->{verbose_sub} = $options{verbose_sub} || \&debug; + $self->{confirm_sub} = $options{confirm_sub} || \&ask_permission_stdio; + $self->{ce} = $options{ce}; + $self->{course_db_versions} = {}; +} + +sub ce { return shift->{ce} } +sub dbh { return shift->{dbh} } +sub verbose { my $sub = shift->{verbose_sub}; return &$sub(@_) } +sub confirm { my $sub = shift->{confirm_sub}; return &$sub(@_) } + +sub DESTROY { + my ($self) = @_; + $self->unlock_database; + $self->SUPER::DESTROY if $self->can("SUPER::DESTROY"); +} + +################################################################################ + +sub lock_database { + my ($self) = @_; + + $self->verbose("Obtaining dbupgrade lock...\n"); + my ($lock_status) = $self->dbh->selectrow_array("SELECT GET_LOCK('dbupgrade', 10)"); + if (not defined $lock_status) { + die "Couldn't obtain lock because an error occurred.\n"; + } + if ($lock_status) { + $self->verbose("Got lock.\n"); + } else { + die "Timed out while waiting for lock.\n"; + } +} + +sub unlock_database { + my ($self) = @_; + + $self->verbose("Releasing dbupgrade lock...\n"); + my ($lock_status) = $self->dbh->selectrow_array("SELECT RELEASE_LOCK('dbupgrade')"); + if (not defined $lock_status) { + die "Couldn't release lock because the lock does not exist.\n"; + } + if ($lock_status) { + $self->verbose("Released lock.\n"); + } else { + die "Couldn't release lock because the lock is not held by this thread.\n"; + } +} + +################################################################################ + +sub load_sql_table_list { + my ($self) = @_; + my $sql_tables_ref = $self->dbh->selectcol_arrayref("SHOW TABLES"); + $self->{sql_tables} = {}; @{$self->{sql_tables}}{@$sql_tables_ref} = (); +} + +sub register_sql_table { + my ($self, $table) = @_; + $self->{sql_tables}{$table} = (); +} + +sub unregister_sql_table { + my ($self, $table) = @_; + delete $self->{sql_tables}{$table}; +} + +sub sql_table_exists { + my ($self, $table) = @_; + return exists $self->{sql_tables}{$table}; +} + +################################################################################ + +use constant DB_TABLE_MISSING => -1; +use constant DB_RECORD_MISSING => -2; + +sub get_db_version { + my ($self, $course) = @_; + my $table = defined $course ? "${course}_setting" : "dbupgrade"; + if ($self->sql_table_exists($table)) { + my $table_quoted = $self->dbh->quote_identifier($table); + my @record = $self->dbh->selectrow_array("SELECT `value` FROM $table_quoted WHERE `name`='db_version'"); + if (@record) { + return $record[0]; + } else { + return DB_RECORD_MISSING; + } + } else { + return DB_TABLE_MISSING; + } +} + +my $vers_value_should_be = "The value should always be a positive integer."; +sub check_db_version_format { + my ($self, $db_version) = @_; + if (not defined $db_version) { + return "'db_version' has a NULL value. $vers_value_should_be"; + } elsif ($db_version !~ /^-?\d+$/) { + return "'db_version' is set to the non-numeric value '$db_version'. $vers_value_should_be"; + } elsif ($db_version < 0) { + return "'db_version' is set to the negative value '$db_version'. $vers_value_should_be"; + } elsif ($db_version == 0) { + return "'db_version' is set to 0, which is reserved to indicate a pre-automatic-upgrade version. $vers_value_should_be"; + } else { + # db_version is a positive integer! yay! + return; + } +} + +sub set_db_version { + my ($self, $vers, $course) = @_; + my $table = defined $course ? "${course}_setting" : "dbupgrade"; + my $table_quoted = $self->dbh->quote_identifier($table); + $self->dbh->do("UPDATE $table_quoted SET `value`=? WHERE `name`='db_version'", {}, $vers); +} + +################################################################################ + +sub do_upgrade { + my ($self) = @_; + + $self->lock_database; + $self->load_sql_table_list; + + #### Get system's database version + + my $system_db_version = $self->get_db_version(); + + if ($system_db_version == DB_TABLE_MISSING) { + warn "No 'upgrade' table exists: assuming system database version is 0.\n"; + $system_db_version = 0; + } elsif ($system_db_version == DB_RECORD_MISSING) { + die "The 'dbupgrade' table exists in the database, but no 'db_version' record exists in it. Can't continue.\n"; + } elsif (my $error = $self->check_db_version_format($system_db_version)) { + die "$error Can't continue.\n"; + } elsif ($system_db_version > $THIS_DB_VERSION) { + die "This database's system db_version value is $system_db_version, but the current database version is only $THIS_DB_VERSION. This database was probably used with a newer version of WeBWorK. Can't continue.\n"; + } + + $self->verbose("Initial system db_version is $system_db_version\n"); + + #### Get database version for each course + # If $system_db_version < $FIRST_COURSE_DB_VERSION, most courses will not have + # a db_version, but some might. (Say, if they were imported from a newer + # version of WeBWorK.) + + my @ww_courses = listCourses($self->ce); + $self->{ww_courses} = \@ww_courses; + + my $course_db_versions = $self->{course_db_versions}; + + foreach my $course (@ww_courses) { + my $course_db_version = $self->get_db_version($course); + + if ($system_db_version < $FIRST_COURSE_DB_VERSION) { + + if ($course_db_version == DB_TABLE_MISSING) { + # this is to be expected -- we assume the course is at the current system version + $self->verbose("Course '$course' has no db_version of it's own, assuming system db_version $system_db_version.\n"); + $course_db_versions->{$course} = $system_db_version; + } else { + # there is a settings table -- the course is probably from a later version of WW + warn "The course '$course' already contains a '${course}_setting' table." + ." Settings tables were introduced at db_version $FIRST_COURSE_DB_VERSION," + ." but the current system db_version is only $system_db_version." + ." We'll assume that this course is from a later version of WeBWorK" + ." and try to determine the course's version...\n"; + if ($course_db_version == DB_RECORD_MISSING) { + warn "There is no 'db_version' record in the course's settings table," + ." so we can't determine the version. This course will be excluded from upgrades." + ." If you know the version of this course," + ." add a 'db_version' record with the appropriate value to the '${course}_setting' table.\n"; + } elsif (my $error = check_db_version_format($course_db_version)) { + warn "$error\n"; + warn "There is a 'db_version' record in the course's settings table," + ." but it has an invalid value , so we can't determine the version." + ." This course will be excluded from upgrades." + ." If you know the version of this course," + ." update 'db_version' record in the '${course}_setting' table with the appropriate value.\n"; + } elsif ($course_db_version < $FIRST_COURSE_DB_VERSION) { + warn "This course's version is $course_db_version, which is before per-course versioning was introduced." + ." Therefore, a course at version $course_db_version should have neither a '${course}_setting' table" + ." nor a 'db_version' record in that table. Regardless, we will assume the recorded version is correct.\n"; + $course_db_versions->{$course} = $system_db_version; + } else { + warn "This course's version is $course_db_version, which makes sense.\n"; + $course_db_versions->{$course} = $course_db_version; + } + } + + } else { + + if ($course_db_version == DB_TABLE_MISSING) { + warn "The course '$course' is missing a '${course}_setting' table, so we can't determine the version." + ." This course will be ignored." + ." If you know the version of this course, add a '${course}_setting' table" + ." and add a 'db_version' record with the appropriate value to the table.\n"; + } else { + # there is a settings table -- good + if ($course_db_version == DB_RECORD_MISSING) { + warn "The course '$course' is missing a 'db_version' record in its '${course}_setting' table," + ." so we can't determine the version. This course will be ignored." + ." If you know the version of this course," + ." add a 'db_version' record with the appropriate value to the '${course}_setting' table.\n"; + } elsif (my $error = check_db_version_format($course_db_version)) { + warn "$error\n"; + warn "The course '$course' has an invalid value in the 'db_version' record in its '${course}_setting' table," + ." so we can't determine the version. This course will be ignored." + ." If you know the version of this course," + ." update the 'db_version' record in the '${course}_setting' table with the appropriate value.\n"; + } elsif ($course_db_version < $FIRST_COURSE_DB_VERSION) { + warn "This course's version is $course_db_version, which is before per-course versioning was introduced." + ." Therefore, a course at version $course_db_version should have neither a '${course}_setting' table" + ." nor a 'db_version' record in that table. Regardless, we will assume the recorded version is correct.\n"; + $course_db_versions->{$course} = $course_db_version; + } else { + $self->verbose("Course '$course' has valid db_version $course_db_version.\n"); + $course_db_versions->{$course} = $system_db_version; + } + } + + } + } + + $self->verbose(map { "$_ => $$course_db_versions{$_}\n" } keys %$course_db_versions); + + #### Determine lowest version + + my $lowest_db_version = $system_db_version; + foreach my $v (values %$course_db_versions) { + $lowest_db_version = $v if $v < $lowest_db_version; + } + + $self->verbose("Lowest db_version is $lowest_db_version\n"); + + #### Do the upgrades + + # upgrade_to_version uses this + $self->{system_db_version} = $system_db_version; + + my $vers = $lowest_db_version; + while ($vers < $THIS_DB_VERSION) { + $vers++; + unless ($self->upgrade_to_version($vers)) { + print "\nUpgrading from version ".($vers-1)." to $vers failed.\n\n"; + unless ($self->ask_permission("Ignore this error and go on to the next version?", 0)) { + exit 3; + } + } + } + + #### All done! + + print "\nDatabase is up-to-date at version $vers.\n"; +} + +################################################################################ + +use constant OK => 0; +use constant SKIPPED => 1; +use constant ERROR => 2; + +sub upgrade_to_version { + my ($self, $vers) = @_; + my %info = %{$DB_VERSIONS[$vers]}; + + print "\nUpgrading database from version " . ($vers-1) . " to $vers...\n"; + my $desc = $info{desc} || "has no description."; + print "(Version $vers $desc)\n"; + + if ($self->{system_db_version} < $vers and exists $info{global_code}) { + eval { + local $WeBWorK::Utils::DBUpgrade::self = $self; + $info{global_code}->(); + }; + if ($@) { + print "\nAn error occured while running the system upgrade code for version $vers:\n"; + print "$@"; + return 0 unless $self->ask_permission("Ignore this error and keep going?", 0); + } + } + $self->set_db_version($vers); + + my $do_upgrade = 1; + foreach my $course (@{$self->{ww_courses}}) { + if ($do_upgrade) { + my $result = $self->upgrade_course_to_version($course, $vers); + if ($result == ERROR) { + if ($self->ask_permission("Update course's stored db_version to $vers anyway?", 0)) { + set_db_version($vers, $course); + print "OK, updated course's stored db_version.\n"; + } else { + print "OK, not updating course's stored db_version.\n"; + } + if ($self->ask_permission("Upgrade the remaining courses to version $vers?", 0)) { + print "OK, going on to the next course...\n"; + } else { + print "OK, we'll skip upgrading the rest of the courses to version $vers.\n"; + if ($self->ask_permission("Update the stored db_version for the courses we're skipping, as if we had upgraded them?", 1)) { + $do_upgrade = 0; + } else { + return 0; + } + } + } elsif ($result == OK) { + $self->set_db_version($vers, $course); + } elsif ($result == SKIPPED) { + # do nothing + } + } else { + $self->set_db_version($vers, $course); + } + } + + return 1; +} + +sub upgrade_course_to_version { + my ($self, $course, $vers) = @_; + my $course_db_versions = $self->{course_db_versions}; + my %info = %{$DB_VERSIONS[$vers]}; + + my $course_vers = $course_db_versions->{$course}; + #$self->verbose("course=$course course_vers=$course_vers vers=$vers\n"); + if (not defined $course_vers) { + $self->verbose("Course '$course' has a missing or invalid version -- skipping.\n"); + return SKIPPED; + } elsif ($course_vers == $vers) { + $self->verbose("Course '$course' is already at version $vers -- skipping.\n"); + return SKIPPED; + } elsif ($course_vers > $vers) { + $self->verbose("Course '$course' version $course_vers > target version $vers -- skipping.\n"); + return SKIPPED; + } elsif ($course_vers < $vers-1) { + warn "Course '$course' at version $course_vers, which is too old to upgrade to $vers. This should never happen. Not upgrading.\n"; + return SKIPPED; + } + + $self->verbose("Upgrading course '$course' to version $vers...\n"); + eval { + local $WeBWorK::Utils::DBUpgrade::self = $self; + $info{course_code}->($course); + }; + if ($@) { + print "\nAn error occured while running the course upgrade code for version $vers on course $course:\n"; + print "$@"; + return ERROR; + } else { + return OK; + } +} + +################################################################################ + +sub ask_permission_stdio { + my ($prompt, $default) = @_; + + $default = 1 if not defined $default; + my $options = $default ? "[Y/n]" : "[y/N]"; + + while (1) { + print "$prompt $options "; + my $resp = <STDIN>; + chomp $resp; + return $default if $resp eq ""; + return 1 if lc $resp eq "y"; + return 0 if lc $resp eq "n"; + $prompt = 'Please enter "y" or "n".'; + } +} + +1; + --- /dev/null +++ lib/WebworkSOAP/Classes/Permission.pm @@ -0,0 +1,20 @@ +package WebworkSOAP::Classes::Permission; + +=pod +=begin WSDL + _ATTR user_id $string user_id + _ATTR permission $string permission +=end WSDL +=cut +sub new { + my $self = shift; + my $data = shift; + $self = {}; + $self->{user_id} = $data->user_id; + $self->{permission} = $data->permission; + bless $self; + return $self; +} + + +1; --- /dev/null +++ lib/WebworkSOAP/Classes/User.pm @@ -0,0 +1,33 @@ +package WebworkSOAP::Classes::User; + +=pod +=begin WSDL + _ATTR user_id $string user_i... [truncated message content] |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 14:46:02
|
Log Message: ----------- Adding Setting.pm into the rel-2-4-patches branch Tags: ---- rel-2-4-patches Added Files: ----------- webwork2/lib/WeBWorK/DB/Record: Setting.pm Revision Data ------------- --- /dev/null +++ lib/WeBWorK/DB/Record/Setting.pm @@ -0,0 +1,42 @@ +################################################################################ +# WeBWorK Online Homework Delivery System +# Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader: webwork2/lib/WeBWorK/DB/Record/Setting.pm,v 1.3.2.1 2008/06/24 14:28:46 gage Exp $ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. +################################################################################ + +package WeBWorK::DB::Record::Setting; +use base WeBWorK::DB::Record; + +=head1 NAME + +WeBWorK::DB::Record::Setting - represent a record from the setting table. + +=cut + +use strict; +use warnings; + +use WeBWorK::Utils::DBUpgrade; + +BEGIN { + __PACKAGE__->_fields( + name => { type=>"VARCHAR(255) NOT NULL", key=>1 }, + value => { type=>"TEXT" }, + ); + __PACKAGE__->_initial_records( + { name=>"db_version", value=>$WeBWorK::Utils::DBUpgrade::THIS_DB_VERSION }, + ); +} + +1; + |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 03:58:02
|
Log Message: ----------- set default library to NPL cosmetic changes Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator/Instructor: SetMaker.pm Revision Data ------------- Index: SetMaker.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm,v retrieving revision 1.83 retrieving revision 1.84 diff -Llib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm -Llib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm -u -r1.83 -r1.84 --- lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm +++ lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm @@ -747,7 +747,7 @@ } $libs = CGI::br()."or Problems from".$libs if $libs ne ''; - my $these_widths = "width: 23ex"; + my $these_widths = "width: 25ex"; if($have_local_sets ==0) { $list_of_local_sets = [NO_LOCAL_SET_STRING]; @@ -786,7 +786,7 @@ print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"center"}, "Browse ", - CGI::submit(-name=>"browse_library", -value=>"Problem Library", -style=>$these_widths, @dis1), + CGI::submit(-name=>"browse_library", -value=>"National Problem Library", -style=>$these_widths, @dis1), CGI::submit(-name=>"browse_local", -value=>"Local Problems", -style=>$these_widths, @dis2), CGI::submit(-name=>"browse_mysets", -value=>"From This Course", -style=>$these_widths, @dis3), CGI::submit(-name=>"browse_setdefs", -value=>"Set Definition Files", -style=>$these_widths, @dis4), @@ -981,7 +981,7 @@ ############# Default of which problem selector to display - my $browse_which = $r->param('browse_which') || 'browse_local'; + my $browse_which = $r->param('browse_which') || 'browse_library'; |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 03:56:54
|
Log Message: ----------- Added support for math2 theme Is the dvipng command supposed to have bgTr.... or bgtr... Modified Files: -------------- webwork2/lib/WeBWorK: Constants.pm Revision Data ------------- Index: Constants.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/Constants.pm,v retrieving revision 1.56 retrieving revision 1.57 diff -Llib/WeBWorK/Constants.pm -Llib/WeBWorK/Constants.pm -u -r1.56 -r1.57 --- lib/WeBWorK/Constants.pm +++ lib/WeBWorK/Constants.pm @@ -88,7 +88,7 @@ # but does not give transparent backgrounds. It does not work for version 1.2. It has not # been tested with other versions. # -$WeBWorK::PG::ImageGenerator::DvipngArgs = "-bgTransparent -D120 -q -depth"; +$WeBWorK::PG::ImageGenerator::DvipngArgs = "-bgtransparent -D120 -q -depth"; # If true, don't delete temporary files # @@ -134,9 +134,9 @@ type => 'text'}, { var => 'defaultTheme', doc => 'Theme (refresh page after saving changes to reveal new theme)', - doc2 => 'There are currently three themes (or skins) to choose from: ur, math, and moodle. The theme + doc2 => 'There are currently four themes (or skins) to choose from: ur, math, math2 and moodle. The theme specifies a unified look and feel for the WeBWorK course web pages.', - values => [qw(math ur moodle union)], + values => [qw(math math2 ur moodle union)], type => 'popuplist'}, { var => 'sessionKeyTimeout', doc => 'Inactivity time before a user is required to login again', |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 02:25:05
|
Log Message: ----------- Formatting changes Tags: ---- rel-2-4-patches Modified Files: -------------- pg: README pg/lib: AnswerHash.pm Parser.pm Value.pm pg/lib/Parser: BOP.pm Complex.pm Constant.pm Context.pm Differentiation.pm Function.pm Item.pm List.pm Number.pm String.pm UOP.pm Value.pm Variable.pm pg/lib/Parser/Context: Default.pm Parens.pm pg/lib/Parser/Legacy: NumberWithUnits.pm Numeric.pm PGcomplexmacros.pl pg/lib/Value: AnswerChecker.pm Complex.pm Context.pm Formula.pm Infinity.pm Interval.pm List.pm Matrix.pm Point.pm Real.pm Set.pm pg/lib/Value/Context: Data.pm pg/lib/WeBWorK/PG: Translator.pm pg/macros: IO.pl MathObjects.pl PG.pl PGanswermacros.pl PGauxiliaryFunctions.pl PGbasicmacros.pl PGinfo.pl Parser.pl Value.pl answerComposition.pl answerCustom.pl answerVariableList.pl contextABCD.pl contextIntegerFunctions.pl contextLimitedComplex.pl contextLimitedNumeric.pl contextLimitedPoint.pl contextLimitedPolynomial.pl contextLimitedPowers.pl contextLimitedVector.pl contextPeriodic.pl contextString.pl contextTF.pl dangerousMacros.pl displayMacros.pl parserCustomization.pl parserDifferenceQuotient.pl parserFormulaWithUnits.pl parserFunction.pl parserImplicitEquation.pl parserParametricLine.pl parserPopUp.pl parserRadioButtons.pl parserSolutionFor.pl parserVectorUtils.pl Revision Data ------------- Index: README =================================================================== RCS file: /webwork/cvs/system/pg/README,v retrieving revision 1.2.4.2 retrieving revision 1.2.4.2.2.1 diff -LREADME -LREADME -u -r1.2.4.2 -r1.2.4.2.2.1 --- README +++ README @@ -1,6 +1,6 @@ WeBWorK Program Generation Language - Version 2.4.0 + Version 2.4.5 Copyright 2000-2007, The WeBWorK Project All rights reserved. Index: AnswerHash.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/AnswerHash.pm,v retrieving revision 1.14.2.2 retrieving revision 1.14.2.2.2.1 diff -Llib/AnswerHash.pm -Llib/AnswerHash.pm -u -r1.14.2.2 -r1.14.2.2.2.1 --- lib/AnswerHash.pm +++ lib/AnswerHash.pm @@ -7,10 +7,8 @@ # Copyright @ 1995-2002 WeBWorK Team # All Rights Reserved #################################################################### - #$Id$ - =head1 NAME AnswerHash.pm -- located in the courseScripts directory Index: Value.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value.pm,v retrieving revision 1.53.2.3 retrieving revision 1.53.2.3.2.1 diff -Llib/Value.pm -Llib/Value.pm -u -r1.53.2.3 -r1.53.2.3.2.1 --- lib/Value.pm +++ lib/Value.pm @@ -1,7 +1,6 @@ package Value; my $pkg = 'Value'; use vars qw($context $defaultContext %Type); - use Scalar::Util; use strict; no strict "refs"; @@ -16,7 +15,6 @@ like equality are "fuzzy", meaning that two items are equal when they are "close enough" (by tolerances that are set in the current Context). - =cut @@ -196,7 +194,6 @@ push(@{$$context->{data}{values}},'method','precedence'); - # # Copy an item and its data # @@ -222,7 +219,6 @@ sub getFlag { my $self = shift; my $name = shift; - if (Value::isHash($self)) { return $self->{$name} if defined($self->{$name}); if (defined $self->{equation}) { @@ -235,11 +231,9 @@ return $context->{answerHash}{$name} if defined($context->{answerHash}) && defined($context->{answerHash}{$name}); # use WW answerHash flags first return $context->{flags}{$name} if defined($context->{flags}{$name}); - return shift; } - # # Get or set the context of an object # @@ -283,10 +277,8 @@ sub isHash { my $self = shift; return ref($self) eq 'HASH' || blessedType($self) eq 'HASH'; - } - sub subclassed { my $self = shift; my $obj = shift; my $method = shift; my $code = UNIVERSAL::can($obj,$method); @@ -311,7 +303,6 @@ # # Check if a value is a number, complex, etc. # - sub matchNumber {my $n = shift; $n =~ m/^$$Value::context->{pattern}{signedNumber}$/i} sub matchInfinite {my $n = shift; $n =~ m/^$$Value::context->{pattern}{infinite}$/i} sub isReal {classMatch(shift,'Real')} @@ -319,7 +310,6 @@ sub isContext {class(shift) eq 'Context'} sub isFormula {classMatch(shift,'Formula')} sub isParser {my $v = shift; isBlessed($v) && $v->isa('Parser::Item')} - sub isValue { my $v = shift; return (ref($v) || $v) =~ m/^Value::/ || (isHash($v) && $v->{isValue}) || isa($v,'Value'); @@ -441,22 +431,18 @@ =cut sub showClass { - my $value = shift; if (ref($value) || $value !~ m/::/) { $value = Value::makeValue($value,makeFormula=>0); return "'".$value."'" unless Value::isValue($value); } return $value->showClass(@_) if Value->subclassed($value,"showClass"); - my $class = class($value); - return showType($value) if Value::classMatch($value,'List'); $class .= ' Number' if Value::classMatch($value,'Real','Complex'); $class .= ' of Intervals' if Value::classMatch($value,'Union'); $class = ($value eq '' ? 'Empty Value' : 'Word') if Value::classMatch($value,'String'); return 'a Formula that returns '.showType($value->{tree}) if Value::isFormula($value); - return 'an '.$class if $class =~ m/^[aeio]/i; return 'a '.$class; } @@ -516,7 +502,6 @@ return 'Matrix' if $ltype =~ m/Point|Matrix/; return 'List'; } - return 'Formula' if Value::isFormula($value); return 'Infinity' if Value::classMatch($value,'Infinity'); return 'Number' if Value::isReal($value); @@ -596,10 +581,8 @@ # sub make { my $self = shift; my $class = ref($self) || $self; - my $context = (Value::isContext($_[0]) ? shift : $self->context); bless {$self->hash, data => [@_], context => $context}, $class; - } # @@ -608,7 +591,6 @@ # is not a deep copy.) # sub with { - my $self = shift; bless {%{$self},@_}, ref($self); } @@ -621,7 +603,6 @@ $self = bless {%{$self}}, ref($self); foreach my $id (@_) {delete $self->{$id} if defined $self->{$id}} return $self; - } ###################################################################### @@ -756,13 +737,10 @@ sub promotePrecedence { my $self = shift; my $other = shift; my $context = $self->context; return 0 unless Value::isValue($other); - my $sprec = $self->precedence; my $oprec = $other->precedence; - return (defined($sprec) && defined($oprec) && $sprec < $oprec); } - sub precedence {my $self = shift; return $self->context->{precedence}{$self->class}} sub promote { @@ -825,7 +803,6 @@ sub _sin {(shift)->sin} sub _cos {(shift)->cos} - # # Default stub to call when no function is defined for an operation # @@ -914,9 +891,7 @@ # sub compare_string { my ($l,$r,$flag) = @_; - $l = $l->string; $r = $r->string if Value::isValue($r); - if ($flag) {my $tmp = $l; $l = $r; $r = $tmp} return $l cmp $r; } @@ -1067,11 +1042,9 @@ =head3 Error - Usage: Value->Error("We're sorry..."); or $mathObject->Error("We're still sorry..."); - # # Report an error and die. This can be used within custom answer checkers # to report errors during the check, or when sub-classing a MathObject to @@ -1081,16 +1054,12 @@ =cut sub Error { - my $self = (UNIVERSAL::can($_[0],"getFlag") ? shift : "Value"); my $message = shift; my $context = $self->context; - $message = [$message,@_] if scalar(@_) > 0; - $context->setError($message,''); $message = $context->{error}{message}; die $message . traceback() if $self->getFlag('showTraceback'); - die $message . getCaller(); } Index: Parser.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser.pm,v retrieving revision 1.32.2.2 retrieving revision 1.32.2.2.2.1 diff -Llib/Parser.pm -Llib/Parser.pm -u -r1.32.2.2 -r1.32.2.2.2.1 --- lib/Parser.pm +++ lib/Parser.pm @@ -35,7 +35,6 @@ variables => {}, values => {}, context => $context, }, $class; - if (Value::isParser($string) || Value::isFormula($string)) { my $tree = $string; $tree = $tree->{tree} if defined $tree->{tree}; $math->{tree} = $tree->copy($math); @@ -53,7 +52,6 @@ return $math; } - # # Get the object's context, or the default one # @@ -734,7 +732,6 @@ # Sets the values of variables for evaluation purposes # sub setValues { - my $self = shift; my ($xref,$value,$type); my $context = $self->context; my $variables = $context->{variables}; @@ -759,7 +756,6 @@ $v->inContext($self->context) if $v->context != $self->context; $self->{values}{$x} = $v; } - } } Index: Number.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Number.pm,v retrieving revision 1.13.4.2 retrieving revision 1.13.4.2.2.1 diff -Llib/Parser/Number.pm -Llib/Parser/Number.pm -u -r1.13.4.2 -r1.13.4.2.2.1 --- lib/Parser/Number.pm +++ lib/Parser/Number.pm @@ -3,16 +3,13 @@ # Implements the Number class # package Parser::Number; - use strict; no strict "refs"; our @ISA = qw(Parser::Item); - $Parser::class->{Number} = 'Parser::Number'; sub new { my $self = shift; my $class = ref($self) || $self; - my $equation = shift; my $context = $equation->{context}; my ($value,$ref) = @_; return $self->Item("Complex",$context)->new($equation,$value,$ref) @@ -24,7 +21,6 @@ type => $Value::Type{number}, isConstant => 1, ref => $ref, equation => $equation, }, $class; - $num->weaken; my $x = $num->Package("Real")->make($context,$value); $num->{isOne} = 1 if $x eq 1; Index: Complex.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Complex.pm,v retrieving revision 1.8.2.2 retrieving revision 1.8.2.2.2.1 diff -Llib/Parser/Complex.pm -Llib/Parser/Complex.pm -u -r1.8.2.2 -r1.8.2.2.2.1 --- lib/Parser/Complex.pm +++ lib/Parser/Complex.pm @@ -3,11 +3,9 @@ # Implements the Complex class # package Parser::Complex; - use strict; no strict "refs"; our @ISA = qw(Parser::Item); - $Parser::class->{Complex} = 'Parser::Complex'; sub new { @@ -22,10 +20,8 @@ value => $value, type => $Value::Type{complex}, isConstant => 1, ref => $ref, equation => $equation, }, $class; - $num->weaken; my $z = $self->Package("Complex",$context)->make($context,@{$value}); - $num->{isOne} = 1 if ($z cmp 1) == 0; $num->{isZero} = 1 if $z == 0; return $num; Index: Value.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Value.pm,v retrieving revision 1.17.6.2 retrieving revision 1.17.6.2.2.1 diff -Llib/Parser/Value.pm -Llib/Parser/Value.pm -u -r1.17.6.2 -r1.17.6.2.2.1 --- lib/Parser/Value.pm +++ lib/Parser/Value.pm @@ -4,11 +4,9 @@ # (used to store constant Vector values, etc.) # package Parser::Value; - use strict; no strict "refs"; our @ISA = qw(Parser::Item); - $Parser::class->{Value} = 'Parser::Value'; # Index: List.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/List.pm,v retrieving revision 1.17.6.2 retrieving revision 1.17.6.2.2.1 diff -Llib/Parser/List.pm -Llib/Parser/List.pm -u -r1.17.6.2 -r1.17.6.2.2.1 --- lib/Parser/List.pm +++ lib/Parser/List.pm @@ -3,11 +3,9 @@ # Implements base List class. # package Parser::List; - use strict; no strict "refs"; our @ISA = qw(Parser::Item); - $Parser::class->{List} = 'Parser::List'; # Index: Context.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Context.pm,v retrieving revision 1.16.2.2 retrieving revision 1.16.2.2.2.1 diff -Llib/Parser/Context.pm -Llib/Parser/Context.pm -u -r1.16.2.2 -r1.16.2.2.2.1 --- lib/Parser/Context.pm +++ lib/Parser/Context.pm @@ -2,11 +2,9 @@ package Parser::Context; my $pkg = "Parser::Context"; - use strict; no strict "refs"; our @ISA = ("Value::Context"); - # # Create a new Context object and initialize its data lists # @@ -123,8 +121,6 @@ - - # # Access to the data lists # @@ -167,17 +163,14 @@ } # - # Get a copy of a named context # (either from the (optional) list provided, the main user's list # or from the default list) # - sub getCopy { my $self = shift; my $contextTable; $contextTable = shift if !defined $_[0] || ref($_[0]) eq 'HASH'; $contextTable = $userContext unless $contextTable; - my $name = shift; my $context = $contextTable->{$name}; $context = $Parser::Context::Default::context{$name} unless $context; return unless $context; Index: Constant.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Constant.pm,v retrieving revision 1.9.6.2 retrieving revision 1.9.6.2.2.1 diff -Llib/Parser/Constant.pm -Llib/Parser/Constant.pm -u -r1.9.6.2 -r1.9.6.2.2.1 --- lib/Parser/Constant.pm +++ lib/Parser/Constant.pm @@ -3,11 +3,9 @@ # Implements named constants (e, pi, etc.) # package Parser::Constant; - use strict; no strict "refs"; our @ISA = qw(Parser::Item); - $Parser::class->{Constant} = 'Parser::Constant'; # @@ -41,7 +39,6 @@ if (Value::isFormula($data)) { $data = $data->copy; $data->{values} = $self->{equation}{values}; - $data = $data->{tree}->eval->inContext($context); return $data; } elsif (ref($data) eq 'ARRAY') { Index: String.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/String.pm,v retrieving revision 1.11.6.2 retrieving revision 1.11.6.2.2.1 diff -Llib/Parser/String.pm -Llib/Parser/String.pm -u -r1.11.6.2 -r1.11.6.2.2.1 --- lib/Parser/String.pm +++ lib/Parser/String.pm @@ -4,11 +4,9 @@ # (Used for things like INFINITY, and so on) # package Parser::String; - use strict; no strict "refs"; our @ISA = qw(Parser::Item); - $Parser::class->{String} = 'Parser::String'; # Index: Differentiation.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Differentiation.pm,v retrieving revision 1.9.4.2 retrieving revision 1.9.4.2.2.1 diff -Llib/Parser/Differentiation.pm -Llib/Parser/Differentiation.pm -u -r1.9.4.2 -r1.9.4.2.2.1 --- lib/Parser/Differentiation.pm +++ lib/Parser/Differentiation.pm @@ -602,7 +602,6 @@ sub Parser::List::AbsoluteValue::D { my $self = shift; my $x = $self->{coords}[0]->copy; my $equation = $self->{equation}; - my $BOP = $self->Item("BOP"); return $BOP->new($equation,"*", Index: BOP.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/BOP.pm,v retrieving revision 1.16.2.2 retrieving revision 1.16.2.2.2.1 diff -Llib/Parser/BOP.pm -Llib/Parser/BOP.pm -u -r1.16.2.2 -r1.16.2.2.2.1 --- lib/Parser/BOP.pm +++ lib/Parser/BOP.pm @@ -4,11 +4,9 @@ # package Parser::BOP; - use strict; no strict "refs"; our @ISA = qw(Parser::Item); - $Parser::class->{BOP} = 'Parser::BOP'; # Index: Variable.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Variable.pm,v retrieving revision 1.9.2.2 retrieving revision 1.9.2.2.2.1 diff -Llib/Parser/Variable.pm -Llib/Parser/Variable.pm -u -r1.9.2.2 -r1.9.2.2.2.1 --- lib/Parser/Variable.pm +++ lib/Parser/Variable.pm @@ -3,11 +3,9 @@ # Implements named variables # package Parser::Variable; - use strict; no strict "refs"; our @ISA = qw(Parser::Item); - $Parser::class->{Variable} = 'Parser::Variable'; # @@ -29,7 +27,6 @@ $equation->Error(["Variable '%s' is not defined in this context",$name],$ref) if $variables-> {$name}{parameter} && $equation->{context}{flags}{no_parameters}; $equation->{variables}{$name} = 1; - my $def = $variables->{$name}; my $v = bless { name => $name, def => $def, type => $def->{type}, Index: Function.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Function.pm,v retrieving revision 1.18.6.2 retrieving revision 1.18.6.2.2.1 diff -Llib/Parser/Function.pm -Llib/Parser/Function.pm -u -r1.18.6.2 -r1.18.6.2.2.1 --- lib/Parser/Function.pm +++ lib/Parser/Function.pm @@ -4,7 +4,6 @@ # package Parser::Function; - use strict; no strict "refs"; our @ISA = qw(Parser::Item); Index: Item.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Item.pm,v retrieving revision 1.8.6.2 retrieving revision 1.8.6.2.2.1 diff -Llib/Parser/Item.pm -Llib/Parser/Item.pm -u -r1.8.6.2 -r1.8.6.2.2.1 --- lib/Parser/Item.pm +++ lib/Parser/Item.pm @@ -53,34 +53,6 @@ } # -# Get the equation context -# -sub context { - my $self = shift; - return (ref($self) ? $self->{equation}{context} : Value->context); -} - -# -# Get the package for a given Parser class -# -sub Item { - my $self = shift; my $class = shift; - my $context = (Value::isContext($_[0]) ? shift : $self->context); - return $context->{parser}{$class} if defined $context->{parser}{$class}; - return "Parser::$class" if defined @{"Parser::${class}::ISA"}; - Value::Error("No such package 'Parser::%s'",$class); -} - -# -# Same but for Value classes -# -sub Package { - my $self = shift; my $class = shift; - my $context = (Value::isContext($_[0]) ? shift : $self->context); - $context->Package($class); -} - -# # Get various type information # sub type {my $self = shift; return $self->{type}{name}} Index: UOP.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/UOP.pm,v retrieving revision 1.16.2.2 retrieving revision 1.16.2.2.2.1 diff -Llib/Parser/UOP.pm -Llib/Parser/UOP.pm -u -r1.16.2.2 -r1.16.2.2.2.1 --- lib/Parser/UOP.pm +++ lib/Parser/UOP.pm @@ -3,11 +3,9 @@ # Implements the base Unary Operator class # package Parser::UOP; - use strict; no strict "refs"; our @ISA = qw(Parser::Item); - $Parser::class->{UOP} = 'Parser::UOP'; sub new { Index: Parens.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Context/Parens.pm,v retrieving revision 1.4.6.2 retrieving revision 1.4.6.2.2.1 diff -Llib/Parser/Context/Parens.pm -Llib/Parser/Context/Parens.pm -u -r1.4.6.2 -r1.4.6.2.2.1 --- lib/Parser/Context/Parens.pm +++ lib/Parser/Context/Parens.pm @@ -11,7 +11,6 @@ $self->{dataName} = 'parens'; $self->{name} = 'parenthesis'; $self->{Name} = 'Parenthesis'; - $self->{namePattern} = qr/\S+/; } @@ -31,7 +30,6 @@ delete $self->{tokens}{$data->{close}} unless $data->{hidden} || $data->{close} eq $token; } - # # Always retain 'start' since it si crucial to the parser # Index: Default.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Context/Default.pm,v retrieving revision 1.37.2.2 retrieving revision 1.37.2.2.2.1 diff -Llib/Parser/Context/Default.pm -Llib/Parser/Context/Default.pm -u -r1.37.2.2 -r1.37.2.2.2.1 --- lib/Parser/Context/Default.pm +++ lib/Parser/Context/Default.pm @@ -132,7 +132,6 @@ 'e' => exp(1), 'pi' => 4*atan2(1,1), 'i' => Value::Complex->new(0,1), - 'j' => Value::Vector->new(0,1,0)->with(ijk=>1), 'k' => Value::Vector->new(0,0,1)->with(ijk=>1), '_blank_' => {value => 0, hidden => 1, string => "", TeX => ""}, Index: NumberWithUnits.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Legacy/NumberWithUnits.pm,v retrieving revision 1.8.2.2 retrieving revision 1.8.2.2.2.1 diff -Llib/Parser/Legacy/NumberWithUnits.pm -Llib/Parser/Legacy/NumberWithUnits.pm -u -r1.8.2.2 -r1.8.2.2.2.1 --- lib/Parser/Legacy/NumberWithUnits.pm +++ lib/Parser/Legacy/NumberWithUnits.pm @@ -157,8 +157,6 @@ sub cmp_reparse {Value::cmp_parse(@_)} -sub _compare {Value::binOp(@_,'compare')} - ###################################################################### # Index: PGcomplexmacros.pl =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Legacy/PGcomplexmacros.pl,v retrieving revision 1.3.2.2 retrieving revision 1.3.2.2.2.1 diff -Llib/Parser/Legacy/PGcomplexmacros.pl -Llib/Parser/Legacy/PGcomplexmacros.pl -u -r1.3.2.2 -r1.3.2.2.2.1 --- lib/Parser/Legacy/PGcomplexmacros.pl +++ lib/Parser/Legacy/PGcomplexmacros.pl @@ -5,11 +5,9 @@ # Copyright @ 1995-2002 The WeBWorK Team # All Rights Reserved #################################################################### - #$Id$ - =head1 NAME Macros for complex numbers for the PG language Index: Numeric.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Parser/Legacy/Numeric.pm,v retrieving revision 1.2.6.2 retrieving revision 1.2.6.2.2.1 diff -Llib/Parser/Legacy/Numeric.pm -Llib/Parser/Legacy/Numeric.pm -u -r1.2.6.2 -r1.2.6.2.2.1 --- lib/Parser/Legacy/Numeric.pm +++ lib/Parser/Legacy/Numeric.pm @@ -25,8 +25,6 @@ step => {class => 'Parser::Legacy::Numeric', perl => 'Parser::Legacy::Numeric::do_step'}, fact => {class => 'Parser::Legacy::Numeric', perl => 'Parser::Legacy::Numeric::do_fact'}, ); - $context->{name} = "LegacyNumeric"; 1; - Index: Real.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Real.pm,v retrieving revision 1.24.2.2 retrieving revision 1.24.2.2.2.1 diff -Llib/Value/Real.pm -Llib/Value/Real.pm -u -r1.24.2.2 -r1.24.2.2.2.1 --- lib/Value/Real.pm +++ lib/Value/Real.pm @@ -18,7 +18,6 @@ my $context = (Value::isContext($_[0]) ? shift : $self->context); my $x = shift; $x = [$x,@_] if scalar(@_) > 0; return $x->inContext($context) if Value::isReal($x); - $x = [$x] unless ref($x) eq 'ARRAY'; Value::Error("Can't convert ARRAY of length %d to %s",scalar(@{$x}),Value::showClass($self)) unless (scalar(@{$x}) == 1); Index: Complex.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Complex.pm,v retrieving revision 1.18.6.2 retrieving revision 1.18.6.2.2.1 diff -Llib/Value/Complex.pm -Llib/Value/Complex.pm -u -r1.18.6.2 -r1.18.6.2.2.1 --- lib/Value/Complex.pm +++ lib/Value/Complex.pm @@ -3,12 +3,10 @@ package Value::Complex; my $pkg = 'Value::Complex'; - use strict; no strict "refs"; our @ISA = qw(Value); our $i; our $pi; - # # Check that the inputs are: # one or two real numbers, or @@ -104,7 +102,6 @@ } sub div { - my ($self,$l,$r,$other) = Value::checkOpOrderWithPromote(@_); my ($a,$b) = $l->value; my ($c,$d) = $r->value; my $x = $c*$c + $d*$d; @@ -120,7 +117,6 @@ return exp($r * log($l)) } - sub modulo { my ($self,$l,$r,$other) = Value::checkOpOrderWithPromote(@_); return $self->inherit($other)->make(0) if abs($r)->value == 0; # non-fuzzy check Index: List.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/List.pm,v retrieving revision 1.19.6.2 retrieving revision 1.19.6.2.2.1 diff -Llib/Value/List.pm -Llib/Value/List.pm -u -r1.19.6.2 -r1.19.6.2.2.1 --- lib/Value/List.pm +++ lib/Value/List.pm @@ -5,7 +5,6 @@ package Value::List; my $pkg = 'Value::List'; - use strict; no strict "refs"; our @ISA = qw(Value); @@ -15,7 +14,6 @@ # sub new { my $self = shift; my $class = ref($self) || $self; - my $context = (Value::isContext($_[0]) ? shift : $self->context); my $def = $context->lists->get("List"); my $p = shift; my $isFormula = 0; Index: Context.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Context.pm,v retrieving revision 1.10.6.2 retrieving revision 1.10.6.2.2.1 diff -Llib/Value/Context.pm -Llib/Value/Context.pm -u -r1.10.6.2 -r1.10.6.2.2.1 --- lib/Value/Context.pm +++ lib/Value/Context.pm @@ -85,7 +85,6 @@ foreach my $data (@{$context->{data}{values}}) { $context->{$data} = {%{$self->{$data}}}; } - $context->{error}{msg} = {%{$self->{error}{msg}}}; $context->{error}{convert} = $self->{error}{convert} if defined $self->{error}{convert}; @@ -94,7 +93,6 @@ return $context; } - # # Returns the package name for the specificied Value object class # (as specified by the context's {value} hash, or "Value::name"). Index: Infinity.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Infinity.pm,v retrieving revision 1.9.6.2 retrieving revision 1.9.6.2.2.1 diff -Llib/Value/Infinity.pm -Llib/Value/Infinity.pm -u -r1.9.6.2 -r1.9.6.2.2.1 --- lib/Value/Infinity.pm +++ lib/Value/Infinity.pm @@ -3,7 +3,6 @@ package Value::Infinity; my $pkg = 'Value::Infinity'; - use strict; no strict "refs"; our @ISA = qw(Value); Index: Set.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Set.pm,v retrieving revision 1.10.6.2 retrieving revision 1.10.6.2.2.1 diff -Llib/Value/Set.pm -Llib/Value/Set.pm -u -r1.10.6.2 -r1.10.6.2.2.1 --- lib/Value/Set.pm +++ lib/Value/Set.pm @@ -3,7 +3,6 @@ package Value::Set; my $pkg = 'Value::Set'; - use strict; no strict "refs"; our @ISA = qw(Value); Index: AnswerChecker.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/AnswerChecker.pm,v retrieving revision 1.91.2.2 retrieving revision 1.91.2.2.2.1 diff -Llib/Value/AnswerChecker.pm -Llib/Value/AnswerChecker.pm -u -r1.91.2.2 -r1.91.2.2.2.1 --- lib/Value/AnswerChecker.pm +++ lib/Value/AnswerChecker.pm @@ -90,7 +90,6 @@ @_, ); $ans->{debug} = $ans->{rh_ans}{debug}; - $ans->install_evaluator(sub { my $ans = shift; $ans->{_filter_name} = "MathObjects answer checker"; @@ -126,9 +125,6 @@ $context->clearError(); $context->{answerHash} = $ans; # values here can override context flags - $context->{answerHash} = $ans; # values here can override context flags - - # # Parse and evaluate the student answer # @@ -244,10 +240,8 @@ my $context = (Value::isValue($self) ? $self->context : Value->context); return eval {$self == $other} unless ref($ans->{checker}) eq 'CODE'; my @equal = eval {&{$ans->{checker}}($self,$other,$ans,$nth,@_)}; - if (!defined($equal) && $@ ne '' && (!$context->{error}{flag} || $ans->{showAllErrors})) { $context->setError(["<I>An error occurred while checking your$nth answer:</I>\n". - '<DIV STYLE="margin-left:1em">%s</DIV>',$@],'',undef,undef,$CMP_ERROR); warn "Please inform your instructor that an error occurred while checking your answer"; } @@ -2056,10 +2050,8 @@ # sub value { my $self = shift; - return $self unless defined $self->{tree}{coords}; my $context = $self->context; - my @array = (); if ($self->{tree}->type eq 'Matrix') { foreach my $row (@{$self->{tree}->coords}) { Index: Formula.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Formula.pm,v retrieving revision 1.43.2.2 retrieving revision 1.43.2.2.2.1 diff -Llib/Value/Formula.pm -Llib/Value/Formula.pm -u -r1.43.2.2 -r1.43.2.2.2.1 --- lib/Value/Formula.pm +++ lib/Value/Formula.pm @@ -8,14 +8,11 @@ use strict; no strict "refs"; our @ISA = qw(Parser Value); - - my $UNDEF = bless {}, "UNDEF"; # used for undefined points # # Call Parser to make the new Formula - # sub new { my $self = shift; @@ -35,7 +32,6 @@ # as the formula itself. # sub with { - my $self = shift; my %hash = @_; $self = $self->SUPER::with(@_); $self->{tree} = $self->{tree}->copy($self); # make a new copy pointing to the new equation. @@ -84,7 +80,6 @@ if (ref($l) eq $class || ref($l) eq $pkg) { $formula->{context} = $l->{context}; $l = $l->{tree}->copy($formula); - } else { $l = $self->new($l)->{tree}->copy($formula); } @@ -446,7 +441,6 @@ } push @A, [@a]; push @b, [(&$F(@p,@P)-$v->[$i])->value]; } - # # Use MatrixReal1.pm to solve system of linear equations # Index: Interval.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Interval.pm,v retrieving revision 1.28.6.2 retrieving revision 1.28.6.2.2.1 diff -Llib/Value/Interval.pm -Llib/Value/Interval.pm -u -r1.28.6.2 -r1.28.6.2.2.1 --- lib/Value/Interval.pm +++ lib/Value/Interval.pm @@ -8,7 +8,6 @@ use strict; no strict "refs"; our @ISA = qw(Value); - # # Convert a value to an interval. The value consists of # an open paren string, one or two real numbers or infinities, @@ -16,7 +15,6 @@ # sub new { my $self = shift; my $class = ref($self) || $self; - my $context = (Value::isContext($_[0]) ? shift : $self->context); if (scalar(@_) == 1) { my $x = Value::makeValue($_[0],context=>$context); Index: Matrix.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Matrix.pm,v retrieving revision 1.22.4.2 retrieving revision 1.22.4.2.2.1 diff -Llib/Value/Matrix.pm -Llib/Value/Matrix.pm -u -r1.22.4.2 -r1.22.4.2.2.1 --- lib/Value/Matrix.pm +++ lib/Value/Matrix.pm @@ -10,7 +10,6 @@ use strict; no strict "refs"; our @ISA = qw(Value); - # # Convert a value to a matrix. The value can be: # a list of numbers or list of (nested) references to arrays of numbers, @@ -191,7 +190,6 @@ Value::Error("Can't subtract Matrices with different dimensions") unless scalar(@l) == scalar(@r); my @s = (); - foreach my $i (0..scalar(@l)-1) {push(@s,$l[$i] - $r[$i])} return $self->inherit($other)->make(@s); } Index: Point.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Point.pm,v retrieving revision 1.18.6.2 retrieving revision 1.18.6.2.2.1 diff -Llib/Value/Point.pm -Llib/Value/Point.pm -u -r1.18.6.2 -r1.18.6.2.2.1 --- lib/Value/Point.pm +++ lib/Value/Point.pm @@ -8,7 +8,6 @@ use strict; no strict "refs"; our @ISA = qw(Value); - # # Convert a value to a point. The value can be # a list of numbers, or an reference to an array of numbers @@ -61,7 +60,6 @@ # sub add { - my ($self,$l,$r,$other) = Value::checkOpOrderWithPromote(@_); my @l = $l->value; my @r = $r->value; Value::Error("Can't add Points with different numbers of coordinates") @@ -72,7 +70,6 @@ } sub sub { - my ($self,$l,$r,$other) = Value::checkOpOrderWithPromote(@_); my @l = $l->value; my @r = $r->value; Value::Error("Can't subtract Points with different numbers of coordinates") @@ -80,7 +77,6 @@ my @s = (); foreach my $i (0..scalar(@l)-1) {push(@s,$l[$i] - $r[$i])} return $self->inherit($other)->make(@s); - } sub mult { Index: Data.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Context/Data.pm,v retrieving revision 1.9.6.2 retrieving revision 1.9.6.2.2.1 diff -Llib/Value/Context/Data.pm -Llib/Value/Context/Data.pm -u -r1.9.6.2 -r1.9.6.2.2.1 --- lib/Value/Context/Data.pm +++ lib/Value/Context/Data.pm @@ -49,7 +49,6 @@ $copy->{$name} = $data->{$name}; } } - $self->{tokens} = {%{$orig->{tokens}}}; foreach my $p (keys %{$orig->{patterns}}) { $self->{patterns}{$p} = Index: Translator.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/WeBWorK/PG/Translator.pm,v retrieving revision 1.18.2.2 retrieving revision 1.18.2.2.2.1 diff -Llib/WeBWorK/PG/Translator.pm -Llib/WeBWorK/PG/Translator.pm -u -r1.18.2.2 -r1.18.2.2.2.1 --- lib/WeBWorK/PG/Translator.pm +++ lib/WeBWorK/PG/Translator.pm @@ -154,6 +154,8 @@ my $class = shift; my $safe_cmpt = new Safe; #('PG_priv'); my $self = { + preprocess_code => \&default_preprocess_code, + postprocess_code => \&default_postprocess_code, envir => undef, PG_PROBLEM_TEXT_ARRAY_REF => [], PG_PROBLEM_TEXT_REF => 0, @@ -882,13 +884,19 @@ ########################################## ###### PG preprocessing code ############# ########################################## - # BEGIN_TEXT and END_TEXT must occur on a line by themselves. - $evalString =~ s/\n\s*END_TEXT[\s;]*\n/\nEND_TEXT\n/g; - $evalString =~ s/\n\s*BEGIN_TEXT[\s;]*\n/\nTEXT\(EV3\(<<'END_TEXT'\)\);\n/g; - $evalString =~ s/ENDDOCUMENT.*/ENDDOCUMENT();/s; # remove text after ENDDOCUMENT + + $evalString = &{$self->{preprocess_code}}($evalString); + + +# # default_preprocess_code +# # BEGIN_TEXT and END_TEXT must occur on a line by themselves. +# $evalString =~ s/\n\s*END_TEXT[\s;]*\n/\nEND_TEXT\n/g; +# $evalString =~ s/\n\s*BEGIN_TEXT[\s;]*\n/\nTEXT\(EV3\(<<'END_TEXT'\)\);\n/g; +# $evalString =~ s/ENDDOCUMENT.*/ENDDOCUMENT();/s; # remove text after ENDDOCUMENT +# +# $evalString =~ s/\\/\\\\/g; # \ can't be used for escapes because of TeX conflict +# $evalString =~ s/~~/\\/g; # use ~~ as escape instead, use # for comments - $evalString =~ s/\\/\\\\/g; # \ can't be used for escapes because of TeX conflict - $evalString =~ s/~~/\\/g; # use ~~ as escape instead, use # for comments =pod @@ -922,6 +930,12 @@ ########## end EVALUATION code ########### ############################################################################# + ########################################## + ###### PG postprocessing code ############# + ########################################## + $PG_PROBLEM_TEXT_REF = &{$self->{postprocess_code}}($PG_PROBLEM_TEXT_REF); + + =pod (5) B<Process errors> @@ -960,7 +974,7 @@ $self -> {errors}."\r\n" . "****************<BR>\n"); - push(@PROBLEM_TEXT_OUTPUT , "------Input Read\r\n"); + push(@PROBLEM_TEXT_OUTPUT , "------Input Read\r\n"); $self->{source} =~ s/</</g; @input=split("\n", $self->{source}); $lineNumber = 1; @@ -1607,6 +1621,37 @@ } +sub original_preprocess_code { + my $evalString = shift; + # BEGIN_TEXT and END_TEXT must occur on a line by themselves. + $evalString =~ s/\n\s*END_TEXT[\s;]*\n/\nEND_TEXT\n/g; + $evalString =~ s/\n\s*BEGIN_TEXT[\s;]*\n/\nTEXT\(EV3\(<<'END_TEXT'\)\);\n/g; + $evalString =~ s/ENDDOCUMENT.*/ENDDOCUMENT();/s; # remove text after ENDDOCUMENT + + $evalString =~ s/\\/\\\\/g; # \ can't be used for escapes because of TeX conflict + $evalString =~ s/~~/\\/g; # use ~~ as escape instead, use # for comments + $evalString; +} +sub default_preprocess_code { + my $evalString = shift; + # BEGIN_TEXT and END_TEXT must occur on a line by themselves. + $evalString =~ s/\n\s*END_TEXT[\s;]*\n/\nEND_TEXT\n/g; + $evalString =~ s/\n\s*END_SOLUTION[\s;]*\n/\nEND_TEXT\n/g; + $evalString =~ s/\n\s*END_HINT[\s;]*\n/\nEND_TEXT\n/g; + $evalString =~ s/\n\s*BEGIN_TEXT[\s;]*\n/\nTEXT\(EV3\(<<'END_TEXT'\)\);\n/g; + $evalString =~ s/\n\s*BEGIN_SOLUTION[\s;]*\n/\nTEXT\(EV3\(<<'END_SOLUTION'\)\);\n/g; + $evalString =~ s/\n\s*BEGIN_HINT[\s;]*\n/\nTEXT\(EV3\(<<'END_HINT'\)\);\n/g; + $evalString =~ s/ENDDOCUMENT.*/ENDDOCUMENT();/s; # remove text after ENDDOCUMENT + + $evalString =~ s/\\/\\\\/g; # \ can't be used for escapes because of TeX conflict + $evalString =~ s/~~/\\/g; # use ~~ as escape instead, use # for comments + $evalString; +} +sub default_postprocess_code { + my $evalString_ref = shift; + $evalString_ref; +} + sub dumpvar { my ($packageName) = @_; Index: parserParametricLine.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/parserParametricLine.pl,v retrieving revision 1.5.2.2 retrieving revision 1.5.2.2.2.1 diff -Lmacros/parserParametricLine.pl -Lmacros/parserParametricLine.pl -u -r1.5.2.2 -r1.5.2.2.2.1 --- macros/parserParametricLine.pl +++ macros/parserParametricLine.pl @@ -16,7 +16,6 @@ =head1 NAME - parserParametricLine.pl - Implements Formulas that represent parametric lines. =head1 DESCRIPTION @@ -107,7 +106,6 @@ return bless $line, $class; } - =head2 $lhs == $rhs # Index: contextLimitedPoint.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextLimitedPoint.pl,v retrieving revision 1.2.6.2 retrieving revision 1.2.6.2.2.1 diff -Lmacros/contextLimitedPoint.pl -Lmacros/contextLimitedPoint.pl -u -r1.2.6.2 -r1.2.6.2.2.1 --- macros/contextLimitedPoint.pl +++ macros/contextLimitedPoint.pl @@ -1,4 +1,3 @@ - ################################################################################ # WeBWorK Online Homework Delivery System # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ @@ -30,12 +29,10 @@ =cut - loadMacros("MathObjects.pl"); sub _contextLimitedPoint_init {LimitedPoint::Init()}; # don't load it again - ################################################## # # Handle common checking for BOPs @@ -169,5 +166,4 @@ main::Context("LimitedPoint"); ### FIXME: probably should require author to set this explicitly } - 1; Index: IO.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/IO.pl,v retrieving revision 1.3.6.2 retrieving revision 1.3.6.2.2.1 diff -Lmacros/IO.pl -Lmacros/IO.pl -u -r1.3.6.2 -r1.3.6.2.2.1 --- macros/IO.pl +++ macros/IO.pl @@ -1,6 +1,4 @@ - ################################################################################ - # WeBWorK Online Homework Delivery System # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ # $CVSHeader$ Index: contextString.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextString.pl,v retrieving revision 1.4.2.2 retrieving revision 1.4.2.2.2.1 diff -Lmacros/contextString.pl -Lmacros/contextString.pl -u -r1.4.2.2 -r1.4.2.2.2.1 --- macros/contextString.pl +++ macros/contextString.pl @@ -18,7 +18,6 @@ contextString.pl - Allow string-valued answers. - =head1 DESCRIPTION Implements contexts for string-valued answers. Index: PGinfo.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/PGinfo.pl,v retrieving revision 1.1.2.2 retrieving revision 1.1.2.2.2.1 diff -Lmacros/PGinfo.pl -Lmacros/PGinfo.pl -u -r1.1.2.2 -r1.1.2.2.2.1 --- macros/PGinfo.pl +++ macros/PGinfo.pl @@ -4,7 +4,6 @@ # All Rights Reserved #################################################################### - =head1 NAME PGinfo.pl Index: contextLimitedVector.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextLimitedVector.pl,v retrieving revision 1.2.6.2 retrieving revision 1.2.6.2.2.1 diff -Lmacros/contextLimitedVector.pl -Lmacros/contextLimitedVector.pl -u -r1.2.6.2 -r1.2.6.2.2.1 --- macros/contextLimitedVector.pl +++ macros/contextLimitedVector.pl @@ -42,12 +42,10 @@ =cut - loadMacros("MathObjects.pl"); sub _contextLimitedVector_init {LimitedVector::Init()}; # don't load it again - ################################################## # # Handle common checking for BOPs @@ -271,6 +269,8 @@ $context->flags->set(vector_format => 'coordinate'); $context->constants->undefine('i','j','k'); + ######################### + main::Context("LimitedVector"); ### FIXME: probably should require author to set this explicitly } Index: MathObjects.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/MathObjects.pl,v retrieving revision 1.2.2.4 retrieving revision 1.2.2.4.2.1 diff -Lmacros/MathObjects.pl -Lmacros/MathObjects.pl -u -r1.2.2.4 -r1.2.2.4.2.1 --- macros/MathObjects.pl +++ macros/MathObjects.pl @@ -1,4 +1,3 @@ - ################################################################################ # WeBWorK Online Homework Delivery System # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ @@ -25,10 +24,8 @@ is to encourage the use of the name MathObjects instead of Parser (which is not as intuitive for those who don't know the history). - It may later be used for other purposes as well. - =head1 SEE ALSO L<Parser.pl>. Index: contextLimitedComplex.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextLimitedComplex.pl,v retrieving revision 1.3.2.2 retrieving revision 1.3.2.2.2.1 diff -Lmacros/contextLimitedComplex.pl -Lmacros/contextLimitedComplex.pl -u -r1.3.2.2 -r1.3.2.2.2.1 --- macros/contextLimitedComplex.pl +++ macros/contextLimitedComplex.pl @@ -62,16 +62,12 @@ loadMacros("MathObjects.pl"); - sub _contextLimitedComplex_init {LimitedComplex::Init()}; # don't load it again - - ################################################## # # Handle common checking for BOPs # - package LimitedComplex::BOP; # Index: dangerousMacros.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/dangerousMacros.pl,v retrieving revision 1.41.2.3 retrieving revision 1.41.2.3.2.1 diff -Lmacros/dangerousMacros.pl -Lmacros/dangerousMacros.pl -u -r1.41.2.3 -r1.41.2.3.2.1 --- macros/dangerousMacros.pl +++ macros/dangerousMacros.pl @@ -1285,7 +1285,6 @@ =head2 sourceAlias - sourceAlias($path_to_PG_file); Returns a relative URL to the F<source.pl> script, which may be installed in a @@ -1349,7 +1348,6 @@ Value->Package("Formula")->new('k')->eval; } - # ^function pi # ^uses &Value::Package sub pi () {Value->Package("Formula")->new('pi')->eval} Index: contextABCD.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextABCD.pl,v retrieving revision 1.3.6.2 retrieving revision 1.3.6.2.2.1 diff -Lmacros/contextABCD.pl -Lmacros/contextABCD.pl -u -r1.3.6.2 -r1.3.6.2.2.1 --- macros/contextABCD.pl +++ macros/contextABCD.pl @@ -16,10 +16,8 @@ =head1 NAME - contextABCD.pl - Contexts for matching problems. - =head1 DESCRIPTION Implements contexts for string-valued answers especially Index: contextLimitedPowers.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextLimitedPowers.pl,v retrieving revision 1.2.4.2 retrieving revision 1.2.4.2.2.1 diff -Lmacros/contextLimitedPowers.pl -Lmacros/contextLimitedPowers.pl -u -r1.2.4.2 -r1.2.4.2.2.1 --- macros/contextLimitedPowers.pl +++ macros/contextLimitedPowers.pl @@ -1,4 +1,3 @@ - ################################################################################ # WeBWorK Online Homework Delivery System # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ @@ -103,7 +102,6 @@ loadMacros("MathObjects.pl"); - sub _contextLimitedPowers_init {}; # don't load it again package LimitedPowers; @@ -153,7 +151,6 @@ # # Legacy code to accommodate older approach to setting the operators # - our @NoBaseE = ( '^' => {class => 'LimitedPowers::NoBaseE', isCommand=>1, perl=>'LimitedPowers::NoBaseE->_eval'}, '**' => {class => 'LimitedPowers::NoBaseE', isCommand=>1, perl=>'LimitedPowers::NoBaseE->_eval'}, Index: contextTF.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextTF.pl,v retrieving revision 1.4.6.2 retrieving revision 1.4.6.2.2.1 diff -Lmacros/contextTF.pl -Lmacros/contextTF.pl -u -r1.4.6.2 -r1.4.6.2.2.1 --- macros/contextTF.pl +++ macros/contextTF.pl @@ -16,7 +16,6 @@ =head1 NAME - contextTF.pl - Imlements contexts for true/false problems. =head1 DESCRIPTION Index: Parser.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/Parser.pl,v retrieving revision 1.6.6.2 retrieving revision 1.6.6.2.2.1 diff -Lmacros/Parser.pl -Lmacros/Parser.pl -u -r1.6.6.2 -r1.6.6.2.2.1 --- macros/Parser.pl +++ macros/Parser.pl @@ -1,4 +1,3 @@ - ################################################################################ # WeBWorK Online Homework Delivery System # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ @@ -26,10 +25,8 @@ ## Set up the functions needed by the Parser. ## - # ^uses $Parser::installed # ^uses $Value::installed - if (!$Parser::installed) { die "\n************************************************************\n" . "* This problem requires the Parser.pm package, which doesn't\n". @@ -87,13 +84,10 @@ =cut - # ^function Compute # ^uses Formula - sub Compute { my $string = shift; - my $formula = Formula($string); $formula = $formula->{tree}->Compute if $formula->{tree}{canCompute}; if (scalar(@_) || $formula->isConstant) { @@ -105,7 +99,6 @@ return $formula; } - =head2 Context Context(); @@ -122,15 +115,12 @@ # ^function Context # ^uses Parser::Context::current # ^uses %context - sub Context {Parser::Context->current(\%context,@_)} - # ^variable our %context %context = (); # Locally defined contexts, including 'current' context # ^uses Context Context(); # Initialize context (for persistent mod_perl) - ########################################################################### # # stubs for trigonometric functions Index: parserImplicitEquation.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/parserImplicitEquation.pl,v retrieving revision 1.2.2.2 retrieving revision 1.2.2.2.2.1 diff -Lmacros/parserImplicitEquation.pl -Lmacros/parserImplicitEquation.pl -u -r1.2.2.2 -r1.2.2.2.2.1 --- macros/parserImplicitEquation.pl +++ macros/parserImplicitEquation.pl @@ -181,7 +181,6 @@ loadMacros("MathObjects.pl"); - sub _parserImplicitEquation_init {ImplicitEquation::Init()}; # don't reload this file # Index: contextLimitedNumeric.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextLimitedNumeric.pl,v retrieving revision 1.2.6.2 retrieving revision 1.2.6.2.2.1 diff -Lmacros/contextLimitedNumeric.pl -Lmacros/contextLimitedNumeric.pl -u -r1.2.6.2 -r1.2.6.2.2.1 --- macros/contextLimitedNumeric.pl +++ macros/contextLimitedNumeric.pl @@ -1,4 +1,3 @@ - ################################################################################ # WeBWorK Online Homework Delivery System # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ @@ -15,10 +14,8 @@ # Artistic License for more details. ################################################################################ - =head1 NAME - contextLimitedNumeric.pl - Allows numeric entry but no operations. =head1 DESCRIPTION @@ -38,7 +35,6 @@ =cut - loadMacros("MathObjects.pl"); sub _contextLimitedNumeric_init { Index: parserCustomization.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/parserCustomization.pl,v retrieving revision 1.2.2.2 retrieving revision 1.2.2.2.2.1 diff -Lmacros/parserCustomization.pl -Lmacros/parserCustomization.pl -u -r1.2.2.2 -r1.2.2.2.2.1 --- macros/parserCustomization.pl +++ macros/parserCustomization.pl @@ -37,7 +37,6 @@ $context{Vector}->{cmpDefaults}{Vector} = {promotePoints => 1}; $context{Vector}->lists->set(Vector=>{open=>'(', close=>')'}); - (This actually just turns points into vectors in the answer checker for vectors, and displays vectors using parens rather than angle brakets. The student is really still entering what the Parser @@ -45,7 +44,6 @@ in the Value package, that should work. But if a problem checks if a student's value is actually a Vector, that will not be true.) - =cut sub _parserCustomization_init {} Index: parserVectorUtils.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/parserVectorUtils.pl,v retrieving revision 1.2.8.2 retrieving revision 1.2.8.2.2.1 diff -Lmacros/parserVectorUtils.pl -Lmacros/parserVectorUtils.pl -u -r1.2.8.2 -r1.2.8.2.2.1 --- macros/parserVectorUtils.pl +++ macros/parserVectorUtils.pl @@ -24,11 +24,8 @@ =cut -=cut - sub _parserVectorUtils_init {}; # don't reload this file - =head1 MACROS =head2 Overline @@ -55,7 +52,6 @@ ); } - =head2 BoldMath BoldMath($vectorName) @@ -120,7 +116,6 @@ sub non_zero_point2D {non_zero_point(2,@_)} sub non_zero_point3D {non_zero_point(3,@_)} - =head2 non_zero_vector, non_zero_vector2D, non_zero_vector3D non_zero_vector($Dim,$L_bound,$U_bound,$step) @@ -138,7 +133,6 @@ sub non_zero_vector2D {non_zero_vector(2,@_)} sub non_zero_vector3D {non_zero_vector(3,@_)} - =head2 Line $P = Point(@coords1); @@ -161,7 +155,6 @@ =cut - sub Line { my @p = Point(shift)->value; my @v = Vector(shift)->value; my $t = shift; $t = 't' unless $t; $t = Formula($t); Index: parserDifferenceQuotient.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/parserDifferenceQuotient.pl,v retrieving revision 1.6.4.2 retrieving revision 1.6.4.2.2.1 diff -Lmacros/parserDifferenceQuotient.pl -Lmacros/parserDifferenceQuotient.pl -u -r1.6.4.2 -r1.6.4.2.2.1 --- macros/parserDifferenceQuotient.pl +++ macros/parserDifferenceQuotient.pl @@ -46,10 +46,8 @@ Context()->variables->are(t=>'Real',a=>'Real'); ANS(DifferenceQuotient("-a/[t(t+dt)]","dt")->cmp); - =cut - loadMacros('MathObjects.pl'); sub _parserDifferenceQuotient_init {DifferenceQuotient::Init()}; # don't reload this file Index: parserFormulaWithUnits.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/parserFormulaWithUnits.pl,v retrieving revision 1.3.4.2 retrieving revision 1.3.4.2.2.1 diff -Lmacros/parserFormulaWithUnits.pl -Lmacros/parserFormulaWithUnits.pl -u -r1.3.4.2 -r1.3.4.2.2.1 --- macros/parserFormulaWithUnits.pl +++ macros/parserFormulaWithUnits.pl @@ -20,7 +20,6 @@ =head1 DESCRIPTION - This is a Parser class that implements a formula with units. It is a temporary version until the Parser can handle it directly. Index: answerComposition.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/answerComposition.pl,v retrieving revision 1.1.8.2 retrieving revision 1.1.8.2.2.1 diff -Lmacros/answerComposition.pl -Lmacros/answerComposition.pl -u -r1.1.8.2 -r1.1.8.2.2.1 --- macros/answerComposition.pl +++ macros/answerComposition.pl @@ -1,4 +1,3 @@ - ################################################################################ # WeBWorK Online Homework Delivery System # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ @@ -29,12 +28,8 @@ =cut - -=cut - sub _answerComposition_init {}; # don't reload this file - =head1 MACROS =head2 COMPOSITION_ANS @@ -63,7 +58,6 @@ =cut - sub COMPOSITION_ANS { my $f = shift; my $g = shift; my $fID = ANS_NUM_TO_NAME($main::ans_rule_count-1); @@ -72,7 +66,6 @@ ANS($ans{$fID},$ans{$gID}); } - =head2 NAMED_COMPOSITION_ANS NAMED_COMPOSITION_ANS($fID=>$f, $gID=>$g, %options) @@ -95,11 +88,8 @@ =cut - - sub NAMED_COMPOSITION_ANS {NAMED_ANS(composition_ans_list(@_))} - =head2 composition_ans_list composition_ans_list($fID=>$f, $gID=>$g, %options) @@ -130,8 +120,6 @@ =cut -=cut - sub composition_ans_list { my ($fID,$f,$gID,$g,%params) = @_; my @IDs = ($fID,$gID); # Index: answerVariableList.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/answerVariableList.pl,v retrieving revision 1.4.2.2 retrieving revision 1.4.2.2.2.1 diff -Lmacros/answerVariableList.pl -Lmacros/answerVariableList.pl -u -r1.4.2.2 -r1.4.2.2.2.1 --- macros/answerVariableList.pl +++ macros/answerVariableList.pl @@ -46,7 +46,6 @@ addVariables('x','y','z','s','t,); ANS(variable_cmp("s,t")); - addVariables('x','y','z'); ANS(variable_cmp("(x)",showHints=>0,showLengthHints=>0)); Index: contextPeriodic.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextPeriodic.pl,v retrieving revision 1.3.2.2 retrieving revision 1.3.2.2.2.1 diff -Lmacros/contextPeriodic.pl -Lmacros/contextPeriodic.pl -u -r1.3.2.2 -r1.3.2.2.2.1 --- macros/contextPeriodic.pl +++ macros/contextPeriodic.pl @@ -1,4 +1,3 @@ - ################################################################################ # WeBWorK Online Homework Delivery System # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ Index: PG.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/PG.pl,v retrieving revision 1.29.2.2 retrieving revision 1.29.2.2.2.1 diff -Lmacros/PG.pl -Lmacros/PG.pl -u -r1.29.2.2 -r1.29.2.2.2.1 --- macros/PG.pl +++ macros/PG.pl @@ -22,7 +22,6 @@ In a PG problem: - DOCUMENT(); # should be the first statment in the problem loadMacros(.....); # (optional) load other macro files if needed. @@ -126,7 +125,6 @@ # there could be conflicts. As I understand the behavior of the Apache child # this cannot occur -- a child finishes with one request before obtaining the next - ################################################################################ =head1 MACROS @@ -135,7 +133,6 @@ =over - =item DOCUMENT() DOCUMENT() should be the first statement in each problem template. It can @@ -340,7 +337,6 @@ $STRINGforOUTPUT .= join(" ",@in); } - =item ANS() TEXT(ans_rule(), ans_rule(), ans_rule()); @@ -392,10 +388,8 @@ =item NAMED_ANS() - Old name for LABELED_ANS(). DEPRECATED. - =cut # ^function NAMED_ANS @@ -421,7 +415,6 @@ Temporarily suspends accumulation of problem text and storing of answer blanks and answer evaluators until RESUME_RENDERING() is called. - =cut # ^function STOP_RENDERING @@ -447,18 +440,15 @@ ""; } - =item ENDDOCUMENT() ENDDOCUMENT(); - When PG problems are evaluated, the result of evaluating the entire problem is interpreted as the return value of ENDDOCUMENT(). Therefore, ENDDOCUMENT() must be the last executable statement of every problem. It can only appear once. It returns a list consisting of: - =over =item * @@ -544,7 +534,6 @@ =back - =cut # ^function ENDDOCUMENT @@ -649,7 +638,6 @@ eval(q!++$main::ans_rule_count!); # evalute at runtime to get correct main:: } - =item RECORD_ANS_NAME() RECORD_ANS_NAME("label"); @@ -669,7 +657,6 @@ $label; } - =item NEW_ANS_NAME() NEW_ANS_NAME($num); @@ -718,7 +705,6 @@ my $vecnum; - =item RECORD_FROM_LABEL() RECORD_FORM_LABEL("label"); @@ -739,7 +725,6 @@ $label; } - =item NEW_ANS_ARRAY_NAME() NEW_ANS_ARRAY_NAME($num, $row, $col); @@ -795,12 +780,13 @@ $label; } - =item get_PG_ANSWERS_HASH() get_PG_ANSWERS_HASH(); get_PG_ANSWERS_HASH($key); + + =cut # ^function get_PG_ANSWERS_HASH @@ -834,7 +820,6 @@ } } - =item includePGproblem($filePath) includePGproblem($filePath); @@ -843,8 +828,7 @@ a path relative to the top of the templates directory. The output of that problem appears in the given problem. -=head1 SEE ALSO - +=cut # ^function includePGproblem # ^uses %envir @@ -881,6 +865,4 @@ =cut - 1; - Index: PGauxiliaryFunctions.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/PGauxiliaryFunctions.pl,v retrieving revision 1.9.6.2 retrieving revision 1.9.6.2.2.1 diff -Lmacros/PGauxiliaryFunctions.pl -Lmacros/PGauxiliaryFunctions.pl -u -r1.9.6.2 -r1.9.6.2.2.1 --- macros/PGauxiliaryFunctions.pl +++ macros/PGauxiliaryFunctions.pl @@ -12,10 +12,8 @@ =cut # ^uses loadMacros - loadMacros("PGcommonFunctions.pl"); - =head3 # @@ -33,6 +31,7 @@ # isPrime($number) # reduce($numerator,$denominator) # preformat($scalar, "QuotedString") +# =cut Index: parserRadioButtons.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/parserRadioButtons.pl,v retrieving revision 1.2.2.2 retrieving revision 1.2.2.2.2.1 diff -Lmacros/parserRadioButtons.pl -Lmacros/parserRadioButtons.pl -u -r1.2.2.2 -r1.2.2.2.2.1 --- macros/parserRadioButtons.pl +++ macros/parserRadioButtons.pl @@ -157,7 +157,6 @@ unless ref($choices) eq 'ARRAY'; Value::Error("A RadioButton's second argument should be the correct button choice") unless defined($value) && $value ne ""; - my $context = Parser::Context->getCopy("String"); my %choiceHash = $self->choiceHash(1); $context->strings->add(map {$_=>{}} (keys %choiceHash)); Index: Value.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/Value.pl,v retrieving revision 1.7.6.2 retrieving revision 1.7.6.2.2.1 diff -Lmacros/Value.pl -Lmacros/Value.pl -u -r1.7.6.2 -r1.7.6.2.2.1 --- macros/Value.pl +++ macros/Value.pl @@ -1,4 +1,5 @@ + =head1 DESCRIPTION # @@ -91,7 +92,6 @@ return $x; } - =head3 NOTE: ########################################################################### Index: PGbasicmacros.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/PGbasicmacros.pl,v retrieving revision 1.47.2.2 retrieving revision 1.47.2.2.2.1 diff -Lmacros/PGbasicmacros.pl -Lmacros/PGbasicmacros.pl -u -r1.47.2.2 -r1.47.2.2.2.1 --- macros/PGbasicmacros.pl +++ macros/PGbasicmacros.pl @@ -1620,6 +1620,113 @@ } } +=head3 EV3P + + ###################################################################### + # + # New version of EV3 that allows `...` and ``...`` to insert TeX produced + # by the new Parser (in math and display modes). + # + # Format: EV3P(string,...); + # EV3P({options},string,...); + # + # `x^2/5` will become \(\frac{x^2}{5}\) and then rendered for hardcopy or screen output + # + # where options can include: + # + # processCommands => 0 or 1 Indicates if the student's answer will + # be allowed to process \{...\}. + # Default: 1 + # + # processVariables => 0 1 Indicates whether variable substitution + # should be performed on the student's + # answer. + # Default: 1 + # + # processMath => 0 or 1 Indicates whether \(...\), \[...\], + # `...` and ``...`` will be processed + # in the student's answer. + # Default: 1 + # + # processParser => 0 or 1 Indicates if `...` and ``...`` should + # be processed when math is being + # processed. + # Default: 1 + # + # fixDollars => 0 or 1 Specifies whether dollar signs not followed + # by a letter should be replaced by ${DOLLAR} + # prior to variable substitution (to prevent + # accidental substitution of strange Perl + # values). + # Default: 1 + # + +=cut + +sub EV3P { + my $option_ref = {}; $option_ref = shift if ref($_[0]) eq 'HASH'; + my %options = ( + processCommands =... [truncated message content] |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 02:23:08
|
Log Message: ----------- Backporting MathObject documentation to rel-2-4-5 Tags: ---- rel-2-4-patches Added Files: ----------- pg/doc/MathObjects: MathObjectsAnswerCheckers.pod README.pod UsingMathObjects.pod pg/doc/MathObjects/extensions: 1-function.pg 2-function.pg 3-operator.pg 4-list.pg 5-operator.pg 6-precedence.pg 7-context.pg 8-answer.pg pg/doc/MathObjects/macros: Differentiation.pl DifferentiationDefs.pl parserTables.pl parserUtils.pl unionImage.pl unionTables.pl pg/doc/MathObjects/problems: sample01.pg sample02.pg sample03.pg sample04.pg sample05.pg sample06.pg sample07.pg sample08.pg sample09.pg sample10.pg sample11.pg sample12.pg sample13.pg sample14.pg sample15.pg sample16.pg sample17.pg sample18.pg sample19.pg sample20.pg sample21.pg sample22.pg Revision Data ------------- --- /dev/null +++ doc/MathObjects/UsingMathObjects.pod @@ -0,0 +1,393 @@ +=head1 Using MathObjects + +To use MathObjects in your own problems, you need to load the +"MathObjects.pl" macro file: + + loadMacros("Parser.pl"); + +which defines the commands you need to interact with MathObjects. +Once you have done that, you can call the MathObjects functions to create +formulas for you. The main call is Formula(), which takes a string and +returns a parsed version of the string. For example: + + $f = Formula("x^2 + 3x + 1"); + +will set $f to a reference to the parsed version of the formula. + +=head2 Working With Formulas + +A formula has a number of methods that you can call. These include: + +=over + +=item $f->eval(x=>5) + +Evaluate the formula when x is 5. +If $f has more variables than that, then +you must provide additional values, as in +$f->eval(x=>3,y=>1/2); + +=item $f->reduce + +Tries to remove redundent items from your +formula. For example, Formula("1x+0") returns "x". +Reduce tries to factor out negatives and do +some other adjustments as well. (There still +needs to be more work done on this. What it does +is correct, but not always smart, and there need +to be many more situations covered.) All the +reduction rules can be individually enabled +or disabled using the Context()->reduction->set() +method, but the documentation for the various +rules is not yet ready. + +=item $f->substitute(x=>5) + +Replace x by the value 5 throughout (you may want +to reduce the result afterword, as this is not +done automatically). Note that you can replace a +variable by another formula, if you wish. To make +this easier, substitute will apply Formula() to +any string values automatically. E.g., + Formula("x-1")->substitute(x=>"y") +returns "y-1" as a formula. + +=item $f->string + +returns a string representation of the formula +(should be equivalent to the original, though not +necessarily equal to it). + +=item $f->TeX + +returns a LaTeX representation of the formula. +You can use this in BEGIN_TEXT...END_TEXT blocks +as follows: + + BEGIN_TEXT + Suppose \(f(x) = \{$f->TeX}\). ... + END_TEXT + +=item $f->perl + +returns a representation of the formula that could +be evaluated by perl's eval() function. + +=item $f->perlFunction + +returns a perl code block that can be called to +evaluate the function. For example: + + $f = Formula('x^2 + 3')->perlFunction; + $y = &$f(5); + +will assign the value 28 to $y. +You can also pass a function name to perlFunction +to get a named function to call: + + Formula('x^2 + 3')->perlFunction('f'); + $y = f(5); + +If the formula involves more than one variable, +then the paramaters should be given in +alphabetical order. + + Formula('x^2 + y')->perlFunction('f'); + $z = f(5,3); # $z is 28. + +Alternatively, you can tell the order for the +parameters: + + Formula('x^2 + y')->perlFunction('f',['y','x']); + $z = f(5,3); $ now $z is 14. + +=back + +=head2 Combining Formulas + +There is a second way to create formulas. Once you have a formula, you can +create additional formulas simply by using perls' built-in operations and +functions, which have been overloaded to handle formulas. For example, + + $x = Formula('x'); + $f = 3*x**2 + 2*$x - 1; + +makes $f be a formula, and is equivalent to having done + + $f = Formula("3x^2 + 2x - 1"); + +This can be very convenient, but also has some pitfalls. First, you +need to include '*' for multiplication, since perl doesn't do implied +multiplication, and you must remember to use '**' not '^'. (If you use '^' +on a formula, the parser will remind you to use '**'.) Second, the +precedences of the operators in perl are fixed, and so changes you make to +the precedence table for the parser are not reflected in formulas produced +in this way. (The reason '^' is not overloaded to do exponentiation is +that the precedence of '^' is wrong for that in perl, and can't be +changed.) As long as you leave the default precedences, however, things +should work as you expect. + +Note that the standard functions, like sin, cos, etc, are overloaded to +generate appropriate formulas when their values are formulas. For example, + + $x = Formula('x'); + $f = cos(3*$x + 1); + +produces the same result as $f = Formula("cos(3x+1)"); and you can then go +on to output its TeX form, etc. + +=head2 Special Syntax + +This parser has support for some things that are missing from the current +one, like absolute values. You can say |1+x| rather than abs(1+x) +(though both are allowed), and even |1 - |x|| works. + +Also, you can use sin^2(x) (or even sin^2 x) to get (sin(x))^2. + +Finally, you can use sin^-1(x) to get arcsin(x). + +There is an experimental set of operator precedences that make it possible +to write sin 2x + 3 and get sin(2x) + 3. See examples/7-precedence.pg +for some details. + +=head2 The Formula Types + +The parser understands a wide range of data types, including real and +complex numbers, points, vectors, matrices, arbitrary lists, intervals, +unions of intervals, and predefined words. Each has a syntax for use +within formulas, as described below: + + numbers the usual form: 153, 233.5, -2.456E-3, etc. + + complex a + b i where a and b are numbers: 1+i, -5i, 6-7i, etc. + + infinitites the words 'infinity' or '-infinity' (or several + equivalents). + + point (a,b,c) where a, b and c are real or complex numbers. + any number of coordinates are allowed. Eg, (1,2), + (1,0,0,0), (-1,2,-3). Points are promoted to vectors + automatically, when necessary. + + vector <a,b,c> or a i + b j + c k (when used in vector context). + As with points, vectors can have any number of + coordinates. For example, <1,0,0>, <-1,3>, <x,1-x>, etc. + + matrix [[a11,...,a1n],...[am1,...amn]], i.e., use [..] around + each row, and around the matrix itself. The elements + are separated by commas (not spaces). e.g, + [[1,2],[3,4]] (a 2x2 matrix) + [1,2] (a 1x2 matrix, really a vector) + [[1],[2]] (a 2x1 matrix, ie. column vector) + Points and vectors are promoted to matrices when + appropriate. Vectors are converted to column vectors + when needed for matrix-vector multiplication. Matrices + can be 3-dimensional or higher by repeated nesting of + matrices. (In this way, a 2-dimensional matrix is really + thought of as a vector of vectors, and n-dimensional + ones as vectors of (n-1)-dimensional ones.) + + list (a,b,c) where a,b,c are arbitrary elements. + For example, (1+i, -3, <1,2,3>, Infinity). + The empty list () is allowed, and the parentheses are + optional if there is only one list. (This makes it + possible to make list-based answer checkers that + really know where the separations occur.) + + interval (a,b), (a,b], [a,b), [a,b], or [a,a] where a and b are + numbers or appropriate forms of infinity. + For example, (-INF,3], [4,4], [2,INF), (-INF,INF). + + union represented by 'U'. For example [-1,0) U (0,1]. + + string special predefined strings like NONE and DNE. + +These forms are what are used in the strings passed to Formula(). +If you want to create versions of these in perl, there are several +ways to do it. One way is to use the Compute() command, which takes a +string parses it and then evaluates the result (it is equivalent to +Formula(...)->eval). If the formula produces a vector, the result +will be a Vector constant that you can use in perl formulas by hand. + +For example: + + $v = Compute("<1,1,0> >< <-1,4,-2>"); + +would compute the dot product of the two vectors and assign the +resulting vector object to $v. + +Another way to generate constants of the various types is to use the +following routines. If their inputs are constant, they produce a +constant of the appropriate type. If an input is a formula, they +produce corresponding formula objects. + + Real(a) create a real number with "fuzzy" + comparisons (so that 1.0000001 == Real(1) is true). + + Complex(a,b) create a complex number a + b i + + Infinity creates the +infinity object + -(Infinity) creates -infinity + + Point(x1,...xn) or Point([x1,...,xn]) produces (x1,...,xn) + + Vector(x1,...,xn) or Vector([x1,...,xn]) produces <x1,...,xn> + + Matrix([a11,...,a1m],...,[am1,...,amn]) or + Matrix([[a11,...,a1m],...,[am1,...,amn]]) produces an n x m matrix + + List(a,...,b) produces a list with the given elements + + Interval('(',a,b,']') produces (a,b], (the other endpoints work as + expected. Use 'INF' and '-INF' for infinities.) + + Union(I1,...,In) takes the union of the n intervals. (where I1 to In + are intervals.) + + String(word) Produces a string object for the given word (if it + is a known word). This is mostly to be able to + call the ->cmp and ->TeX methods. + +For example, + + $a = random(-5,5,1) + $V = Vector($a,1-$a,$a**2+1); + +produces a vector with some random coordinates. + +Objects of these types also have TeX, string and perl methods, so you can +use: + + Vector(1,2,3)->TeX + +to produce a TeX version of the vector, just as you can with formulas. + +There are several "constant" functions that generate common constant +values. These include pi, i, j, k and Infininty. you can use these +in perl expressions as though they were their actual values: + + $z = $a + $b * i; + $v = $a*i + $b*j + $c*k; + $I = Infinity; + +Note that because of a peculiarity of perl, you need to use -(pi) +or - pi (with a space) rather than -pi, and similary for the other +functions. Without this, you will get an error message about an +ambiguity being resolved. (This is not a problem if you process your +expressions through the parser itself, only if you are writing +expressions in perl directly. Note that since student answers are +processed by the parser, not perl directly, they can write -pi without +problems.) + +Another useful command is Compute(), which evaluates a formula and +returns its value. This is one way to create point or vector-valued +constants, but there is an easier way discussed below. + +=head2 Specifying the Context + +You may have noticed that "i" was used in two different ways in the +examples above. In the first example, it was treated as a complex +number and the second as a coordinate unit vector. To control which +interpretation is used, you specify a parser "context". + +The context controls what operations and functions are defined in the +parser, what variables and constants to allow, how to interpret +various paretheses, and so on. Changing the context can completely +change the way a formula is interpreted. + +There are several predefined contexts: Numeric, Complex, Vector, +Interval and Full. (You can also define your own contexts, but that +will be described elsewhere.) To select a context, use the Context() +function, e.g. + + Context("Numeric"); + +selects the numeric context, where i, j and k have no special meaning, +points and vectors can't be used, and the only predefined variable is +'x'. + +On the other hand, Context("Vector") makes i, j and k represent the +unit coordinate vectors, and defines variables 'x', 'y' and 'z'. + +Context("Interval") is like numeric context, but it also defines the +parentheses so that they will form intervals (rather than points or +lists). + +Once you have selected a context, you can modify it to suit the +particular needs of your problem. The command + + $context = Context(); + +gets you a reference to the current context object (you can also use +something like + + $context = Context("Numeric"); + +to set the context and get its reference at the same time). Once you +have this reference, you can call the Context methods to change values +in the context. These are discussed in more detail in the +documentation of the Context object [not yet written], but some of the +more common actions are described here. + +To add a variable, use, for example, + + $context->variables->add(y=>'Real'); + +To delete any existing variables and replace them with new ones, use + + $context->variables->are(t=>'Real'); + +To remove a variable, use + + $context->variables->remove('t'); + +To get the names of the defind variables, use + + @names = $context->variables->names; + + +Similarly, you can add a named constant via + + $context->constants->add(M=>1/log(10)); + +and can change, remove or list the constants via methods like those +used for variables above. The command + + $M = $constant->constants->get('M'); + +will return the value of the consant M. (See the +pg/lib/Value/Context/Data.pm file for more information on the methods +you can call for the various types of context data.) + +To add new predefined words (like 'NONE' and 'DNE'), use something +like + + $constant->strings->add(TRUE=>{},FALSE=>{}); + +Note that strings are case-sensitive, so you might want to add + + $constant->strings->add( + true => {alias=>'TRUE'}, + false => {alias=>'FALSE'}, + ); + +so that either "TRUE" or "true" will be interpreted as TRUE. + +There are a number of values stored in the context that control things +like the tolerance used when comparing numbers, and so on. You +control these via commands like: + + $context->flags->set(tolerance=>.00001); + +For example, + + $context->flags->set(ijk=>1); + +will cause the output of all vectors to be written in ijk format +rather than <...> format. + +Finally, you can add or modify the operators and functions that are +available in the parser via calls to $context->operators and +$context->functions. See the files in webwork2/docs/parser/extensions +for examples of how to do this. + --- /dev/null +++ doc/MathObjects/README.pod @@ -0,0 +1,197 @@ +=head1 NAME + +MathObjects - Object system for manipulating mathematics in PG. + +=head1 OVERVIEW + +This directory contains the documentation for a new +mathematical-expression parser written in perl. It was developed for +use with the WeBWorK on-line homework system, but it can be used in +any perl program. + +The goal was to process vector-valued expressions, but the parser was +designed to be extensible, so that you could add your own functions, +operators, and data types. It is still a work in progress, but should +provide a framework for building more sophisticated expression handling. + +Currenlty, the parser understands: + +=over + +=item * real and complex numbers, + +=item * points, vectors, and matrices (with real or complex entries) + +=item * arbitrary lists of elements + +=item * intervals and unions of intervals + +=item * predefined strings like 'infinity' + +=back + +Some other useful features are that you can write sin^2 x for (sin(x))^2 +and sin^-1 x for arcsin(x), and so on. + +Most of the documentation still needs to be written, but you can get some +ideas from the samples in the problems and extensions directories, and by +reading the files in this directory. + +=head1 INSTALLATION + +The parser should already be installed as part of the WeBWorK 2.1 +distribution, so you should not need to install it separately. If you +don't seem to have it installed, then it can be obtained from the +Union CVS repository at +http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/WeBWorKCVS + +The README file in that directory contains the installation instructions. + +=head1 SAMPLE FILES + +Sample problems are given in the problems and extensions directories. Move +these to the templates directory of a course where you want to test the +Parser, and move the contents of the macros directory to that course's +macros directory. + +Now try looking at these problems using the Library Browser. Edit the +source to see how they work, and to read the comments within the code +itself. + +=head1 EXAMPLE FILES + +The 'problems' directory contains several examples that show how to use +Parser within your problem files. + +=over + +=item problems/sample01.pg + +Uses the parser to make a string into a formula that you can +evaluate and print in TeX form + +=item problems/sample02.pg + +Shows how to create formulas using perl's usual mathematical +expressions rather than character strings. + +=item problems/sample03.pg + +Shows how to use the parser's differentiation abilities. + +=item problems/sample04.pg + +=item problems/sample05.pg + +Use the parser in conjunction with the graphics macros to generate +function graphs on the fly. These also show how to create a +perl function to evaluate an expression. + +=item problems/sample06.pg + +Shows some simple use of vectors in a problem. + +=item problems/sample07.pg + +Example if using the build-in Real object and its answer +checker + +=item problems/sample08.pg + +Uses complex numbers and the built-in checker + +=item problems/sample09.pg + +=item problems/sample10.pg + +Demonstrates points and vectors and their answer checkers + +=item problems/sample11.pg + +=item problems/sample12.pg + +Shows the answer checkers for intervals and unions. + +=item problems/sample13.pg + +=item problems/sample14.pg + +=item problems/sample15.pg + +Demonstrate various list checkers, including a check for the +word 'NONE', which is a predefined string. + +=item problems/sample16.pg + +=item problems/sample17.pg + +=item problems/sample18.pg + +These show the multi-variable function checker in use (for +functions of the form R->R, R^2->R and R->R^3). + +=item problems/sample19.pg + +Uses the function checker to implement a "constant" that can +be used in formulas. + +=item problems/sample20.pg + +Shows how to use the parser's substitution abilities. + +=item problems/sample21.pg + +Checks for a list of points. + +=item problems/sample22.pg + +Shows how to provide named constants that the student can +use in his answer. + +=back + +The 'examples' directory contains samples that show how to extend the +parser to include your own functions, operators, and so on. There are also +some samples of how to call the methods available for Formula objects +generated by the parser, and what some error messages look like. + +=over + +=item examples/1-function.pg + +Adds a single-variable function to the parsers list of functions. + +=item examples/2-function.pg + +Adds a two-variable function to the parser. + +=item examples/3-operator.pg + +Adds a binary operator to the parser. (Unary operators are similar.) + +=item examples/4-list.pg + +Adds a new "list type" object. In this case, it's really an +operation [n,r] that returns n choose r. + +=item examples/5-list.pg + +Add a new "equality" operator that you can use to handle answers +like "x+y=0". + +=item examples/6-precedence.pg + +Shows an experimental precedence setting that can be used to make +sin 2x return sin(2x) rather than (sin(2))x. + +=item examples/7-context.pg + +Shows how to switch contexts (in this case, to complex and to vector +contexts), and how this affects the parsing. + +=item examples/8-answer.pg + +Implements a simple vector-valued answer checker using the +parser's computation and comparison ability. + +=back --- /dev/null +++ doc/MathObjects/MathObjectsAnswerCheckers.pod @@ -0,0 +1,427 @@ +=head1 MathObjects-based Answer Checkers + +MathObjects are designed to be used in two ways. First, you can use it +within your perl code when writing problems as a means of making it +easier to handle formulas, and in particular, to be able to use a single +object to produce numeric values, TeX output and answer strings from a +single formula entry. This avoids having to type a function three +different ways (which makes maintaining a problem much harder). Since +MathObjects also included vector and complex arthimetic, it is easier to +work with these types of values as well. + +Secondly using MathObjects improves the processing of student input. +This is accomplished through special answer checkers that are part of +the Parser package (rather than the traditional WeBWorK answer +checkers). Each of these checkers has error checking customized to the +type of input expected from the student and can provide helpful feedback +if the syntax of the student's entry is incorrect. + +Checkers are available for each of the types of values that the parser +can produce (numbers, complex numbers, infinities, points, vectors, +intervals, unions, formulas, lists of numbers, lists of points, lists of +intervals, lists of formulas returning numbers, lists of formulas +returning points, and so on). + +To use one of these checkers, simply call the ->cmp method of the +object that represents the correct answer. For example: + + $n = Real(sqrt(2)); + ANS($n->cmp); + +will produce an answer checker that matches the square root of two. +Similarly, + + ANS(Vector(1,2,3)->cmp); + +matches the vector <1,2,3> (or any computation that produces it, e.g., +i+2j+3k, or <4,4,4>-<3,2,1>), while + + ANS(Interval("(-inf,3]")->cmp); + +matches the given interval. Other examples include: + + ANS(Infinity->cmp); + ANS(String('NONE')->cmp); + ANS(Union("(-inf,$a) U ($a,inf)")->cmp); + +and so on. + +Formulas are handled in the same way: + + ANS(Formula("x+1")->cmp); + + $a = random(-5,5,1); $b = random(-5,5,1); $x = random(-5,5,1); + $f = Formula("x^2 + $a x + $b")->reduce; + ANS($f->cmp); + ANS($f->eval(x=>$x)->cmp); + + $x = Formula('x'); + ANS((1+$a*$x)->cmp); + + Context("Vector")->variables->are(t=>'Real'); + $v = Formula("<t,t^2,t^3>"); $t = random(-5,5,1); + ANS($v->cmp); + ANS($v->eval(t=>$t)->cmp); + +and so on. + +Lists of items can be checked as easily: + + ANS(List(1,-1,0)->cmp); + ANS(List(Point($a,$b),Point($a,-$b))->cmp); + ANS(List(Vector(1,0,0),Vector(0,1,1))->cmp); + ANS(Compute("(-inf,2),(4,5)")->cmp); # easy way to get list of intervals + ANS(Formula("x, x+1, x^2-1")->cmp); + ANS(Formula("<x,2x>,<x,-2x>,<0,x>")->cmp); + ANS(List('NONE')->cmp); + +and so on. The last example may seem strange, as you could have used +ANS(String('NONE')->cmp), but there is a reason for using this type +of construction. You might be asking for one or more numbers (or +points, or whatever) or the word 'NONE' of there are no numbers (or +points). If you used String('NONE')->cmp, the student would get an +error message about a type mismatch if he entered a list of numbers, +but with List('NONE')->cmp, he will get appropriate error messages for +the wrong entries in the list. + +It is often appropriate to use the list checker in this way even when +the correct answer is a single value, if the student might type a list +of answers. + +On the other hand, using the list checker has its disadvantages. For +example, if you use + + ANS(Interval("(-inf,3]")->cmp); + +and the student enters (-inf,3), she will get a message indicating +that the type of interval is incorrect, while that would not be the +case if + + ANS(List(Interval("(-inf,3]"))->cmp); + +were used. (This is because the student doesn't know how many +intervals there are, so saying that the type of interval is wrong +would inform her that there is only one.) + +The rule of thumb is: the individual checkers can give more detailed +information about what is wrong with the student's answer; the list +checker allows a wider range of answers to be given without giving +away how many answers there are. If the student knows there's only +one, use the individual checker; if there may or may not be more than +one, use the list checker. + +Note that you can form lists of formulas as well. The following all +produce the same answer checker: + + ANS(List(Formula("x+1"),Formula("x-1"))->cmp); + + ANS(Formula("x+1,x-1")->cmp); # easier + + $f = Formula("x+1"); $g = Formula("x-1"); + ANS(List($f,$g)->cmp); + + $x = Formula('x'); + ANS(List($x+1,$x-1)->cmp); + +See the files in webwork2/doc/parser/problems for more +examples of using the parser's answer checkers. + +=head2 Controlling the Details of the Answer Checkers + +The action of the answer checkers can be modified by passing flags to +the cmp() method. For example: + + ANS(Real(pi)->cmp(showTypeWarnings=>0)); + +will prevent the answer checker from reporting errors due to the +student entering in the wrong type of answer (say a vector rather than +a number). + +=head3 Flags common to all answer checkers + +There are a number of flags common to all the checkers: + +=over + +=item S<C<< showTypeWarnings=>1 or 0 >>> + +show/don't show messages about student +answers not being of the right type. +(default: 1) + +=item S<C<< showEqualErrors=>1 or 0 >>> + +show/don't show messages produced by +trying to compare the professor and +student values for equality, e.g., +conversion errors between types. +(default: 1) + +=item S<C<< ignoreStrings=>1 or 0 >>> + +show/don't show type mismatch errors +produced by strings (so that 'NONE' will +not cause a type mismatch in a checker +looking for a list of numbers, for example). +(default: 1) + +=back + +In addition to these, the individual types have their own flags: + +=head3 Flags for Real()->cmp + +=over + +=item S<C<< ignoreInfinity=>1 or 0 >>> + +Don't report type mismatches if the +student enters an infinity. +(default: 1) + +=back + +=head3 Flags for String()->cmp + +=over + +=item S<C<< typeMatch=>value >>> + +Specifies the type of object that +the student should be allowed to enter +(in addition the string). +(default: 'Value::Real') + +=back + +=head3 Flags for Point()->cmp + +=over + +=item S<C<< showDimensionHints=>1 or 0 >>> + +show/don't show messages about the +wrong number of coordinates. +(default: 1) + +=item S<C<< showCoordinateHints=>1 or 0 >>> + +show/don't show message about +which coordinates are right. +(default: 1) + +=back + +=head3 Flags for Vector()->cmp + +=over + +=item S<C<< showDimensionHints=>1 or 0 >>> + +show/don't show messages about the +wrong number of coordinates. +(default: 1) + +=item S<C<< showCoordinateHints=>1 or 0 >>> + +show/don't show message about +which coordinates are right. +(default: 1) + +=item S<C<< promotePoints=>1 or 0 >>> + +do/don't allow the student to +enter a point rather than a vector. +(default: 1) + +=item S<C<< parallel=>1 or 0 >>> + +Mark the answer as correct if it +is parallel to the professor's answer. +Note that a value of 1 forces +showCoordinateHints to be 0. +(default: 0) + +=item S<C<< sameDirection=>1 or 0 >>> + +During a parallel check, mark the +answer as correct only if it is in +the same (not the opposite) +direction as the professor's answer. +(default: 0) + +=back + +=head3 Flags for Matrix()->cmp + +=over + +=item S<C<< showDimensionHints=>1 or 0 >>> + +show/don't show messages about the +wrong number of coordinates. +(default: 1) + +=back + +The default for showEqualErrors is set to 0 for Matrices, since +these errors usually are dimension errors, and that is handled +separately (and after the equality check). + +=head3 Flags for Interval()->cmp + +=over + +=item S<C<< showEndpointHints=>1 or 0 >>> + +do/don't show messages about which +endpoints are correct. +(default: 1) + +=item S<C<< showEndTypeHints=>1 or 0 >>> + +do/don't show messages about +whether the open/closed status of +the enpoints are correct (only +shown when the endpoints themselves +are correct). +(default: 1) + +=back + +=head3 Flags for Union()->cmp and List()->cmp + +all the flags from the Real()->cmp, plus: + +=over + +=item S<C<< showHints=>1 or 0 >>> + +do/don't show messages about which +entries are incorrect. +(default: $showPartialCorrectAnswers) + +=item S<C<< showLengthHints=>1 or 0 >>> + +do/don't show messages about having the +correct number of entries (only shown +when all the student answers are +correct but there are more needed, or +all the correct answsers are among the +ones given, but some extras were given). +(default: $showPartialCorrectAnswers) + +=item S<C<< partialCredit=>1 or 0 >>> + +do/don't give partial credit for when +some answers are right, but not all. +(default: $showPartialCorrectAnswers) +(currently the default is 0 since WW +can't handle partial credit properly). + +=item S<C<< ordered=>1 or 0 >>> + +give credit only if the student answers +are in the same order as the +professor's answers. +(default: 0) + +=item S<C<< entry_type=>'a (name)' >>> + +The string to use in error messages +about type mismatches. +(default: dynamically determined from list) + +=item S<C<< list_type=>'a (name)' >>> + +The string to use in error messages +about numbers of entries in the list. +(default: dynamically determined from list) + +=item S<C<< typeMatch=>value >>> + +Specifies the type of object that +the student should be allowed to enter +in the list (determines what +constitutes a type mismatch error). +(default: dynamically determined from list) + +=item S<C<< requireParenMatch=>1 or 0 >>> + +Do/don't require the parentheses in the +student's answer to match those in the +professor's answer exactly. +(default: 1) + +=item S<C<< removeParens=>1 or 0 >>> + +Do/don't remove the parentheses from the +professor's list as part of the correct +answer string. This is so that if you +use List() to create the list (which +doesn't allow you to control the parens +directly), you can still get a list +with no parentheses. +(default: 0 for List() and 1 for Formula()) + +=back + +=head3 Flags for Formula()->cmp + +The flags for formulas are dependent on the type of the result of +the formula. If the result is a list or union, it gets the flags +for that type above, otherwise it gets that flags of the Real +type above. + +More flags need to be added in order to allow more control over the +answer checkers to give the full flexibility of the traditional +WeBWorK answer checkers. Note that some things, like whether trig +functions are allowed in the answer, are controlled through the +Context() rather than the answer checker itself. For example, + + Context()->functions->undefine('sin','cos','tan'); + +would remove those three functions from use. (One would need to remove +cot, sec, csc, arcsin, asin, etc., to do this properly; there could be +a function call to do this.) + +Similarly, which arithmetic operations are available is controlled +through Context()->operations. + +The tolerances used in comparing numbers are part of the Context as +well. You can set these via: + + Context()->flags->set( + tolerance => .0001, # the relative or absolute tolerance + tolType => 'relative', # or 'absolute' + zeroLevel => 1E-14, # when to use zeroLevelTol + zeroLevelTol => 1E-12, # smaller than this matches zero + # when one of the two is less + # than zeroLevel + limits => [-2,2], # limits for variables in formulas + num_points => 5, # the number of test points + ); + +[These need to be handled better.] + +Note that for testing formulas, you can override the limits and +num_points settings by setting these fields of the formula itself: + + $f = Formula("sqrt(x-10)"); + $f->{limits} = [10,12]; + + $f = Formula("log(xy)"); + $f->{limits} = [[.1,2],[.1,2]]; # x and y limits + +You can also specify the test points explicitly: + + $f = Formula("sqrt(x-10)"); + $f->{test_points} = [[11],[11.5],[12]]; + + $f = Formula("log(xy)"); + $f->{test_points} = [[.1,.1],[.1,.5],[.1,.75], + [.5,.1],[.5,.5],[.5,.75]]; + +[There still needs to be a means of handling the tolerances similarly, +and through the ->cmp() call itself.] + --- /dev/null +++ doc/MathObjects/extensions/2-function.pg @@ -0,0 +1,83 @@ +########################################################## +# +# Example showing how to add a new two-variable function to the Parser +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +########################################################### +# +# Use standard numeric mode +# +Context('Numeric'); + +############################################# +# +# Create a "Combinations" function +# + +package MyFunction2; +our @ISA = qw(Parser::Function::numeric2); # this is what makes it R^2 -> R + +sub C { + shift; my ($n,$r) = @_; my $C = 1; + $r = $n-$r if ($r > $n-$r); # find the smaller of the two + for (1..$r) {$C = $C*($n-$_+1)/$_} + return $C +} + +package main; + +# +# Make it work on formulas as well as numbers +# +sub C {Parser::Function->call('C',@_)} + +# +# Add the new functions into the Parser +# + +Context()->functions->add(C => {class => 'MyFunction2'}); + +$x = Formula('x'); + +########################################################### +# +# The problem text +# +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we have added a new function to the Parser: ${BTT}C(n,r)${ETT}. +(Edit the code to see how this is done). +$PAR +Assuming that ${BTT}${DOLLAR}x = Formula('x')${ETT}, it can be used as follows: +$PAR + +\{ParserTable( + 'Formula("C(x,3)")', + 'C(6,2)', + 'C($x,3)', + 'Formula("C(x,3)")->eval(x=>6)', + '(C($x,2))->eval(x=>6)', + 'Formula("C(x)")', + 'Formula("C(1,2,3)")', + 'C(1)', + 'C(1,2,3)', + )\} + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/4-list.pg @@ -0,0 +1,106 @@ +########################################################## +# +# Example showing how to add a new list-type object +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +########################################################## +# +# Define our own [n,r] notation for n choose r +# + +package MyChoose; +our @ISA = qw(Parser::List); # subclass of List + +# +# Check that two numbers are given +# +sub _check { + my $self = shift; + $self->{type}{list} = 0; # our result is a single number, not really a list + $self->Error("You need two numbers within '[' and ']'") + if ($self->{type}{length} < 2); + $self->Error("Only two numbers can appear within '[' and ']'") + if ($self->{type}{length} > 2); + my ($n,$r) = @{$self->{coords}}; + $self->Error("The arguments for '[n,r]' must be numbers") + unless ($n->type eq 'Number' && $r->type eq 'Number'); + $self->{type} = $Value::Type{number}; +} + +# +# Compute n choose r +# +sub _eval { + shift; my ($n,$r) = @_; my $C = 1; + $r = $n-$r if ($r > $n-$r); # find the smaller of the two + for (1..$r) {$C = $C*($n-$_+1)/$_} + return $C +} + +# +# Non-standard TeX output +# +sub TeX { + my $self = shift; + return '{'.$self->{coords}[0]->TeX.' \choose '.$self->{coords}[1]->TeX.'}'; +} + +# +# Non-standard perl output +# +sub perl { + my $self = shift; + return '(MyChoose->_eval('.$self->{coords}[0]->perl.','.$self->{coords}[1]->perl.'))'; +} + + +package main; + +########################################################## +# +# Add the new list to the context +# + +Context()->lists->add(Choose => {class => 'MyChoose'}); +Context()->parens->replace('[' => {close => ']', type => 'Choose'}); + +########################################################### +# +# The problem text +# +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we have added a new list to the Parser: ${BTT}[n,r]${ETT}, +which returns \(n\choose r\). +$PAR + +\{ParserTable( + 'Formula("[x,3]")', + 'Formula("[5,3]")', + 'Formula("[x,3]")->eval(x=>5)', + '$C = Formula("[x,y]"); $C->substitute(x=>5)', + 'Formula("[x,y]")->perlFunction("C"); C(5,3)', + 'Formula("[x,y,3]")', + 'Formula("[x]")', + 'Formula("[x,[y,2]]")', + 'Formula("[x,<1,2>]")', + )\} + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/7-context.pg @@ -0,0 +1,86 @@ +########################################################## +# +# Example showing how to switch different contexts +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we compare formulas in complex and vector contexts. +Note the difference between how ${BTT}i${ETT} is treated in the two +contexts. Note that 'Number' comprises both real and complex numbers. +$PAR + +Assuming that ${BTT}${DOLLAR}x = Formula('x')${ETT}, it can be used as follows: +$PAR + +END_TEXT + +$x = Formula('x'); + +########################################################## +# +# Use Complex context +# + +Context('Complex'); + +BEGIN_TEXT +\{Title("The Complex context:")\} +$PAR +\{ParserTable( + 'i', + 'Formula("1+3i")', + 'Formula("x+3i")', + '1 + 3*i', + '$x + 3*i', + '$z = tan(2*i)', + 'Formula("sinh(zi)")', + 'Formula("3i+4j-k")', + 'Formula("3i+4j-k")->eval', + '3*i + 4*j - k', +)\} +$PAR$BR +END_TEXT + + +########################################################## +# +# Use Vector context +# + +Context('Vector'); + +BEGIN_TEXT +\{Title("The Vector context:")\} +$PAR +\{ParserTable( + 'i', + 'Formula("1+3i")', + 'Formula("x+3i")', + '1 + 3*i', + '$x + 3*i', + '$z = tan(2*i)', + 'Formula("sinh(zi)")', + 'Formula("3i+4j-k")', + 'Formula("3i+4j-k")->eval', + '3*i + 4*j - k', +)\} + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/5-operator.pg @@ -0,0 +1,89 @@ +########################################################## +# +# Example of how to implement equalities in the Parser +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +########################################################## +# +# Define our own operator for equality +# + +package Equality; +our @ISA = qw(Parser::BOP); # subclass of Binary OPerator + +# +# Check that the operand types are numbers. +# +sub _check { + my $self = shift; my $name = $self->{bop}; + $self->Error("Only one equality is allowed in an equation") + if ($self->{lop}->class eq 'Equality' || $self->{rop}->class eq 'Equality') ; + $self->Error("Operands of '$name' must be Numbers") unless $self->checkNumbers(); + $self->{type} = Value::Type('Equality',1); # Make it not a number, to get errors with other operations. +} + +# +# Determine if the two sides are equal +# +sub _eval {return ($_[1] == $_[2])? 1: 0} + +package main; + +# +# Add the operator into the current context +# + +$prec = Context()->operators->get(',')->{precedence} + .25; + +Context()->operators->add( + '=' => { + class => 'Equality', + precedence => $prec, # just above comma + associativity => 'left', # computed left to right + type => 'bin', # binary operator + string => '=', # output string for it + perl => '==', # perl string + } +); + + +########################################################### +# +# The problem text +# +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we have added a new operator to the Parser: ${BTT} a += b${ETT}, for equality. +$PAR + +\{ParserTable( + 'Formula("x + y = 0")', + 'Formula("x + y = 0")->{tree}->class', + 'Formula("x + y = 0")->{tree}{lop}', + 'Formula("x + y = 0")->{tree}{rop}', + 'Formula("x + y = 0")->eval(x=>2,y=>3)', + 'Formula("x + y = 0")->eval(x=>2,y=>-2)', + 'Formula("x + y = 0 = z")', + 'Formula("(x + y = 0) + 5")', + 'Formula("x + y = 0, 3x-y = 4")', # you CAN get a list of equalities + )\} + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/8-answer.pg @@ -0,0 +1,112 @@ +########################################################## +# +# Example showing an answer checker that uses the parser +# to evaluate the student (and professor's) answers. +# +# This is now obsolete, as the paser's ->cmp method +# can be used to produce an answer checker for any +# of the parser types. +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserUtils.pl", +); + +TEXT(beginproblem()); + +########################################################## +# +# Use Vector context +# + +Context('Vector'); + +########################################################## +# +# Make the answer checker +# +sub vector_cmp { + my $v = shift; + die "vector_cmp requires a vector argument" unless defined $v; + my $v = Vector($v); # covert to vector if it isn't already + my $ans = new AnswerEvaluator; + $ans->ans_hash(type => "vector",correct_ans => $v->string, vector=>$v); + $ans->install_evaluator(~~&vector_cmp_check); + return $ans; +} + +sub vector_cmp_check { + my $ans = shift; my $v = $ans->{vector}, + $ans->score(0); # assume failure + my $f = Parser::Formula($ans->{student_ans}); + my $V = Parser::Evaluate($f); + if (defined $V) { + $V = Formula($V) unless Value::isValue($V); # make sure we can call Value methods + $ans->{preview_latex_string} = $f->TeX; + $ans->{preview_text_string} = $f->string; + $ans->{student_ans} = $V->string; + if ($V->type eq 'Vector') { + $ans->score(1) if ($V == $v); # Let the overloaded == do the check + } else { + $ans->{ans_message} = $ans->{error_message} = + "Your answer doesn't seem to be a Vector (it looks like ".Value::showClass($V).")" + unless $inputs_ref->{previewAnswers}; + } + } else { + # + # Student answer evaluation failed. + # Report the error, with formatting, if possible. + # + my $context = Context(); + my $message = $context->{error}{message}; + if ($context->{error}{pos}) { + my $string = $context->{error}{string}; + my ($s,$e) = @{$context->{error}{pos}}; + $message =~ s/; see.*//; # remove the position from the message + $ans->{student_ans} = protectHTML(substr($string,0,$s)) . + '<SPAN CLASS="parsehilight">' . + protectHTML(substr($string,$s,$e-$s)) . + '</SPAN>' . + protectHTML(substr($string,$e)); + } + $ans->{ans_message} = $ans->{error_message} = $message; + } + return $ans; +} + +########################################################## +# +# The problem text +# + +$V = Vector(1,2,3); + +Context()->flags->set(ijk=>0); +Context()->constants->add(a=>1,b=>1,c=>1); + +$ABC = Formula("<a,b,c>"); + +BEGIN_TEXT +Enter the vector \(\{$V->TeX\}\) in any way you like: \{ans_rule(20)\}. +$PAR +You can use either \(\{$ABC->TeX\}\) or \(\{$ABC->ijk\}\) notation,$BR +and can perform vector operations to produce your answer. +$PAR +${BBOLD}Note:${EBOLD} This problem is obsolete. +END_TEXT + +########################################################### +# +# The answer +# + +ANS(vector_cmp($V)); + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/6-precedence.pg @@ -0,0 +1,84 @@ +########################################################## +# +# Example of the non-standard precedences as a possible alternative +# that makes it possible to write "sin 2x" and get "sin(2x)" +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +########################################################## +# +# Use standard precedences for multiplication +# + +Context()->usePrecedence("Standard"); + +$standard = ParserTable( + 'Formula("sin 2xy/3")', + 'Formula("sin 2x y/3")', + 'Formula("sin 2x y / 3")', + 'Formula("sin 2x+5")', + 'Formula("sin x(x+1)")', + 'Formula("sin x (x+1)")', + 'Formula("1/2xy")', + 'Formula("1/2 xy")', + 'Formula("1/2x y")', + 'Formula("sin^2 x")', + 'Formula("sin^(-1) x")', + 'Formula("x^2x")', +); + +Context()->usePrecedence("Non-Standard"); + +$nonstandard = ParserTable( + 'Formula("sin 2xy/3")', + 'Formula("sin 2x y/3")', + 'Formula("sin 2x y / 3")', + 'Formula("sin 2x+5")', + 'Formula("sin x(x+1)")', + 'Formula("sin x (x+1)")', + 'Formula("1/2xy")', + 'Formula("1/2 xy")', + 'Formula("1/2x y")', + 'Formula("sin^2 x")', + 'Formula("sin^(-1) x")', + 'Formula("x^2x")', +); + + + +########################################################### +# +# The problem text +# +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we compare the standard and non-standard precedences for +multiplication. +$PAR + +\{Title("The Non-Standard precedences:")\} +$PAR +$nonstandard +$PAR$BR + +\{Title("The Standard precedences:")\} +$PAR +$standard + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/3-operator.pg @@ -0,0 +1,113 @@ +########################################################## +# +# Example showing how to add new operators to the Parser +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +########################################################## +# +# Define our own binary operator +# + +package MyOperator; +our @ISA = qw(Parser::BOP); # subclass of Binary OPerator + +# +# Check that the operand types are numbers. +# +sub _check { + my $self = shift; my $name = $self->{bop}; + return if $self->checkNumbers(); + $self->Error("Operands of '$name' must be Numbers"); +} + +# +# Compute the value of n choose r. +# +sub _eval { + shift; my ($n,$r) = @_; my $C = 1; + $r = $n-$r if ($r > $n-$r); # find the smaller of the two + for (1..$r) {$C = $C*($n-$_+1)/$_} + return $C +} + +# +# Non-standard TeX output +# +sub TeX { + my $self = shift; + return '{'.$self->{lop}->TeX.' \choose '.$self->{rop}->TeX.'}'; +} + +# +# Non-standard perl output +# +sub perl { + my $self = shift; + return '(MyOperator->_eval('.$self->{lop}->perl.','.$self->{rop}->perl.'))'; +} + +package main; + +########################################################## +# +# Add the operator into the current context +# + +$prec = Context()->operators->get('+')->{precedence} - .25; + +Context()->operators->add( + '#' => { + class => 'MyOperator', + precedence => $prec, # just below addition + associativity => 'left', # computed left to right + type => 'bin', # binary operator + string => ' # ', # output string for it + TeX => '\mathop{\#}', # TeX version (overridden above, but just an example) + } +); + + +$CHOOSE = MODES(TeX => '\#', HTML => '#'); + + +########################################################### +# +# The problem text +# +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we have added a new operator to the Parser: ${BTT}n $CHOOSE r${ETT}, +which returns \(n\choose r\). +$PAR + +\{ParserTable( + 'Formula("x # y")', + 'Formula("x+1 # 5")', + 'Formula("x # 5")->eval(x=>7)', + 'Formula("(x#5)+(x#4)")', + 'Formula("x#5+x#4")', + 'Formula("x # y")', + 'Formula("x # y")->substitute(x=>5)', + 'Formula("x # y")->eval(x=>5,y=>2)', + 'Formula("x # y")->perlFunction(~~'C~~'); C(5,2)', + 'Formula("1 # <x,3>")', + )\} + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/1-function.pg @@ -0,0 +1,83 @@ +########################################################## +# +# Example showing how to add a new single-variable function to the Parser +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +########################################################### +# +# Use standard numeric mode +# +Context('Numeric'); + +############################################# +# +# Create a 'log2' function to the Parser for log base 2 +# + +package MyFunction1; +our @ISA = qw(Parser::Function::numeric); # this is what makes it R -> R + +sub log2 { + shift; my $x = shift; + return CORE::log($x)/CORE::log(2); +} + +package main; + +# +# Make it work on formulas as well as numbers +# +sub log2 {Parser::Function->call('log2',@_)} + +# +# Add the new functions into the Parser +# + +Context()->functions->add( + log2 => {class => 'MyFunction1', TeX => '\log_2'}, # fancier TeX output +); + +$x = Formula('x'); + +########################################################### +# +# The problem text +# +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we have added a new function to the Parser: ${BTT}log2(x)${ETT}. +(Edit the code to see how this is done.) +$PAR +Assuming that ${BTT}${DOLLAR}x = Formula('x')${ETT}, it can be used as follows: +$PAR + +\{ParserTable( + 'Formula("log2(x)")', + 'log2(8)', + 'log2($x+1)', + 'Formula("log2(x)")->eval(x=>16)', + '(log2($x))->eval(x=>16)', + 'Formula("log2()")', + 'Formula("log2(1,x)")', + 'log2()', + 'log2(1,3)', + )\} + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/macros/parserTables.pl @@ -0,0 +1,87 @@ +loadMacros("parserUtils.pl"); + +############################################# +# +# For Parser example tables: +# + +$BTT = MODES(TeX=>'{\tt ', Latex2HTML => $bHTML.'<TT>'.$eHTML, HTML => '<TT>'); +$ETT = MODES(TeX=>'}', Latex2HTML => $bHTML.'</TT>'.$eHTML, HTML => '</TT>'); + +$BC = MODES( + TeX=>'{\small\it ', + Latex2HTML => $bHTML.'<SMALL><I>'.$eHTML, + HTML => '<SMALL><I>' +); +$EC = MODES( + TeX=>'}', + Latex2HTML => $bHTML.'</I></SMALL>'.$eHTML, + HTML => '</I></SMALL>' +); + +$LT = MODES(TeX => "<", Latex2HTML => "<", HTML => '<'); +$GT = MODES(TeX => ">", Latex2HTML => ">", HTML => '>'); + +$TEX = MODES(TeX => '{\TeX}', HTML => 'TeX', HTML_dpng => '\(\bf\TeX\)'); + +@rowOptions = ( + indent => 0, + separation => 0, + align => 'LEFT" NOWRAP="1', # alignment hack to get NOWRAP +); + +sub ParserRow { + my $f = shift; my $t = ''; + Context()->clearError; + my ($s,$err) = PG_restricted_eval($f); + if (defined $s) { + my $ss = $s; + if (ref($s) && \&{$s->string}) { + $t = '\('.$s->TeX.'\)'; + $s = $s->string; + } elsif ($s !~ m/^[a-z]+$/i) { + $t = '\('.Formula($s)->TeX.'\)'; + $s = Formula($s)->string; + } + $s =~ s/</$LT/g; $s =~ s/>/$GT/g; + if (ref($ss) && \&{$ss->class}) { + if ($ss->class eq 'Formula') { + $s .= ' '.$BC.'(Formula returning '.$ss->showType.')'.$EC; + } else { + $s .= ' '.$BC.'('.$ss->class.' object)'.$EC; + } + } + } else { + $s = $BC. (Context()->{error}{message} || $err) . $EC; + $t = ''; + } + $f =~ s/</$LT/g; $f =~ s/>/$GT/g; + if ($displayMode eq 'TeX') { + $f =~ s/\^/\\char`\\^/g; $s =~ s/\^/\\char`\\^/g; + $f =~ s/#/\\#/g; $s =~ s/#/\\#/g; + } + my $row = Row([$BTT.$f.$ETT,$BTT.$s.$ETT,$t],@rowOptions); + $row =~ s/\$/\${DOLLAR}/g; + return $row; +} + +sub ParserTable { + my $table = + BeginTable(border=>1, padding=>20). + Row([$BBOLD."Perl Code".$EBOLD, + $BBOLD."Result".$EBOLD, + $BBOLD.$TEX.' version'.$EBOLD],@rowOptions); + foreach my $f (@_) {$table .= ParserRow($f)} + $table .= EndTable(); + return $table; +} + +sub Title { + my $title = shift; + + MODES( + TeX => "\\par\\centerline{\\bf $title}\\par\\nobreak\n", + Latex2HTML => $bHTML.'<CENTER><H2>'.$title.'</H2></CENTER>'.$eHTML, + HTML => '<CENTER><H2>'.$title.'</H2></CENTER>' + ); +} --- /dev/null +++ doc/MathObjects/macros/Differentiation.pl @@ -0,0 +1,20 @@ +# +# Example of how to add new functionality to the Parser. +# +# Here we load new methods for the Parser object classes. Note, however, +# that these are PERSISTANT when used with webwork2 (mod_perl), and so we +# need to take care not to load them more than once. We look for the +# variable $Parser::Differentiation::loaded, which is defined in the +# differentiation package, in order to tell. +# +# DifferentiationDefs.pl is really just a copy of the +# Parser::Differentiation.pm file, and you really could just preload the +# latter instead by uncommenting the 'use Parser::Differentiation' line at +# the bottom of Parser.pm. (This file is really just a sample). The way +# it's done here will load it the first time it gets used, then will keep +# it around, so not much overhead even this way. +# + +loadMacros("DifferentiationDefs.pl") unless $Parser::Differentiation::loaded; + +1; --- /dev/null +++ doc/MathObjects/macros/DifferentiationDefs.pl @@ -0,0 +1,635 @@ +# +# Extend differentiation to multiple variables +# Check differentiation for complex functions +# Do derivatives for norm and unit. +# +# Make shortcuts for getting numbers 1, 2, and sqrt, etc. +# + +################################################## +# +# Differentiate the formula in terms of the given variable +# +sub Parser::D { + my $self = shift; my $x = shift; + if (!defined($x)) { + my @vars = keys(%{$self->{variables}}); + my $n = scalar(@vars); + if ($n == 0) { + return $self->new('0') if $self->{isNumber}; + $x = 'x'; + } else { + $self->Error("You must specify a variable to differentiate by") unless $n ==1; + $x = $vars[0]; + } + } else { + return $self->new('0') unless defined $self->{variables}{$x}; + } + return $self->new($self->{tree}->D($x)); +} + +sub Item::D { + my $self = shift; + my $type = ref($self); $type =~ s/.*:://; + $self->Error("Differentiation for '$type' is not implemented",$self->{ref}); +} + + +######################################################################### + +sub Parser::BOP::comma::D {Item::D(shift)} +sub Parser::BOP::union::D {Item::D(shift)} + +sub Parser::BOP::add::D { + my $self = shift; my $x = shift; + $self = Parser::BOP->new( + $self->{equation},$self->{bop}, + $self->{lop}->D($x),$self->{rop}->D($x) + ); + return $self->reduce; +} + + +sub Parser::BOP::subtract::D { + my $self = shift; my $x = shift; + $self = Parser::BOP->new( + $self->{equation},$self->{bop}, + $self->{lop}->D($x),$self->{rop}->D($x) + ); + return $self->reduce; +} + +sub Parser::BOP::multiply::D { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + $self = + Parser::BOP->new($equation,'+', + Parser::BOP->new($equation,$self->{bop}, + $self->{lop}->D($x),$self->{rop}->copy($equation)), + Parser::BOP->new($equation,$self->{bop}, + $self->{lop}->copy($equation),$self->{rop}->D($x)) + ); + return $self->reduce; +} + +sub Parser::BOP::divide::D { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + $self = + Parser::BOP->new($equation,$self->{bop}, + Parser::BOP->new($equation,'-', + Parser::BOP->new($equation,'*', + $self->{lop}->D($x),$self->{rop}->copy($equation)), + Parser::BOP->new($equation,'*', + $self->{lop}->copy($equation),$self->{rop}->D($x)) + ), + Parser::BOP->new($equation,'^', + $self->{rop},Parser::Number->new($equation,2) + ) + ); + return $self->reduce; +} + +sub Parser::BOP::power::D { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + my $vars = $self->{rop}->getVariables; + if (defined($vars->{$x})) { + $vars = $self->{lop}->getVariables; + if (defined($vars->{$x})) { + $self = + Parser::Function->new($equation,'exp', + [Parser::BOP->new($equation,'*',$self->{rop}->copy($equation), + Parser::Function->new($equation,'log',[$self->{lop}->copy($equation)],0))]); + return $self->D($x); + } + $self = Parser::BOP->new($equation,'*', + Parser::Function->new($equation,'log',[$self->{lop}->copy($equation)],0), + Parser::BOP->new($equation,'*', + $self->copy($equation),$self->{rop}->D($x)) + ); + } else { + $self = + Parser::BOP->new($equation,'*', + Parser::BOP->new($equation,'*', + $self->{rop}->copy($equation), + Parser::BOP->new($equation,$self->{bop}, + $self->{lop}->copy($equation), + Parser::BOP->new($equation,'-', + $self->{rop}->copy($equation), + Parser::Number->new($equation,1) + ) + ) + ), + $self->{lop}->D($x) + ); + } + return $self->reduce; +} + +sub Parser::BOP::cross::D {Item::D(shift)} +sub Parser::BOP::dot::D {Item::D(shift)} +sub Parser::BOP::underscore::D {Item::D(shift)} + +######################################################################### + +sub Parser::UOP::plus::D { + my $self = shift; my $x = shift; + return $self->{op}->D($x) +} + +sub Parser::UOP::minus::D { + my $self = shift; my $x = shift; + $self = Parser::UOP->new($self->{equation},'u-',$self->{op}->D($x)); + return $self->reduce; +} + +sub Parser::UOP::factorial::D {Item::D(shift)} + +######################################################################### + +sub Parser::Function::D { + my $self = shift; + $self->Error("Differentiation of '$self->{name}' not implemented",$self->{ref}); +} + +sub Parser::Function::D_chain { + my $self = shift; my $x = $self->{params}[0]; + my $name = "D_" . $self->{name}; + $self = Parser::BOP->new($self->{equation},'*',$self->$name($x->copy),$x->D(shift)); + return $self->reduce; +} + +############################# + +sub Parser::Function::trig::D {Parser::Function::D_chain(@_)} + +sub Parser::Function::trig::D_sin { + my $self = s... [truncated message content] |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 01:23:01
|
Log Message: ----------- removed ==== Tags: ---- rel-2-4-patches Modified Files: -------------- pg/lib/Value: Union.pm Revision Data ------------- Index: Union.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/Union.pm,v retrieving revision 1.24.6.2 retrieving revision 1.24.6.2.2.1 diff -Llib/Value/Union.pm -Llib/Value/Union.pm -u -r1.24.6.2 -r1.24.6.2.2.1 --- lib/Value/Union.pm +++ lib/Value/Union.pm @@ -4,7 +4,6 @@ my $pkg = 'Value::Union'; qw(Value); -======= use strict; no strict "refs"; our @ISA = qw(Value); |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 01:02:15
|
Log Message: ----------- merging with HEAD 6/23/2008 see Value.pm for list of significant changes Tags: ---- rel-2-4-dev Modified Files: -------------- pg/macros: IO.pl LinearProgramming.pl MathObjects.pl PG.pl PGanswermacros.pl PGasu.pl PGauxiliaryFunctions.pl PGbasicmacros.pl PGchoicemacros.pl PGcomplexmacros.pl PGgraphmacros.pl PGinfo.pl Parser.pl Value.pl answerComposition.pl answerCustom.pl answerVariableList.pl contextABCD.pl contextIntegerFunctions.pl contextLimitedComplex.pl contextLimitedNumeric.pl contextLimitedPoint.pl contextLimitedPolynomial.pl contextLimitedPowers.pl contextLimitedVector.pl contextPeriodic.pl contextString.pl contextTF.pl dangerousMacros.pl displayMacros.pl extraAnswerEvaluators.pl parserCustomization.pl parserDifferenceQuotient.pl parserFormulaWithUnits.pl parserFunction.pl parserImplicitEquation.pl parserImplicitPlane.pl parserMultiAnswer.pl parserMultiPart.pl parserNumberWithUnits.pl parserParametricLine.pl parserPopUp.pl parserRadioButtons.pl parserSolutionFor.pl parserVectorUtils.pl Added Files: ----------- pg/macros: AppletObjects.pl PGcourse.pl PGfunctionevaluators.pl PGmiscevaluators.pl PGnumericevaluators.pl PGstringevaluators.pl PGtextevaluators.pl answerHints.pl compoundProblem.pl contextCurrency.pl contextInequalities.pl contextPiecewiseFunction.pl contextScientificNotation.pl parserAssignment.pl parserAutoStrings.pl parserFormulaUpToConstant.pl problemPreserveAnswers.pl problemRandomize.pl Revision Data ------------- Index: parserParametricLine.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/parserParametricLine.pl,v retrieving revision 1.5.2.1 retrieving revision 1.5.2.2 diff -Lmacros/parserParametricLine.pl -Lmacros/parserParametricLine.pl -u -r1.5.2.1 -r1.5.2.2 --- macros/parserParametricLine.pl +++ macros/parserParametricLine.pl @@ -1,63 +1,63 @@ -loadMacros('Parser.pl'); +################################################################################ +# WeBWorK Online Homework Delivery System +# Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader$ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. +################################################################################ -sub _parserParametricLine_init {}; # don't reload this file +=head1 NAME + + +parserParametricLine.pl - Implements Formulas that represent parametric lines. =head1 DESCRIPTION -###################################################################### -# -# This is a Parser class that implements parametric lines as -# a subclass of the Formula class. The standard ->cmp routine -# will work for this, provided we define the compare() function -# needed by the overloaded ==. We assign the special precedence -# so that overloaded operations will be promoted to the ones below. -# -# Use ParametricLine(point,vector) or ParametricLine(formula) -# to create a ParametricLine object. You can pass an optional -# additional parameter that indicated the variable to use for the -# parameter for the line. -# -# Usage examples: -# -# $L = ParametricLine(Point(3,-1,2),Vector(1,1,3)); -# $L = ParametricLine([3,-1,2],[1,1,3]); -# $L = ParametricLine("<t,1-t,2t-3>"); -# -# $p = Point(3,-1,2); $v = Vector(1,1,3); -# $L = ParametricLine($p,$v); -# -# $t = Formula('t'); $p = Point(3,-1,2); $v = Vector(1,1,3); -# $L = ParametricLine($p+$t*$v); -# -# Context()->constants->are(a=>1+pi^2); # won't guess this value -# $L = ParametricLine("(a,2a,-1) + t <1,a,a^2>"); -# -# Then use -# -# ANS($L->cmp); -# -# to get the answer checker for $L. -# +This is a Parser class that implements parametric lines as +a subclass of the Formula class. The standard ->cmp routine +will work for this, provided we define the compare() function +needed by the overloaded ==. We assign the special precedence +so that overloaded operations will be promoted to the ones below. + +Use ParametricLine(point,vector) or ParametricLine(formula) +to create a ParametricLine object. You can pass an optional +additional parameter that indicated the variable to use for the +parameter for the line. + +Usage examples: + + $L = ParametricLine(Point(3,-1,2),Vector(1,1,3)); + $L = ParametricLine([3,-1,2],[1,1,3]); + $L = ParametricLine("<t,1-t,2t-3>"); + + $p = Point(3,-1,2); $v = Vector(1,1,3); + $L = ParametricLine($p,$v); + + $t = Formula('t'); $p = Point(3,-1,2); $v = Vector(1,1,3); + $L = ParametricLine($p+$t*$v); + + Context()->constants->are(a=>1+pi^2); # won't guess this value + $L = ParametricLine("(a,2a,-1) + t <1,a,a^2>"); + +Then use + + ANS($L->cmp); + +to get the answer checker for $L. =cut -# -# Define a new context for lines -# -$context{ParametricLine} = Parser::Context->getCopy(undef,"Vector"); -$context{ParametricLine}->variables->are(t=>'Real'); -$context{ParametricLine}->{precedence}{ParametricLine} = - $context{ParametricLine}->{precedence}{special}; -$context{ParametricLine}->reduction->set('(-x)-y'=>0); -# -# Make it active -# -Context("ParametricLine"); +loadMacros('MathObjects.pl'); -# -# Syntactic sugar -# -sub ParametricLine {ParametricLine->new(@_)} +sub _parserParametricLine_init {ParametricLine::Init()}; # don't reload this file # # Define the subclass of Formula @@ -65,6 +65,18 @@ package ParametricLine; our @ISA = qw(Value::Formula); +sub Init { + my $context = $main::context{ParametricLine} = Parser::Context->getCopy("Vector"); + $context->{name} = "ParametricLine"; + $context->variables->are(t=>'Real'); + $context->{precedence}{ParametricLine} = $context->{precedence}{special}; + $context->reduction->set('(-x)-y'=>0); + + main::Context("ParametricLine"); ### FIXME: probably should require author to set this explicitly + + main::PG_restricted_eval('sub ParametricLine {ParametricLine->new(@_)}'); +} + sub new { my $self = shift; my $class = ref($self) || $self; my $context = (Value::isContext($_[0]) ? shift : $self->context); @@ -95,14 +107,15 @@ return bless $line, $class; } -=head3 compare($lhs,$rhs) -# -# Two parametric lines are equal if they have -# parallel direction vectors and either the same -# points or the vector between the points is -# parallel to the (common) direction vector. -# +=head2 $lhs == $rhs + + # + # Two parametric lines are equal if they have + # parallel direction vectors and either the same + # points or the vector between the points is + # parallel to the (common) direction vector. + # =cut @@ -129,7 +142,7 @@ # sub cmp_postprocess { my $self = shift; my $ans = shift; - my $error = $sef->context->{error}{message}; + my $error = $self->context->{error}{message}; $self->cmp_error($ans) if $error =~ m/^(Your formula (isn't linear|doesn't look)|A line can't|The direction vector)/; } Index: contextLimitedPoint.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextLimitedPoint.pl,v retrieving revision 1.2.6.1 retrieving revision 1.2.6.2 diff -Lmacros/contextLimitedPoint.pl -Lmacros/contextLimitedPoint.pl -u -r1.2.6.1 -r1.2.6.2 --- macros/contextLimitedPoint.pl +++ macros/contextLimitedPoint.pl @@ -1,20 +1,42 @@ -loadMacros("Parser.pl"); +################################################################################ +# WeBWorK Online Homework Delivery System +# Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader$ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. +################################################################################ + +=head1 NAME + +contextLimitedPoint.pl - Allow point entry but no point operations. + +=head1 DESCRIPTION + +Implements a context in which points can be entered, +but no operations are permitted between points. So +students will be able to perform operations within the +coordinates of the points, but not between points. -sub _contextLimitedPoint_init {}; # don't load it again + Context("LimitedPoint") -=head3 Context("LimitedPoint") +=cut -########################################################## -# -# Implements a context in which points can be entered, -# but no operations are permitted between points. So -# students will be able to perform operations within the -# coordinates of the points, but not between points. -# -=cut +loadMacros("MathObjects.pl"); + +sub _contextLimitedPoint_init {LimitedPoint::Init()}; # don't load it again + +################################################## # # Handle common checking for BOPs # @@ -106,41 +128,46 @@ ############################################## ############################################## -package main; +package LimitedPoint; -# -# Now build the new context that calls the -# above classes rather than the usual ones -# +sub Init { + # + # Build the new context that calls the + # above classes rather than the usual ones + # + + my $context = $main::context{LimitedPoint} = Parser::Context->getCopy("Point"); + $context->{name} = "LimitedPoint"; + $context->operators->set( + '+' => {class => 'LimitedPoint::BOP::add'}, + '-' => {class => 'LimitedPoint::BOP::subtract'}, + '*' => {class => 'LimitedPoint::BOP::multiply'}, + '* ' => {class => 'LimitedPoint::BOP::multiply'}, + ' *' => {class => 'LimitedPoint::BOP::multiply'}, + ' ' => {class => 'LimitedPoint::BOP::multiply'}, + '/' => {class => 'LimitedPoint::BOP::divide'}, + ' /' => {class => 'LimitedPoint::BOP::divide'}, + '/ ' => {class => 'LimitedPoint::BOP::divide'}, + 'u+' => {class => 'LimitedPoint::UOP::plus'}, + 'u-' => {class => 'LimitedPoint::UOP::minus'}, + ); + # + # Remove these operators and functions + # + $context->operators->undefine('_','U','><','.'); + $context->functions->undefine('norm','unit'); + $context->lists->set( + AbsoluteValue => {class => 'LimitedPoint::List::AbsoluteValue'}, + ); + $context->parens->set( + '(' => {formMatrix => 0}, + '[' => {formMatrix => 0}, + ); + $context->variables->are(x=>'Real'); + $context->constants->remove('i','j','k'); + + main::Context("LimitedPoint"); ### FIXME: probably should require author to set this explicitly +} -$context{LimitedPoint} = Parser::Context->getCopy(undef,"Point"); -$context{LimitedPoint}->operators->set( - '+' => {class => 'LimitedPoint::BOP::add'}, - '-' => {class => 'LimitedPoint::BOP::subtract'}, - '*' => {class => 'LimitedPoint::BOP::multiply'}, - '* ' => {class => 'LimitedPoint::BOP::multiply'}, - ' *' => {class => 'LimitedPoint::BOP::multiply'}, - ' ' => {class => 'LimitedPoint::BOP::multiply'}, - '/' => {class => 'LimitedPoint::BOP::divide'}, - ' /' => {class => 'LimitedPoint::BOP::divide'}, - '/ ' => {class => 'LimitedPoint::BOP::divide'}, - 'u+' => {class => 'LimitedPoint::UOP::plus'}, - 'u-' => {class => 'LimitedPoint::UOP::minus'}, -); -# -# Remove these operators and functions -# -$context{LimitedPoint}->operators->undefine('_','U','><','.'); -$context{LimitedPoint}->functions->undefine('norm','unit'); -$context{LimitedPoint}->lists->set( - AbsoluteValue => {class => 'LimitedPoint::List::AbsoluteValue'}, -); -$context{LimitedPoint}->parens->set( - '(' => {formMatrix => 0}, - '[' => {formMatrix => 0}, -); -$context{LimitedPoint}->parens->remove('<'); -$context{LimitedPoint}->variables->are(x=>'Real'); -$context{LimitedPoint}->constants->remove('i','j','k'); -Context("LimitedPoint"); +1; Index: IO.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/IO.pl,v retrieving revision 1.3.6.1 retrieving revision 1.3.6.2 diff -Lmacros/IO.pl -Lmacros/IO.pl -u -r1.3.6.1 -r1.3.6.2 --- macros/IO.pl +++ macros/IO.pl @@ -1,19 +1,35 @@ ################################################################################ -# WeBWorK mod-perl (c) 2000-2002 WeBWorK Project -# $Id$ + +# WeBWorK Online Homework Delivery System +# Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader$ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. ################################################################################ =head1 NAME -IO.pl - Temporary location for IO functions that need access to the problem -environment. Formerly defined in IO.pm +IO.pl - Input/optput macros that require access to the problem environment. + +=head1 DESCRIPTION -See notes in Translator.pm +See notes in L<WeBWorK::PG::Translator>. =cut +# ^function _IO_init sub _IO_init {} + +# ^function _IO_export sub _IO_export { return ( '&send_mail_to', @@ -22,7 +38,25 @@ ); } +=head1 MACROS + +=head2 [DEPRECATED] send_mail_to + + send_mail_to($address, subject=>$subject, body=>$body) + +Send an email message with the subject $subject and body $body to the address +$address. This used to be used by mail_answers_to in PGbasicmacros.pl, but it no +longer is. Don't use this, I tell yah! + +=cut + # send_mail_to($user_address,'subject'=>$subject,'body'=>$body) +# ^function send_mail_to +# ^uses $envir{mailSmtpServer} +# ^uses $envir{mailSmtpSender} +# ^uses $REMOTE_HOST +# ^uses $REMOTE_ADDR +# ^uses Net::SMTP::new sub send_mail_to { my $user_address = shift; # user must be an instructor my %options = @_; @@ -80,34 +114,38 @@ return $out; } -sub getCourseTempDirectory { - return $envir{tempDirectory}; -} +=head2 getCourseTempDirectory -=head2 surePathToTmpFile + $path = getCourseTempDirectory() - surePathToTmpFile($path) - Returns: $path +Returns the path to the current course's temporary directory. -Defined in FILE.pl +=cut -Creates all of the subdirectories between the directory specified -by C<&getCourseTempDirectory> and the address of the path. +# ^function getCourseTempDirectory +# ^uses $envir{tempDirectory} +sub getCourseTempDirectory { + return $envir{tempDirectory}; +} -Uses +=head2 surePathToTmpFile - &createDirectory($path,$Global::tmp_directory_permission, $Global::numericalGroupID) + $path = surePathToTmpFile($path); -The path may begin with the correct path to the temporary -directory. Any other prefix causes a path relative to the temporary -directory to be created. +Creates all of the intermediate directories between the directory specified by +getCourseTempDirectory() and file specified in $path. -The quality of the error checking could be improved. :-) +If $path begins with the path returned by getCourseTempDirectory(), then the +path is treated as absolute. Otherwise, the path is treated as relative the the +course temp directory. =cut # A very useful macro for making sure that all of the directories to a file have been constructed. +# ^function surePathToTmpFile +# ^uses getCourseTempDirectory +# ^uses createDirectory sub surePathToTmpFile { # constructs intermediate directories if needed beginning at ${Global::htmlDirectory}tmp/ # the input path must be either the full path, or the path relative to this tmp sub directory --- /dev/null +++ macros/parserAssignment.pl @@ -0,0 +1,396 @@ +################################################################################ +# WeBWorK Online Homework Delivery System +# Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader: pg/macros/parserAssignment.pl,v 1.2.2.1 2008/06/24 00:44:54 gage Exp $ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. +################################################################################ + +=head1 NAME + +parserAssignment.pl - Implements assignments to variables + +=head1 DESCRIPTION + +This file implements an assignment operator that allows only a single +variable reference on the left and any value on the right. You can use +this to require students to enter things like + + y = 3x + 1 + +rather than making the "y = " part of the text of the question. This +also allows you to ask for lists of assignments more easily. + +To use it, load the macro file, select the Context you want to use, +add any variables you may need, and enable the assignment operator as +in the following example: + + loadMacros( + "PGstandard.pl", + "MathObjects.pl", + "parserAssignment.pl", + ); + + Context("Numeric")->variables->add(y=>'Real'); + parser::Assignment->Allow; + +Now you can use the equal sign in Formula() objects to create assignments. + + $f = Formula("y = 3x + 1"); + ... + ANS($f->cmp); + +The student will have to make an assignment to the same variable in +order to get credit. For example, he or she could enter y = 1+3x to get +credit for the answer above. + +The left-hand side of an assignment must be a single variable, so + + $f = Formula("3y = 2x"); + +will produce an error. The right-hand side can not include the +variable being assigned on the left, so + + $f = Formula("x = 2x+1"); + +also is not allowed. + +You can produce lists of assignments just as easily: + + $f = Formula("y = 3x, y = 2x-1"); + +and the assignment can be of any type of MathObject. For example: + + Context("Vector")->variables->add(p=>'Vector3D'); + parser::Assignment->Allow; + + $f = Formula("p = <1,2x,1-x>"); + +To produce a constant assignment, use Compute(), as in: + + $p = Compute("p = <1,2,3>"); + +(in fact, Compute() could be used for in place of Formula() in the +examples above as well, since it returns a Formula when the value is +one). + +The left-hand side of an assignment can also be a function +declaration, as in + + f(x) = 3x + 1 + +To allow this, use + + parser::Assignment->Function("f"); + +You can supply more than one function name if you want. E.g., + + parser::Assignment->Function("f","g"); + +The number of variables for these functions is determined by the +assignment itself, so after declaring f to be a function, you can use +either + + f(x) = x+1 +or + f(x,y) = x^2 + y^2 + +provided the variables are defined in the current context. + +Type-checking between the student and correct answers is performed +using the right-hand values of the assignment, and a warning message +will be issued if the types are not compatible. The type of the +variable on the left-hand side, however, is not checked. + +For function declarations, the name of the function and the order +of the variables must match the professor's answer; however, the +names of the variables don't have to match, as long as the function +returns the same results for the same inputs. So + + f(x) = x + 1 +and + f(y) = y + 1 + +will be marked as equal. + +=cut + +# +# FIXME: allow any variables in declaration +# FIXME: Add more hints when variable name isn't right +# or function name or number of arguments isn't right. +# + +sub _parserAssignment_init {parser::Assignment::Init()} + +###################################################################### + +package parser::Assignment; +our @ISA = qw(Parser::BOP); + +sub Init { + main::PG_restricted_eval('sub Assignment {parser::Assignment::List->new(@_)}'); +} + +# +# Check that the left operand is a variable and not used on the right +# +sub _check { + my $self = shift; my $name = $self->{def}{string} || $self->{bop}; + $self->Error("Only one assignment is allowed in an equation") + if $self->{lop}->type eq 'Assignment' || $self->{rop}->type eq 'Assignment'; + $self->Error("The left side of an assignment must be a variable or function",$name) + unless $self->{lop}->class eq 'Variable' || $self->{lop}{isDummy} || $self->context->flag("allowBadOperands"); + if ($self->{lop}{isDummy}) { + my $fvars = $self->{lop}->getVariables; + foreach my $x (keys(%{$self->{rop}->getVariables})) { + $self->Error("The formula for %s can't use the variable '%s'",$self->{lop}->string,$x) + unless $fvars->{$x}; + } + } else { + $self->Error("The right side of an assignment must not include the variable being defined") + if $self->{rop}->getVariables->{$self->{lop}{name}}; + delete $self->{equation}{variables}{$self->{lop}{name}}; + } + $self->{type} = Value::Type('Assignment',2,$self->{rop}->typeRef,list => 1); +} + +# +# Convert to an Assignment object +# +sub eval { + my $self = shift; my $context = $self->context; + my ($a,$b) = ($self->Package("String")->make($context,$self->{lop}->string),$self->{rop}); + $b = Value::makeValue($b->eval,context => $context); + return parser::Assignment::List->make($context,$a,$b); +} + +# +# Don't count the left-hand variable +# +sub getVariables { + my $self = shift; + return $self->{lop}->getVariables if $self->{lop}{isDummy}; + $self->{rop}->getVariables; +} + +# +# Create an Assignment object +# +sub perl { + my $self = shift; + return "parser::Assignment::List->new('".$self->{lop}->string."',".$self->{rop}->perl.")"; +} + +# +# Add/Remove the Assignment operator to/from a context +# +sub Allow { + my $self = shift || "Value"; my $context = shift || $self->context; + my $allow = shift; $allow = 1 unless defined($allow); + if ($allow) { + my $prec = $context->{operators}{','}{precedence}; + $prec = 1 unless defined($prec); + $context->operators->add( + '=' => { + class => 'parser::Assignment', + precedence => $prec+.25, # just above comma + associativity => 'left', # computed left to right + type => 'bin', # binary operator + string => ' = ', # output string for it + } + ); + $context->{value}{Formula} = 'parser::Assignment::Formula'; + $context->{value}{Assignment} = 'parser::Assignment::List'; + } else {$context->operators->remove('=')} + return; +} + +sub Function { + my $self = shift || "Value"; + my $context = (Value::isContext($_[0]) ? shift : $self->context); + Value->Error("You must provide a function name") unless scalar(@_) > 0; + foreach my $f (@_) { + Value->Error("Function name '%s' is illegal",$f) unless $f =~ m/^[a-z][a-z0-9]*$/i; + my $name = $f; $name = $1.'_{'.$2.'}' if ($name =~ m/^(\D+)(\d+)$/); + $context->functions->add( + $f => {class => 'parser::Assignment::Function', TeX => $name, type => $Value::Type{number}} + ); + } +} + +###################################################################### + +# +# A special List object that holds a variable and a value, and +# that prints with an equal sign. +# + +package parser::Assignment::List; +our @ISA = ("Value::List"); + +sub new { + my $self = shift; my $class = ref($self) || $self; + my $context = (Value::isContext($_[0]) ? shift : $self->context); + Value->Error("Too many arguments") if scalar(@_) > 2; + my ($x,$v) = @_; + if (defined($v)) { + my $context = $self->context; + $v = Value::makeValue($v,context=>$context); + if ($v->isFormula) { + $x = $self->Package("Formula")->new($context,$x); + $v->{tree} = parser::Assignment->new($v,"=",$x->{tree},$v->{tree}); + bless $v, $self->Package("Formula"); + return $v; + } + return $self->make($self->Package("String")->make($context,$x),$v); + } else { + $v = $self->Package("Formula")->new($x); + Value->Error("Your formula doesn't seem to be an assignment") + unless $v->{tree}->type eq "Assignment"; + return $v; + } +} + +sub string { + my $self = shift; my ($x,$v) = $self->value; + $x->string . ' = ' . $v->string; +} + +sub TeX { + my $self = shift; my ($x,$v) = $self->value; + $x = $self->Package("Formula")->new($x->{data}[0]); + $x->TeX . ' = ' . $v->string; +} + +# +# Needed since these are called explicitly without an object +# +sub cmp_defaults { + my $self = shift; + $self->SUPER::cmp_defaults(@_); +} + +# +# Class is an a variable assigned to whatever +# +sub cmp_class { + my $self = shift; + my $type = ($self->{data}[0] =~ m/\(/ ? 'Function' : 'Variable'); + "a $type equal to ".$self->{data}[1]->showClass; +} +sub showClass {cmp_class(@_)} + +# +# Return the proper type +# +sub typeRef { + my $self = shift; + Value::Type('Assignment',2,$self->{data}[1]->typeRef,list=>1); +} + +###################################################################### + +# +# A subclass of Formula that does typematching properly for Assignments +# (the match is against the right-hand sides) +# + +package parser::Assignment::Formula; +our @ISA = ("Value::Formula"); + +sub new { + my $self = shift; $class = ref($self) || $self; + my $f = $self->SUPER::new(@_); + bless $f, $class if $f->type eq 'Assignment'; + return $f; +} + +sub typeMatch { + my $self = shift; my $other = shift; my $ans = shift; + return 0 unless $self->type eq $other->type; + $other = $other->Package("Formula")->new($self->context,$other) unless $other->isFormula; + my $typeMatch = ($self->createRandomPoints(1))[1]->[0]{data}[1]; + $main::__other__ = sub {($other->createRandomPoints(1))[1]->[0]{data}[1]}; + $other = main::PG_restricted_eval('&$__other__()'); + delete $main::{__other__}; + return 1 unless defined($other); # can't really tell, so don't report type mismatch + $typeMatch->typeMatch($other,$ans); +} + +sub cmp_class { + my $self = shift; my $value; + if ($self->{tree}{rop}{isConstant}) { + $value = ($self->createRandomPoints(1))[1]->[0]{data}[1]; + } else { + $value = $self->Package("Formula")->new($self->context,$self->{tree}{rop}); + } + my $type = ($self->{tree}{lop}{isDummy} ? "Function" : "Variable"); + return "a $type equal to ".$value->showClass; +} +sub showClass {cmp_class(@_)} + +# +# Convert varaible names to those used in the correct answer, if the +# student answer uses different ones +# +sub compare { + my ($l,$r) = @_; my $self = $l; + my $context = $self->context; + $r = $context->Package("Formula")->new($context,$r) unless Value::isFormula($r); + if ($l->{tree}{lop}{isDummy} && $r->type eq 'Assignment' && $r->{tree}{lop}{isDummy}) { + my ($F,$f) = ($l->{tree}{lop}{params},$r->{tree}{lop}{params}); + if (scalar(@{$F}) == scalar(@{$f})) { + my @subs = (); + for (my $i = 0; $i < scalar(@{$F}); $i++) { + push(@subs,$f->[$i]{name} => $F->[$i]{name}) + unless $F->[$i]{name} eq $f->[$i]{name}; + } + $r = $r->substitute(@subs) if scalar(@subs); + delete $r->{f}; + } + } + $l->SUPER::compare($r,@_); +} + +###################################################################### + +# +# A dummy function that is used for assignments like f(x) = x^2 +# + +package parser::Assignment::Function; +our @ISA = ("Parser::Function"); + +sub _check { + my $self = shift; my %var; + foreach my $x (@{$self->{params}}) { + $self->Error("The arguments of '%s' must be variables",$self->{name}) + unless $x->class eq 'Variable'; + $self->Error("The arguments of '%s' must all be different",$self->{name}) + if $var{$x->{name}}; + $var{$x->{name}} = 1; + } + $self->{type} = $self->{def}{type}; + $self->{isDummy} = 1; +} + +sub eval { + my $self = shift; + $self->Error("Dummy function '%s' can not be evaluated",$self->{name}); +} + +sub call { + my $self = shift; + $self->Error("Dummy function '%s' can not be called",$self->{name}); +} + +1; Index: contextString.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextString.pl,v retrieving revision 1.4.2.1 retrieving revision 1.4.2.2 diff -Lmacros/contextString.pl -Lmacros/contextString.pl -u -r1.4.2.1 -r1.4.2.2 --- macros/contextString.pl +++ macros/contextString.pl @@ -1,28 +1,47 @@ -loadMacros("Parser.pl"); +################################################################################ +# WeBWorK Online Homework Delivery System +# Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader$ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. +################################################################################ -sub _contextString_init {}; # don't load it again +=head1 NAME -=head3 Context("String") +contextString.pl - Allow string-valued answers. -########################################################## -# -# Implements contexts for string-valued answers. -# -# You can add new strings to the context as needed -# via the Context()->strings->add() method. E.g., -# -# Context("String")->strings->add(Foo=>{}, Bar=>{alias=>"Foo"}); -# -# Use string_cmp() to produce the answer checker(s) for your -# correct values. Eg. -# -# ANS(string_cmp("Foo")); -# -# + +=head1 DESCRIPTION + +Implements contexts for string-valued answers. + +You can add new strings to the context as needed +via the Context()->strings->add() method. E.g., + + Context("String")->strings->add(Foo=>{}, Bar=>{alias=>"Foo"}); + +Use string_cmp() to produce the answer checker(s) for your +correct values. Eg. + + ANS(string_cmp("Foo")); =cut -package contextString::Variable; +loadMacros("MathObjects.pl"); + +sub _contextString_init {context::String::Init()}; # don't load it again + +################################################## + +package context::String::Variable; sub new { my $self = shift; my $equation = shift; @@ -33,36 +52,59 @@ $equation->Error(["Your answer should be one of %s",$strings]); } -package contextString::Formula; -our @ISA = qw(Value::Formula Parser Value); +################################################## + +package context::String::Formula; +our @ISA = qw(Value::Formula); sub parse { my $self = shift; foreach my $ref (@{$self->{tokens}}) { $self->{ref} = $ref; - contextString::Variable->new($self) if ($ref->[0] eq 'error'); # display the error + context::String::Variable->new($self->{equation}) if ($ref->[0] eq 'error'); # display the error } $self->SUPER::parse(@_); } -package main; +package context::String::BOP::mult; +our @ISA = qw(Parser::BOP); + +sub _check { + my $self = shift; + context::String::Variable->new($self->{equation}); # report an error +} + +################################################## + +package context::String; -$context{String} = Parser::Context->getCopy(undef,"Numeric"); -$context{String}->parens->undefine('|','{','(','['); -$context{String}->variables->clear(); -$context{String}->constants->clear(); -$context{String}->operators->clear(); -$context{String}->functions->clear(); -$context{String}->strings->clear(); -$context{String}->{parser}{Variable} = 'contextString::Variable'; -$context{String}->{parser}{Formula} = 'contextString::Formula'; - -Context("String"); - -sub string_cmp { - my $strings = shift; - $strings = [$strings,@_] if (scalar(@_)); - $strings = [$strings] unless ref($strings) eq 'ARRAY'; - return map {String($_)->cmp(showHints=>0,showLengthHints=>0)} @{$strings}; +sub Init { + my $context = $main::context{String} = Parser::Context->getCopy("Numeric"); + $context->{name} = "String"; + $context->parens->clear(); + $context->variables->clear(); + $context->constants->clear(); + $context->operators->clear(); + $context->functions->clear(); + $context->strings->clear(); + $context->{parser}{Variable} = 'context::String::Variable'; + $context->{parser}{Formula} = 'context::String::Formula'; + $context->operators->add( + ' ' => {precedence => 3, associativity=>"left", type=>"bin", string => "*", class => 'context::String::BOP::mult'}, + '*' => {precedence => 3, associativity=>"left", type=>"bin", class => 'context::String::BOP::mult'} + ); + + main::PG_restricted_eval(<<' END_EVAL'); + sub string_cmp { + my $strings = shift; + $strings = [$strings,@_] if (scalar(@_)); + $strings = [$strings] unless ref($strings) eq 'ARRAY'; + return map {String($_)->cmp(showHints=>0,showLengthHints=>0)} @{$strings}; + } + END_EVAL + + main::Context("String"); ### FIXME: probably should require author to set this explicitly } +1; + Index: PGinfo.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/PGinfo.pl,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -Lmacros/PGinfo.pl -Lmacros/PGinfo.pl -u -r1.1.2.1 -r1.1.2.2 --- macros/PGinfo.pl +++ macros/PGinfo.pl @@ -4,23 +4,32 @@ # All Rights Reserved #################################################################### + =head1 NAME - PGinfo.pl - -Provides macros for determining the values of the current context in which the problem + PGinfo.pl + + +Provides macros for determining the values of the current context in which the problem is being written. -loadMacros("Parser.pl"); +=cut + + +loadMacros("MathObjects.pl"); + + + + =head3 listVariables Usage: listVariables(); -Prints all variables submitted in the problem form and all variables in the +Prints all variables submitted in the problem form and all variables in the the Problem environment and all of the flag variables in Context(). This is used for debugging and to determine the current -context for the problem. +context for the problem. =cut @@ -35,7 +44,7 @@ } =head4 listFormVariables() - + Called by listVariables to print out the input form variables. =cut @@ -48,7 +57,7 @@ } =head4 listEnvironmentVariables() - + Called by listVariables to print out the environment variables (in %envir). =cut @@ -60,8 +69,8 @@ } =head4 listContextFlags() - - Called by listVariables to print out context flags for Math Objects. + + Called by listVariables to print out context flags for Math Objects. =cut @@ -73,21 +82,33 @@ =head3 listContext() Usage: listContext(Context()) - + Prints out the contents of the current context hash -- includes flags and much more =cut -sub listContext { # include +sub listContext { # include my $context = shift; return TEXT("$PAR Error in listContext: usage: listContext(Context()); # must specify a context to list $BR") unless defined $context; foreach $key (keys %$context) { - next if $key =~/^_/; # skip if it begins with _ + next if $key =~/^_/; # skip if it begins with TEXT($HR, $key, $BR); TEXT( pretty_print($context->{$key}) ); } } + +=head3 pp() + + Usage: pp(Hash ); + pp(Object); + + + Prints out the contents of Hash or the instance variables of Object + +=cut + sub pp { my $hash = shift; "printing |". ref($hash)."|$BR". pretty_print($hash); -} \ No newline at end of file +} +1; \ No newline at end of file Index: PGchoicemacros.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/PGchoicemacros.pl,v retrieving revision 1.8 retrieving revision 1.8.2.1 diff -Lmacros/PGchoicemacros.pl -Lmacros/PGchoicemacros.pl -u -r1.8 -r1.8.2.1 --- macros/PGchoicemacros.pl +++ macros/PGchoicemacros.pl @@ -1,380 +1,331 @@ - -BEGIN{ - be_strict; -} - -package main; - +################################################################################ +# WeBWorK Program Generation Language +# Copyright � 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader$ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. +################################################################################ =head1 NAME -PGchoicemacros.pl --- located in the courseScripts directory +PGchoicemacros.pl - Macros for multiple choice, matching, and true/false questions. +=head1 SYNOPSIS -=head1 SYNPOSIS - -=pod - -There are two types of choice macros. The older versions are simply scripts. -The newer versions involve the "List.pm" class and its sub-classes -and the use of objects based on these classes. The list sub-classes are: -"Match.pm" which aids in setting up matching question - and answer lists, "Select.pm" which aids in selecting - and presenting a subset of questions with short answers -(e.g. true/false questions) from a larger question set, and -"Multiple.pm" which aids in setting up a -standard style, one question, many answers type multiple -choice question. +Matching example: + loadMacros("PGchoicemacros.pl"); + + # create a new match list + $ml = new_match_list(); + + # enter three questions and their answers + $ml->qa( + "What color is a rose?", + "Red", + "What color is the sky?", + "Blue", + "What color is the sea?", + "Green", + ); + + # choose two of these questions, ordered at random, + # which will be printed in the problem. + $ml->choose(2); + + # print the question and answer choices + BEGIN_TEXT + Match the answers below with these questions: $BR + \{ $ml->print_q \} $BR + Answers: + \{ $ml->print_a \} + END_TEXT + + # register the correct answer + ANS($ml->ra_correct_ans); =head1 DESCRIPTION -Sample usage: - - - $ml = new_match_list(); - # enter three questions and their answers - $ml->qa( "What color is a rose?", - "Red", - "What color is the sky?", - "Blue", - "What color is the sea?", - "Green" - ); - # choose two of these questions, ordered at random, - # which will be printed in the problem. - $ml->choose(2); - BEGIN_TEXT - Match the answers below with these questions:$BR - \\{$ml->print_q\\} $BR - Answers: - \\{$ml->print_a\\} - END_TEXT - - ANS( $ml->ra_correct_ans() ); - -=cut - - -=head2 Matching List macros - - -=head3 new_match_list - -Matching list object creation macro - -Usage: - - - $ml = new_match_list(); - -Which is short hand for the following direct call to Match - - $ml = new Match(random(1,2000,1), ~~&std_print_q, ~~&std_print_a); - - -Either call will create a matching list object in the variable $ml. -(I< Note: $ml cannot be a my variable if it is to be used within a BEGIN_TEXT/END_TEXT block.>) - -The first argument is the seed for the match list (choosen at random between 1 and 2000 in -the example above.). The next two arguments are references to the print subroutines -used to print the questions and the answers. -Other printing methods can be used instead of the standard ones. An -example of how to do this is demonstrated with -"pop_up_list_print_q" below. - -=head4 std_print_q - -Standard method for formatting a list of questions with answer blanks. - -This formatting routine is the default method for formatting the -way questions are printed -for each of the three sub-classes of "List.pm". It lists the questions vertically, numbering -them sequentially and providing an answer blank before each question. -C<std_print_q> checks which mode the user is trying to print the -questions from and returns the appropriately formatted string. - -The length of the answer blank can be set with C<$ml-> +There are two types of choice macros. The older versions are simple subroutines. +The newer versions involve the List class and its sub-classes and the use of +objects based on these classes. The list sub-classes are: -To replace the standard question formatting method with your own, use: +=over - $ml->rf_print_q(~~&my_question_format_method) +=item * -Your method should be a subroutine of the form C<my_question_format_method($self, @questions)> -and should return a string to be printed. The @questions array contains the -questions to be listed, while $self can be used to obtain extra information from -the object for formatting purposes. The variable C<$main::displayMode> contains the -current display mode. (See "MODES" for more details on display modes and -see "writing print methods for lists" for details on constructing formatting subroutines.) +B<Match>, which aids in setting up matching question and answer lists, +=item * -=head4 std_print_a +B<Select>, which aids in selecting and presenting a subset of questions with short +answers (e.g. true/false questions) from a larger question set, and -Standard method for formatting a list of answers. +=item * -This simple formatting routine is the default method for formatting -the answers for matching lists. It lists the answers vertically -lettered sequentially. - -To replace the standard answer formatting method with your own subroutine use: - - $ml->rf_print_q(~~&my_answer_format_method) - -The answer formatting method has the same interface as the question formatting -method. - - -=head2 Select List macros - - -=head3 new_select_list - -Select list object creation macro - -Usage: - - $sl = new_select_list; - -Which is equivalent to this direct call to Select - - $sl = new Select(random(1,2000,1), ~~&std_print_q, ~~&std_print_a); - - -Either call will create a select list object in the variable $sl. ( Note that -$sl cannot be a my variable if it is to be used within a BEGIN_TEXT/END_TEXT -block.) The printing methods are the same as those defined for C<new_match_list> -above. -See the documentation for "Select.pm" to see how to use this -object to create a true/false question. - -std_print_a is only intended to be used for debugging with select lists, as there is rarely a reason to -print out the answers to a select list. - - -=head3 new_pop_up_select_list - - - -Usage: - - $sl = new_pop_up_select_list;</I></PRE> - -Which is equivalent to this direct call to Select - - $sl = new Select(random(1,2000,1), ~~&pop_up_list_print_q, ~~&std_print_a); - - -Either call will create a select list object in the variable $sl. ( Note that -$sl cannot be a my variable if it is to be used within a BEGIN_TEXT/END_TEXT -block.) The printing methods are passed as references (~~ in PG equals \ in -perl) to subroutines so that no matter what printing subroutines are used, -those subroutines can be used by saying $sl->print_q and $sl->print_a. This -also means that other subroutines can be used instead of the default ones. +B<Multiple>, which aids in setting up a standard one-question-many-answers multiple +choice question. -See the documentation for <a href='Select'>Select.pm</a> to see how to use this - object to create a true/false question. +=back +=cut -=head4 std_print_q +# ^uses be_strict +BEGIN{ + be_strict; +} -Standard method for printing questions with answer boxes +package main; -See std_print_q under Matching Lists above. +BEGIN { + be_strict(); +} -=head4 pop_up_list_print_q +# ^function _PGchoicemacros_init -Alternate method for print questions with pop up lists. +sub _PGchoicemacros_init{ +} -Usage: +=head1 MACROS -This printing routine is used to print the questions for a true/false or other -select list with a preceding pop up list of possible answers. A list of values -and labels need to be given to the pop_up_list so that the intended answer is -returned when a student selects an answer form the list. Notethe use of => to -associate the values on the left with the labels on the right, this means that, -for instance, the student will see the word True in the pop_up_list but the -answer that is returned to the grader is T, so that it corresponds with what -the professor typed in as the answer when using $sl->qa('blah blah', 'T'); +=cut -=for html - <PRE> - <I>$sl->ra_pop_up_list([</I>value<I> => </I>label<I>, - T => 'True', - F => 'False']);</I></PRE> +################################################################################ +=head2 Match lists -=head4 std_print_a +=over -This is only intended to be used for debugging as there is rarely a reason to -print out the answers to a select list. +=item new_match_list -See std_print_a under Matching Lists above. + $ml = new_match_list(); +new_match_list() creates a new Match object and initializes it with sensible +defaults. It is equivalent to: -=head2 Multiple Choice macros + $ml = new Match(random(1,2000,1), ~~&std_print_q, ~~&std_print_a); +The first argument is the seed for the match list (choosen at random between 1 +and 2000 in the example above). The next two arguments are references to the +print subroutines used to print the questions and the answers. Other printing +methods can be used instead of the standard ones. An example of how to do this +is demonstrated with pop_up_list_print_q() below. -=head3 new_multiple_choice +=cut -Multiple choice object creation macro +# ^function new_match_list +# ^uses Match::new +# ^uses &std_print_q +# ^uses &std_print_a -Usage: +sub new_match_list { + new Match(random(1,2000,1), \&std_print_q, \&std_print_a); +} -=for html - <PRE> - <I>$mc = new_multiple_choice;</I></PRE> +=back -Which is equivalent to this direct call to Multiple +=cut -=for html - <PRE> - <I>$mc = new Multiple(random(1,2000,1), ~~&std_print_q, ~~&std_print_a);</I></PRE> +################################################################################ -Either call will create a multiple choice object in the variable $mc. Note that -$mc cannot be a my variable if it is to be used within a BEGIN_TEXT/END_TEXT -block. +=head2 Select lists -=for html - <P>See the documentation for <a href='Multiple'>Multiple.pm</a> to see how to use - this object to create a multiple choice question. +=over +=item new_select_list -=head4 std_print_q + $sl = new_select_list(); -Standard method for printing questions +new_select_list() creates a new Select object and initializes it with sensible +defaults. It is equivalent to: -See std_print_q under Matching Lists above. + $sl = new Select(random(1,2000,1), ~~&std_print_q, ~~&std_print_a); +The parameters to the Select constructor are the same as those for the Match +constrcutor described above under new_match_list(). -=head4 radio_print_a +See the documentation for the Select class to see how to use this object to +create a true/false question. -Method for printing answers with radio buttons +std_print_a is only intended to be used for debugging with select lists, as +there is rarely a reason to print out the answers to a select list. -This simple printing routine is used to print the answers to multiple choice -questions in a bulleted style with radio buttons preceding each possible answer. -When a multiple choice object is created, a reference to radio_print_a is passed -to that object so that it can be used from within the object later. +=cut -radio_print_a checks which mode the user is trying to print the answers from and -returns the appropriately formatted string. +# ^function new_select_list +# ^uses Select::new +# ^uses &std_print_q +# ^uses &std_print_a +sub new_select_list { + new Select(random(1,2000,1), \&std_print_q, \&std_print_a); +} -=head3 new_checkbox_multiple_choice +=item new_pop_up_select_list() -Checkbox multiple choice object creation macro + $sl = new_pop_up_select_list(); -Usage: +new_popup_select_list() creates a new Select object and initializes it such that +it will render as a popup list. It is equivalent to: -=for html - <PRE> - <I>$cmc = new_checkbox_multiple_choice;</I></PRE> + $selectlist = new Select(random(1,2000,1), ~~&pop_up_list_print_q, ~~&std_print_a); -Which is equivalent to this direct call to Multiple +=cut -=for html - <PRE> - <I>$cmc = new Multiple(random(1,2000,1), ~~&std_print_q, ~~&checkbox_print_a);</I></PRE> +# ^function new_pop_up_select_list +# ^uses Select::new +# ^uses &pop_up_list_print_q +# ^uses &std_print_a -Either call will create a checkbox multiple choice object in the variable $cmc. Note that -$cmc cannot be a my variable if it is to be used within a BEGIN_TEXT/END_TEXT -block. +sub new_pop_up_select_list { + new Select(random(1,2000,1), \&pop_up_list_print_q, \&std_print_a); +} -=for html - <P>See the documentation for <a href='Multiple'>Multiple.pm</a> to see how to use - this object to create a multiple choice question. +=back +=cut -=head4 std_print_q +################################################################################ -Standard method for printing questions +=head2 Multiple choice quesitons -See std_print_q under Matching Lists above. +=over +=item new_multiple_choice() -=head4 checkbox_print_a + $mc = new_multiple_choice(); -Method for printing answers with radio buttons +new_multiple_choice() creates a new Multiple object that presents a question and +a number possible answers, only one of which can be chosen. It is equivalent to: -This simple printing routine is used to print the answers to multiple choice -questions in a bulleted style with checkboxes preceding each possible answer. -When a multiple choice object is created, a reference to checkbox_print_a is passed -to that object so that it can be used from within the object later. + $mc = new Multiple(random(1,2000,1), ~~&std_print_q, ~~&radio_print_a); -checkbox_print_a checks which mode the user is trying to print the answers from and -returns the appropriately formatted string. +The parameters to the Multiple constructor are the same as those for the Match +constrcutor described above under new_match_list(). +=cut +# ^function new_multiple_choice +# ^uses Multiple::new +# ^uses &std_print_q +# ^uses &radio_print_a -=cut -BEGIN { - be_strict(); -} -sub _PGchoicemacros_init{ +sub new_multiple_choice { + new Multiple(random(1,2000,1), \&std_print_q, \&radio_print_a); } -=head4 new_match_list +=item new_checkbox_multiple_choice() - Usage: $ml = new_match_list(); + $mc = new_checkbox_multiple_choice(); +new_checkbox_multiple_choice() creates a new Multiple object that presents a +question and a number possible answers, any number of which can be chosen. It is +equivalent to: -Note that $ml cannot be a my variable if used within a BEGIN_TEXT/END_TEXT block + $mc = new Multiple(random(1,2000,1), ~~&std_print_q, ~~&checkbox_print_a); =cut -sub new_match_list { - new Match(random(1,2000,1), \&std_print_q, \&std_print_a); +# ^function new_checkbox_multiple_choice +# ^uses Multiple::new +# ^uses &std_print_q +# ^uses &checkbox_print_a +sub new_checkbox_multiple_choice { + new Multiple(random(1,2000,1), \&std_print_q, \&checkbox_print_a); } -=head4 new_select_list - sage: $sl = new_select_list(); - -Note that $sl cannot be a my variable if used within a BEGIN_TEXT/END_TEXT block +=back =cut -sub new_select_list { - new Select(random(1,2000,1), \&std_print_q, \&std_print_a); -} - -=head4 new_pop_up_select_list; +################################################################################ - Usage: $pusl = new_pop_up_select_list(); +=head2 Question printing subroutines -=cut +=over -sub new_pop_up_select_list { - new Select(random(1,2000,1), \&pop_up_list_print_q, \&std_print_a); -} +=item std_print_q() -=head4 new_multiple_choice + # $list can be a matching list, a select list, or a multiple choice list + $list->rf_print_q(~~&std_print_q); + TEXT($list->print_q); - Usage: $mc = new_multiple_choice(); +This formatting routine is the default method for formatting the way questions +are printed for each of the three List sub-classes. It lists the questions +vertically, numbering them sequentially and providing an answer blank before +each question. std_print_q() checks which mode the user is trying to print the +questions from and returns the appropriately formatted string. =cut -sub new_multiple_choice { - new Multiple(random(1,2000,1), \&std_print_q, \&radio_print_a); -} +# ^function std_print_q -=head4 new_checkbox_multiple_choice +sub std_print_q { + my $self = shift; + my (@questions) = @_; + my $length = $self->{ans_rule_len}; + my $out = ""; + #if ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth') { + if ($main::displayMode =~ /^HTML/) { + my $i=1; my $quest; $out = "\n<P>\n"; + foreach $quest (@questions) { + $out.= ans_rule($length) . " <B>$i.</B> $quest<BR>"; + $i++; + } + } elsif ($main::displayMode eq 'Latex2HTML') { + my $i=1; my $quest; $out = "\\par\n"; + foreach $quest (@questions) { + $out.= ans_rule($length) . "\\begin{rawhtml}<B>$i. </B>\\end{rawhtml} $quest\\begin{rawhtml}<BR>\\end{rawhtml}\n"; + $i++; + } + } elsif ($main::displayMode eq 'TeX') { + $out = "\n\\par\\begin{enumerate}\n"; + my $i=1; my $quest; + foreach $quest (@questions) { + $out .= "\\item[" . ans_rule($length) . "$i.] $quest\n"; + $i++; + } + $out .= "\\end{enumerate}\n"; + } else { + $out = "Error: PGchoicemacros: std_print_q: Unknown displayMode: $main::displayMode.\n"; + } + $out; - Usage: $mcc = new_checkbox_multiple_choice(); +} -=cut +=item pop_up_list_print_q() -sub new_checkbox_multiple_choice { - new Multiple(random(1,2000,1), \&std_print_q, \&checkbox_print_a); -} + $sl->rf_print_q(~~&pop_up_list_print_q); + $sl->ra_pop_up_list([T => 'True', F => 'False']); + TEXT($sl->print_q); -=head4 initializing a pop_up_list +Alternate method for print questions with pop up lists. - Usage: $sl->rf_print_a(~~&pop_up_list_print_q); - $sl->ra_pop_up_list([</I>value<I> => </I>label<I>, T => 'True', F => 'False']); +This printing routine is used to print the questions for a true/false or other +select list with a preceding pop up list of possible answers. A list of values +and labels need to be given to the pop_up_list so that the intended answer is +returned when a student selects an answer form the list. Note the use of => in +the example above to associate the values on the left with the labels on the +right, this means that, for instance, the student will see the word True in the +pop_up_list but the answer that is returned to the grader is T, so that it +corresponds with what the professor typed in as the answer when using +$sl->qa('blah blah', 'T'); =cut + +# ^function pop_up_list_print_q + sub pop_up_list_print_q { my $self = shift; my (@questions) = @_; @@ -413,22 +364,23 @@ } -# For graphs in a matching question. -#sub format_graphs { -# my $self = shift; -# my @in = @_; -# my $out = ""; -# while (@in) { -# $out .= shift(@in). "#" ; -# } -# $out; -#} +=item quest_first_pop_up_list_print_q() + $sl->rf_print_q(~~&quest_first_pop_up_list_print_q); + $sl->ra_pop_up_list([T => 'True', F => 'False']); + TEXT($sl->print_q); + +Similar to pop_up_list_print_q(), but places the popup list after the question +text in the output. + +=cut # To put pop-up-list at the end of a question. # contributed by Mark Schmitt 3-6-03 +# ^function quest_first_pop_up_list_print_q + sub quest_first_pop_up_list_print_q { my $self = shift; my (@questions) = @_; @@ -467,9 +419,24 @@ $out; } + +=item ans_in_middle_pop_up_list_print_q() + + $sl->rf_print_q(~~&ans_in_middle_pop_up_list_print_q); + $sl->ra_pop_up_list([T => 'True', F => 'False']); + TEXT($sl->print_q); + +Similar to quest_first_pop_up_list_print_q(), except that no linebreaks are +printed between questions, allowing for the popup list to be placed in the +middle of the text of a problem. + +=cut + # To put pop-up-list in the middle of a question. # contributed by Mark Schmitt 3-6-03 +# ^function ans_in_middle_pop_up_list_print_q + sub ans_in_middle_pop_up_list_print_q { my $self = shift; my (@questions) = @_; @@ -509,10 +476,18 @@ } +=item units_list_print_q + +A simple popup question printer. No question text is printed, instead the +pop_up_list contents only are printed as a popup menu. + +=cut # Units for physics class # contributed by Mark Schmitt 3-6-03 +# ^function units_list_print_q + sub units_list_print_q { my $self = shift; my (@questions) = @_; @@ -525,7 +500,29 @@ $out; } +=back + +=cut + +################################################################################ + +=head2 Answer printing subroutines + +=over + +=item std_print_a + + # $list can be a matching list, a select list, or a multiple choice list + $list->rf_print_a(~~&std_print_a); + TEXT($list->print_a); + +This simple formatting routine is the default method for formatting the answers +for matching lists. It lists the answers vertically lettered sequentially. + +=cut + #Standard method of printing answers in a matching list +# ^function std_print_a sub std_print_a { my $self = shift; my(@array) = @_; @@ -560,10 +557,26 @@ } +=item radio_print_a() + + # $list can be a matching list, a select list, or a multiple choice list + $list->rf_print_q(~~&radio_print_q); + TEXT($list->print_q); + +This simple printing routine is used to print the answers to multiple choice +questions in a bulleted style with radio buttons preceding each possible answer. +When a multiple choice object is created, a reference to radio_print_a is passed +to that object so that it can be used from within the object later. +radio_print_a checks which mode the user is trying to print the answers from and +returns the appropriately formatted string. +=cut #Alternate method of printing answers as a list of radio buttons for multiple choice +#Method for naming radio buttons is no longer round about and hackish + +# ^function radio_print_a sub radio_print_a { my $self = shift; my (@answers) = @_; @@ -603,8 +616,25 @@ } -#Second alternate method of printing answers as a list of radio buttons for multiple choice -#Method for naming radio buttons is no longer round about and hackish +=item checkbox_print_a() + + # $list can be a matching list, a select list, or a multiple choice list + $list->rf_print_q(~~&radio_print_q); + TEXT($list->print_q); + +This simple printing routine is used to print the answers to multiple choice +questions in a bulleted style with checkboxe... [truncated message content] |
From: Mike G. v. a. <we...@ma...> - 2008-06-24 00:05:12
|
Log Message: ----------- - [ ] pg - [ ] lib - [ ] Value - [ ] inheritance improvements The make() method now inherits all the settings of the parent object, so that flags set by the user (e.g., tolerances, periods, and so on) will be passed on as new objects are created. For example, in $x = Real(1)=>with(tolerance=>.0001); $y = sin($x); $y will also have tolerance set to .0001. This also applies to binary operations, where the result will now inherit all the values of either operand, with the left-hand operand taking precedence when they both have a flag set but to different values. This is a significant change, and there may be unforeseen side effects that I'll have to take care of as they appear. It passes my test suite, however, so I'm hoping they will be limited. - [ ] AnswerChecker.pm - [ ] allow diagonostics to work for Complex types - [ ] equivalent wrong answer message is now part of Formula->cmp - [ ] bug fixes - [ ] Complex.pm - [ ] inheritance - [ ] Context.pm - [ ] point context no longer includes vector operations - [ ] error message methods Allow conversion of error messages after the value substitution has been performed. Also provide a subroutine to do more complex conversion of error messages: Context()->{error}{convert} = sub { my $message = shift; ... manipulate message ... return $message; } - [ ] Formula.pm - [ ] 1.59 fixed memory leak. - [ ] bug fixes - [ ] Infinity.pm - [ ] bug fixes - [ ] Interval.pm - [ ] generalize input Allow interval data to be given in more forms (eg, (a,b,"(",")") in addition to ("(",a,b,")"), since that is the order that the value() method returns the data.) - [ ] bug fixes - [ ] List.pm bug fixes - [ ] Matrix.pm - [ ] inheritance - [ ] Point.pm - [ ] inheritance - [ ] Real.pm - [ ] inheritance - [ ] Set.pm - [ ] bug fixes - [ ] improved error reporting - [ ] String.pm - [ ] Union.pm - [ ] improved error reporting - [ ] Vectorpm - [ ] inheritance - [ ] ijkAnyDimension Make vectors that are creates using ijk notation remain in ijk notation when displayed. (This is easy now that objects produced by combining others inherit the parent objects' flags.) Added another context flag (ijkAnyDimension) that controls whether vectors in ijk notation will conform to whatever dimension is used by the vector they are being compared to. When set, i+2*j will equal <1,2> even though i and j are vectors in 3-space. The value of ijkAnyDimension is 1 by default. This eliminates the need for the Vector2D context. - [ ] WeBWorK - [ ] Translator.pm bug and security fixes - [ ] Parser memory leak Formula objects and Context objects contain reference loops, which prevent them from being freed properly by perl when they are no longer needed. This is a source of an important memory leak in WeBWorK. The problem has been fixed by using Scalar::Util::weaken for these recursive references, so these objects can be freed properly when they go out of scope. This should cause an improvement in the memory usage of the httpd child processes. - [ ] Context.pm point to name attribute - [ ] Differentian.pm improved differentiation of log() and abs() - [ ] bug fixes - [ ] operator // provides in line fractions in TeX form a//b is in-line - [ ] BOP-bug fixes - [ ] Context - bug fixes - [ ] Function - - [ ] numeric2.pm In the past, Formula objects included a pointer to the Context in which the object was created, but other MathObject did not. This update is the first round of updates to include the context in the other MathObjects, but more work needs to be done. - [ ] Legacy - [ ] NumberWithUnits.pm Has this been replaced??? Fixed a problem where Real's were being promoted to NumberWithReals during the numeric comparison (when units should be ignored). This error was a result of the changes made this summer. [This class should probably be redesigned to implement the overloaded operators and, in particular, handle the equality check in compare() rather than an over-ridden cmp_parse. That would make it possible to manipulate numbers-with-units via perl code in a natural way, just like all the other MathObjects.] - [ ] List - [ ] UOP --bug fixes - [ ] Applet - [ ] Fraction.pm - [ ] List.pm - [ ] Parser.pm - [ ] Units.pm - [ ] Value.pm - [ ] VectorField.pm - [ ] macros - [ ] PGchoicemacros.pl - [ ] PGinfo.pl - [ ] compoundProblem.pl - [ ] contextPiecewiseFunction.pl - [ ] parserAssignment.pl - [ ] PGstringevaluators - [ ] contextInequalities - [ ] PGbasicmacros.pl - [ ] PGfunctionevaluators.pl - [ ] AppletObjects.pl - [ ] parserFormulaUpToConstant.pl - [ ] parserRadioButtons.pl - [ ] dangerousMacros.pl Fix loadMacros() and alias() so that they find auxiliary files even when the .pg file is in templates/tmpEdit. The Library Browser has a bad interaction with browser image caches if it displays two .pg files with fixed .gif files that have the same name (this happens in several of the setMV* files, for example setMVlevelsets/levels-1/levels-1.pg and setMVlevelsets/levels-2/levels-2.pg). This fixes the problem by including a portion of the file name in the name of the gif file to (help) make it unique. - [ ] extraAnswerEvaluators.pl Modifications to pass answer label for previous answer. This still does not provide correct functionality because the previous answer is an equation of the form lhs = rhs while the form being passed to fun_cmp is lhs - rhs - [ ] MultiAnswer.pl (renamed from MultiPart) -- point to features - [ ] contextCurrency.pl -- new - [ ] PGnumericevaluators.pl -- new - [ ] PGmiscevaluators.pl -- new - [ ] PGtextevaluators.pl -- new - [ ] contextLimitedPolynomial.pl -- point to features - [ ] PGgraphmacros.pl Changed plot_functions so that it uses the Formula MathObject to parse the the function in $f1 = qq! x^2 - 3*x + 45 for x in [0, 45) using color:red and weight:2! instead of using the built in perl parser. This allows things such as $formula=Formula("|x|"); $f1 = qq! $formula for x in [0, 45) using color:red and weight:2! to be evaluated. There should be no apparent change to old problems since the Formula MathObject parser handles a superset of the builtin perl parser syntax. -- some conflicts with old matrix types. - [ ] displayMacros.pl --- remove???? -- only used in webwork 1.9 - [ ] problemPreserveAnswers.pl This is a temporary hack that allows sticky answers to preserve all the characters the student typed. PGbasicmacros.pl currently removes several characters, including $, which is needed for monitary answers. Eventually, PGbasicmacros.pl should be fixed, but for now this will work, and it should not cause trouble after PGbasicmacros.pl is fixed. In the end, this file can be emptied, then it should issue a warning message, and finally it can be removed. The hack is to copy the inputs_ref and modify the answers so that the PGbasicmacros.pl macros will not remove those characters (the key is to convert them to HTML entities instead). Then after the problem has been processed, we put the original answers back so that the answer checkers will work properly on them. This is accomplished by replacing ENDDOCUMENT with a new routine that first puts back the answers and then calls the old ENDDOCUMENT. This has the unwanted side effect of putting error messages into the error log, but I can't seem to work around that. - [ ] problemRandomize.pl -- new Had a typo: answer_submitted should have been answers_submitted, but it turns out that this is ALWAYS set, even when answers AREN'T submitted, so I had to look for the individual buttons instead. This might break if someone adds more buttons, but it works for now. - [ ] answerHints.pl -- new Use alternative method of testing if whether two objects are the same (without causing them to stringify first). [Technically, this should call Value::address, the renamed version of Value::Ref, but I didn't want the AIM participants to have to update to the latests version of MathObjects to be able to use this.] Revision 1.1 / (view) - annotate - [select for diffs] , Wed Aug 15 02:58:26 2007 UTC (10 months, 1 week ago) by dpvc Branch: MAIN This file implements a postfilter for AnswerEvaluators that allows you to specify answer hint messages to use when specific answers or sets of answers are given by the student. You can use specific constants or a perl subroutine to determine which answers to respond to. You can also specify a score to use when the answers are triggered, and whether to replace existing messages or not. See the comments in the file for more details. - [ ] answerVariableList.pl -- point to features - [ ] contextLimitedPowers.pl -- point to features Updated to allow more flexibility in controlling the range of powers to be allowed (as per John Jones' suggestion). Also changed the way that you request the changes: you now make a function call rather than modify the operators list directly yourself. (The old way is still provided, however, for backward compatibility.) See the comments in the file for more details. - [ ] contextScientificNotation -- new Use new feature to make Real() create ScientificNotation objects. -- fix e vs. E used by perl-- safe compartment troubles? - [ ] contextString.pl - [ ] bug fixes - [ ] parserAutoStrings.pl -- new - [ ] parserFunction.pl -- point to features - [ ] parserMultipart.pl -- remove???? - [ ] doc Tags: ---- rel-2-4-dev Modified Files: -------------- pg/lib: Value.pm Revision Data ------------- Index: Value.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value.pm,v retrieving revision 1.53.2.2 retrieving revision 1.53.2.3 diff -Llib/Value.pm -Llib/Value.pm -u -r1.53.2.2 -r1.53.2.3 --- lib/Value.pm +++ lib/Value.pm @@ -16,6 +16,7 @@ like equality are "fuzzy", meaning that two items are equal when they are "close enough" (by tolerances that are set in the current Context). + =cut |