Update of /cvsroot/aimmath/AIM/WEB-INF/maple/aim
In directory sc8-pr-cvs1:/tmp/cvs-serv10431/WEB-INF/maple/aim
Modified Files:
Tag: windows
Compile.mpl MultiQuestion.mpl Student.mpl Util.mpl Zone.mpl
Log Message:
merged from head
Index: Compile.mpl
===================================================================
RCS file: /cvsroot/aimmath/AIM/WEB-INF/maple/aim/Compile.mpl,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -C2 -d -r1.3 -r1.3.2.1
*** Compile.mpl 25 Aug 2003 21:47:19 -0000 1.3
--- Compile.mpl 27 Aug 2003 06:55:16 -0000 1.3.2.1
***************
*** 171,175 ****
then instead the procedure returns an error report in the format
described under #`aim/Compile/ErrorReport`#. If supplied,
! the optional argument @nam_@ is used to set the question name.
",
proc(lines::list(list(string)),
--- 171,177 ----
then instead the procedure returns an error report in the format
described under #`aim/Compile/ErrorReport`#. If supplied,
! the optional arguments @nam_@, @level_@ and @partlabel_@ are used to set
! the name, level (in terms of nesting of subquestions) and part label
! of the question.
",
proc(lines::list(list(string)),
***************
*** 346,349 ****
--- 348,354 ----
##########
elif `Util/StartsWith`(flag,"<") then
+ # lines like <foo> bar are parameter assignments rather
+ # than ordinary flags.
+
# any assignment to a parameter after the first is ignored
if not assigned(params[flag]) then
***************
*** 630,691 ****
fi;
! mproc := eval(x[1]);
!
! # At this point, mproc is a function like f(ans). The following block
! # of code converts it to the function g(attempt,ans) = f(ans). Later
! # blocks will modify g so that it no longer ignores the first argument.
! err :=
! traperror(
! codegen[swapargs](
! codegen[makeparam](attempt,mproc), 1 = 2));
! if err = lasterror then
! RETURN([
! cat(
! __("Error while manipulating marking procedure:"),
! "\n<br/>\n",`HTML/Escape`(lasterr),"\n<br/>\n",
! "mproc = \n",
! "<pre>\n",`HTML/Escape`(sprintf("%a",mproc)),"\n</pre>\n"),
! nam,0,lines]);
! else
! mproc := eval(err);
! fi;
!
! # The mproc function will typically contain calls to printf(),
! # `aim/t` and so on, to 'print' feedback strings to be shown to
! # the student. The next block of code modifies mproc so that the
! # strings are captured in attempt['Feedback'] or
! # attempt['AnswerNote'] rather than being printed immediately.
! mproctext := sprintf("%a",eval(mproc));
! mproctext :=
! `aim/Compile/RedirectOutput`("attempt['Feedback']",mproctext);
! mproctext :=
! `aim/Compile/Replace`(
! "`aim/SetAnswerNote`(" = "`aim/SetAnswerNote`(attempt,",
! "`aim/SetInvalid`(" = "`aim/SetInvalid`(attempt,",
! mproctext);
!
! y := traperror(`Util/Parse`(mproctext,err,0));
!
! if err <> NULL then
! RETURN([
! cat(
! __("Problem while reparsing marking procedure:"),
! "\n<br/>\n",err[1],
! "\n<pre>\n",err[3],"\n</pre>\n"),
! nam,0,lines]);
! else
! mproc := eval(y);
! fi;
!
! # At this point, the function mproc expects two arguments (attempt
! # and ans) and returns the appropriate raw mark. We next modify it
! # so that it only needs one argument (called attempt), it takes ans
! # to be attempt['Answer'], and it inserts the raw mark in the
! # attempt['RawAnswer'] field.
! question['MProc'] :=
! subs(MPROC_ = eval(mproc),
! proc(attempt::`aim/Question/Attempt`)
! attempt['RawMark'] := MPROC_(attempt,attempt['Answer']);
! end);
setans :=
--- 635,639 ----
fi;
! mproc := `aim/Compile/ModifyMPROC`(eval(x[1]));
setans :=
***************
*** 795,800 ****
# global Maple variables. This is necessary so that the values set
# up by iproc are available when mproc is called.
! err :=
! traperror(codegen[makeglobal](map((s) -> convert(s,name),aimlocals),iproc));
if err = lasterror then
--- 743,747 ----
# global Maple variables. This is necessary so that the values set
# up by iproc are available when mproc is called.
! err := `aim/Compile/MakeGlobal`(aimlocals,iproc);
if err = lasterror then
***************
*** 810,815 ****
fi;
! err :=
! traperror(codegen[makeglobal](map((s) -> convert(s,name),aimlocals),sproc));
if err = lasterror then
--- 757,761 ----
fi;
! err := `aim/Compile/MakeGlobal`(aimlocals,sproc);
if err = lasterror then
***************
*** 1185,1190 ****
# global Maple variables. This is necessary so that the values set
# up by iproc are available when mproc is called.
! err :=
! traperror(codegen[makeglobal](map((s) -> convert(s,name),aimlocals),iproc));
if err = lasterror then
--- 1131,1135 ----
# global Maple variables. This is necessary so that the values set
# up by iproc are available when mproc is called.
! err := `aim/Compile/MakeGlobal`(aimlocals,iproc);
if err = lasterror then
***************
*** 1273,1276 ****
--- 1218,1225 ----
done for the functions @print@, @lprint@, @`aim/t`@ and @`aim/p`@ as
well as @printf@.
+
+ Note that this function operates on strings. The function
+ @`aim/Compile/ConvertMPROC/Aux1`@ contains code that performs a
+ similar function, but operates on inert procedures.
",
proc(var::string,s::string)
***************
*** 1572,1575 ****
--- 1521,1891 ----
od;
od;
+ end
+ ):
+
+ `Package/Assign`(
+ `aim/Compile/VarName`::string,
+ "The argument @x@ is expected to be of the form
+ @_Inert_NAME(s)@ or @_Inert_ASSIGNEDNAME(s,...)@ or
+ @_Inert_DCOLON(_Inert_NAME(s),...)@ or
+ @_Inert_DCOLON(_Inert_ASSIGNEDNAME(s),...)@. The function
+ returns the string @s@.
+ ",
+ proc(x)
+ local y;
+ if type(x,function) then
+ if op(0,x) = _Inert_NAME then
+ return(op(1,x));
+ elif op(0,x) = _Inert_ASSIGNEDNAME then
+ return(op(1,x));
+ elif op(0,x) = _Inert_DCOLON then
+ y := op(1,x);
+ if op(0,y) = _Inert_NAME then
+ return(op(1,y));
+ elif op(0,y) = _Inert_ASSIGNEDNAME then
+ return(op(1,y));
+ fi;
+ fi;
+ fi;
+ error("Argument of unexpected form");
+ end
+ ):
+
+ `Package/Assign`(
+ `aim/Compile/ConvertMPROC`,
+ "This function accepts a marking procedure @f@ supplied
+ in an @s>/answertest>@ flag, and applies the
+ following transformations:
+ <ul>
+ <li>The procedure @f@ originally accepts a single argument,
+ containing the student's parsed and evaluated answer.
+ It is converted to accept a single argument (called
+ @attempt@) of type @`aim/Question/[Short]Attempt`@,
+ and to extract the answer from the field
+ @attempt['Answer']@.
+ </li>
+ <li>Any calls to printing functions (@print@, @lprint@,
+ @printf@, @`aim/t`@ and @`aim/p`@) are converted to
+ append their output to @attempt['Feedback']@ rather
+ than sending it to standard output.
+ </li>
+ <li>Any calls to @`aim/SetAnswerNote`@ or @`aim/SetInvalid`@
+ are converted by inserting @attempt@ as the first argument.
+ </li>
+ <li>Whatever would previously have been the return value of
+ @f@ is assigned to @attempt['RawMark']@. The modified
+ function returns @NULL@ instead.
+ </li>
+ </ul>
+ ",
+ proc(f)
+ local f_inert,params,locals,optseq,remtab,
+ stats,desc,globals,lexseq,param;
+
+ f_inert := ToInert(eval(f));
+
+ if not(type(f_inert,function) and
+ op(0,f_inert) = _Inert_PROC) then
+ error("Argument is not a procedure");
+ fi;
+
+ params := op(1,f_inert);
+ locals := op(2,f_inert);
+ optseq := op(3,f_inert);
+ remtab := op(4,f_inert);
+ stats := op(5,f_inert);
+ desc := op(6,f_inert);
+ globals := op(7,f_inert);
+ lexseq := op(8,f_inert);
+
+ if nops(params) = 0 then
+ error("Argument is a procedure with no parameters");
+ elif nops(params) > 1 then
+ error("Argument is a procedure with more than one parameter");
+ fi;
+
+ # Now change the parameter to a local variable.
+ # (It should not be possible for this to cause a name conflict,
+ # as it is already forbidden for parameters to have the same
+ # names as local variables.)
+ param := `aim/Compile/VarName`(op(1,params));
+ locals :=
+ _Inert_LOCALSEQ(op(locals),op(params));
+ stats := `aim/Compile/ConvertMPROC/Aux0`(stats,nops(locals));
+ stats := `aim/Compile/ConvertMPROC/Aux1`(stats);
+
+ params :=
+ _Inert_PARAMSEQ(_Inert_NAME("attempt"));
+
+ stats :=
+ _Inert_STATSEQ(
+ _Inert_ASSIGN(
+ _Inert_LOCAL(nops(locals)),
+ _Inert_TABLEREF(
+ _Inert_PARAM(1),
+ _Inert_EXPSEQ(
+ _Inert_UNEVAL(
+ _Inert_NAME("Answer"))))),
+ op(stats),
+ _Inert_ASSIGN(
+ _Inert_TABLEREF(
+ _Inert_PARAM(1),
+ _Inert_EXPSEQ(
+ _Inert_UNEVAL(_Inert_NAME("RawMark")))),
+ _Inert_NAME("%")),
+ _Inert_NAME("NULL"));
+
+ FromInert(
+ _Inert_PROC(
+ params,locals,optseq,_Inert_EXPSEQ(),stats,desc,globals,lexseq));
+ end
+ ):
+
+ `Package/Assign`(
+ `aim/Compile/ConvertMPROC/Aux0`,
+ "",
+ proc(x,p)
+ if x = _Inert_PARAM(1) then
+ return(_Inert_LOCAL(p));
+ elif type(x,function) then
+ if op(0,x) = _Inert_PROC then
+ return(x);
+ else
+ return(map(`aim/Compile/ConvertMPROC/Aux0`,x,p));
+ fi;
+ else
+ return(x);
+ fi;
+ end
+ ):
+
+ `Package/Assign`(
+ `aim/Compile/ConvertMPROC/Aux1`,
+ "",
+ proc(x)
+ local y,z;
+ global printfunctions;
+ if type(x,function) then
+ if op(0,x) = _Inert_FUNCTION then
+ y := op(1,x);
+ if type(y,function) and
+ member(op(0,y),{_Inert_NAME,_Inert_ASSIGNEDNAME}) then
+ z := op(1,y);
+ if type([printfunctions[z]],[string]) then
+ return(
+ _Inert_FUNCTION(
+ _Inert_ASSIGNEDNAME(printfunctions[z],"PROC"),
+ _Inert_EXPSEQ(
+ _Inert_TABLEREF(
+ _Inert_PARAM(1),
+ _Inert_EXPSEQ(
+ _Inert_UNEVAL(_Inert_NAME("Feedback")))),
+ op(op(2,x)))));
+ elif member(z,["aim/SetAnswerNote","aim/SetInvalid"]) then
+ return(
+ _Inert_FUNCTION(
+ _Inert_ASSIGNEDNAME(z,"PROC"),
+ _Inert_EXPSEQ(
+ _Inert_PARAM(1),
+ op(op(2,x)))));
+ elif z = "RETURN" then
+ return(
+ _Inert_ASSIGN(
+ _Inert_TABLEREF(
+ _Inert_PARAM(1),
+ _Inert_EXPSEQ(
+ _Inert_UNEVAL(_Inert_NAME("RawMark")))),
+ op(op(2,x))),
+ _Inert_RETURN(_Inert_NAME("NULL")));
+ fi;
+ fi;
+ elif op(0,x) = _Inert_RETURN then
+ return(
+ _Inert_ASSIGN(
+ _Inert_TABLEREF(
+ _Inert_PARAM(1),
+ _Inert_EXPSEQ(
+ _Inert_UNEVAL(_Inert_NAME("RawMark")))),
+ op(x)),
+ _Inert_RETURN(_Inert_NAME("NULL")));
+ fi;
+ return(map(`aim/Compile/ConvertMPROC/Aux1`,x));
+ fi;
+ return(x);
+ end
+ ):
+
+ `Package/Assign`(
+ `aim/Compile/PrintFunctions`,
+ "This table lists some functions that print to standard output,
+ and corresponding functions that append to a string instead.
+ ",
+ table([
+ "print" = "aim/printTo",
+ "lprint" = "aim/lprintTo",
+ "printf" = "aim/printfTo",
+ "aim/t" = "aim/tTo",
+ "aim/p" = "aim/pTo"
+ ])
+ ):
+
+ `Package/Assign`(
+ `aim/Compile/MakeGlobal`,
+ "This is a replacement for the buggy @codegen[makeglobal]@ function,
+ based on @ToInert@ rather than the deprecated @maple2intrep@ function.
+ The syntax is slightly different, in that the first argument must
+ be a list of strings, whereas @codegen[makeglobal]@ accepts a name or
+ a list of names.
+
+ The effect is to return a version of the procedure @f@ in which the
+ local variables named in @vars@ have been replaced by global variables
+ of the same name.
+ ",
+ proc(vars::list(string),f)
+ local f_inert,params,locals,optseq,remtab,stats,desc,
+ globals,lexseq,globalnames,newglobals,newlocals,
+ transtable,i,j,loc,nam;
+
+ f_inert := ToInert(eval(f));
+
+ if not(type(f_inert,function) and
+ op(0,f_inert) = _Inert_PROC) then
+ error("Second argument is not a procedure");
+ fi;
+
+ params := op(1,f_inert);
+ locals := op(2,f_inert);
+ optseq := op(3,f_inert);
+ remtab := op(4,f_inert);
+ stats := op(5,f_inert);
+ desc := op(6,f_inert);
+ globals := op(7,f_inert);
+ lexseq := op(8,f_inert);
+
+ globalnames := map(`aim/Compile/VarName`,[op(globals)]);
+
+ newglobals :=
+ _Inert_GLOBALSEQ(
+ op(globals),
+ op(map(_Inert_NAME,remove(member,vars,globalnames)))
+ );
+
+ transtable := table([]);
+ for i to nops(params) do
+ transtable[_Inert_PARAM(i)] := _Inert_PARAM(i);
+ od;
+
+ newlocals := NULL;
+
+ j := 0;
+ for i to nops(locals) do
+ loc := op(i,locals);
+ nam := `aim/Compile/VarName`(loc);
+ if member(nam,vars) then
+ transtable[_Inert_LOCAL(i)] := _Inert_NAME(nam);
+ else
+ j := j+1;
+ newlocals := newlocals,loc;
+ transtable[_Inert_LOCAL(i)] := _Inert_LOCAL(j);
+ fi;
+ od;
+
+ newlocals := _Inert_LOCALSEQ(newlocals);
+
+ stats := map(`aim/Compile/MakeGlobal/Aux`,stats,eval(transtable));
+
+ FromInert(_Inert_PROC(
+ params,newlocals,optseq,remtab,stats,desc,newglobals,lexseq));
+ end
+ ):
+
+ `Package/Assign`(
+ `aim/Compile/MakeGlobal/Aux`,
+ "This is an auxiliary function, designed for recursive invocation,
+ and called by @`aim/Compile/MakeGlobal`@.
+ ",
+ proc(x,t)
+ local params,locals,optseq,remtab,stats,desc,globals,lexseq,
+ transtable,i,j,a,b,c,newlexseq,lexpair,globalnames;
+
+ if type(x,function) then
+ if member(op(0,x), {_Inert_LOCAL,_Inert_PARAM,
+ _Inert_LEXICAL_LOCAL,_Inert_LEXICAL_PARAM}) then
+ return(t[x]);
+ elif op(0,x) = _Inert_PROC then
+ # This is the most complex case; a typical example comes from
+ # something like this:
+ #
+ # f := proc(x) local b,c; map((t) -> t+b+c,x); end;
+ # `aim/Compile/MakeGlobal`(["b"],f);
+ #
+ # The statement sequence for f contains a representation of
+ # the function (t) -> t+b; The lexical table for the inner
+ # function contains the information that b and c refer to
+ # local variables in the outer function. The main problem
+ # is to reconstruct this lexical table when we convert b
+ # to a global variable.
+
+ params := op(1,x);
+ locals := op(2,x);
+ optseq := op(3,x);
+ remtab := op(4,x);
+ stats := op(5,x);
+ desc := op(6,x);
+ globals := op(7,x);
+ lexseq := op(8,x);
+
+ transtable := table([]);
+ for i to nops(params) do
+ transtable[_Inert_PARAM(i)] := _Inert_PARAM(i);
+ od;
+ for i to nops(locals) do
+ transtable[_Inert_LOCAL(i)] := _Inert_LOCAL(i);
+ od;
+
+ globalnames := op(map(`aim/Compile/VarName`,globals));
+
+ newlexseq := NULL;
+ i := 0;
+ j := 0;
+ for lexpair in lexseq do
+ i := i+1;
+ a,b := op(lexpair);
+ c := t[b];
+ if type(c,function) and op(0,c) = _Inert_NAME then
+ # Here a variable in the inner function referred to one
+ # of the local variables in the outer function that are
+ # being globalized. The new lexical table should no longer
+ # mention this variable.
+
+ # In any given case, one of the next two assignments is needed,
+ # and the other is harmless. It would be a lot of work to decide
+ # which is which.
+ transtable[_Inert_LEXICAL_LOCAL(i)] := c;
+ transtable[_Inert_LEXICAL_PARAM(i)] := c;
+ globalnames := globalnames,op(1,c);
+ else
+ j := j+1;
+ transtable[_Inert_LEXICAL_LOCAL(i)] := _Inert_LEXICAL_LOCAL(j);
+ transtable[_Inert_LEXICAL_PARAM(i)] := _Inert_LEXICAL_PARAM(j);
+ newlexseq := newlexseq,_Inert_LEXICALPAIR(a,c);
+ fi;
+ od;
+
+ globalnames := op({globalnames});
+ globals := map(_Inert_NAME,_Inert_GLOBALSEQ(globalnames));
+ stats := map(`aim/Compile/MakeGlobal/Aux`,stats,eval(transtable));
+
+ return(
+ _Inert_PROC(
+ params,locals,optseq,remtab,stats,desc,globals,
+ _Inert_LEXICALSEQ(newlexseq)
+ ));
+ else
+ return(map(`aim/Compile/MakeGlobal/Aux`,x,eval(t)));
+ fi;
+ else
+ return(x);
+ fi;
end
):
Index: MultiQuestion.mpl
===================================================================
RCS file: /cvsroot/aimmath/AIM/WEB-INF/maple/aim/MultiQuestion.mpl,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -C2 -d -r1.2 -r1.2.2.1
*** MultiQuestion.mpl 25 Aug 2003 21:47:19 -0000 1.2
--- MultiQuestion.mpl 27 Aug 2003 06:55:16 -0000 1.2.2.1
***************
*** 44,48 ****
['Method','GetPart'::`aim/Question`,
! "",
proc(partlabel::string)
local l,m,n,subquestion;
--- 44,48 ----
['Method','GetPart'::`aim/Question`,
! "Return the subquestion with a given part label.",
proc(partlabel::string)
local l,m,n,subquestion;
***************
*** 69,73 ****
],
! ['Method','BadTrialPenalty'::numeric,"",
proc()
ERROR(__("The BadTrialPenalty field is not valid for multipart questions"));
--- 69,74 ----
],
! ['Method','BadTrialPenalty'::numeric,
! "The @BadTrialPenalty@ field is not valid for multipart questions",
proc()
ERROR(__("The BadTrialPenalty field is not valid for multipart questions"));
***************
*** 75,79 ****
],
! ['Method','VProc',"The VProc field is not valid for multipart questions",
proc()
ERROR(__("The VProc field is not valid for multipart questions"));
--- 76,80 ----
],
! ['Method','VProc',"The @VProc@ field is not valid for multipart questions",
proc()
ERROR(__("The VProc field is not valid for multipart questions"));
***************
*** 81,85 ****
],
! ['Method','MProc',"The MProc field is not valid for multipart questions",
proc()
ERROR(__("The MProc field is not valid for multipart questions"));
--- 82,86 ----
],
! ['Method','MProc',"The @MProc@ field is not valid for multipart questions",
proc()
ERROR(__("The MProc field is not valid for multipart questions"));
***************
*** 87,91 ****
],
! ['Method','AProc',"The AProc field is not valid for multipart questions",
proc()
ERROR(__("The AProc field is not valid for multipart questions"));
--- 88,92 ----
],
! ['Method','AProc',"The @AProc@ field is not valid for multipart questions",
proc()
ERROR(__("The AProc field is not valid for multipart questions"));
***************
*** 122,126 ****
proc(this,
#optional
! seed_::integer,toplabel_::string)
local vrsion;
--- 123,128 ----
proc(this,
#optional
! seed_::integer,
! toplabel_::string)
local vrsion;
***************
*** 281,285 ****
['Method','Validate',
! "The Validate method should not be invoked for a multipart question",
proc()
ERROR(__("The Validate method should not be invoked for a multipart question."));
--- 283,287 ----
['Method','Validate',
! "The @Validate@ method should not be invoked for a multipart question",
proc()
ERROR(__("The Validate method should not be invoked for a multipart question."));
***************
*** 288,292 ****
['Method','Mark',
! "The Mark method should not be invoked for a multipart question",
proc()
ERROR(__("The Mark method should not be invoked for a multipart question."));
--- 290,294 ----
['Method','Mark',
! "The @Mark@ method should not be invoked for a multipart question",
proc()
ERROR(__("The Mark method should not be invoked for a multipart question."));
***************
*** 295,299 ****
['Method','AdjustMark',
! "The AdjustMark method should not be invoked for a multipart question",
proc()
ERROR(__("The AdjustMark method should not be invoked for a multipart question."));
--- 297,301 ----
['Method','AdjustMark',
! "The @AdjustMark@ method should not be invoked for a multipart question",
proc()
ERROR(__("The AdjustMark method should not be invoked for a multipart question."));
Index: Student.mpl
===================================================================
RCS file: /cvsroot/aimmath/AIM/WEB-INF/maple/aim/Student.mpl,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -C2 -d -r1.3 -r1.3.2.1
*** Student.mpl 25 Aug 2003 21:47:19 -0000 1.3
--- Student.mpl 27 Aug 2003 06:55:16 -0000 1.3.2.1
***************
*** 187,191 ****
`if`(nargs > 1,
preamble_,
! __("Your ID and password for the Alice Interactive Mathematics system are as follows:"));
postamble :=
--- 187,191 ----
`if`(nargs > 1,
preamble_,
! __("Your ID and password for the AiM system are as follows:"));
postamble :=
Index: Util.mpl
===================================================================
RCS file: /cvsroot/aimmath/AIM/WEB-INF/maple/aim/Util.mpl,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -C2 -d -r1.3 -r1.3.2.1
*** Util.mpl 25 Aug 2003 21:47:19 -0000 1.3
--- Util.mpl 27 Aug 2003 06:55:16 -0000 1.3.2.1
***************
*** 25,29 ****
if nargs > 1 then url := cat(url,"#",target_); fi;
! cat("<a href='",url,"'>",linktext,"</a>");
end
):
--- 25,29 ----
if nargs > 1 then url := cat(url,"#",target_); fi;
! cat("<a href='",url,"' target='aim_help_window'>",linktext,"</a>");
end
):
Index: Zone.mpl
===================================================================
RCS file: /cvsroot/aimmath/AIM/WEB-INF/maple/aim/Zone.mpl,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -C2 -d -r1.3 -r1.3.2.1
*** Zone.mpl 25 Aug 2003 21:47:19 -0000 1.3
--- Zone.mpl 27 Aug 2003 06:55:16 -0000 1.3.2.1
***************
*** 339,343 ****
if not(`OS/FileExists`(zonehead)) then
fd := `OS/Fopen`(zonehead,'WRITE');
! fprintf(fd,"<h1>Alice Interactive Mathematics</h1>\n<br/>\n");
fclose(fd);
fi;
--- 339,344 ----
if not(`OS/FileExists`(zonehead)) then
fd := `OS/Fopen`(zonehead,'WRITE');
! fprintf(fd,"<img src=\"images/aim.gif\" align=\"absbottom\">
! <font size=\"+3\"><b> Assessment in Mathematics</b></font>\n<br/>\n");
fclose(fd);
fi;
***************
*** 354,361 ****
fd := `OS/Fopen`(adminhead,'WRITE');
fprintf(fd,
! "<h1>Alice Interactive Mathematics
! <br/>
! Administrator login page
! <h1>");
fclose(fd);
fi;
--- 355,362 ----
fd := `OS/Fopen`(adminhead,'WRITE');
fprintf(fd,
! "<img src=\"images/aim.gif\" align=\"absbottom\">
! <font size=\"+3\"><b> Assessment in Mathematics</b></font>\n
! <h1>Administrator login page</h1>
! ");
fclose(fd);
fi;
***************
*** 385,388 ****
EndPackage():
-
-
--- 386,387 ----
|